Skip to content

Commit 94f633e

Browse files
edumazetdavem330
authored andcommitted
net/packet: remove data races in fanout operations
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 <edumazet@google.com> Reported-by: "Gong, Sishuai" <sishuai@purdue.edu> Cc: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent ae1ea84 commit 94f633e

File tree

2 files changed

+10
-7
lines changed

2 files changed

+10
-7
lines changed

net/packet/af_packet.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,7 +1359,7 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f,
13591359
struct packet_sock *po, *po_next, *po_skip = NULL;
13601360
unsigned int i, j, room = ROOM_NONE;
13611361

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

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

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

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

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

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

14961496
spin_lock(&f->lock);
14971497
for (i = 0; i < f->num_members; i++) {
1498-
if (f->arr[i] == sk)
1498+
if (rcu_dereference_protected(f->arr[i],
1499+
lockdep_is_held(&f->lock)) == sk)
14991500
break;
15001501
}
15011502
BUG_ON(i >= f->num_members);
1502-
f->arr[i] = f->arr[f->num_members - 1];
1503+
rcu_assign_pointer(f->arr[i],
1504+
rcu_dereference_protected(f->arr[f->num_members - 1],
1505+
lockdep_is_held(&f->lock)));
15031506
f->num_members--;
15041507
if (f->num_members == 0)
15051508
__dev_remove_pack(&f->prot_hook);

net/packet/internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct packet_fanout {
9494
spinlock_t lock;
9595
refcount_t sk_ref;
9696
struct packet_type prot_hook ____cacheline_aligned_in_smp;
97-
struct sock *arr[];
97+
struct sock __rcu *arr[];
9898
};
9999

100100
struct packet_rollover {

0 commit comments

Comments
 (0)