lkml.org 
[lkml]   [2017]   [Nov]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.13 13/44] packet: avoid panic in packet_getsockopt()
    Date
    4.13-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Eric Dumazet <edumazet@google.com>


    [ Upstream commit 509c7a1ecc8601f94ffba8a00889fefb239c00c6 ]

    syzkaller got crashes in packet_getsockopt() processing
    PACKET_ROLLOVER_STATS command while another thread was managing
    to change po->rollover

    Using RCU will fix this bug. We might later add proper RCU annotations
    for sparse sake.

    In v2: I replaced kfree(rollover) in fanout_add() to kfree_rcu()
    variant, as spotted by John.

    Fixes: a9b6391814d5 ("packet: rollover statistics")
    Signed-off-by: Eric Dumazet <edumazet@google.com>
    Cc: Willem de Bruijn <willemb@google.com>
    Cc: John Sperbeck <jsperbeck@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    net/packet/af_packet.c | 24 ++++++++++++++++--------
    1 file changed, 16 insertions(+), 8 deletions(-)

    --- a/net/packet/af_packet.c
    +++ b/net/packet/af_packet.c
    @@ -1771,7 +1771,7 @@ static int fanout_add(struct sock *sk, u

    out:
    if (err && rollover) {
    - kfree(rollover);
    + kfree_rcu(rollover, rcu);
    po->rollover = NULL;
    }
    mutex_unlock(&fanout_mutex);
    @@ -1798,8 +1798,10 @@ static struct packet_fanout *fanout_rele
    else
    f = NULL;

    - if (po->rollover)
    + if (po->rollover) {
    kfree_rcu(po->rollover, rcu);
    + po->rollover = NULL;
    + }
    }
    mutex_unlock(&fanout_mutex);

    @@ -3853,6 +3855,7 @@ static int packet_getsockopt(struct sock
    void *data = &val;
    union tpacket_stats_u st;
    struct tpacket_rollover_stats rstats;
    + struct packet_rollover *rollover;

    if (level != SOL_PACKET)
    return -ENOPROTOOPT;
    @@ -3931,13 +3934,18 @@ static int packet_getsockopt(struct sock
    0);
    break;
    case PACKET_ROLLOVER_STATS:
    - if (!po->rollover)
    + rcu_read_lock();
    + rollover = rcu_dereference(po->rollover);
    + if (rollover) {
    + rstats.tp_all = atomic_long_read(&rollover->num);
    + rstats.tp_huge = atomic_long_read(&rollover->num_huge);
    + rstats.tp_failed = atomic_long_read(&rollover->num_failed);
    + data = &rstats;
    + lv = sizeof(rstats);
    + }
    + rcu_read_unlock();
    + if (!rollover)
    return -EINVAL;
    - rstats.tp_all = atomic_long_read(&po->rollover->num);
    - rstats.tp_huge = atomic_long_read(&po->rollover->num_huge);
    - rstats.tp_failed = atomic_long_read(&po->rollover->num_failed);
    - data = &rstats;
    - lv = sizeof(rstats);
    break;
    case PACKET_TX_HAS_OFF:
    val = po->tp_tx_has_off;

    \
     
     \ /
      Last update: 2017-11-17 17:18    [W:2.993 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site