From 6305df8009f950691451fc87e24822f9f78d9592 Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Thu, 6 Apr 2023 20:26:22 +0800 Subject: [PATCH] UPSTREAM: bpf, sockmap: fix deadlocks in the sockhash and sockmap [ Upstream commit ed17aa92dc56b6d8883e4b7a8f1c6fbf5ed6cd29 ] When huang uses sched_switch tracepoint, the tracepoint does only one thing in the mounted ebpf program, which deletes the fixed elements in sockhash ([0]) It seems that elements in sockhash are rarely actively deleted by users or ebpf program. Therefore, we do not pay much attention to their deletion. Compared with hash maps, sockhash only provides spin_lock_bh protection. This causes it to appear to have self-locking behavior in the interrupt context. [0]:https://lore.kernel.org/all/CABcoxUayum5oOqFMMqAeWuS8+EzojquSOSyDA3J_2omY=2EeAg@mail.gmail.com/ Bug: 293551383 Reported-by: Hsin-Wei Hung Fixes: 604326b41a6f ("bpf, sockmap: convert to generic sk_msg interface") Signed-off-by: Xin Liu Acked-by: John Fastabend Link: https://lore.kernel.org/r/20230406122622.109978-1-liuxin350@huawei.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin (cherry picked from commit f333854dce4a079783f00c201869b9ee8f7ff3c3) Signed-off-by: Lee Jones Change-Id: I913aa014f16e294ab9f9fec04d3e63afb8aa803f --- net/core/sock_map.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/core/sock_map.c b/net/core/sock_map.c index d38267201892..7904811ff62d 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -414,8 +414,9 @@ static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test, { struct sock *sk; int err = 0; + unsigned long flags; - raw_spin_lock_bh(&stab->lock); + raw_spin_lock_irqsave(&stab->lock, flags); sk = *psk; if (!sk_test || sk_test == sk) sk = xchg(psk, NULL); @@ -425,7 +426,7 @@ static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test, else err = -EINVAL; - raw_spin_unlock_bh(&stab->lock); + raw_spin_unlock_irqrestore(&stab->lock, flags); return err; } @@ -923,11 +924,12 @@ static int sock_hash_delete_elem(struct bpf_map *map, void *key) struct bpf_shtab_bucket *bucket; struct bpf_shtab_elem *elem; int ret = -ENOENT; + unsigned long flags; hash = sock_hash_bucket_hash(key, key_size); bucket = sock_hash_select_bucket(htab, hash); - raw_spin_lock_bh(&bucket->lock); + raw_spin_lock_irqsave(&bucket->lock, flags); elem = sock_hash_lookup_elem_raw(&bucket->head, hash, key, key_size); if (elem) { hlist_del_rcu(&elem->node); @@ -935,7 +937,7 @@ static int sock_hash_delete_elem(struct bpf_map *map, void *key) sock_hash_free_elem(htab, elem); ret = 0; } - raw_spin_unlock_bh(&bucket->lock); + raw_spin_unlock_irqrestore(&bucket->lock, flags); return ret; }