Skip to content

Commit

Permalink
net/packet: remove data races in fanout operations
Browse files Browse the repository at this point in the history
af_packet fanout uses RCU rules to ensure f->arr elements
are not dismantled before RCU grace period.

However, it lacks rcu accessors to make sure KCSAN and other tools
wont detect data races. Stupid compilers could also play games.

Fixes: dc99f60 ("packet: Add fanout support.")
Signed-off-by: Eric Dumazet <[email protected]>
Reported-by: "Gong, Sishuai" <[email protected]>
Cc: Willem de Bruijn <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Eric Dumazet authored and davem330 committed Apr 14, 2021
1 parent ae1ea84 commit 94f633e
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 7 deletions.
15 changes: 9 additions & 6 deletions net/packet/af_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,7 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f,
struct packet_sock *po, *po_next, *po_skip = NULL;
unsigned int i, j, room = ROOM_NONE;

po = pkt_sk(f->arr[idx]);
po = pkt_sk(rcu_dereference(f->arr[idx]));

if (try_self) {
room = packet_rcv_has_room(po, skb);
Expand All @@ -1371,7 +1371,7 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f,

i = j = min_t(int, po->rollover->sock, num - 1);
do {
po_next = pkt_sk(f->arr[i]);
po_next = pkt_sk(rcu_dereference(f->arr[i]));
if (po_next != po_skip && !READ_ONCE(po_next->pressure) &&
packet_rcv_has_room(po_next, skb) == ROOM_NORMAL) {
if (i != j)
Expand Down Expand Up @@ -1466,7 +1466,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
if (fanout_has_flag(f, PACKET_FANOUT_FLAG_ROLLOVER))
idx = fanout_demux_rollover(f, skb, idx, true, num);

po = pkt_sk(f->arr[idx]);
po = pkt_sk(rcu_dereference(f->arr[idx]));
return po->prot_hook.func(skb, dev, &po->prot_hook, orig_dev);
}

Expand All @@ -1480,7 +1480,7 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po)
struct packet_fanout *f = po->fanout;

spin_lock(&f->lock);
f->arr[f->num_members] = sk;
rcu_assign_pointer(f->arr[f->num_members], sk);
smp_wmb();
f->num_members++;
if (f->num_members == 1)
Expand All @@ -1495,11 +1495,14 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po)

spin_lock(&f->lock);
for (i = 0; i < f->num_members; i++) {
if (f->arr[i] == sk)
if (rcu_dereference_protected(f->arr[i],
lockdep_is_held(&f->lock)) == sk)
break;
}
BUG_ON(i >= f->num_members);
f->arr[i] = f->arr[f->num_members - 1];
rcu_assign_pointer(f->arr[i],
rcu_dereference_protected(f->arr[f->num_members - 1],
lockdep_is_held(&f->lock)));
f->num_members--;
if (f->num_members == 0)
__dev_remove_pack(&f->prot_hook);
Expand Down
2 changes: 1 addition & 1 deletion net/packet/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ struct packet_fanout {
spinlock_t lock;
refcount_t sk_ref;
struct packet_type prot_hook ____cacheline_aligned_in_smp;
struct sock *arr[];
struct sock __rcu *arr[];
};

struct packet_rollover {
Expand Down

0 comments on commit 94f633e

Please sign in to comment.