Skip to content

Commit 7027e70

Browse files
devnexengregkh
authored andcommitted
bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path
[ Upstream commit 8ed82f8 ] The DEVMAP_HASH branch in dev_map_redirect_multi() uses hlist_for_each_entry_safe() to iterate hash buckets, but this function runs under RCU protection (called from xdp_do_generic_redirect_map() in softirq context). Concurrent writers (__dev_map_hash_update_elem, dev_map_hash_delete_elem) modify the list using RCU primitives (hlist_add_head_rcu, hlist_del_rcu). hlist_for_each_entry_safe() performs plain pointer dereferences without rcu_dereference(), missing the acquire barrier needed to pair with writers' rcu_assign_pointer(). On weakly-ordered architectures (ARM64, POWER), a reader can observe a partially-constructed node. It also defeats CONFIG_PROVE_RCU lockdep validation and KCSAN data-race detection. Replace with hlist_for_each_entry_rcu() using rcu_read_lock_bh_held() as the lockdep condition, consistent with the rcu_dereference_check() used in the DEVMAP (non-hash) branch of the same functions. Also fix the same incorrect lockdep_is_held(&dtab->index_lock) condition in dev_map_enqueue_multi(), where the lock is not held either. Fixes: e624d4e ("xdp: Extend xdp_redirect_map with broadcast support") Signed-off-by: David Carlier <devnexen@gmail.com> Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org> Link: https://patch.msgid.link/20260320072645.16731-1-devnexen@gmail.com Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent bfa998d commit 7027e70

1 file changed

Lines changed: 2 additions & 3 deletions

File tree

kernel/bpf/devmap.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx,
665665
for (i = 0; i < dtab->n_buckets; i++) {
666666
head = dev_map_index_hash(dtab, i);
667667
hlist_for_each_entry_rcu(dst, head, index_hlist,
668-
lockdep_is_held(&dtab->index_lock)) {
668+
rcu_read_lock_bh_held()) {
669669
if (!is_valid_dst(dst, xdpf))
670670
continue;
671671

@@ -747,7 +747,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,
747747
struct bpf_dtab_netdev *dst, *last_dst = NULL;
748748
int excluded_devices[1+MAX_NEST_DEV];
749749
struct hlist_head *head;
750-
struct hlist_node *next;
751750
int num_excluded = 0;
752751
unsigned int i;
753752
int err;
@@ -787,7 +786,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,
787786
} else { /* BPF_MAP_TYPE_DEVMAP_HASH */
788787
for (i = 0; i < dtab->n_buckets; i++) {
789788
head = dev_map_index_hash(dtab, i);
790-
hlist_for_each_entry_safe(dst, next, head, index_hlist) {
789+
hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) {
791790
if (is_ifindex_excluded(excluded_devices, num_excluded,
792791
dst->dev->ifindex))
793792
continue;

0 commit comments

Comments
 (0)