From nobody Tue Apr 7 06:19:58 2026 Received: from mail-oo1-f69.google.com (mail-oo1-f69.google.com [209.85.161.69]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A639A1A3157 for ; Sun, 15 Mar 2026 15:52:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.69 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773589966; cv=none; b=DtduvEKPyxq3pTrqQU0bZ3xNjzWXXBDR35Bi/k+EkvDNwASWtry/4/hHDxRuqd+U8qthYJEUvxgCy03a86/BwUfP8dSHpB0BfZa6lSyoGcL8TJI0ijhVyk8sOx4+lCBQaDF1+In0aFOG+2N91vAW5Pf7yNjeJcuSl2iz7dgBuro= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773589966; c=relaxed/simple; bh=XMKmE1gfNZ7BuS5NqtoxK5mf1kh0FSSMQvmK2BMVv54=; h=MIME-Version:Date:In-Reply-To:Message-ID:Subject:From:To: Content-Type; b=QGEwKrAyG7SUFMQkmh1R6NNXUWaRXJCLHK1QBE6w0jHNpwCZAacf8lhoDSuMMcpvcBXsh8zXH3wghbNu0/mmNw5hfHwiXRk+5k2iAns1n6k+XkhQATKqmcNy/hAN88DViHhDlg/hsEKZ8ql7zWkQA82g2NRcNQni4CfD7R9yNRM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com; arc=none smtp.client-ip=209.85.161.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com Received: by mail-oo1-f69.google.com with SMTP id 006d021491bc7-672c40f3873so90482933eaf.2 for ; Sun, 15 Mar 2026 08:52:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773589963; x=1774194763; h=to:from:subject:message-id:in-reply-to:date:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=usJ/SF4LPsqpmEBldzlycVu0nlSx4jr76jimwPDBzRQ=; b=pS07r18NkgS3czYek/W0xMe02x+bl8MD2GddJ0MemxAU3QVo3FOjmCMRCT5Z+gv9Vs eizL/fRdG2iMCV/Ezhgm0eg8dtq89p8YH3wrFia2PuSUeezhngNa5AmAjyTl0+4oZK0r XROPHmNqjzXrFBnRh3ql+HeEy4LKi5W864CXXSGBbFzzV7M5EFdpKfqu+wByeX3yOW/K 78v7XsME4/1eDRSujrdB3tmP1VqAfoklklFhU52qGdCGH5MqIxh/LOyOxoWCdSb94FIW /Iv9UYZ5YDC8FUH9RiiUYk+tcX/YQuxQtWbrjcJ/15MaDE9KVy/3NN4msyGDMNvn33Je OaNg== X-Gm-Message-State: AOJu0Ywi9xjB90hIDrJrTX8Xibo9nKABiKuOtWqqoSqeD9YpIDCNhsfR Fpr1WLbZfnI5xEJCcaD4LanhBPkI1oobKMogwJgDXQPED8cuQVE7GeoEPtqfDwAWB1MYpxxUwWP CrG+3qKWp4WgZHpmqsLSAE3Ekct0T2PjLfrEfxpM/2QcvJ4QahUP9jcobjHg= Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Received: by 2002:a05:6820:1ca9:b0:67b:b098:2871 with SMTP id 006d021491bc7-67bda9eb75amr7067541eaf.34.1773589963582; Sun, 15 Mar 2026 08:52:43 -0700 (PDT) Date: Sun, 15 Mar 2026 08:52:43 -0700 In-Reply-To: <694995bf.050a0220.2fb209.01a1.GAE@google.com> X-Google-Appengine-App-Id: s~syzkaller X-Google-Appengine-App-Id-Alias: syzkaller Message-ID: <69b6d5cb.050a0220.248e02.0100.GAE@google.com> Subject: Forwarded: test: bpf lru nmi deadlock fix From: syzbot To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" For archival purposes, forwarding an incoming command email to linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com. *** Subject: test: bpf lru nmi deadlock fix Author: nooraineqbal@gmail.com #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git master From b1add52f63c8309c3a91bcc294139134ce1c0fa5 Mon Sep 17 00:00:00 2001 From: Noorain Eqbal Date: Sun, 15 Mar 2026 21:02:42 +0530 Subject: [PATCH] bpf: Fix NMI deadlocks in LRU map operations LRU maps can deadlock when accessed from NMI context (e.g., when attached to perf events with hardware breakpoints). The issue occurs because raw_spin_lock_irqsave() cannot prevent NMI interruption on the same CPU. This is the same issue that was fixed for queue and stack maps in commit a34a9f1a19af ("bpf: Avoid deadlock when using queue and stack maps from NMI"). The queue/stack map fix was later updated to use resilient spinlocks which provide built in NMI deadlock detection. Apply the same fix to LRU maps by replacing raw_spin_lock_irqsave() with raw_res_spin_lock_irqsave() in all LRU pop/push operations: - bpf_common_lru_pop_free() - bpf_percpu_lru_pop_free() - bpf_common_lru_push_free() - bpf_percpu_lru_push_free() The resilient spinlock will return -EDEADLK when it detects a deadlock scenario (NMI trying to acquire a lock already held), allowing the operation to fail safely instead of deadlocking. Reproducer and lockdep splat: https://syzkaller.appspot.com/bug?id=3Dc4d6f5f7d392471722983a2e85ae391360ca= 7ae8 Related discussion: https://lore.kernel.org/bpf/CAPPBnEYO4R+m+SpVc2gNj_x31R6fo1uJvj2bK2YS1P09GW= T6kQ@mail.gmail.com/ Fixes: 3a08c2fd7634 ("bpf: LRU List") Reported-by: syzbot+c69a0a2c816716f1e0d5@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3Dc69a0a2c816716f1e0d5 Signed-off-by: Noorain Eqbal --- kernel/bpf/bpf_lru_list.c | 46 +++++++++++++++++++++++---------------- kernel/bpf/bpf_lru_list.h | 5 +++-- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/kernel/bpf/bpf_lru_list.c b/kernel/bpf/bpf_lru_list.c index e7a2fc60523f..0cd1d5c511fa 100644 --- a/kernel/bpf/bpf_lru_list.c +++ b/kernel/bpf/bpf_lru_list.c @@ -4,6 +4,7 @@ #include #include #include +#include =20 #include "bpf_lru_list.h" =20 @@ -307,9 +308,10 @@ static void bpf_lru_list_push_free(struct bpf_lru_list= *l, if (WARN_ON_ONCE(IS_LOCAL_LIST_TYPE(node->type))) return; =20 - raw_spin_lock_irqsave(&l->lock, flags); + if (raw_res_spin_lock_irqsave(&l->lock, flags)) + return; __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_FREE); - raw_spin_unlock_irqrestore(&l->lock, flags); + raw_res_spin_unlock_irqrestore(&l->lock, flags); } =20 static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru, @@ -319,7 +321,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_l= ru *lru, struct bpf_lru_node *node, *tmp_node; unsigned int nfree =3D 0; =20 - raw_spin_lock(&l->lock); + raw_res_spin_lock(&l->lock); =20 __local_list_flush(l, loc_l); =20 @@ -338,7 +340,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_l= ru *lru, local_free_list(loc_l), BPF_LRU_LOCAL_LIST_T_FREE); =20 - raw_spin_unlock(&l->lock); + raw_res_spin_unlock(&l->lock); } =20 static void __local_list_add_pending(struct bpf_lru *lru, @@ -404,7 +406,8 @@ static struct bpf_lru_node *bpf_percpu_lru_pop_free(str= uct bpf_lru *lru, =20 l =3D per_cpu_ptr(lru->percpu_lru, cpu); =20 - raw_spin_lock_irqsave(&l->lock, flags); + if (raw_res_spin_lock_irqsave(&l->lock, flags)) + return NULL; =20 __bpf_lru_list_rotate(lru, l); =20 @@ -420,7 +423,7 @@ static struct bpf_lru_node *bpf_percpu_lru_pop_free(str= uct bpf_lru *lru, __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_INACTIVE); } =20 - raw_spin_unlock_irqrestore(&l->lock, flags); + raw_res_spin_unlock_irqrestore(&l->lock, flags); =20 return node; } @@ -437,7 +440,8 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(str= uct bpf_lru *lru, =20 loc_l =3D per_cpu_ptr(clru->local_list, cpu); =20 - raw_spin_lock_irqsave(&loc_l->lock, flags); + if (raw_res_spin_lock_irqsave(&loc_l->lock, flags)) + return NULL; =20 node =3D __local_list_pop_free(loc_l); if (!node) { @@ -448,7 +452,7 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(str= uct bpf_lru *lru, if (node) __local_list_add_pending(lru, loc_l, cpu, node, hash); =20 - raw_spin_unlock_irqrestore(&loc_l->lock, flags); + raw_res_spin_unlock_irqrestore(&loc_l->lock, flags); =20 if (node) return node; @@ -466,13 +470,14 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(s= truct bpf_lru *lru, do { steal_loc_l =3D per_cpu_ptr(clru->local_list, steal); =20 - raw_spin_lock_irqsave(&steal_loc_l->lock, flags); + if (raw_res_spin_lock_irqsave(&steal_loc_l->lock, flags)) + return NULL; =20 node =3D __local_list_pop_free(steal_loc_l); if (!node) node =3D __local_list_pop_pending(lru, steal_loc_l); =20 - raw_spin_unlock_irqrestore(&steal_loc_l->lock, flags); + raw_res_spin_unlock_irqrestore(&steal_loc_l->lock, flags); =20 steal =3D cpumask_next_wrap(steal, cpu_possible_mask); } while (!node && steal !=3D first_steal); @@ -480,9 +485,10 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(st= ruct bpf_lru *lru, loc_l->next_steal =3D steal; =20 if (node) { - raw_spin_lock_irqsave(&loc_l->lock, flags); + if (raw_res_spin_lock_irqsave(&loc_l->lock, flags)) + return NULL; __local_list_add_pending(lru, loc_l, cpu, node, hash); - raw_spin_unlock_irqrestore(&loc_l->lock, flags); + raw_res_spin_unlock_irqrestore(&loc_l->lock, flags); } =20 return node; @@ -511,10 +517,11 @@ static void bpf_common_lru_push_free(struct bpf_lru *= lru, =20 loc_l =3D per_cpu_ptr(lru->common_lru.local_list, node->cpu); =20 - raw_spin_lock_irqsave(&loc_l->lock, flags); + if (raw_res_spin_lock_irqsave(&loc_l->lock, flags)) + return; =20 if (unlikely(node->type !=3D BPF_LRU_LOCAL_LIST_T_PENDING)) { - raw_spin_unlock_irqrestore(&loc_l->lock, flags); + raw_res_spin_unlock_irqrestore(&loc_l->lock, flags); goto check_lru_list; } =20 @@ -522,7 +529,7 @@ static void bpf_common_lru_push_free(struct bpf_lru *lr= u, bpf_lru_node_clear_ref(node); list_move(&node->list, local_free_list(loc_l)); =20 - raw_spin_unlock_irqrestore(&loc_l->lock, flags); + raw_res_spin_unlock_irqrestore(&loc_l->lock, flags); return; } =20 @@ -538,11 +545,12 @@ static void bpf_percpu_lru_push_free(struct bpf_lru *= lru, =20 l =3D per_cpu_ptr(lru->percpu_lru, node->cpu); =20 - raw_spin_lock_irqsave(&l->lock, flags); + if (raw_res_spin_lock_irqsave(&l->lock, flags)) + return; =20 __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_FREE); =20 - raw_spin_unlock_irqrestore(&l->lock, flags); + raw_res_spin_unlock_irqrestore(&l->lock, flags); } =20 void bpf_lru_push_free(struct bpf_lru *lru, struct bpf_lru_node *node) @@ -625,7 +633,7 @@ static void bpf_lru_locallist_init(struct bpf_lru_local= list *loc_l, int cpu) =20 loc_l->next_steal =3D cpu; =20 - raw_spin_lock_init(&loc_l->lock); + raw_res_spin_lock_init(&loc_l->lock); } =20 static void bpf_lru_list_init(struct bpf_lru_list *l) @@ -640,7 +648,7 @@ static void bpf_lru_list_init(struct bpf_lru_list *l) =20 l->next_inactive_rotation =3D &l->lists[BPF_LRU_LIST_T_INACTIVE]; =20 - raw_spin_lock_init(&l->lock); + raw_res_spin_lock_init(&l->lock); } =20 int bpf_lru_init(struct bpf_lru *lru, bool percpu, u32 hash_offset, diff --git a/kernel/bpf/bpf_lru_list.h b/kernel/bpf/bpf_lru_list.h index fe2661a58ea9..ecd93c77a7ff 100644 --- a/kernel/bpf/bpf_lru_list.h +++ b/kernel/bpf/bpf_lru_list.h @@ -7,6 +7,7 @@ #include #include #include +#include =20 #define NR_BPF_LRU_LIST_T (3) #define NR_BPF_LRU_LIST_COUNT (2) @@ -34,13 +35,13 @@ struct bpf_lru_list { /* The next inactive list rotation starts from here */ struct list_head *next_inactive_rotation; =20 - raw_spinlock_t lock ____cacheline_aligned_in_smp; + rqspinlock_t lock ____cacheline_aligned_in_smp; }; =20 struct bpf_lru_locallist { struct list_head lists[NR_BPF_LRU_LOCAL_LIST_T]; u16 next_steal; - raw_spinlock_t lock; + rqspinlock_t lock; }; =20 struct bpf_common_lru { --=20 2.53.0