Skip to content

Commit abd672d

Browse files
edumazetgregkh
authored andcommitted
packet: fix races in fanout_add()
[ Upstream commit d199fab63c11998a602205f7ee7ff7c05c97164b ] Multiple threads can call fanout_add() at the same time. We need to grab fanout_mutex earlier to avoid races that could lead to one thread freeing po->rollover that was set by another thread. Do the same in fanout_release(), for peace of mind, and to help us finding lockdep issues earlier. Fixes: dc99f60 ("packet: Add fanout support.") Fixes: 0648ab7 ("packet: rollover prepare: per-socket state") Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2b3eb43 commit abd672d

1 file changed

Lines changed: 30 additions & 25 deletions

File tree

net/packet/af_packet.c

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ static void fanout_release_data(struct packet_fanout *f)
16231623

16241624
static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
16251625
{
1626+
struct packet_rollover *rollover = NULL;
16261627
struct packet_sock *po = pkt_sk(sk);
16271628
struct packet_fanout *f, *match;
16281629
u8 type = type_flags & 0xff;
@@ -1645,23 +1646,28 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
16451646
return -EINVAL;
16461647
}
16471648

1649+
mutex_lock(&fanout_mutex);
1650+
1651+
err = -EINVAL;
16481652
if (!po->running)
1649-
return -EINVAL;
1653+
goto out;
16501654

1655+
err = -EALREADY;
16511656
if (po->fanout)
1652-
return -EALREADY;
1657+
goto out;
16531658

16541659
if (type == PACKET_FANOUT_ROLLOVER ||
16551660
(type_flags & PACKET_FANOUT_FLAG_ROLLOVER)) {
1656-
po->rollover = kzalloc(sizeof(*po->rollover), GFP_KERNEL);
1657-
if (!po->rollover)
1658-
return -ENOMEM;
1659-
atomic_long_set(&po->rollover->num, 0);
1660-
atomic_long_set(&po->rollover->num_huge, 0);
1661-
atomic_long_set(&po->rollover->num_failed, 0);
1661+
err = -ENOMEM;
1662+
rollover = kzalloc(sizeof(*rollover), GFP_KERNEL);
1663+
if (!rollover)
1664+
goto out;
1665+
atomic_long_set(&rollover->num, 0);
1666+
atomic_long_set(&rollover->num_huge, 0);
1667+
atomic_long_set(&rollover->num_failed, 0);
1668+
po->rollover = rollover;
16621669
}
16631670

1664-
mutex_lock(&fanout_mutex);
16651671
match = NULL;
16661672
list_for_each_entry(f, &fanout_list, list) {
16671673
if (f->id == id &&
@@ -1708,11 +1714,11 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
17081714
}
17091715
}
17101716
out:
1711-
mutex_unlock(&fanout_mutex);
1712-
if (err) {
1713-
kfree(po->rollover);
1717+
if (err && rollover) {
1718+
kfree(rollover);
17141719
po->rollover = NULL;
17151720
}
1721+
mutex_unlock(&fanout_mutex);
17161722
return err;
17171723
}
17181724

@@ -1721,23 +1727,22 @@ static void fanout_release(struct sock *sk)
17211727
struct packet_sock *po = pkt_sk(sk);
17221728
struct packet_fanout *f;
17231729

1724-
f = po->fanout;
1725-
if (!f)
1726-
return;
1727-
17281730
mutex_lock(&fanout_mutex);
1729-
po->fanout = NULL;
1731+
f = po->fanout;
1732+
if (f) {
1733+
po->fanout = NULL;
1734+
1735+
if (atomic_dec_and_test(&f->sk_ref)) {
1736+
list_del(&f->list);
1737+
dev_remove_pack(&f->prot_hook);
1738+
fanout_release_data(f);
1739+
kfree(f);
1740+
}
17301741

1731-
if (atomic_dec_and_test(&f->sk_ref)) {
1732-
list_del(&f->list);
1733-
dev_remove_pack(&f->prot_hook);
1734-
fanout_release_data(f);
1735-
kfree(f);
1742+
if (po->rollover)
1743+
kfree_rcu(po->rollover, rcu);
17361744
}
17371745
mutex_unlock(&fanout_mutex);
1738-
1739-
if (po->rollover)
1740-
kfree_rcu(po->rollover, rcu);
17411746
}
17421747

17431748
static bool packet_extra_vlan_len_allowed(const struct net_device *dev,

0 commit comments

Comments
 (0)