Iterating a sk_storage map is two stages: bpf_sk_storage_map_seq_find_next() returns a selem, then __bpf_sk_storage_map_seq_show() uses that selem. __bpf_sk_storage_map_seq_show() re-reads selem->local_storage via rcu_dereference() with no NULL check. A concurrent close() can run bpf_selem_unlink_nofail() in between and set that field to NULL, causing a NULL dereference of sk_storage->owner. Oops: general protection fault, probably for non-canonical address 0xdffffc0000000011 net/core/bpf_sk_storage.c:809 __bpf_sk_storage_map_seq_show() bpf_seq_read+0x366/0x1120 vfs_read+0x174/0xa50 ksys_read+0xfc/0x1d0 Return if the re-read yields NULL. Fixes: 5d800f87d0a5 ("bpf: Support lockless unlink when freeing map or local storage") Reported-by: Xiang Mei (Microsoft) Cc: AutonomousCodeSecurity@microsoft.com Assisted-by: Copilot (Grok 4.6) Signed-off-by: Cen Zhang (Microsoft Security FORGE Labs) --- net/core/bpf_sk_storage.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c index 1d295a8769fa..7228520aa2b6 100644 --- a/net/core/bpf_sk_storage.c +++ b/net/core/bpf_sk_storage.c @@ -806,6 +806,8 @@ static int __bpf_sk_storage_map_seq_show(struct seq_file *seq, ctx.map = info->map; if (selem) { sk_storage = rcu_dereference(selem->local_storage); + if (!sk_storage) + return 0; ctx.sk = sk_storage->owner; ctx.value = SDATA(selem)->data; } -- 2.55.0