On Thu, 2017-02-09 at 19:19 -0800, Eric Dumazet wrote: > More likely the bug is in fanout_add(), with a buggy sequence in error > case, and not correct locking. > > kfree(po->rollover); > po->rollover = NULL; > > Two cpus entering fanout_add() (using the same af_packet socket, > syzkaller courtesy...) might both see po->fanout being NULL. > > Then they grab the mutex. Too late...
Patch could be : net/packet/af_packet.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d56ee46b11fc9524e457e5fe8adf10c105a66ab6..11725a350f6953d077f754c10e9f52e48924d780 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1657,7 +1657,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) atomic_long_set(&po->rollover->num_failed, 0); } - mutex_lock(&fanout_mutex); match = NULL; list_for_each_entry(f, &fanout_list, list) { if (f->id == id && @@ -1704,7 +1703,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) } } out: - mutex_unlock(&fanout_mutex); if (err) { kfree(po->rollover); po->rollover = NULL; @@ -3698,7 +3696,10 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - return fanout_add(sk, val & 0xffff, val >> 16); + mutex_lock(&fanout_mutex); + ret = fanout_add(sk, val & 0xffff, val >> 16); + mutex_unlock(&fanout_mutex); + return ret; } case PACKET_FANOUT_DATA: {