From: Sasha Levin Date: Tue, 2 Jun 2026 18:20:52 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=6c55b6cc3e4aa09233a3bd9e62ecffc0ff13cebc;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/alsa-usb-audio-fix-null-pointer-dereference-on-point.patch b/queue-5.10/alsa-usb-audio-fix-null-pointer-dereference-on-point.patch new file mode 100644 index 0000000000..7ebabfb78b --- /dev/null +++ b/queue-5.10/alsa-usb-audio-fix-null-pointer-dereference-on-point.patch @@ -0,0 +1,55 @@ +From b4a9ea2b55c10bfd11b13a3ba981babdd49f788b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 18:29:50 +0300 +Subject: ALSA: usb-audio: fix null pointer dereference on pointer cs_desc + +From: Chengfeng Ye + +commit b97053df0f04747c3c1e021ecbe99db675342954 upstream. + +The pointer cs_desc return from snd_usb_find_clock_source could +be null, so there is a potential null pointer dereference issue. +Fix this by adding a null check before dereference. + +Signed-off-by: Chengfeng Ye +Link: https://lore.kernel.org/r/20211024111736.11342-1-cyeaa@connect.ust.hk +Signed-off-by: Takashi Iwai +Fixes: 1dc669fed61a ("ALSA: usb-audio: UAC2: support read-only freq control") +[ kovalev: bp to fix CVE-2021-47211; added Fixes tag; the null + check was added into both UAC2 and UAC3 branches since the + older kernel still has the clock source lookup split between + snd_usb_find_clock_source() and snd_usb_find_clock_source_v3() + (see upstream commit 9ec730052fa2); return -ENXIO instead of 0 + to match upstream behavior, where the caller reaches the clock + validation path and returns -ENXIO ] +Signed-off-by: Vasiliy Kovalev +Signed-off-by: Sasha Levin +--- + sound/usb/clock.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sound/usb/clock.c b/sound/usb/clock.c +index 197a6b7d8ad6f9..8759e20c419ed5 100644 +--- a/sound/usb/clock.c ++++ b/sound/usb/clock.c +@@ -646,11 +646,17 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, + struct uac3_clock_source_descriptor *cs_desc; + + cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); ++ ++ if (!cs_desc) ++ return -ENXIO; + bmControls = le32_to_cpu(cs_desc->bmControls); + } else { + struct uac_clock_source_descriptor *cs_desc; + + cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); ++ ++ if (!cs_desc) ++ return -ENXIO; + bmControls = cs_desc->bmControls; + } + +-- +2.53.0 + diff --git a/queue-5.10/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch b/queue-5.10/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch new file mode 100644 index 0000000000..424bdccb5e --- /dev/null +++ b/queue-5.10/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch @@ -0,0 +1,122 @@ +From 500f36193c6c19b959dcfad8ad70029000cad7fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 17:24:36 +0200 +Subject: net/sched: cls_fw: fix NULL dereference of "old" filters before + change() + +From: Davide Caratti + +[ Upstream commit 65782b2db7321d5f97c16718c4c7f6c7205a56be ] + +Like pointed out by Sashiko [1], since commit ed76f5edccc9 ("net: sched: +protect filter_chain list with filter_chain_lock mutex") TC filters are +added to a shared block and published to datapath before their ->change() +function is called. This is a problem for cls_fw: an invalid filter +created with the "old" method can still classify some packets before it +is destroyed by the validation logic added by Xiang. +Therefore, insisting with repeated runs of the following script: + + # ip link add dev crash0 type dummy + # ip link set dev crash0 up + # mausezahn crash0 -c 100000 -P 10 \ + > -A 4.3.2.1 -B 1.2.3.4 -t udp "dp=1234" -q & + # sleep 1 + # tc qdisc add dev crash0 egress_block 1 clsact + # tc filter add block 1 protocol ip prio 1 matchall \ + > action skbedit mark 65536 continue + # tc filter add block 1 protocol ip prio 2 fw + # ip link del dev crash0 + +can still make fw_classify() hit the WARN_ON() in [2]: + + WARNING: ./include/net/pkt_cls.h:88 at fw_classify+0x244/0x250 [cls_fw], CPU#18: mausezahn/1399 + Modules linked in: cls_fw(E) act_skbedit(E) + CPU: 18 UID: 0 PID: 1399 Comm: mausezahn Tainted: G E 7.0.0-rc6-virtme #17 PREEMPT(full) + Tainted: [E]=UNSIGNED_MODULE + Hardware name: Red Hat KVM, BIOS 1.16.3-2.el9 04/01/2014 + RIP: 0010:fw_classify+0x244/0x250 [cls_fw] + Code: 5c 49 c7 45 00 00 00 00 00 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 5b b8 ff ff ff ff 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 90 <0f> 0b 90 eb a0 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 + RSP: 0018:ffffd1b7026bf8a8 EFLAGS: 00010202 + RAX: ffff8c5ac9c60800 RBX: ffff8c5ac99322c0 RCX: 0000000000000004 + RDX: 0000000000000001 RSI: ffff8c5b74d7a000 RDI: ffff8c5ac8284f40 + RBP: ffffd1b7026bf8d0 R08: 0000000000000000 R09: ffffd1b7026bf9b0 + R10: 00000000ffffffff R11: 0000000000000000 R12: 0000000000010000 + R13: ffffd1b7026bf930 R14: ffff8c5ac8284f40 R15: 0000000000000000 + FS: 00007fca40c37740(0000) GS:ffff8c5b74d7a000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007fca40e822a0 CR3: 0000000005ca0001 CR4: 0000000000172ef0 + Call Trace: + + tcf_classify+0x17d/0x5c0 + tc_run+0x9d/0x150 + __dev_queue_xmit+0x2ab/0x14d0 + ip_finish_output2+0x340/0x8f0 + ip_output+0xa4/0x250 + raw_sendmsg+0x147d/0x14b0 + __sys_sendto+0x1cc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x126/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7fca40e822ba + Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89 + RSP: 002b:00007ffc248a42c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 000055ef233289d0 RCX: 00007fca40e822ba + RDX: 000000000000001e RSI: 000055ef23328c30 RDI: 0000000000000003 + RBP: 000055ef233289d0 R08: 00007ffc248a42d0 R09: 0000000000000010 + R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000001e + R13: 00000000000186a0 R14: 0000000000000000 R15: 00007fca41043000 + + irq event stamp: 1045778 + hardirqs last enabled at (1045784): [] __up_console_sem+0x52/0x60 + hardirqs last disabled at (1045789): [] __up_console_sem+0x37/0x60 + softirqs last enabled at (1045426): [] __alloc_skb+0x207/0x260 + softirqs last disabled at (1045434): [] __dev_queue_xmit+0x78/0x14d0 + +Then, because of the value in the packet's mark, dereference on 'q->handle' +with NULL 'q' occurs: + + BUG: kernel NULL pointer dereference, address: 0000000000000038 + [...] + RIP: 0010:fw_classify+0x1fe/0x250 [cls_fw] + [...] + +Skip "old-style" classification on shared blocks, so that the NULL +dereference is fixed and WARN_ON() is not hit anymore in the short +lifetime of invalid cls_fw "old-style" filters. + +[1] https://sashiko.dev/#/patchset/20260331050217.504278-1-xmei5%40asu.edu +[2] https://elixir.bootlin.com/linux/v7.0-rc6/source/include/net/pkt_cls.h#L86 + +Fixes: faeea8bbf6e9 ("net/sched: cls_fw: fix NULL pointer dereference on shared blocks") +Fixes: ed76f5edccc9 ("net: sched: protect filter_chain list with filter_chain_lock mutex") +Acked-by: Jamal Hadi Salim +Signed-off-by: Davide Caratti +Link: https://patch.msgid.link/e39cbd3103a337f1e515d186fe697b4459d24757.1775661704.git.dcaratti@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_fw.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c +index 23cf4f71111740..1dfbae9dc050a6 100644 +--- a/net/sched/cls_fw.c ++++ b/net/sched/cls_fw.c +@@ -72,9 +72,13 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, + } + } + } else { +- struct Qdisc *q = tcf_block_q(tp->chain->block); ++ struct Qdisc *q; + + /* Old method: classify the packet using its skb mark. */ ++ if (tcf_block_shared(tp->chain->block)) ++ return -1; ++ ++ q = tcf_block_q(tp->chain->block); + if (id && (TC_H_MAJ(id) == 0 || + !(TC_H_MAJ(id ^ q->handle)))) { + res->classid = id; +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch b/queue-5.10/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch new file mode 100644 index 0000000000..27e137d3eb --- /dev/null +++ b/queue-5.10/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch @@ -0,0 +1,79 @@ +From 602911ed40bd0d82a6aca27ef3576b28bc5fe2a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 11:29:56 -0400 +Subject: net/sched: sch_sfb: Replace direct dequeue call with peek and + qdisc_dequeue_peeked + +From: Victor Nogueria + +[ Upstream commit 1b9bc71153b01dbde8045b9edede4240f4f5520e ] + +When sfb has children (eg qfq qdisc) whose peek() callback is +qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such +qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from +its child (sfb in this case), it will do the following: + 1a. do a peek() - and when sensing there's an skb the child can offer, then + - the child in this case(sfb) calls its child's (qfq) peek. + qfq does the right thing and will return the gso_skb queue packet. + Note: if there wasnt a gso_skb entry then qfq will store it there. + 1b. invoke a dequeue() on the child (sfb). And herein lies the problem. + - sfb will call the child's dequeue() which will essentially just + try to grab something of qfq's queue. + +[ 127.594489][ T453] KASAN: null-ptr-deref in range [0x0000000000000048-0x000000000000004f] +[ 127.594741][ T453] CPU: 2 UID: 0 PID: 453 Comm: ping Not tainted 7.1.0-rc1-00035-gac961974495b-dirty #793 PREEMPT(full) +[ 127.595059][ T453] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +[ 127.595254][ T453] RIP: 0010:qfq_dequeue+0x35c/0x1650 [sch_qfq] +[ 127.595461][ T453] Code: 00 fc ff df 80 3c 02 00 0f 85 17 0e 00 00 4c 8d 73 48 48 89 9d b8 02 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 76 0c 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b +[ 127.596081][ T453] RSP: 0018:ffff88810e5af440 EFLAGS: 00010216 +[ 127.596337][ T453] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: dffffc0000000000 +[ 127.596623][ T453] RDX: 0000000000000009 RSI: 0000001880000000 RDI: ffff888104fd82b0 +[ 127.596917][ T453] RBP: ffff888104fd8000 R08: ffff888104fd8280 R09: 1ffff110211893a3 +[ 127.597165][ T453] R10: 1ffff110211893a6 R11: 1ffff110211893a7 R12: 0000001880000000 +[ 127.597404][ T453] R13: ffff888104fd82b8 R14: 0000000000000048 R15: 0000000040000000 +[ 127.597644][ T453] FS: 00007fc380cbfc40(0000) GS:ffff88816f2a8000(0000) knlGS:0000000000000000 +[ 127.597956][ T453] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 127.598160][ T453] CR2: 00005610aa9890a8 CR3: 000000010369e000 CR4: 0000000000750ef0 +[ 127.598390][ T453] PKRU: 55555554 +[ 127.598509][ T453] Call Trace: +[ 127.598629][ T453] +[ 127.598718][ T453] ? mark_held_locks+0x40/0x70 +[ 127.598890][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599053][ T453] sfb_dequeue+0x88/0x4d0 +[ 127.599174][ T453] ? ktime_get+0x137/0x230 +[ 127.599328][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599480][ T453] ? qdisc_peek_dequeued+0x7b/0x350 [sch_qfq] +[ 127.599670][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599831][ T453] tbf_dequeue+0x6b1/0x1098 [sch_tbf] +[ 127.599988][ T453] __qdisc_run+0x169/0x1900 + +The right thing to do in #1b is to grab the skb off gso_skb queue. +This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked() +method instead. + +Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler") +Signed-off-by: Victor Nogueria +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260430152957.194015-3-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index 1b04e760e47d6c..ce6c7e34e3c470 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -439,7 +439,7 @@ static struct sk_buff *sfb_dequeue(struct Qdisc *sch) + struct Qdisc *child = q->qdisc; + struct sk_buff *skb; + +- skb = child->dequeue(q->qdisc); ++ skb = qdisc_dequeue_peeked(child); + + if (skb) { + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-5.10/phy-renesas-rcar-gen3-usb2-fix-the-use-of-msleep-dur.patch b/queue-5.10/phy-renesas-rcar-gen3-usb2-fix-the-use-of-msleep-dur.patch new file mode 100644 index 0000000000..c38b070df8 --- /dev/null +++ b/queue-5.10/phy-renesas-rcar-gen3-usb2-fix-the-use-of-msleep-dur.patch @@ -0,0 +1,76 @@ +From 6217f4dacef15c78d1d236e2b86d8a7c4887d3bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 2 May 2026 07:58:59 +0900 +Subject: phy: renesas: rcar-gen3-usb2: Fix the use of msleep during spinlock + +From: Nobuhiro Iwamatsu + +This fixes an issue caused by the use of msleep during spinlock. +In the original commit, msleep was changed to mdelay, but this fix was not +carried over during the backport to 5.10.y tree. + +This is a backporting error, so no fix is needed in the upstream. + +``` +[ 62.677594] BUG: scheduling while atomic: kworker/1:2/126/0x00000002 +[ 62.683957] Modules linked in: +[ 62.687014] CPU: 1 PID: 126 Comm: kworker/1:2 Not tainted 5.10.253 #1 +[ 62.693447] Hardware name: HopeRun HiHope RZ/G2M with sub board (DT) +[ 62.699812] Workqueue: events deferred_probe_work_func +[ 62.704948] Call trace: +[ 62.707397] dump_backtrace+0x0/0x1c0 +[ 62.711058] show_stack+0x18/0x40 +[ 62.714375] dump_stack+0xe8/0x124 +[ 62.717776] __schedule_bug+0x54/0x70 +[ 62.721436] __schedule+0x6b4/0x710 +[ 62.724920] schedule+0x70/0x104 +[ 62.728145] schedule_timeout+0x80/0xf0 +[ 62.728153] msleep+0x30/0x44 +[ 62.728165] rcar_gen3_phy_usb2_init+0x180/0x1e0 +[ 62.736946] phy_init+0x64/0x100 +[ 62.736955] usb_phy_roothub_init+0x48/0xa0 +[ 62.736962] usb_add_hcd+0x54/0x6c0 +[ 62.736974] ehci_platform_probe+0x1ec/0x4b0 +[ 62.744541] platform_drv_probe+0x54/0xac +[ 62.744548] really_probe+0xec/0x4f0 +[ 62.744552] driver_probe_device+0x58/0xec +[ 62.744556] __device_attach_driver+0xb8/0x120 +[ 62.744562] bus_for_each_drv+0x78/0xd0 +[ 62.744568] __device_attach+0xa8/0x1c0 +[ 62.744575] device_initial_probe+0x14/0x20 +[ 62.752315] bus_probe_device+0x9c/0xa4 +[ 62.752319] deferred_probe_work_func+0x88/0xc0 +[ 62.752327] process_one_work+0x1cc/0x370 +[ 62.759977] worker_thread+0x218/0x480 +[ 62.759984] kthread+0x154/0x160 +[ 62.759990] ret_from_fork+0x10/0x18 +[ 62.760115] ehci-platform ee080100.usb: EHCI Host Controller +[ 62.839982] ehci-platform ee080100.usb: new USB bus registered, assigned bus number 3 +``` + +Fixes: 0f86a559900f ("phy: renesas: rcar-gen3-usb2: Lock around hardware registers and driver data") +Cc: stable@vger.kernel.org +Cc: Claudiu Beznea +Cc: Sasha Levin +Signed-off-by: Nobuhiro Iwamatsu +Signed-off-by: Sasha Levin +--- + drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +index 5166a115879ea1..90f2a0e5b2aa05 100644 +--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c ++++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +@@ -386,7 +386,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + +- msleep(20); ++ mdelay(20); + + writel(0xffffffff, usb2_base + USB2_OBINTSTA); + writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series new file mode 100644 index 0000000000..f27a9a696b --- /dev/null +++ b/queue-5.10/series @@ -0,0 +1,4 @@ +alsa-usb-audio-fix-null-pointer-dereference-on-point.patch +net-sched-cls_fw-fix-null-dereference-of-old-filters.patch +phy-renesas-rcar-gen3-usb2-fix-the-use-of-msleep-dur.patch +net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch diff --git a/queue-5.15/dmaengine-idxd-fix-not-releasing-workqueue-on-.relea.patch b/queue-5.15/dmaengine-idxd-fix-not-releasing-workqueue-on-.relea.patch new file mode 100644 index 0000000000..47ab200250 --- /dev/null +++ b/queue-5.15/dmaengine-idxd-fix-not-releasing-workqueue-on-.relea.patch @@ -0,0 +1,53 @@ +From dd377066acf6a499d33d775bc6b01e388213a569 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 13:24:12 +0800 +Subject: dmaengine: idxd: Fix not releasing workqueue on .release() + +From: Vinicius Costa Gomes + +[ Upstream commit 3d33de353b1ff9023d5ec73b9becf80ea87af695 ] + +The workqueue associated with an DSA/IAA device is not released when +the object is freed. + +Fixes: 47c16ac27d4c ("dmaengine: idxd: fix idxd conf_dev 'struct device' lifetime") +Reviewed-by: Dave Jiang +Signed-off-by: Vinicius Costa Gomes +Link: https://patch.msgid.link/20260121-idxd-fix-flr-on-kernel-queues-v3-v3-7-7ed70658a9d1@intel.com +Signed-off-by: Vinod Koul +[ Remove destroy_workqueue(idxd->wq) from the function idxd_remove() to +avoid the workqueue is released twice. ] +Signed-off-by: Wenshan Lan +Signed-off-by: Sasha Levin +--- + drivers/dma/idxd/init.c | 1 - + drivers/dma/idxd/sysfs.c | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c +index f2d27c6ec1ce88..698387103da738 100644 +--- a/drivers/dma/idxd/init.c ++++ b/drivers/dma/idxd/init.c +@@ -829,7 +829,6 @@ static void idxd_remove(struct pci_dev *pdev) + pci_iounmap(pdev, idxd->reg_base); + iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); + pci_disable_device(pdev); +- destroy_workqueue(idxd->wq); + perfmon_pmu_remove(idxd); + put_device(idxd_confdev(idxd)); + } +diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c +index 489a9d8850764b..ee208dfdd0cb51 100644 +--- a/drivers/dma/idxd/sysfs.c ++++ b/drivers/dma/idxd/sysfs.c +@@ -1271,6 +1271,7 @@ static void idxd_conf_device_release(struct device *dev) + { + struct idxd_device *idxd = confdev_to_idxd(dev); + ++ destroy_workqueue(idxd->wq); + kfree(idxd->groups); + kfree(idxd->wqs); + kfree(idxd->engines); +-- +2.53.0 + diff --git a/queue-5.15/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch b/queue-5.15/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch new file mode 100644 index 0000000000..0f3fecd8e7 --- /dev/null +++ b/queue-5.15/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch @@ -0,0 +1,66 @@ +From 7dbfa79727370ef895b883a5e7be5772b163ef45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Sep 2023 11:15:18 -0300 +Subject: drm: Remove plane hsub/vsub alignment requirement for core helpers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Carlos Eduardo Gallo Filho + +[ Upstream commit f2f455981a34ce8ca88a41458c09494b387d344f ] + +The drm_format_info_plane_{height,width} functions was implemented using +regular division for the plane size calculation, which cause issues [1][2] +when used on contexts where the dimensions are misaligned with relation +to the subsampling factors. So, replace the regular division by the +DIV_ROUND_UP macro. + +This allows these functions to be used in more drivers, making further +work to bring more core presence on them possible. + +[1] http://patchwork.freedesktop.org/patch/msgid/20170321181218.10042-3-ville.syrjala@linux.intel.com +[2] https://patchwork.freedesktop.org/patch/msgid/20211026225105.2783797-2-imre.deak@intel.com + +Signed-off-by: Carlos Eduardo Gallo Filho +Reviewed-by: André Almeida +Signed-off-by: Thomas Zimmermann +Link: https://patchwork.freedesktop.org/patch/msgid/20230926141519.9315-2-gcarlos@disroot.org +Signed-off-by: Sasha Levin +--- + include/drm/drm_fourcc.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h +index 22aa64d07c7905..78ef00b94a4635 100644 +--- a/include/drm/drm_fourcc.h ++++ b/include/drm/drm_fourcc.h +@@ -22,6 +22,7 @@ + #ifndef __DRM_FOURCC_H__ + #define __DRM_FOURCC_H__ + ++#include + #include + #include + +@@ -276,7 +277,7 @@ int drm_format_info_plane_width(const struct drm_format_info *info, int width, + if (plane == 0) + return width; + +- return width / info->hsub; ++ return DIV_ROUND_UP(width, info->hsub); + } + + /** +@@ -298,7 +299,7 @@ int drm_format_info_plane_height(const struct drm_format_info *info, int height, + if (plane == 0) + return height; + +- return height / info->vsub; ++ return DIV_ROUND_UP(height, info->vsub); + } + + const struct drm_format_info *__drm_format_info(u32 format); +-- +2.53.0 + diff --git a/queue-5.15/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch b/queue-5.15/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch new file mode 100644 index 0000000000..16fccf4523 --- /dev/null +++ b/queue-5.15/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch @@ -0,0 +1,55 @@ +From f9ae7c1e69f317ef515bc4e59db6c94b118c06c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 15:38:11 +0800 +Subject: net: cpsw_new: Fix potential unregister of netdev that has not been + registered yet + +From: Kevin Hao + +[ Upstream commit 9d724b34fbe13b71865ad0906a4be97571f19cf5 ] + +If an error occurs during register_netdev() for the first MAC in +cpsw_register_ports(), even though cpsw->slaves[0].ndev is set to NULL, +cpsw->slaves[1].ndev would remain unchanged. This could later cause +cpsw_unregister_ports() to attempt unregistering the second MAC. +To address this, add a check for ndev->reg_state before calling +unregister_netdev(). With this change, setting cpsw->slaves[i].ndev +to NULL becomes unnecessary and can be removed accordingly. + +Fixes: ed3525eda4c4 ("net: ethernet: ti: introduce cpsw switchdev based driver part 1 - dual-emac") +Signed-off-by: Kevin Hao +Cc: stable@vger.kernel.org +Reviewed-by: Alexander Sverdlin +Link: https://patch.msgid.link/20260205-cpsw-error-path-v1-2-6e58bae6b299@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Wenshan Lan +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/cpsw_new.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index 9d52b949ae3f95..bef2c71b905972 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -1447,7 +1447,8 @@ static void cpsw_unregister_ports(struct cpsw_common *cpsw) + int i = 0; + + for (i = 0; i < cpsw->data.slaves; i++) { +- if (!cpsw->slaves[i].ndev) ++ if (!cpsw->slaves[i].ndev || ++ cpsw->slaves[i].ndev->reg_state != NETREG_REGISTERED) + continue; + + unregister_netdev(cpsw->slaves[i].ndev); +@@ -1467,7 +1468,6 @@ static int cpsw_register_ports(struct cpsw_common *cpsw) + if (ret) { + dev_err(cpsw->dev, + "cpsw: err registering net device%d\n", i); +- cpsw->slaves[i].ndev = NULL; + break; + } + } +-- +2.53.0 + diff --git a/queue-5.15/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch b/queue-5.15/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch new file mode 100644 index 0000000000..d4c6c1ff6a --- /dev/null +++ b/queue-5.15/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch @@ -0,0 +1,71 @@ +From 064f67d7f6cea701db841802e86e75a12951291b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:50:14 +0800 +Subject: net: mctp: ensure our nlmsg responses are initialised + +From: Jeremy Kerr + +[ Upstream commit a6a9bc544b675d8b5180f2718ec985ad267b5cbf ] + +Syed Faraz Abrar (@farazsth98) from Zellic, and Pumpkin (@u1f383) from +DEVCORE Research Team working with Trend Micro Zero Day Initiative +report that a RTM_GETNEIGH will return uninitalised data in the pad +bytes of the ndmsg data. + +Ensure we're initialising the netlink data to zero, in the link, addr +and neigh response messages. + +Fixes: 831119f88781 ("mctp: Add neighbour netlink interface") +Fixes: 06d2f4c583a7 ("mctp: Add netlink route management") +Fixes: 583be982d934 ("mctp: Add device handling and netlink interface") +Signed-off-by: Jeremy Kerr +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260209-dev-mctp-nlmsg-v1-1-f1e30c346a43@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Li hongliang <1468888505@139.com> +Signed-off-by: Sasha Levin +--- + net/mctp/device.c | 1 + + net/mctp/neigh.c | 1 + + net/mctp/route.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/net/mctp/device.c b/net/mctp/device.c +index aec7ffad2666ab..a11d5aca201c27 100644 +--- a/net/mctp/device.c ++++ b/net/mctp/device.c +@@ -55,6 +55,7 @@ static int mctp_fill_addrinfo(struct sk_buff *skb, struct netlink_callback *cb, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ifa_family = AF_MCTP; + hdr->ifa_prefixlen = 0; + hdr->ifa_flags = 0; +diff --git a/net/mctp/neigh.c b/net/mctp/neigh.c +index bc75a263719c77..18a6be38f17211 100644 +--- a/net/mctp/neigh.c ++++ b/net/mctp/neigh.c +@@ -217,6 +217,7 @@ static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ndm_family = AF_MCTP; + hdr->ndm_ifindex = dev->ifindex; + hdr->ndm_state = 0; // TODO other state bits? +diff --git a/net/mctp/route.c b/net/mctp/route.c +index 48d32bfd386363..a93796eb0a092c 100644 +--- a/net/mctp/route.c ++++ b/net/mctp/route.c +@@ -1031,6 +1031,7 @@ static int mctp_fill_rtinfo(struct sk_buff *skb, struct mctp_route *rt, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->rtm_family = AF_MCTP; + + /* we use the _len fields as a number of EIDs, rather than +-- +2.53.0 + diff --git a/queue-5.15/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch b/queue-5.15/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch new file mode 100644 index 0000000000..9b0ea7f02b --- /dev/null +++ b/queue-5.15/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch @@ -0,0 +1,122 @@ +From f183caf9869e5a9abe3197437c92966494630e77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 17:24:36 +0200 +Subject: net/sched: cls_fw: fix NULL dereference of "old" filters before + change() + +From: Davide Caratti + +[ Upstream commit 65782b2db7321d5f97c16718c4c7f6c7205a56be ] + +Like pointed out by Sashiko [1], since commit ed76f5edccc9 ("net: sched: +protect filter_chain list with filter_chain_lock mutex") TC filters are +added to a shared block and published to datapath before their ->change() +function is called. This is a problem for cls_fw: an invalid filter +created with the "old" method can still classify some packets before it +is destroyed by the validation logic added by Xiang. +Therefore, insisting with repeated runs of the following script: + + # ip link add dev crash0 type dummy + # ip link set dev crash0 up + # mausezahn crash0 -c 100000 -P 10 \ + > -A 4.3.2.1 -B 1.2.3.4 -t udp "dp=1234" -q & + # sleep 1 + # tc qdisc add dev crash0 egress_block 1 clsact + # tc filter add block 1 protocol ip prio 1 matchall \ + > action skbedit mark 65536 continue + # tc filter add block 1 protocol ip prio 2 fw + # ip link del dev crash0 + +can still make fw_classify() hit the WARN_ON() in [2]: + + WARNING: ./include/net/pkt_cls.h:88 at fw_classify+0x244/0x250 [cls_fw], CPU#18: mausezahn/1399 + Modules linked in: cls_fw(E) act_skbedit(E) + CPU: 18 UID: 0 PID: 1399 Comm: mausezahn Tainted: G E 7.0.0-rc6-virtme #17 PREEMPT(full) + Tainted: [E]=UNSIGNED_MODULE + Hardware name: Red Hat KVM, BIOS 1.16.3-2.el9 04/01/2014 + RIP: 0010:fw_classify+0x244/0x250 [cls_fw] + Code: 5c 49 c7 45 00 00 00 00 00 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 5b b8 ff ff ff ff 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 90 <0f> 0b 90 eb a0 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 + RSP: 0018:ffffd1b7026bf8a8 EFLAGS: 00010202 + RAX: ffff8c5ac9c60800 RBX: ffff8c5ac99322c0 RCX: 0000000000000004 + RDX: 0000000000000001 RSI: ffff8c5b74d7a000 RDI: ffff8c5ac8284f40 + RBP: ffffd1b7026bf8d0 R08: 0000000000000000 R09: ffffd1b7026bf9b0 + R10: 00000000ffffffff R11: 0000000000000000 R12: 0000000000010000 + R13: ffffd1b7026bf930 R14: ffff8c5ac8284f40 R15: 0000000000000000 + FS: 00007fca40c37740(0000) GS:ffff8c5b74d7a000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007fca40e822a0 CR3: 0000000005ca0001 CR4: 0000000000172ef0 + Call Trace: + + tcf_classify+0x17d/0x5c0 + tc_run+0x9d/0x150 + __dev_queue_xmit+0x2ab/0x14d0 + ip_finish_output2+0x340/0x8f0 + ip_output+0xa4/0x250 + raw_sendmsg+0x147d/0x14b0 + __sys_sendto+0x1cc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x126/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7fca40e822ba + Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89 + RSP: 002b:00007ffc248a42c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 000055ef233289d0 RCX: 00007fca40e822ba + RDX: 000000000000001e RSI: 000055ef23328c30 RDI: 0000000000000003 + RBP: 000055ef233289d0 R08: 00007ffc248a42d0 R09: 0000000000000010 + R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000001e + R13: 00000000000186a0 R14: 0000000000000000 R15: 00007fca41043000 + + irq event stamp: 1045778 + hardirqs last enabled at (1045784): [] __up_console_sem+0x52/0x60 + hardirqs last disabled at (1045789): [] __up_console_sem+0x37/0x60 + softirqs last enabled at (1045426): [] __alloc_skb+0x207/0x260 + softirqs last disabled at (1045434): [] __dev_queue_xmit+0x78/0x14d0 + +Then, because of the value in the packet's mark, dereference on 'q->handle' +with NULL 'q' occurs: + + BUG: kernel NULL pointer dereference, address: 0000000000000038 + [...] + RIP: 0010:fw_classify+0x1fe/0x250 [cls_fw] + [...] + +Skip "old-style" classification on shared blocks, so that the NULL +dereference is fixed and WARN_ON() is not hit anymore in the short +lifetime of invalid cls_fw "old-style" filters. + +[1] https://sashiko.dev/#/patchset/20260331050217.504278-1-xmei5%40asu.edu +[2] https://elixir.bootlin.com/linux/v7.0-rc6/source/include/net/pkt_cls.h#L86 + +Fixes: faeea8bbf6e9 ("net/sched: cls_fw: fix NULL pointer dereference on shared blocks") +Fixes: ed76f5edccc9 ("net: sched: protect filter_chain list with filter_chain_lock mutex") +Acked-by: Jamal Hadi Salim +Signed-off-by: Davide Caratti +Link: https://patch.msgid.link/e39cbd3103a337f1e515d186fe697b4459d24757.1775661704.git.dcaratti@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_fw.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c +index a4ffee135c8557..60249d7b333af3 100644 +--- a/net/sched/cls_fw.c ++++ b/net/sched/cls_fw.c +@@ -72,9 +72,13 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, + } + } + } else { +- struct Qdisc *q = tcf_block_q(tp->chain->block); ++ struct Qdisc *q; + + /* Old method: classify the packet using its skb mark. */ ++ if (tcf_block_shared(tp->chain->block)) ++ return -1; ++ ++ q = tcf_block_q(tp->chain->block); + if (id && (TC_H_MAJ(id) == 0 || + !(TC_H_MAJ(id ^ q->handle)))) { + res->classid = id; +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch b/queue-5.15/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch new file mode 100644 index 0000000000..67e545dd36 --- /dev/null +++ b/queue-5.15/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch @@ -0,0 +1,79 @@ +From 4fdf09884af2aa559968839a79ac8ab334110825 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 11:29:56 -0400 +Subject: net/sched: sch_sfb: Replace direct dequeue call with peek and + qdisc_dequeue_peeked + +From: Victor Nogueria + +[ Upstream commit 1b9bc71153b01dbde8045b9edede4240f4f5520e ] + +When sfb has children (eg qfq qdisc) whose peek() callback is +qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such +qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from +its child (sfb in this case), it will do the following: + 1a. do a peek() - and when sensing there's an skb the child can offer, then + - the child in this case(sfb) calls its child's (qfq) peek. + qfq does the right thing and will return the gso_skb queue packet. + Note: if there wasnt a gso_skb entry then qfq will store it there. + 1b. invoke a dequeue() on the child (sfb). And herein lies the problem. + - sfb will call the child's dequeue() which will essentially just + try to grab something of qfq's queue. + +[ 127.594489][ T453] KASAN: null-ptr-deref in range [0x0000000000000048-0x000000000000004f] +[ 127.594741][ T453] CPU: 2 UID: 0 PID: 453 Comm: ping Not tainted 7.1.0-rc1-00035-gac961974495b-dirty #793 PREEMPT(full) +[ 127.595059][ T453] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +[ 127.595254][ T453] RIP: 0010:qfq_dequeue+0x35c/0x1650 [sch_qfq] +[ 127.595461][ T453] Code: 00 fc ff df 80 3c 02 00 0f 85 17 0e 00 00 4c 8d 73 48 48 89 9d b8 02 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 76 0c 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b +[ 127.596081][ T453] RSP: 0018:ffff88810e5af440 EFLAGS: 00010216 +[ 127.596337][ T453] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: dffffc0000000000 +[ 127.596623][ T453] RDX: 0000000000000009 RSI: 0000001880000000 RDI: ffff888104fd82b0 +[ 127.596917][ T453] RBP: ffff888104fd8000 R08: ffff888104fd8280 R09: 1ffff110211893a3 +[ 127.597165][ T453] R10: 1ffff110211893a6 R11: 1ffff110211893a7 R12: 0000001880000000 +[ 127.597404][ T453] R13: ffff888104fd82b8 R14: 0000000000000048 R15: 0000000040000000 +[ 127.597644][ T453] FS: 00007fc380cbfc40(0000) GS:ffff88816f2a8000(0000) knlGS:0000000000000000 +[ 127.597956][ T453] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 127.598160][ T453] CR2: 00005610aa9890a8 CR3: 000000010369e000 CR4: 0000000000750ef0 +[ 127.598390][ T453] PKRU: 55555554 +[ 127.598509][ T453] Call Trace: +[ 127.598629][ T453] +[ 127.598718][ T453] ? mark_held_locks+0x40/0x70 +[ 127.598890][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599053][ T453] sfb_dequeue+0x88/0x4d0 +[ 127.599174][ T453] ? ktime_get+0x137/0x230 +[ 127.599328][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599480][ T453] ? qdisc_peek_dequeued+0x7b/0x350 [sch_qfq] +[ 127.599670][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599831][ T453] tbf_dequeue+0x6b1/0x1098 [sch_tbf] +[ 127.599988][ T453] __qdisc_run+0x169/0x1900 + +The right thing to do in #1b is to grab the skb off gso_skb queue. +This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked() +method instead. + +Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler") +Signed-off-by: Victor Nogueria +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260430152957.194015-3-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index 497bc022fc0c10..45787f7d86477d 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -439,7 +439,7 @@ static struct sk_buff *sfb_dequeue(struct Qdisc *sch) + struct Qdisc *child = q->qdisc; + struct sk_buff *skb; + +- skb = child->dequeue(q->qdisc); ++ skb = qdisc_dequeue_peeked(child); + + if (skb) { + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series new file mode 100644 index 0000000000..b08d13ad77 --- /dev/null +++ b/queue-5.15/series @@ -0,0 +1,6 @@ +net-sched-cls_fw-fix-null-dereference-of-old-filters.patch +net-mctp-ensure-our-nlmsg-responses-are-initialised.patch +net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch +drm-remove-plane-hsub-vsub-alignment-requirement-for.patch +dmaengine-idxd-fix-not-releasing-workqueue-on-.relea.patch +net-cpsw_new-fix-potential-unregister-of-netdev-that.patch diff --git a/queue-6.1/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch b/queue-6.1/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch new file mode 100644 index 0000000000..3d9f5d7928 --- /dev/null +++ b/queue-6.1/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch @@ -0,0 +1,66 @@ +From 496aa7947f806ec8bd59668275ffbf136e5f9269 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Sep 2023 11:15:18 -0300 +Subject: drm: Remove plane hsub/vsub alignment requirement for core helpers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Carlos Eduardo Gallo Filho + +[ Upstream commit f2f455981a34ce8ca88a41458c09494b387d344f ] + +The drm_format_info_plane_{height,width} functions was implemented using +regular division for the plane size calculation, which cause issues [1][2] +when used on contexts where the dimensions are misaligned with relation +to the subsampling factors. So, replace the regular division by the +DIV_ROUND_UP macro. + +This allows these functions to be used in more drivers, making further +work to bring more core presence on them possible. + +[1] http://patchwork.freedesktop.org/patch/msgid/20170321181218.10042-3-ville.syrjala@linux.intel.com +[2] https://patchwork.freedesktop.org/patch/msgid/20211026225105.2783797-2-imre.deak@intel.com + +Signed-off-by: Carlos Eduardo Gallo Filho +Reviewed-by: André Almeida +Signed-off-by: Thomas Zimmermann +Link: https://patchwork.freedesktop.org/patch/msgid/20230926141519.9315-2-gcarlos@disroot.org +Signed-off-by: Sasha Levin +--- + include/drm/drm_fourcc.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h +index 532ae78ca747e6..ccf91daa430702 100644 +--- a/include/drm/drm_fourcc.h ++++ b/include/drm/drm_fourcc.h +@@ -22,6 +22,7 @@ + #ifndef __DRM_FOURCC_H__ + #define __DRM_FOURCC_H__ + ++#include + #include + #include + +@@ -279,7 +280,7 @@ int drm_format_info_plane_width(const struct drm_format_info *info, int width, + if (plane == 0) + return width; + +- return width / info->hsub; ++ return DIV_ROUND_UP(width, info->hsub); + } + + /** +@@ -301,7 +302,7 @@ int drm_format_info_plane_height(const struct drm_format_info *info, int height, + if (plane == 0) + return height; + +- return height / info->vsub; ++ return DIV_ROUND_UP(height, info->vsub); + } + + const struct drm_format_info *__drm_format_info(u32 format); +-- +2.53.0 + diff --git a/queue-6.1/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch b/queue-6.1/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch new file mode 100644 index 0000000000..2c8056014d --- /dev/null +++ b/queue-6.1/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch @@ -0,0 +1,55 @@ +From 051d4a307d558c6da4bb63af2abe7fa45d0ac563 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 15:37:56 +0800 +Subject: net: cpsw_new: Fix potential unregister of netdev that has not been + registered yet + +From: Kevin Hao + +[ Upstream commit 9d724b34fbe13b71865ad0906a4be97571f19cf5 ] + +If an error occurs during register_netdev() for the first MAC in +cpsw_register_ports(), even though cpsw->slaves[0].ndev is set to NULL, +cpsw->slaves[1].ndev would remain unchanged. This could later cause +cpsw_unregister_ports() to attempt unregistering the second MAC. +To address this, add a check for ndev->reg_state before calling +unregister_netdev(). With this change, setting cpsw->slaves[i].ndev +to NULL becomes unnecessary and can be removed accordingly. + +Fixes: ed3525eda4c4 ("net: ethernet: ti: introduce cpsw switchdev based driver part 1 - dual-emac") +Signed-off-by: Kevin Hao +Cc: stable@vger.kernel.org +Reviewed-by: Alexander Sverdlin +Link: https://patch.msgid.link/20260205-cpsw-error-path-v1-2-6e58bae6b299@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Wenshan Lan +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/cpsw_new.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index c99dde9dbe7750..17c267f6d79aa9 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -1437,7 +1437,8 @@ static void cpsw_unregister_ports(struct cpsw_common *cpsw) + int i = 0; + + for (i = 0; i < cpsw->data.slaves; i++) { +- if (!cpsw->slaves[i].ndev) ++ if (!cpsw->slaves[i].ndev || ++ cpsw->slaves[i].ndev->reg_state != NETREG_REGISTERED) + continue; + + unregister_netdev(cpsw->slaves[i].ndev); +@@ -1457,7 +1458,6 @@ static int cpsw_register_ports(struct cpsw_common *cpsw) + if (ret) { + dev_err(cpsw->dev, + "cpsw: err registering net device%d\n", i); +- cpsw->slaves[i].ndev = NULL; + break; + } + } +-- +2.53.0 + diff --git a/queue-6.1/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch b/queue-6.1/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch new file mode 100644 index 0000000000..79d67366c4 --- /dev/null +++ b/queue-6.1/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch @@ -0,0 +1,71 @@ +From c4c0c7079ec5427e9e949372ba9bb6f98f8416bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:50:05 +0800 +Subject: net: mctp: ensure our nlmsg responses are initialised + +From: Jeremy Kerr + +[ Upstream commit a6a9bc544b675d8b5180f2718ec985ad267b5cbf ] + +Syed Faraz Abrar (@farazsth98) from Zellic, and Pumpkin (@u1f383) from +DEVCORE Research Team working with Trend Micro Zero Day Initiative +report that a RTM_GETNEIGH will return uninitalised data in the pad +bytes of the ndmsg data. + +Ensure we're initialising the netlink data to zero, in the link, addr +and neigh response messages. + +Fixes: 831119f88781 ("mctp: Add neighbour netlink interface") +Fixes: 06d2f4c583a7 ("mctp: Add netlink route management") +Fixes: 583be982d934 ("mctp: Add device handling and netlink interface") +Signed-off-by: Jeremy Kerr +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260209-dev-mctp-nlmsg-v1-1-f1e30c346a43@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Li hongliang <1468888505@139.com> +Signed-off-by: Sasha Levin +--- + net/mctp/device.c | 1 + + net/mctp/neigh.c | 1 + + net/mctp/route.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/net/mctp/device.c b/net/mctp/device.c +index 85cc5f31f1e7c0..fd368249246dff 100644 +--- a/net/mctp/device.c ++++ b/net/mctp/device.c +@@ -71,6 +71,7 @@ static int mctp_fill_addrinfo(struct sk_buff *skb, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ifa_family = AF_MCTP; + hdr->ifa_prefixlen = 0; + hdr->ifa_flags = 0; +diff --git a/net/mctp/neigh.c b/net/mctp/neigh.c +index 590f642413e4ef..c0151a69d2b7c2 100644 +--- a/net/mctp/neigh.c ++++ b/net/mctp/neigh.c +@@ -218,6 +218,7 @@ static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ndm_family = AF_MCTP; + hdr->ndm_ifindex = dev->ifindex; + hdr->ndm_state = 0; // TODO other state bits? +diff --git a/net/mctp/route.c b/net/mctp/route.c +index fdeaf80691e555..c9b0b75422432e 100644 +--- a/net/mctp/route.c ++++ b/net/mctp/route.c +@@ -1331,6 +1331,7 @@ static int mctp_fill_rtinfo(struct sk_buff *skb, struct mctp_route *rt, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->rtm_family = AF_MCTP; + + /* we use the _len fields as a number of EIDs, rather than +-- +2.53.0 + diff --git a/queue-6.1/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch b/queue-6.1/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch new file mode 100644 index 0000000000..9d81e1250b --- /dev/null +++ b/queue-6.1/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch @@ -0,0 +1,122 @@ +From 32307ae23d1035c2d7aca164930f2f7b987e666c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 17:24:36 +0200 +Subject: net/sched: cls_fw: fix NULL dereference of "old" filters before + change() + +From: Davide Caratti + +[ Upstream commit 65782b2db7321d5f97c16718c4c7f6c7205a56be ] + +Like pointed out by Sashiko [1], since commit ed76f5edccc9 ("net: sched: +protect filter_chain list with filter_chain_lock mutex") TC filters are +added to a shared block and published to datapath before their ->change() +function is called. This is a problem for cls_fw: an invalid filter +created with the "old" method can still classify some packets before it +is destroyed by the validation logic added by Xiang. +Therefore, insisting with repeated runs of the following script: + + # ip link add dev crash0 type dummy + # ip link set dev crash0 up + # mausezahn crash0 -c 100000 -P 10 \ + > -A 4.3.2.1 -B 1.2.3.4 -t udp "dp=1234" -q & + # sleep 1 + # tc qdisc add dev crash0 egress_block 1 clsact + # tc filter add block 1 protocol ip prio 1 matchall \ + > action skbedit mark 65536 continue + # tc filter add block 1 protocol ip prio 2 fw + # ip link del dev crash0 + +can still make fw_classify() hit the WARN_ON() in [2]: + + WARNING: ./include/net/pkt_cls.h:88 at fw_classify+0x244/0x250 [cls_fw], CPU#18: mausezahn/1399 + Modules linked in: cls_fw(E) act_skbedit(E) + CPU: 18 UID: 0 PID: 1399 Comm: mausezahn Tainted: G E 7.0.0-rc6-virtme #17 PREEMPT(full) + Tainted: [E]=UNSIGNED_MODULE + Hardware name: Red Hat KVM, BIOS 1.16.3-2.el9 04/01/2014 + RIP: 0010:fw_classify+0x244/0x250 [cls_fw] + Code: 5c 49 c7 45 00 00 00 00 00 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 5b b8 ff ff ff ff 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 90 <0f> 0b 90 eb a0 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 + RSP: 0018:ffffd1b7026bf8a8 EFLAGS: 00010202 + RAX: ffff8c5ac9c60800 RBX: ffff8c5ac99322c0 RCX: 0000000000000004 + RDX: 0000000000000001 RSI: ffff8c5b74d7a000 RDI: ffff8c5ac8284f40 + RBP: ffffd1b7026bf8d0 R08: 0000000000000000 R09: ffffd1b7026bf9b0 + R10: 00000000ffffffff R11: 0000000000000000 R12: 0000000000010000 + R13: ffffd1b7026bf930 R14: ffff8c5ac8284f40 R15: 0000000000000000 + FS: 00007fca40c37740(0000) GS:ffff8c5b74d7a000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007fca40e822a0 CR3: 0000000005ca0001 CR4: 0000000000172ef0 + Call Trace: + + tcf_classify+0x17d/0x5c0 + tc_run+0x9d/0x150 + __dev_queue_xmit+0x2ab/0x14d0 + ip_finish_output2+0x340/0x8f0 + ip_output+0xa4/0x250 + raw_sendmsg+0x147d/0x14b0 + __sys_sendto+0x1cc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x126/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7fca40e822ba + Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89 + RSP: 002b:00007ffc248a42c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 000055ef233289d0 RCX: 00007fca40e822ba + RDX: 000000000000001e RSI: 000055ef23328c30 RDI: 0000000000000003 + RBP: 000055ef233289d0 R08: 00007ffc248a42d0 R09: 0000000000000010 + R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000001e + R13: 00000000000186a0 R14: 0000000000000000 R15: 00007fca41043000 + + irq event stamp: 1045778 + hardirqs last enabled at (1045784): [] __up_console_sem+0x52/0x60 + hardirqs last disabled at (1045789): [] __up_console_sem+0x37/0x60 + softirqs last enabled at (1045426): [] __alloc_skb+0x207/0x260 + softirqs last disabled at (1045434): [] __dev_queue_xmit+0x78/0x14d0 + +Then, because of the value in the packet's mark, dereference on 'q->handle' +with NULL 'q' occurs: + + BUG: kernel NULL pointer dereference, address: 0000000000000038 + [...] + RIP: 0010:fw_classify+0x1fe/0x250 [cls_fw] + [...] + +Skip "old-style" classification on shared blocks, so that the NULL +dereference is fixed and WARN_ON() is not hit anymore in the short +lifetime of invalid cls_fw "old-style" filters. + +[1] https://sashiko.dev/#/patchset/20260331050217.504278-1-xmei5%40asu.edu +[2] https://elixir.bootlin.com/linux/v7.0-rc6/source/include/net/pkt_cls.h#L86 + +Fixes: faeea8bbf6e9 ("net/sched: cls_fw: fix NULL pointer dereference on shared blocks") +Fixes: ed76f5edccc9 ("net: sched: protect filter_chain list with filter_chain_lock mutex") +Acked-by: Jamal Hadi Salim +Signed-off-by: Davide Caratti +Link: https://patch.msgid.link/e39cbd3103a337f1e515d186fe697b4459d24757.1775661704.git.dcaratti@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_fw.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c +index 366bcc960e43e6..979662292dced6 100644 +--- a/net/sched/cls_fw.c ++++ b/net/sched/cls_fw.c +@@ -72,9 +72,13 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, + } + } + } else { +- struct Qdisc *q = tcf_block_q(tp->chain->block); ++ struct Qdisc *q; + + /* Old method: classify the packet using its skb mark. */ ++ if (tcf_block_shared(tp->chain->block)) ++ return -1; ++ ++ q = tcf_block_q(tp->chain->block); + if (id && (TC_H_MAJ(id) == 0 || + !(TC_H_MAJ(id ^ q->handle)))) { + res->classid = id; +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch b/queue-6.1/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch new file mode 100644 index 0000000000..5f56c68996 --- /dev/null +++ b/queue-6.1/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch @@ -0,0 +1,79 @@ +From 0a4acbedca9332c494ab8692a7ed701e8b7d6096 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 11:29:56 -0400 +Subject: net/sched: sch_sfb: Replace direct dequeue call with peek and + qdisc_dequeue_peeked + +From: Victor Nogueria + +[ Upstream commit 1b9bc71153b01dbde8045b9edede4240f4f5520e ] + +When sfb has children (eg qfq qdisc) whose peek() callback is +qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such +qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from +its child (sfb in this case), it will do the following: + 1a. do a peek() - and when sensing there's an skb the child can offer, then + - the child in this case(sfb) calls its child's (qfq) peek. + qfq does the right thing and will return the gso_skb queue packet. + Note: if there wasnt a gso_skb entry then qfq will store it there. + 1b. invoke a dequeue() on the child (sfb). And herein lies the problem. + - sfb will call the child's dequeue() which will essentially just + try to grab something of qfq's queue. + +[ 127.594489][ T453] KASAN: null-ptr-deref in range [0x0000000000000048-0x000000000000004f] +[ 127.594741][ T453] CPU: 2 UID: 0 PID: 453 Comm: ping Not tainted 7.1.0-rc1-00035-gac961974495b-dirty #793 PREEMPT(full) +[ 127.595059][ T453] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +[ 127.595254][ T453] RIP: 0010:qfq_dequeue+0x35c/0x1650 [sch_qfq] +[ 127.595461][ T453] Code: 00 fc ff df 80 3c 02 00 0f 85 17 0e 00 00 4c 8d 73 48 48 89 9d b8 02 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 76 0c 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b +[ 127.596081][ T453] RSP: 0018:ffff88810e5af440 EFLAGS: 00010216 +[ 127.596337][ T453] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: dffffc0000000000 +[ 127.596623][ T453] RDX: 0000000000000009 RSI: 0000001880000000 RDI: ffff888104fd82b0 +[ 127.596917][ T453] RBP: ffff888104fd8000 R08: ffff888104fd8280 R09: 1ffff110211893a3 +[ 127.597165][ T453] R10: 1ffff110211893a6 R11: 1ffff110211893a7 R12: 0000001880000000 +[ 127.597404][ T453] R13: ffff888104fd82b8 R14: 0000000000000048 R15: 0000000040000000 +[ 127.597644][ T453] FS: 00007fc380cbfc40(0000) GS:ffff88816f2a8000(0000) knlGS:0000000000000000 +[ 127.597956][ T453] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 127.598160][ T453] CR2: 00005610aa9890a8 CR3: 000000010369e000 CR4: 0000000000750ef0 +[ 127.598390][ T453] PKRU: 55555554 +[ 127.598509][ T453] Call Trace: +[ 127.598629][ T453] +[ 127.598718][ T453] ? mark_held_locks+0x40/0x70 +[ 127.598890][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599053][ T453] sfb_dequeue+0x88/0x4d0 +[ 127.599174][ T453] ? ktime_get+0x137/0x230 +[ 127.599328][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599480][ T453] ? qdisc_peek_dequeued+0x7b/0x350 [sch_qfq] +[ 127.599670][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599831][ T453] tbf_dequeue+0x6b1/0x1098 [sch_tbf] +[ 127.599988][ T453] __qdisc_run+0x169/0x1900 + +The right thing to do in #1b is to grab the skb off gso_skb queue. +This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked() +method instead. + +Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler") +Signed-off-by: Victor Nogueria +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260430152957.194015-3-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index ce67826fdf9b6d..58bf4c803f7fee 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -439,7 +439,7 @@ static struct sk_buff *sfb_dequeue(struct Qdisc *sch) + struct Qdisc *child = q->qdisc; + struct sk_buff *skb; + +- skb = child->dequeue(q->qdisc); ++ skb = qdisc_dequeue_peeked(child); + + if (skb) { + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series new file mode 100644 index 0000000000..55f8f58b1d --- /dev/null +++ b/queue-6.1/series @@ -0,0 +1,5 @@ +net-sched-cls_fw-fix-null-dereference-of-old-filters.patch +net-mctp-ensure-our-nlmsg-responses-are-initialised.patch +net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch +drm-remove-plane-hsub-vsub-alignment-requirement-for.patch +net-cpsw_new-fix-potential-unregister-of-netdev-that.patch diff --git a/queue-6.12/arm64-debug-always-unmask-interrupts-in-el0_softstp.patch b/queue-6.12/arm64-debug-always-unmask-interrupts-in-el0_softstp.patch new file mode 100644 index 0000000000..028827db3e --- /dev/null +++ b/queue-6.12/arm64-debug-always-unmask-interrupts-in-el0_softstp.patch @@ -0,0 +1,74 @@ +From 17c66a6670c62932ac125ce694477bd575a37318 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:54 +0200 +Subject: arm64: debug: always unmask interrupts in el0_softstp() + +From: Ada Couprie Diaz + +[ Upstream commit ea0d55ae4b3207c33691a73da3443b1fd379f1d2 ] + +We intend that EL0 exception handlers unmask all DAIF exceptions +before calling exit_to_user_mode(). + +When completing single-step of a suspended breakpoint, we do not call +local_daif_restore(DAIF_PROCCTX) before calling exit_to_user_mode(), +leaving all DAIF exceptions masked. + +When pseudo-NMIs are not in use this is benign. + +When pseudo-NMIs are in use, this is unsound. At this point interrupts +are masked by both DAIF.IF and PMR_EL1, and subsequent irq flag +manipulation may not work correctly. For example, a subsequent +local_irq_enable() within exit_to_user_mode_loop() will only unmask +interrupts via PMR_EL1 (leaving those masked via DAIF.IF), and +anything depending on interrupts being unmasked (e.g. delivery of +signals) will not work correctly. + +This was detected by CONFIG_ARM64_DEBUG_PRIORITY_MASKING. + +Move the call to `try_step_suspended_breakpoints()` outside of the check +so that interrupts can be unmasked even if we don't call the step handler. + +Fixes: 0ac7584c08ce ("arm64: debug: split single stepping exception entry") +Cc: # 6.17 +Signed-off-by: Ada Couprie Diaz +Acked-by: Mark Rutland +[catalin.marinas@arm.com: added Mark's rewritten commit log and some whitespace] +Signed-off-by: Catalin Marinas +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/entry-common.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c +index b98d6d1a1dfd63..ea3876d99c2ec5 100644 +--- a/arch/arm64/kernel/entry-common.c ++++ b/arch/arm64/kernel/entry-common.c +@@ -796,6 +796,8 @@ static void noinstr el0_breakpt(struct pt_regs *regs, unsigned long esr) + + static void noinstr el0_softstp(struct pt_regs *regs, unsigned long esr) + { ++ bool step_done; ++ + if (!is_ttbr0_addr(regs->pc)) + arm64_apply_bp_hardening(); + +@@ -806,10 +808,10 @@ static void noinstr el0_softstp(struct pt_regs *regs, unsigned long esr) + * If we are stepping a suspended breakpoint there's nothing more to do: + * the single-step is complete. + */ +- if (!try_step_suspended_breakpoints(regs)) { +- local_daif_restore(DAIF_PROCCTX); ++ step_done = try_step_suspended_breakpoints(regs); ++ local_daif_restore(DAIF_PROCCTX); ++ if (!step_done) + do_el0_softstep(esr, regs); +- } + exit_to_user_mode(regs); + } + +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-call-software-breakpoint-handlers-static.patch b/queue-6.12/arm64-debug-call-software-breakpoint-handlers-static.patch new file mode 100644 index 0000000000..d23e837142 --- /dev/null +++ b/queue-6.12/arm64-debug-call-software-breakpoint-handlers-static.patch @@ -0,0 +1,514 @@ +From e0ad41f855475ceff58d110677a66e1b9f2d7b7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:43 +0200 +Subject: arm64: debug: call software breakpoint handlers statically + +From: Ada Couprie Diaz + +[ Upstream commit 6adfdc5e2ef9c71a76d8d127a2eb54f0fbe9be5e ] + +Software breakpoints pass an immediate value in ESR ("comment") that can +be used to call a specialized handler (KGDB, KASAN...). +We do so in two different ways : + - During early boot, `early_brk64` statically checks against known + immediates and calls the corresponding handler, + - During init, handlers are dynamically registered into a list. When + called, the generic software breakpoint handler will iterate over + the list to find the appropriate handler. + +The dynamic registration does not provide any benefit here as it is not +exported and all its uses are within the arm64 tree. It also depends on an +RCU list, whose safe access currently relies on the non-preemptible state +of `do_debug_exception`. + +Replace the list iteration logic in `call_break_hooks` to call +the breakpoint handlers statically if they are enabled, like in +`early_brk64`. +Expose the handlers in their respective headers to be reachable from +`arch/arm64/kernel/debug-monitors.c` at link time. + +Unify the naming of the software breakpoint handlers to XXX_brk_handler(), +making it clear they are related and to differentiate from the +hardware breakpoints. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-4-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/kgdb.h | 3 + + arch/arm64/include/asm/kprobes.h | 8 +++ + arch/arm64/include/asm/traps.h | 6 ++ + arch/arm64/include/asm/uprobes.h | 2 + + arch/arm64/kernel/debug-monitors.c | 53 +++++++++++++---- + arch/arm64/kernel/kgdb.c | 22 ++----- + arch/arm64/kernel/probes/kprobes.c | 31 ++-------- + arch/arm64/kernel/probes/kprobes_trampoline.S | 2 +- + arch/arm64/kernel/probes/uprobes.c | 9 +-- + arch/arm64/kernel/traps.c | 59 ++++--------------- + 10 files changed, 82 insertions(+), 113 deletions(-) + +diff --git a/arch/arm64/include/asm/kgdb.h b/arch/arm64/include/asm/kgdb.h +index 21fc85e9d2bed8..82a76b2102fb61 100644 +--- a/arch/arm64/include/asm/kgdb.h ++++ b/arch/arm64/include/asm/kgdb.h +@@ -24,6 +24,9 @@ static inline void arch_kgdb_breakpoint(void) + extern void kgdb_handle_bus_error(void); + extern int kgdb_fault_expected; + ++int kgdb_brk_handler(struct pt_regs *regs, unsigned long esr); ++int kgdb_compiled_brk_handler(struct pt_regs *regs, unsigned long esr); ++ + #endif /* !__ASSEMBLY__ */ + + /* +diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h +index be7a3680dadff7..f2782560647bef 100644 +--- a/arch/arm64/include/asm/kprobes.h ++++ b/arch/arm64/include/asm/kprobes.h +@@ -41,4 +41,12 @@ void __kretprobe_trampoline(void); + void __kprobes *trampoline_probe_handler(struct pt_regs *regs); + + #endif /* CONFIG_KPROBES */ ++ ++int __kprobes kprobe_brk_handler(struct pt_regs *regs, ++ unsigned long esr); ++int __kprobes kprobe_ss_brk_handler(struct pt_regs *regs, ++ unsigned long esr); ++int __kprobes kretprobe_brk_handler(struct pt_regs *regs, ++ unsigned long esr); ++ + #endif /* _ARM_KPROBES_H */ +diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h +index 82cf1f879c61df..e3e8944a71c3e6 100644 +--- a/arch/arm64/include/asm/traps.h ++++ b/arch/arm64/include/asm/traps.h +@@ -29,6 +29,12 @@ void arm64_force_sig_fault_pkey(unsigned long far, const char *str, int pkey); + void arm64_force_sig_mceerr(int code, unsigned long far, short lsb, const char *str); + void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far, const char *str); + ++int bug_brk_handler(struct pt_regs *regs, unsigned long esr); ++int cfi_brk_handler(struct pt_regs *regs, unsigned long esr); ++int reserved_fault_brk_handler(struct pt_regs *regs, unsigned long esr); ++int kasan_brk_handler(struct pt_regs *regs, unsigned long esr); ++int ubsan_brk_handler(struct pt_regs *regs, unsigned long esr); ++ + int early_brk64(unsigned long addr, unsigned long esr, struct pt_regs *regs); + + /* +diff --git a/arch/arm64/include/asm/uprobes.h b/arch/arm64/include/asm/uprobes.h +index 014b02897f8e22..3659a79a9f325f 100644 +--- a/arch/arm64/include/asm/uprobes.h ++++ b/arch/arm64/include/asm/uprobes.h +@@ -28,4 +28,6 @@ struct arch_uprobe { + bool simulate; + }; + ++int uprobe_brk_handler(struct pt_regs *regs, unsigned long esr); ++ + #endif +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index 8275b7f5754626..5e892448030005 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -21,8 +21,11 @@ + #include + #include + #include ++#include ++#include + #include + #include ++#include + + /* Determine debug architecture. */ + u8 debug_monitors_arch(void) +@@ -299,22 +302,48 @@ void unregister_kernel_break_hook(struct break_hook *hook) + + static int call_break_hook(struct pt_regs *regs, unsigned long esr) + { +- struct break_hook *hook; +- struct list_head *list; +- int (*fn)(struct pt_regs *regs, unsigned long esr) = NULL; ++ if (user_mode(regs)) { ++ if (IS_ENABLED(CONFIG_UPROBES) && ++ esr_brk_comment(esr) == UPROBES_BRK_IMM) ++ return uprobe_brk_handler(regs, esr); ++ return DBG_HOOK_ERROR; ++ } + +- list = user_mode(regs) ? &user_break_hook : &kernel_break_hook; ++ if (esr_brk_comment(esr) == BUG_BRK_IMM) ++ return bug_brk_handler(regs, esr); + +- /* +- * Since brk exception disables interrupt, this function is +- * entirely not preemptible, and we can use rcu list safely here. +- */ +- list_for_each_entry_rcu(hook, list, node) { +- if ((esr_brk_comment(esr) & ~hook->mask) == hook->imm) +- fn = hook->fn; ++ if (IS_ENABLED(CONFIG_CFI_CLANG) && esr_is_cfi_brk(esr)) ++ return cfi_brk_handler(regs, esr); ++ ++ if (esr_brk_comment(esr) == FAULT_BRK_IMM) ++ return reserved_fault_brk_handler(regs, esr); ++ ++ if (IS_ENABLED(CONFIG_KASAN_SW_TAGS) && ++ (esr_brk_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM) ++ return kasan_brk_handler(regs, esr); ++ ++ if (IS_ENABLED(CONFIG_UBSAN_TRAP) && esr_is_ubsan_brk(esr)) ++ return ubsan_brk_handler(regs, esr); ++ ++ if (IS_ENABLED(CONFIG_KGDB)) { ++ if (esr_brk_comment(esr) == KGDB_DYN_DBG_BRK_IMM) ++ return kgdb_brk_handler(regs, esr); ++ if (esr_brk_comment(esr) == KGDB_COMPILED_DBG_BRK_IMM) ++ return kgdb_compiled_brk_handler(regs, esr); + } + +- return fn ? fn(regs, esr) : DBG_HOOK_ERROR; ++ if (IS_ENABLED(CONFIG_KPROBES)) { ++ if (esr_brk_comment(esr) == KPROBES_BRK_IMM) ++ return kprobe_brk_handler(regs, esr); ++ if (esr_brk_comment(esr) == KPROBES_BRK_SS_IMM) ++ return kprobe_ss_brk_handler(regs, esr); ++ } ++ ++ if (IS_ENABLED(CONFIG_KRETPROBES) && ++ esr_brk_comment(esr) == KRETPROBES_BRK_IMM) ++ return kretprobe_brk_handler(regs, esr); ++ ++ return DBG_HOOK_ERROR; + } + NOKPROBE_SYMBOL(call_break_hook); + +diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c +index 4e1f983df3d1c2..e3c9e6e11a318c 100644 +--- a/arch/arm64/kernel/kgdb.c ++++ b/arch/arm64/kernel/kgdb.c +@@ -234,21 +234,21 @@ int kgdb_arch_handle_exception(int exception_vector, int signo, + return err; + } + +-static int kgdb_brk_fn(struct pt_regs *regs, unsigned long esr) ++int kgdb_brk_handler(struct pt_regs *regs, unsigned long esr) + { + kgdb_handle_exception(1, SIGTRAP, 0, regs); + return DBG_HOOK_HANDLED; + } +-NOKPROBE_SYMBOL(kgdb_brk_fn) ++NOKPROBE_SYMBOL(kgdb_brk_handler) + +-static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned long esr) ++int kgdb_compiled_brk_handler(struct pt_regs *regs, unsigned long esr) + { + compiled_break = 1; + kgdb_handle_exception(1, SIGTRAP, 0, regs); + + return DBG_HOOK_HANDLED; + } +-NOKPROBE_SYMBOL(kgdb_compiled_brk_fn); ++NOKPROBE_SYMBOL(kgdb_compiled_brk_handler); + + static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned long esr) + { +@@ -260,16 +260,6 @@ static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned long esr) + } + NOKPROBE_SYMBOL(kgdb_step_brk_fn); + +-static struct break_hook kgdb_brkpt_hook = { +- .fn = kgdb_brk_fn, +- .imm = KGDB_DYN_DBG_BRK_IMM, +-}; +- +-static struct break_hook kgdb_compiled_brkpt_hook = { +- .fn = kgdb_compiled_brk_fn, +- .imm = KGDB_COMPILED_DBG_BRK_IMM, +-}; +- + static struct step_hook kgdb_step_hook = { + .fn = kgdb_step_brk_fn + }; +@@ -316,8 +306,6 @@ int kgdb_arch_init(void) + if (ret != 0) + return ret; + +- register_kernel_break_hook(&kgdb_brkpt_hook); +- register_kernel_break_hook(&kgdb_compiled_brkpt_hook); + register_kernel_step_hook(&kgdb_step_hook); + return 0; + } +@@ -329,8 +317,6 @@ int kgdb_arch_init(void) + */ + void kgdb_arch_exit(void) + { +- unregister_kernel_break_hook(&kgdb_brkpt_hook); +- unregister_kernel_break_hook(&kgdb_compiled_brkpt_hook); + unregister_kernel_step_hook(&kgdb_step_hook); + unregister_die_notifier(&kgdb_notifier); + } +diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c +index b0e0f0aed748a8..8661cd4064732a 100644 +--- a/arch/arm64/kernel/probes/kprobes.c ++++ b/arch/arm64/kernel/probes/kprobes.c +@@ -306,8 +306,8 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr) + return 0; + } + +-static int __kprobes +-kprobe_breakpoint_handler(struct pt_regs *regs, unsigned long esr) ++int __kprobes ++kprobe_brk_handler(struct pt_regs *regs, unsigned long esr) + { + struct kprobe *p, *cur_kprobe; + struct kprobe_ctlblk *kcb; +@@ -350,13 +350,8 @@ kprobe_breakpoint_handler(struct pt_regs *regs, unsigned long esr) + return DBG_HOOK_HANDLED; + } + +-static struct break_hook kprobes_break_hook = { +- .imm = KPROBES_BRK_IMM, +- .fn = kprobe_breakpoint_handler, +-}; +- +-static int __kprobes +-kprobe_breakpoint_ss_handler(struct pt_regs *regs, unsigned long esr) ++int __kprobes ++kprobe_ss_brk_handler(struct pt_regs *regs, unsigned long esr) + { + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + unsigned long addr = instruction_pointer(regs); +@@ -374,13 +369,8 @@ kprobe_breakpoint_ss_handler(struct pt_regs *regs, unsigned long esr) + return DBG_HOOK_ERROR; + } + +-static struct break_hook kprobes_break_ss_hook = { +- .imm = KPROBES_BRK_SS_IMM, +- .fn = kprobe_breakpoint_ss_handler, +-}; +- +-static int __kprobes +-kretprobe_breakpoint_handler(struct pt_regs *regs, unsigned long esr) ++int __kprobes ++kretprobe_brk_handler(struct pt_regs *regs, unsigned long esr) + { + if (regs->pc != (unsigned long)__kretprobe_trampoline) + return DBG_HOOK_ERROR; +@@ -389,11 +379,6 @@ kretprobe_breakpoint_handler(struct pt_regs *regs, unsigned long esr) + return DBG_HOOK_HANDLED; + } + +-static struct break_hook kretprobes_break_hook = { +- .imm = KRETPROBES_BRK_IMM, +- .fn = kretprobe_breakpoint_handler, +-}; +- + /* + * Provide a blacklist of symbols identifying ranges which cannot be kprobed. + * This blacklist is exposed to userspace via debugfs (kprobes/blacklist). +@@ -436,9 +421,5 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p) + + int __init arch_init_kprobes(void) + { +- register_kernel_break_hook(&kprobes_break_hook); +- register_kernel_break_hook(&kprobes_break_ss_hook); +- register_kernel_break_hook(&kretprobes_break_hook); +- + return 0; + } +diff --git a/arch/arm64/kernel/probes/kprobes_trampoline.S b/arch/arm64/kernel/probes/kprobes_trampoline.S +index a362f3dbb3d117..b60739d3983f60 100644 +--- a/arch/arm64/kernel/probes/kprobes_trampoline.S ++++ b/arch/arm64/kernel/probes/kprobes_trampoline.S +@@ -12,7 +12,7 @@ + SYM_CODE_START(__kretprobe_trampoline) + /* + * Trigger a breakpoint exception. The PC will be adjusted by +- * kretprobe_breakpoint_handler(), and no subsequent instructions will ++ * kretprobe_brk_handler(), and no subsequent instructions will + * be executed from the trampoline. + */ + brk #KRETPROBES_BRK_IMM +diff --git a/arch/arm64/kernel/probes/uprobes.c b/arch/arm64/kernel/probes/uprobes.c +index a2f137a595fc1c..fc1bd19c827e6f 100644 +--- a/arch/arm64/kernel/probes/uprobes.c ++++ b/arch/arm64/kernel/probes/uprobes.c +@@ -165,7 +165,7 @@ int arch_uprobe_exception_notify(struct notifier_block *self, + return NOTIFY_DONE; + } + +-static int uprobe_breakpoint_handler(struct pt_regs *regs, ++int uprobe_brk_handler(struct pt_regs *regs, + unsigned long esr) + { + if (uprobe_pre_sstep_notifier(regs)) +@@ -186,12 +186,6 @@ static int uprobe_single_step_handler(struct pt_regs *regs, + return DBG_HOOK_ERROR; + } + +-/* uprobe breakpoint handler hook */ +-static struct break_hook uprobes_break_hook = { +- .imm = UPROBES_BRK_IMM, +- .fn = uprobe_breakpoint_handler, +-}; +- + /* uprobe single step handler hook */ + static struct step_hook uprobes_step_hook = { + .fn = uprobe_single_step_handler, +@@ -199,7 +193,6 @@ static struct step_hook uprobes_step_hook = { + + static int __init arch_init_uprobes(void) + { +- register_user_break_hook(&uprobes_break_hook); + register_user_step_hook(&uprobes_step_hook); + + return 0; +diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c +index c38ebf715be764..013159bc0882ee 100644 +--- a/arch/arm64/kernel/traps.c ++++ b/arch/arm64/kernel/traps.c +@@ -978,7 +978,7 @@ void do_serror(struct pt_regs *regs, unsigned long esr) + int is_valid_bugaddr(unsigned long addr) + { + /* +- * bug_handler() only called for BRK #BUG_BRK_IMM. ++ * bug_brk_handler() only called for BRK #BUG_BRK_IMM. + * So the answer is trivial -- any spurious instances with no + * bug table entry will be rejected by report_bug() and passed + * back to the debug-monitors code and handled as a fatal +@@ -988,7 +988,7 @@ int is_valid_bugaddr(unsigned long addr) + } + #endif + +-static int bug_handler(struct pt_regs *regs, unsigned long esr) ++int bug_brk_handler(struct pt_regs *regs, unsigned long esr) + { + switch (report_bug(regs->pc, regs)) { + case BUG_TRAP_TYPE_BUG: +@@ -1008,13 +1008,8 @@ static int bug_handler(struct pt_regs *regs, unsigned long esr) + return DBG_HOOK_HANDLED; + } + +-static struct break_hook bug_break_hook = { +- .fn = bug_handler, +- .imm = BUG_BRK_IMM, +-}; +- + #ifdef CONFIG_CFI_CLANG +-static int cfi_handler(struct pt_regs *regs, unsigned long esr) ++int cfi_brk_handler(struct pt_regs *regs, unsigned long esr) + { + unsigned long target; + u32 type; +@@ -1037,15 +1032,9 @@ static int cfi_handler(struct pt_regs *regs, unsigned long esr) + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); + return DBG_HOOK_HANDLED; + } +- +-static struct break_hook cfi_break_hook = { +- .fn = cfi_handler, +- .imm = CFI_BRK_IMM_BASE, +- .mask = CFI_BRK_IMM_MASK, +-}; + #endif /* CONFIG_CFI_CLANG */ + +-static int reserved_fault_handler(struct pt_regs *regs, unsigned long esr) ++int reserved_fault_brk_handler(struct pt_regs *regs, unsigned long esr) + { + pr_err("%s generated an invalid instruction at %pS!\n", + "Kernel text patching", +@@ -1055,11 +1044,6 @@ static int reserved_fault_handler(struct pt_regs *regs, unsigned long esr) + return DBG_HOOK_ERROR; + } + +-static struct break_hook fault_break_hook = { +- .fn = reserved_fault_handler, +- .imm = FAULT_BRK_IMM, +-}; +- + #ifdef CONFIG_KASAN_SW_TAGS + + #define KASAN_ESR_RECOVER 0x20 +@@ -1067,7 +1051,7 @@ static struct break_hook fault_break_hook = { + #define KASAN_ESR_SIZE_MASK 0x0f + #define KASAN_ESR_SIZE(esr) (1 << ((esr) & KASAN_ESR_SIZE_MASK)) + +-static int kasan_handler(struct pt_regs *regs, unsigned long esr) ++int kasan_brk_handler(struct pt_regs *regs, unsigned long esr) + { + bool recover = esr & KASAN_ESR_RECOVER; + bool write = esr & KASAN_ESR_WRITE; +@@ -1098,26 +1082,14 @@ static int kasan_handler(struct pt_regs *regs, unsigned long esr) + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); + return DBG_HOOK_HANDLED; + } +- +-static struct break_hook kasan_break_hook = { +- .fn = kasan_handler, +- .imm = KASAN_BRK_IMM, +- .mask = KASAN_BRK_MASK, +-}; + #endif + + #ifdef CONFIG_UBSAN_TRAP +-static int ubsan_handler(struct pt_regs *regs, unsigned long esr) ++int ubsan_brk_handler(struct pt_regs *regs, unsigned long esr) + { + die(report_ubsan_failure(regs, esr & UBSAN_BRK_MASK), regs, esr); + return DBG_HOOK_HANDLED; + } +- +-static struct break_hook ubsan_break_hook = { +- .fn = ubsan_handler, +- .imm = UBSAN_BRK_IMM, +- .mask = UBSAN_BRK_MASK, +-}; + #endif + + /* +@@ -1129,31 +1101,20 @@ int __init early_brk64(unsigned long addr, unsigned long esr, + { + #ifdef CONFIG_CFI_CLANG + if (esr_is_cfi_brk(esr)) +- return cfi_handler(regs, esr) != DBG_HOOK_HANDLED; ++ return cfi_brk_handler(regs, esr) != DBG_HOOK_HANDLED; + #endif + #ifdef CONFIG_KASAN_SW_TAGS + if ((esr_brk_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM) +- return kasan_handler(regs, esr) != DBG_HOOK_HANDLED; ++ return kasan_brk_handler(regs, esr) != DBG_HOOK_HANDLED; + #endif + #ifdef CONFIG_UBSAN_TRAP + if (esr_is_ubsan_brk(esr)) +- return ubsan_handler(regs, esr) != DBG_HOOK_HANDLED; ++ return ubsan_brk_handler(regs, esr) != DBG_HOOK_HANDLED; + #endif +- return bug_handler(regs, esr) != DBG_HOOK_HANDLED; ++ return bug_brk_handler(regs, esr) != DBG_HOOK_HANDLED; + } + + void __init trap_init(void) + { +- register_kernel_break_hook(&bug_break_hook); +-#ifdef CONFIG_CFI_CLANG +- register_kernel_break_hook(&cfi_break_hook); +-#endif +- register_kernel_break_hook(&fault_break_hook); +-#ifdef CONFIG_KASAN_SW_TAGS +- register_kernel_break_hook(&kasan_break_hook); +-#endif +-#ifdef CONFIG_UBSAN_TRAP +- register_kernel_break_hook(&ubsan_break_hook); +-#endif + debug_traps_init(); + } +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-call-step-handlers-statically.patch b/queue-6.12/arm64-debug-call-step-handlers-statically.patch new file mode 100644 index 0000000000..3ac845e886 --- /dev/null +++ b/queue-6.12/arm64-debug-call-step-handlers-statically.patch @@ -0,0 +1,210 @@ +From 322065ec410b7e9895c61592efc665ecfed4ba94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:44 +0200 +Subject: arm64: debug: call step handlers statically + +From: Ada Couprie Diaz + +[ Upstream commit 403b48aad5b3e857b8c2576ce6a421f3d23dd6a6 ] + +Software stepping checks for the correct handler by iterating over a list +of dynamically registered handlers and calling all of them until one +handles the exception. + +This is the only generic way to handle software stepping handlers in arm64 +as the exception does not provide an immediate that could be checked, +contrary to software breakpoints. + +However, the registration mechanism is not exported and has only +two current users : the KGDB stepping handler, and the uprobe single step +handler. +Given that one comes from user mode and the other from kernel mode, call +the appropriate one by checking the source EL of the exception. +Add a stand-in that returns DBG_HOOK_ERROR when the configuration +options are not enabled. + +Remove `arch_init_uprobes()` as it is not useful anymore and is +specific to arm64. + +Unify the naming of the handler to XXX_single_step_handler(), making it +clear they are related. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-5-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/kgdb.h | 9 +++++++++ + arch/arm64/include/asm/uprobes.h | 9 +++++++++ + arch/arm64/kernel/debug-monitors.c | 25 ++++++------------------- + arch/arm64/kernel/kgdb.c | 17 +++-------------- + arch/arm64/kernel/probes/uprobes.c | 15 +-------------- + 5 files changed, 28 insertions(+), 47 deletions(-) + +diff --git a/arch/arm64/include/asm/kgdb.h b/arch/arm64/include/asm/kgdb.h +index 82a76b2102fb61..3184f5d1e3ae49 100644 +--- a/arch/arm64/include/asm/kgdb.h ++++ b/arch/arm64/include/asm/kgdb.h +@@ -26,6 +26,15 @@ extern int kgdb_fault_expected; + + int kgdb_brk_handler(struct pt_regs *regs, unsigned long esr); + int kgdb_compiled_brk_handler(struct pt_regs *regs, unsigned long esr); ++#ifdef CONFIG_KGDB ++int kgdb_single_step_handler(struct pt_regs *regs, unsigned long esr); ++#else ++static inline int kgdb_single_step_handler(struct pt_regs *regs, ++ unsigned long esr) ++{ ++ return DBG_HOOK_ERROR; ++} ++#endif + + #endif /* !__ASSEMBLY__ */ + +diff --git a/arch/arm64/include/asm/uprobes.h b/arch/arm64/include/asm/uprobes.h +index 3659a79a9f325f..89bfb0213a500c 100644 +--- a/arch/arm64/include/asm/uprobes.h ++++ b/arch/arm64/include/asm/uprobes.h +@@ -29,5 +29,14 @@ struct arch_uprobe { + }; + + int uprobe_brk_handler(struct pt_regs *regs, unsigned long esr); ++#ifdef CONFIG_UPROBES ++int uprobe_single_step_handler(struct pt_regs *regs, unsigned long esr); ++#else ++static inline int uprobe_single_step_handler(struct pt_regs *regs, ++ unsigned long esr) ++{ ++ return DBG_HOOK_ERROR; ++} ++#endif + + #endif +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index 5e892448030005..f929b107840de6 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -200,30 +200,17 @@ void unregister_kernel_step_hook(struct step_hook *hook) + } + + /* +- * Call registered single step handlers ++ * Call single step handlers + * There is no Syndrome info to check for determining the handler. +- * So we call all the registered handlers, until the right handler is +- * found which returns zero. ++ * However, there is only one possible handler for user and kernel modes, so ++ * check and call the appropriate one. + */ + static int call_step_hook(struct pt_regs *regs, unsigned long esr) + { +- struct step_hook *hook; +- struct list_head *list; +- int retval = DBG_HOOK_ERROR; ++ if (user_mode(regs)) ++ return uprobe_single_step_handler(regs, esr); + +- list = user_mode(regs) ? &user_step_hook : &kernel_step_hook; +- +- /* +- * Since single-step exception disables interrupt, this function is +- * entirely not preemptible, and we can use rcu list safely here. +- */ +- list_for_each_entry_rcu(hook, list, node) { +- retval = hook->fn(regs, esr); +- if (retval == DBG_HOOK_HANDLED) +- break; +- } +- +- return retval; ++ return kgdb_single_step_handler(regs, esr); + } + NOKPROBE_SYMBOL(call_step_hook); + +diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c +index e3c9e6e11a318c..f8eaf6084c3d5a 100644 +--- a/arch/arm64/kernel/kgdb.c ++++ b/arch/arm64/kernel/kgdb.c +@@ -250,7 +250,7 @@ int kgdb_compiled_brk_handler(struct pt_regs *regs, unsigned long esr) + } + NOKPROBE_SYMBOL(kgdb_compiled_brk_handler); + +-static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned long esr) ++int kgdb_single_step_handler(struct pt_regs *regs, unsigned long esr) + { + if (!kgdb_single_step) + return DBG_HOOK_ERROR; +@@ -258,11 +258,7 @@ static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned long esr) + kgdb_handle_exception(0, SIGTRAP, 0, regs); + return DBG_HOOK_HANDLED; + } +-NOKPROBE_SYMBOL(kgdb_step_brk_fn); +- +-static struct step_hook kgdb_step_hook = { +- .fn = kgdb_step_brk_fn +-}; ++NOKPROBE_SYMBOL(kgdb_single_step_handler); + + static int __kgdb_notify(struct die_args *args, unsigned long cmd) + { +@@ -301,13 +297,7 @@ static struct notifier_block kgdb_notifier = { + */ + int kgdb_arch_init(void) + { +- int ret = register_die_notifier(&kgdb_notifier); +- +- if (ret != 0) +- return ret; +- +- register_kernel_step_hook(&kgdb_step_hook); +- return 0; ++ return register_die_notifier(&kgdb_notifier); + } + + /* +@@ -317,7 +307,6 @@ int kgdb_arch_init(void) + */ + void kgdb_arch_exit(void) + { +- unregister_kernel_step_hook(&kgdb_step_hook); + unregister_die_notifier(&kgdb_notifier); + } + +diff --git a/arch/arm64/kernel/probes/uprobes.c b/arch/arm64/kernel/probes/uprobes.c +index fc1bd19c827e6f..6ae4396577d4a6 100644 +--- a/arch/arm64/kernel/probes/uprobes.c ++++ b/arch/arm64/kernel/probes/uprobes.c +@@ -174,7 +174,7 @@ int uprobe_brk_handler(struct pt_regs *regs, + return DBG_HOOK_ERROR; + } + +-static int uprobe_single_step_handler(struct pt_regs *regs, ++int uprobe_single_step_handler(struct pt_regs *regs, + unsigned long esr) + { + struct uprobe_task *utask = current->utask; +@@ -186,16 +186,3 @@ static int uprobe_single_step_handler(struct pt_regs *regs, + return DBG_HOOK_ERROR; + } + +-/* uprobe single step handler hook */ +-static struct step_hook uprobes_step_hook = { +- .fn = uprobe_single_step_handler, +-}; +- +-static int __init arch_init_uprobes(void) +-{ +- register_user_step_hook(&uprobes_step_hook); +- +- return 0; +-} +- +-device_initcall(arch_init_uprobes); +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-clean-up-single_step_handler-logic.patch b/queue-6.12/arm64-debug-clean-up-single_step_handler-logic.patch new file mode 100644 index 0000000000..b64ab461e7 --- /dev/null +++ b/queue-6.12/arm64-debug-clean-up-single_step_handler-logic.patch @@ -0,0 +1,65 @@ +From 97b8f48a02154f7313ebda4199bed6a881ae1d90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:41 +0200 +Subject: arm64: debug: clean up single_step_handler logic + +From: Ada Couprie Diaz + +[ Upstream commit ad8b22648b7d0bc6f84230508436b1aafc2e2516 ] + +Remove the unnecessary boolean which always checks if the handler was found +and return early instead. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Anshuman Khandual +Acked-by: Mark Rutland +Reviewed-by: Will Deacon +Link: https://lore.kernel.org/r/20250707114109.35672-2-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/debug-monitors.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index 024a7b245056a8..b7a2155bca42b1 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -241,8 +241,6 @@ static void send_user_sigtrap(int si_code) + static int single_step_handler(unsigned long unused, unsigned long esr, + struct pt_regs *regs) + { +- bool handler_found = false; +- + /* + * If we are stepping a pending breakpoint, call the hw_breakpoint + * handler first. +@@ -250,10 +248,10 @@ static int single_step_handler(unsigned long unused, unsigned long esr, + if (!reinstall_suspended_bps(regs)) + return 0; + +- if (!handler_found && call_step_hook(regs, esr) == DBG_HOOK_HANDLED) +- handler_found = true; ++ if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED) ++ return 0; + +- if (!handler_found && user_mode(regs)) { ++ if (user_mode(regs)) { + send_user_sigtrap(TRAP_TRACE); + + /* +@@ -263,7 +261,7 @@ static int single_step_handler(unsigned long unused, unsigned long esr, + * to the active-not-pending state). + */ + user_rewind_single_step(current); +- } else if (!handler_found) { ++ } else { + pr_warn("Unexpected kernel single-step exception at EL1\n"); + /* + * Re-enable stepping since we know that we will be +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-refactor-reinstall_suspended_bps.patch b/queue-6.12/arm64-debug-refactor-reinstall_suspended_bps.patch new file mode 100644 index 0000000000..c30c8b07ae --- /dev/null +++ b/queue-6.12/arm64-debug-refactor-reinstall_suspended_bps.patch @@ -0,0 +1,145 @@ +From e750d255f943d56545a39d9f07a907c9895df714 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:48 +0200 +Subject: arm64: debug: refactor reinstall_suspended_bps() + +From: Ada Couprie Diaz + +[ Upstream commit 80691d35523de3292b64c2ffa444aab3d55e51ba ] + +`reinstall_suspended_bps()` plays a key part in the stepping process +when we have hardware breakpoints and watchpoints enabled. +It checks if we need to step one, will re-enable it if it has +been handled and will return whether or not we need to proceed with +a single-step. + +However, the current naming and return values make it harder to understand +the logic and goal of the function. + +Rename it `try_step_suspended_breakpoints()` and change the return value +to a boolean, aligning it with similar functions used in +`do_el0_undef()` like `try_emulate_mrs()`, and making its behaviour +more obvious. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Anshuman Khandual +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-9-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/debug-monitors.h | 6 +++--- + arch/arm64/kernel/debug-monitors.c | 2 +- + arch/arm64/kernel/hw_breakpoint.c | 25 ++++++++++++------------- + 3 files changed, 16 insertions(+), 17 deletions(-) + +diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h +index 5319da0f0ca4ea..24c7981abeb0b9 100644 +--- a/arch/arm64/include/asm/debug-monitors.h ++++ b/arch/arm64/include/asm/debug-monitors.h +@@ -83,11 +83,11 @@ int kernel_active_single_step(void); + void kernel_rewind_single_step(struct pt_regs *regs); + + #ifdef CONFIG_HAVE_HW_BREAKPOINT +-int reinstall_suspended_bps(struct pt_regs *regs); ++bool try_step_suspended_breakpoints(struct pt_regs *regs); + #else +-static inline int reinstall_suspended_bps(struct pt_regs *regs) ++static inline bool try_step_suspended_breakpoints(struct pt_regs *regs) + { +- return -ENODEV; ++ return false; + } + #endif + +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index a28482e25c4c31..b95a135ef10a99 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -195,7 +195,7 @@ static int single_step_handler(unsigned long unused, unsigned long esr, + * If we are stepping a pending breakpoint, call the hw_breakpoint + * handler first. + */ +- if (!reinstall_suspended_bps(regs)) ++ if (try_step_suspended_breakpoints(regs)) + return 0; + + if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED) +diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c +index d7eede5d869c2b..309ae24d454805 100644 +--- a/arch/arm64/kernel/hw_breakpoint.c ++++ b/arch/arm64/kernel/hw_breakpoint.c +@@ -847,36 +847,35 @@ NOKPROBE_SYMBOL(watchpoint_handler); + /* + * Handle single-step exception. + */ +-int reinstall_suspended_bps(struct pt_regs *regs) ++bool try_step_suspended_breakpoints(struct pt_regs *regs) + { + struct debug_info *debug_info = ¤t->thread.debug; +- int handled_exception = 0, *kernel_step; +- +- kernel_step = this_cpu_ptr(&stepping_kernel_bp); ++ int *kernel_step = this_cpu_ptr(&stepping_kernel_bp); ++ bool handled_exception = false; + + /* + * Called from single-step exception handler. +- * Return 0 if execution can resume, 1 if a SIGTRAP should be +- * reported. ++ * Return true if we stepped a breakpoint and can resume execution, ++ * false if we need to handle a single-step. + */ + if (user_mode(regs)) { + if (debug_info->bps_disabled) { + debug_info->bps_disabled = 0; + toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 1); +- handled_exception = 1; ++ handled_exception = true; + } + + if (debug_info->wps_disabled) { + debug_info->wps_disabled = 0; + toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1); +- handled_exception = 1; ++ handled_exception = true; + } + + if (handled_exception) { + if (debug_info->suspended_step) { + debug_info->suspended_step = 0; + /* Allow exception handling to fall-through. */ +- handled_exception = 0; ++ handled_exception = false; + } else { + user_disable_single_step(current); + } +@@ -890,17 +889,17 @@ int reinstall_suspended_bps(struct pt_regs *regs) + + if (*kernel_step != ARM_KERNEL_STEP_SUSPEND) { + kernel_disable_single_step(); +- handled_exception = 1; ++ handled_exception = true; + } else { +- handled_exception = 0; ++ handled_exception = false; + } + + *kernel_step = ARM_KERNEL_STEP_NONE; + } + +- return !handled_exception; ++ return handled_exception; + } +-NOKPROBE_SYMBOL(reinstall_suspended_bps); ++NOKPROBE_SYMBOL(try_step_suspended_breakpoints); + + /* + * Context-switcher for restoring suspended breakpoints. +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-remove-break-step-handler-registration-i.patch b/queue-6.12/arm64-debug-remove-break-step-handler-registration-i.patch new file mode 100644 index 0000000000..0451c25c37 --- /dev/null +++ b/queue-6.12/arm64-debug-remove-break-step-handler-registration-i.patch @@ -0,0 +1,146 @@ +From ea8b41531689ddff22defdb4c11a2060cb0d43c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:45 +0200 +Subject: arm64: debug: remove break/step handler registration infrastructure + +From: Ada Couprie Diaz + +[ Upstream commit d4e0b12620946a4011ad695490211fc38bf5cb42 ] + +Remove all infrastructure for the dynamic registration previously used by +software breakpoints and stepping handlers. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Anshuman Khandual +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-6-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/debug-monitors.h | 24 ---------- + arch/arm64/kernel/debug-monitors.c | 63 ------------------------- + 2 files changed, 87 deletions(-) + +diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h +index 3eeea1c9f06664..5319da0f0ca4ea 100644 +--- a/arch/arm64/include/asm/debug-monitors.h ++++ b/arch/arm64/include/asm/debug-monitors.h +@@ -62,30 +62,6 @@ struct task_struct; + #define DBG_HOOK_HANDLED 0 + #define DBG_HOOK_ERROR 1 + +-struct step_hook { +- struct list_head node; +- int (*fn)(struct pt_regs *regs, unsigned long esr); +-}; +- +-void register_user_step_hook(struct step_hook *hook); +-void unregister_user_step_hook(struct step_hook *hook); +- +-void register_kernel_step_hook(struct step_hook *hook); +-void unregister_kernel_step_hook(struct step_hook *hook); +- +-struct break_hook { +- struct list_head node; +- int (*fn)(struct pt_regs *regs, unsigned long esr); +- u16 imm; +- u16 mask; /* These bits are ignored when comparing with imm */ +-}; +- +-void register_user_break_hook(struct break_hook *hook); +-void unregister_user_break_hook(struct break_hook *hook); +- +-void register_kernel_break_hook(struct break_hook *hook); +-void unregister_kernel_break_hook(struct break_hook *hook); +- + u8 debug_monitors_arch(void); + + enum dbg_active_el { +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index f929b107840de6..a28482e25c4c31 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -159,46 +159,6 @@ NOKPROBE_SYMBOL(clear_user_regs_spsr_ss); + #define set_regs_spsr_ss(r) set_user_regs_spsr_ss(&(r)->user_regs) + #define clear_regs_spsr_ss(r) clear_user_regs_spsr_ss(&(r)->user_regs) + +-static DEFINE_SPINLOCK(debug_hook_lock); +-static LIST_HEAD(user_step_hook); +-static LIST_HEAD(kernel_step_hook); +- +-static void register_debug_hook(struct list_head *node, struct list_head *list) +-{ +- spin_lock(&debug_hook_lock); +- list_add_rcu(node, list); +- spin_unlock(&debug_hook_lock); +- +-} +- +-static void unregister_debug_hook(struct list_head *node) +-{ +- spin_lock(&debug_hook_lock); +- list_del_rcu(node); +- spin_unlock(&debug_hook_lock); +- synchronize_rcu(); +-} +- +-void register_user_step_hook(struct step_hook *hook) +-{ +- register_debug_hook(&hook->node, &user_step_hook); +-} +- +-void unregister_user_step_hook(struct step_hook *hook) +-{ +- unregister_debug_hook(&hook->node); +-} +- +-void register_kernel_step_hook(struct step_hook *hook) +-{ +- register_debug_hook(&hook->node, &kernel_step_hook); +-} +- +-void unregister_kernel_step_hook(struct step_hook *hook) +-{ +- unregister_debug_hook(&hook->node); +-} +- + /* + * Call single step handlers + * There is no Syndrome info to check for determining the handler. +@@ -264,29 +224,6 @@ static int single_step_handler(unsigned long unused, unsigned long esr, + } + NOKPROBE_SYMBOL(single_step_handler); + +-static LIST_HEAD(user_break_hook); +-static LIST_HEAD(kernel_break_hook); +- +-void register_user_break_hook(struct break_hook *hook) +-{ +- register_debug_hook(&hook->node, &user_break_hook); +-} +- +-void unregister_user_break_hook(struct break_hook *hook) +-{ +- unregister_debug_hook(&hook->node); +-} +- +-void register_kernel_break_hook(struct break_hook *hook) +-{ +- register_debug_hook(&hook->node, &kernel_break_hook); +-} +- +-void unregister_kernel_break_hook(struct break_hook *hook) +-{ +- unregister_debug_hook(&hook->node); +-} +- + static int call_break_hook(struct pt_regs *regs, unsigned long esr) + { + if (user_mode(regs)) { +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-remove-debug-exception-registration-infr.patch b/queue-6.12/arm64-debug-remove-debug-exception-registration-infr.patch new file mode 100644 index 0000000000..4c6b115405 --- /dev/null +++ b/queue-6.12/arm64-debug-remove-debug-exception-registration-infr.patch @@ -0,0 +1,248 @@ +From 6f897c500d0f4b7ac2ac85792f60f292bdc2eeb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:53 +0200 +Subject: arm64: debug: remove debug exception registration infrastructure + +From: Ada Couprie Diaz + +[ Upstream commit a8b8cce9d96d65dfe3d89abf02033151f8b7d670 ] + +Now that debug exceptions are handled individually and without the need +for dynamic registration, remove the unused registration infrastructure. + +This removes the external caller for `debug_exception_enter()` and +`debug_exception_exit()`. +Make them static again and remove them from the header. + +Remove `early_brk64()` as it has been made redundant by +(arm64: debug: split brk64 exception entry) and is not used anymore. +Note : in `early_brk64()` `bug_brk_handler()` is called unconditionally +as a fall-through, but now `call_break_hook()` only calls it if the +immediate matches. +This does not change the behaviour in early boot, as if +`bug_brk_handler()` was called on a non-BUG immediate it would return +DBG_HOOK_ERROR anyway, which `call_break_hook()` will do if no immediate +matches. + +Remove `trap_init()`, as it would be empty and a weak definition already +exists in `init/main.c`. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-14-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/debug-monitors.h | 2 - + arch/arm64/include/asm/exception.h | 6 --- + arch/arm64/include/asm/system_misc.h | 4 -- + arch/arm64/kernel/debug-monitors.c | 3 -- + arch/arm64/kernel/entry-common.c | 4 +- + arch/arm64/kernel/traps.c | 27 ------------- + arch/arm64/mm/fault.c | 53 ------------------------- + 7 files changed, 2 insertions(+), 97 deletions(-) + +diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h +index 24c7981abeb0b9..4f3901884c5d85 100644 +--- a/arch/arm64/include/asm/debug-monitors.h ++++ b/arch/arm64/include/asm/debug-monitors.h +@@ -93,7 +93,5 @@ static inline bool try_step_suspended_breakpoints(struct pt_regs *regs) + + bool try_handle_aarch32_break(struct pt_regs *regs); + +-void debug_traps_init(void); +- + #endif /* __ASSEMBLY */ + #endif /* __ASM_DEBUG_MONITORS_H */ +diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h +index 9b05c6f487ccf1..50c5329ff2edae 100644 +--- a/arch/arm64/include/asm/exception.h ++++ b/arch/arm64/include/asm/exception.h +@@ -57,8 +57,6 @@ void do_el0_undef(struct pt_regs *regs, unsigned long esr); + void do_el1_undef(struct pt_regs *regs, unsigned long esr); + void do_el0_bti(struct pt_regs *regs); + void do_el1_bti(struct pt_regs *regs, unsigned long esr); +-void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr, +- struct pt_regs *regs); + #ifdef CONFIG_HAVE_HW_BREAKPOINT + void do_breakpoint(unsigned long esr, struct pt_regs *regs); + void do_watchpoint(unsigned long addr, unsigned long esr, +@@ -91,8 +89,4 @@ void do_serror(struct pt_regs *regs, unsigned long esr); + void do_signal(struct pt_regs *regs); + + void __noreturn panic_bad_stack(struct pt_regs *regs, unsigned long esr, unsigned long far); +- +-void debug_exception_enter(struct pt_regs *regs); +-void debug_exception_exit(struct pt_regs *regs); +- + #endif /* __ASM_EXCEPTION_H */ +diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h +index c343442567625d..344b1c1a4bbb69 100644 +--- a/arch/arm64/include/asm/system_misc.h ++++ b/arch/arm64/include/asm/system_misc.h +@@ -25,10 +25,6 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, + int signo, int sicode, unsigned long far, + unsigned long err); + +-void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned long, +- struct pt_regs *), +- int sig, int code, const char *name); +- + struct mm_struct; + extern void __show_regs(struct pt_regs *); + +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index ed03270fa34375..16390fd4ba5edd 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -316,9 +316,6 @@ bool try_handle_aarch32_break(struct pt_regs *regs) + } + NOKPROBE_SYMBOL(try_handle_aarch32_break); + +-void __init debug_traps_init(void) +-{} +- + /* Re-enable single step for syscall restarting. */ + void user_rewind_single_step(struct task_struct *task) + { +diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c +index 9a1ea5a6e6b72a..b98d6d1a1dfd63 100644 +--- a/arch/arm64/kernel/entry-common.c ++++ b/arch/arm64/kernel/entry-common.c +@@ -448,7 +448,7 @@ static __always_inline void fpsimd_syscall_exit(void) + * accidentally schedule in exception context and it will force a warning + * if we somehow manage to schedule by accident. + */ +-void debug_exception_enter(struct pt_regs *regs) ++static void debug_exception_enter(struct pt_regs *regs) + { + preempt_disable(); + +@@ -457,7 +457,7 @@ void debug_exception_enter(struct pt_regs *regs) + } + NOKPROBE_SYMBOL(debug_exception_enter); + +-void debug_exception_exit(struct pt_regs *regs) ++static void debug_exception_exit(struct pt_regs *regs) + { + preempt_enable_no_resched(); + } +diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c +index 013159bc0882ee..e6e815ef03c777 100644 +--- a/arch/arm64/kernel/traps.c ++++ b/arch/arm64/kernel/traps.c +@@ -1091,30 +1091,3 @@ int ubsan_brk_handler(struct pt_regs *regs, unsigned long esr) + return DBG_HOOK_HANDLED; + } + #endif +- +-/* +- * Initial handler for AArch64 BRK exceptions +- * This handler only used until debug_traps_init(). +- */ +-int __init early_brk64(unsigned long addr, unsigned long esr, +- struct pt_regs *regs) +-{ +-#ifdef CONFIG_CFI_CLANG +- if (esr_is_cfi_brk(esr)) +- return cfi_brk_handler(regs, esr) != DBG_HOOK_HANDLED; +-#endif +-#ifdef CONFIG_KASAN_SW_TAGS +- if ((esr_brk_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM) +- return kasan_brk_handler(regs, esr) != DBG_HOOK_HANDLED; +-#endif +-#ifdef CONFIG_UBSAN_TRAP +- if (esr_is_ubsan_brk(esr)) +- return ubsan_brk_handler(regs, esr) != DBG_HOOK_HANDLED; +-#endif +- return bug_brk_handler(regs, esr) != DBG_HOOK_HANDLED; +-} +- +-void __init trap_init(void) +-{ +- debug_traps_init(); +-} +diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c +index 7c87d2b3b06eaa..9ee5a2d2b32151 100644 +--- a/arch/arm64/mm/fault.c ++++ b/arch/arm64/mm/fault.c +@@ -53,18 +53,12 @@ struct fault_info { + }; + + static const struct fault_info fault_info[]; +-static struct fault_info debug_fault_info[]; + + static inline const struct fault_info *esr_to_fault_info(unsigned long esr) + { + return fault_info + (esr & ESR_ELx_FSC); + } + +-static inline const struct fault_info *esr_to_debug_fault_info(unsigned long esr) +-{ +- return debug_fault_info + DBG_ESR_EVT(esr); +-} +- + static void data_abort_decode(unsigned long esr) + { + unsigned long iss2 = ESR_ELx_ISS2(esr); +@@ -911,53 +905,6 @@ void do_sp_pc_abort(unsigned long addr, unsigned long esr, struct pt_regs *regs) + } + NOKPROBE_SYMBOL(do_sp_pc_abort); + +-/* +- * __refdata because early_brk64 is __init, but the reference to it is +- * clobbered at arch_initcall time. +- * See traps.c and debug-monitors.c:debug_traps_init(). +- */ +-static struct fault_info __refdata debug_fault_info[] = { +- { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware breakpoint" }, +- { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware single-step" }, +- { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware watchpoint" }, +- { do_bad, SIGKILL, SI_KERNEL, "unknown 3" }, +- { do_bad, SIGTRAP, TRAP_BRKPT, "aarch32 BKPT" }, +- { do_bad, SIGKILL, SI_KERNEL, "aarch32 vector catch" }, +- { early_brk64, SIGTRAP, TRAP_BRKPT, "aarch64 BRK" }, +- { do_bad, SIGKILL, SI_KERNEL, "unknown 7" }, +-}; +- +-void __init hook_debug_fault_code(int nr, +- int (*fn)(unsigned long, unsigned long, struct pt_regs *), +- int sig, int code, const char *name) +-{ +- BUG_ON(nr < 0 || nr >= ARRAY_SIZE(debug_fault_info)); +- +- debug_fault_info[nr].fn = fn; +- debug_fault_info[nr].sig = sig; +- debug_fault_info[nr].code = code; +- debug_fault_info[nr].name = name; +-} +- +-void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr, +- struct pt_regs *regs) +-{ +- const struct fault_info *inf = esr_to_debug_fault_info(esr); +- unsigned long pc = instruction_pointer(regs); +- +- debug_exception_enter(regs); +- +- if (user_mode(regs) && !is_ttbr0_addr(pc)) +- arm64_apply_bp_hardening(); +- +- if (inf->fn(addr_if_watchpoint, esr, regs)) { +- arm64_notify_die(inf->name, regs, inf->sig, inf->code, pc, esr); +- } +- +- debug_exception_exit(regs); +-} +-NOKPROBE_SYMBOL(do_debug_exception); +- + /* + * Used during anonymous page fault handling. + */ +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-split-bkpt32-exception-entry.patch b/queue-6.12/arm64-debug-split-bkpt32-exception-entry.patch new file mode 100644 index 0000000000..c3e08e080a --- /dev/null +++ b/queue-6.12/arm64-debug-split-bkpt32-exception-entry.patch @@ -0,0 +1,127 @@ +From 41f7de14999f10ff56b1abf68e1184c1b73d243f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:52 +0200 +Subject: arm64: debug: split bkpt32 exception entry + +From: Ada Couprie Diaz + +[ Upstream commit fc5e5d0477c532054ce8692fd16fdaab2cb8946f ] + +Currently all debug exceptions share common entry code and are routed +to `do_debug_exception()`, which calls dynamically-registered +handlers for each specific debug exception. This is unfortunate as +different debug exceptions have different entry handling requirements, +and it would be better to handle these distinct requirements earlier. + +The BKPT32 exception can only be triggered by a BKPT instruction. Thus, +we know that the PC is a legitimate address and isn't being used to train +a branch predictor with a bogus address : we don't need to call +`arm64_apply_bp_hardening()`. + +The handler for this exception only pends a signal and doesn't depend +on any per-CPU state : we don't need to inhibit preemption, nor do we +need to keep the DAIF exceptions masked, so we can unmask them earlier. + +Split the BKPT32 exception entry and adjust function signatures and its +behaviour to match its relaxed constraints compared to other +debug exceptions. +We can also remove `NOKRPOBE_SYMBOL`, as this cannot lead to a kprobe +recursion. + +This replaces the last usage of `el0_dbg()`, so remove it. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-13-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/exception.h | 1 + + arch/arm64/kernel/debug-monitors.c | 7 +++++++ + arch/arm64/kernel/entry-common.c | 22 +++++++++------------- + 3 files changed, 17 insertions(+), 13 deletions(-) + +diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h +index 7bc79602840fd0..9b05c6f487ccf1 100644 +--- a/arch/arm64/include/asm/exception.h ++++ b/arch/arm64/include/asm/exception.h +@@ -72,6 +72,7 @@ void do_el0_softstep(unsigned long esr, struct pt_regs *regs); + void do_el1_softstep(unsigned long esr, struct pt_regs *regs); + void do_el0_brk64(unsigned long esr, struct pt_regs *regs); + void do_el1_brk64(unsigned long esr, struct pt_regs *regs); ++void do_bkpt32(unsigned long esr, struct pt_regs *regs); + void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs); + void do_sve_acc(unsigned long esr, struct pt_regs *regs); + void do_sme_acc(unsigned long esr, struct pt_regs *regs); +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index 45e0dbe17c82fd..ed03270fa34375 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -270,6 +270,13 @@ void do_el1_brk64(unsigned long esr, struct pt_regs *regs) + } + NOKPROBE_SYMBOL(do_el1_brk64); + ++#ifdef CONFIG_COMPAT ++void do_bkpt32(unsigned long esr, struct pt_regs *regs) ++{ ++ arm64_notify_die("aarch32 BKPT", regs, SIGTRAP, TRAP_BRKPT, regs->pc, esr); ++} ++#endif /* CONFIG_COMPAT */ ++ + bool try_handle_aarch32_break(struct pt_regs *regs) + { + u32 arm_instr; +diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c +index ba114bfdb32b5a..9a1ea5a6e6b72a 100644 +--- a/arch/arm64/kernel/entry-common.c ++++ b/arch/arm64/kernel/entry-common.c +@@ -834,18 +834,6 @@ static void noinstr el0_brk64(struct pt_regs *regs, unsigned long esr) + exit_to_user_mode(regs); + } + +-static void noinstr __maybe_unused +-el0_dbg(struct pt_regs *regs, unsigned long esr) +-{ +- /* Only watchpoints write FAR_EL1, otherwise its UNKNOWN */ +- unsigned long far = read_sysreg(far_el1); +- +- enter_from_user_mode(regs); +- do_debug_exception(far, esr, regs); +- local_daif_restore(DAIF_PROCCTX); +- exit_to_user_mode(regs); +-} +- + static void noinstr el0_svc(struct pt_regs *regs) + { + enter_from_user_mode(regs); +@@ -1003,6 +991,14 @@ static void noinstr el0_svc_compat(struct pt_regs *regs) + exit_to_user_mode(regs); + } + ++static void noinstr el0_bkpt32(struct pt_regs *regs, unsigned long esr) ++{ ++ enter_from_user_mode(regs); ++ local_daif_restore(DAIF_PROCCTX); ++ do_bkpt32(esr, regs); ++ exit_to_user_mode(regs); ++} ++ + asmlinkage void noinstr el0t_32_sync_handler(struct pt_regs *regs) + { + unsigned long esr = read_sysreg(esr_el1); +@@ -1046,7 +1042,7 @@ asmlinkage void noinstr el0t_32_sync_handler(struct pt_regs *regs) + el0_watchpt(regs, esr); + break; + case ESR_ELx_EC_BKPT32: +- el0_dbg(regs, esr); ++ el0_bkpt32(regs, esr); + break; + default: + el0_inv(regs, esr); +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-split-brk64-exception-entry.patch b/queue-6.12/arm64-debug-split-brk64-exception-entry.patch new file mode 100644 index 0000000000..2c85ecd2d3 --- /dev/null +++ b/queue-6.12/arm64-debug-split-brk64-exception-entry.patch @@ -0,0 +1,222 @@ +From 522c9125740a098c684585636b6959dab66c5865 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:51 +0200 +Subject: arm64: debug: split brk64 exception entry + +From: Ada Couprie Diaz + +[ Upstream commit 31575e11ecf7e44face72d1e624cb147a9283733 ] + +Currently all debug exceptions share common entry code and are routed +to `do_debug_exception()`, which calls dynamically-registered +handlers for each specific debug exception. This is unfortunate as +different debug exceptions have different entry handling requirements, +and it would be better to handle these distinct requirements earlier. + +The BRK64 instruction can only be triggered by a BRK instruction. Thus, +we know that the PC is a legitimate address and isn't being used to train +a branch predictor with a bogus address : we don't need to call +`arm64_apply_bp_hardening()`. + +We do not need to handle the Cortex-A76 erratum #1463225 either, as it +only relevant for single stepping at EL1. +BRK64 does not write FAR_EL1 either, as only hardware watchpoints do so. + +Split the BRK64 exception entry, adjust the function signature, and its +behaviour to match the lack of needed mitigations. +Further, as the EL0 and EL1 code paths are cleanly separated, we can split +`do_brk64()` into `do_el0_brk64()` and `do_el1_brk64()`, and call them +directly from the relevant entry paths. +Use `die()` directly for the EL1 error path, as in `do_el1_bti()` and +`do_el1_undef()`. +We can also remove `NOKRPOBE_SYMBOL` for the EL0 path, as it cannot +lead to a kprobe recursion. + +When taking a BRK64 exception from EL0, the exception handling is safely +preemptible : the only possible handler is `uprobe_brk_handler()`. +It only operates on task-local data and properly checks its validity, +then raises a Thread Information Flag, processed before returning +to userspace in `do_notify_resume()`, which is already preemptible. +Thus we can safely unmask interrupts and enable preemption before +handling the break itself, fixing a PREEMPT_RT issue where the handler +could call a sleeping function with preemption disabled. + +Given that the break hook registration is handled statically in +`call_break_hook` since +(arm64: debug: call software break handlers statically) +and that we now bypass the exception handler registration, this change +renders `early_brk64` redundant : its functionality is now handled through +the post-init path. + +This also removes the last usage of `el1_dbg()`. + +This also removes the last usage of `el0_dbg()` without `CONFIG_COMPAT`. +Mark it `__maybe_unused`, to prevent a warning when building this patch +without `CONFIG_COMPAT`, as the following patch removes `el0_dbg()`. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-12-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/exception.h | 2 ++ + arch/arm64/kernel/debug-monitors.c | 46 ++++++++++++++---------------- + arch/arm64/kernel/entry-common.c | 24 ++++++++++------ + 3 files changed, 39 insertions(+), 33 deletions(-) + +diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h +index 594350e552e112..7bc79602840fd0 100644 +--- a/arch/arm64/include/asm/exception.h ++++ b/arch/arm64/include/asm/exception.h +@@ -70,6 +70,8 @@ static inline void do_watchpoint(unsigned long addr, unsigned long esr, + #endif /* CONFIG_HAVE_HW_BREAKPOINT */ + void do_el0_softstep(unsigned long esr, struct pt_regs *regs); + void do_el1_softstep(unsigned long esr, struct pt_regs *regs); ++void do_el0_brk64(unsigned long esr, struct pt_regs *regs); ++void do_el1_brk64(unsigned long esr, struct pt_regs *regs); + void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs); + void do_sve_acc(unsigned long esr, struct pt_regs *regs); + void do_sme_acc(unsigned long esr, struct pt_regs *regs); +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index 10d2bc51a32f7c..45e0dbe17c82fd 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -207,15 +207,8 @@ void do_el1_softstep(unsigned long esr, struct pt_regs *regs) + } + NOKPROBE_SYMBOL(do_el1_softstep); + +-static int call_break_hook(struct pt_regs *regs, unsigned long esr) ++static int call_el1_break_hook(struct pt_regs *regs, unsigned long esr) + { +- if (user_mode(regs)) { +- if (IS_ENABLED(CONFIG_UPROBES) && +- esr_brk_comment(esr) == UPROBES_BRK_IMM) +- return uprobe_brk_handler(regs, esr); +- return DBG_HOOK_ERROR; +- } +- + if (esr_brk_comment(esr) == BUG_BRK_IMM) + return bug_brk_handler(regs, esr); + +@@ -252,24 +245,30 @@ static int call_break_hook(struct pt_regs *regs, unsigned long esr) + + return DBG_HOOK_ERROR; + } +-NOKPROBE_SYMBOL(call_break_hook); ++NOKPROBE_SYMBOL(call_el1_break_hook); + +-static int brk_handler(unsigned long unused, unsigned long esr, +- struct pt_regs *regs) ++/* ++ * We have already unmasked interrupts and enabled preemption ++ * when calling do_el0_brk64() from entry-common.c. ++ */ ++void do_el0_brk64(unsigned long esr, struct pt_regs *regs) + { +- if (call_break_hook(regs, esr) == DBG_HOOK_HANDLED) +- return 0; ++ if (IS_ENABLED(CONFIG_UPROBES) && ++ esr_brk_comment(esr) == UPROBES_BRK_IMM && ++ uprobe_brk_handler(regs, esr) == DBG_HOOK_HANDLED) ++ return; + +- if (user_mode(regs)) { +- send_user_sigtrap(TRAP_BRKPT); +- } else { +- pr_warn("Unexpected kernel BRK exception at EL1\n"); +- return -EFAULT; +- } ++ send_user_sigtrap(TRAP_BRKPT); ++} + +- return 0; ++void do_el1_brk64(unsigned long esr, struct pt_regs *regs) ++{ ++ if (call_el1_break_hook(regs, esr) == DBG_HOOK_HANDLED) ++ return; ++ ++ die("Oops - BRK", regs, esr); + } +-NOKPROBE_SYMBOL(brk_handler); ++NOKPROBE_SYMBOL(do_el1_brk64); + + bool try_handle_aarch32_break(struct pt_regs *regs) + { +@@ -311,10 +310,7 @@ bool try_handle_aarch32_break(struct pt_regs *regs) + NOKPROBE_SYMBOL(try_handle_aarch32_break); + + void __init debug_traps_init(void) +-{ +- hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP, +- TRAP_BRKPT, "BRK handler"); +-} ++{} + + /* Re-enable single step for syscall restarting. */ + void user_rewind_single_step(struct task_struct *task) +diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c +index b90babcf2e2b10..ba114bfdb32b5a 100644 +--- a/arch/arm64/kernel/entry-common.c ++++ b/arch/arm64/kernel/entry-common.c +@@ -547,13 +547,12 @@ static void noinstr el1_watchpt(struct pt_regs *regs, unsigned long esr) + arm64_exit_el1_dbg(regs); + } + +-static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr) ++static void noinstr el1_brk64(struct pt_regs *regs, unsigned long esr) + { +- unsigned long far = read_sysreg(far_el1); +- + arm64_enter_el1_dbg(regs); +- if (!cortex_a76_erratum_1463225_debug_handler(regs)) +- do_debug_exception(far, esr, regs); ++ debug_exception_enter(regs); ++ do_el1_brk64(esr, regs); ++ debug_exception_exit(regs); + arm64_exit_el1_dbg(regs); + } + +@@ -599,7 +598,7 @@ asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs) + el1_watchpt(regs, esr); + break; + case ESR_ELx_EC_BRK64: +- el1_dbg(regs, esr); ++ el1_brk64(regs, esr); + break; + case ESR_ELx_EC_FPAC: + el1_fpac(regs, esr); +@@ -827,7 +826,16 @@ static void noinstr el0_watchpt(struct pt_regs *regs, unsigned long esr) + exit_to_user_mode(regs); + } + +-static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr) ++static void noinstr el0_brk64(struct pt_regs *regs, unsigned long esr) ++{ ++ enter_from_user_mode(regs); ++ local_daif_restore(DAIF_PROCCTX); ++ do_el0_brk64(esr, regs); ++ exit_to_user_mode(regs); ++} ++ ++static void noinstr __maybe_unused ++el0_dbg(struct pt_regs *regs, unsigned long esr) + { + /* Only watchpoints write FAR_EL1, otherwise its UNKNOWN */ + unsigned long far = read_sysreg(far_el1); +@@ -912,7 +920,7 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs) + el0_watchpt(regs, esr); + break; + case ESR_ELx_EC_BRK64: +- el0_dbg(regs, esr); ++ el0_brk64(regs, esr); + break; + case ESR_ELx_EC_FPAC: + el0_fpac(regs, esr); +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-split-hardware-breakpoint-exception-entr.patch b/queue-6.12/arm64-debug-split-hardware-breakpoint-exception-entr.patch new file mode 100644 index 0000000000..971cd3472a --- /dev/null +++ b/queue-6.12/arm64-debug-split-hardware-breakpoint-exception-entr.patch @@ -0,0 +1,209 @@ +From df0d2dd7be9c4c325300ca1c09e84c63d42c707a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:47 +0200 +Subject: arm64: debug: split hardware breakpoint exception entry + +From: Ada Couprie Diaz + +[ Upstream commit 43e2ae77fcab8a01101a2e5da528b5222b338e5f ] + +Currently all debug exceptions share common entry code and are routed +to `do_debug_exception()`, which calls dynamically-registered +handlers for each specific debug exception. This is unfortunate as +different debug exceptions have different entry handling requirements, +and it would be better to handle these distinct requirements earlier. + +Hardware breakpoints exceptions are generated by the hardware after user +configuration. As such, they can be exploited when training branch +predictors outside of the userspace VA range: they still need to call +`arm64_apply_bp_hardening()` if needed to mitigate against this attack. + +However, they do not need to handle the Cortex-A76 erratum #1463225 as +it only applies to single stepping exceptions. +It does not set an address in FAR_EL1 either, only the hardware +watchpoint does. + +As the hardware breakpoint handler only returns 0 and never triggers +the call to `arm64_notify_die()`, we can call it directly from +`entry-common.c`. +Split the hardware breakpoint exception entry, adjust +the function signature, and handling of the Cortex-A76 erratum to fit +the behaviour of the exception. + +Move the call to `arm64_apply_bp_hardening()` to `entry-common.c` so that +we can do it as early as possible, and only for the exceptions coming +from EL0, where it is needed. +This is safe to do as it is `noinstr`, as are all the functions it +may call. `el0_ia()` and `el0_pc()` already call it this way. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-8-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/exception.h | 5 +++++ + arch/arm64/kernel/entry-common.c | 28 ++++++++++++++++++++++++++++ + arch/arm64/kernel/hw_breakpoint.c | 16 ++++++---------- + 3 files changed, 39 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h +index b1d6a65f6d2256..94f46e96515160 100644 +--- a/arch/arm64/include/asm/exception.h ++++ b/arch/arm64/include/asm/exception.h +@@ -59,6 +59,11 @@ void do_el0_bti(struct pt_regs *regs); + void do_el1_bti(struct pt_regs *regs, unsigned long esr); + void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr, + struct pt_regs *regs); ++#ifdef CONFIG_HAVE_HW_BREAKPOINT ++void do_breakpoint(unsigned long esr, struct pt_regs *regs); ++#else ++static inline void do_breakpoint(unsigned long esr, struct pt_regs *regs) {} ++#endif /* CONFIG_HAVE_HW_BREAKPOINT */ + void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs); + void do_sve_acc(unsigned long esr, struct pt_regs *regs); + void do_sme_acc(unsigned long esr, struct pt_regs *regs); +diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c +index 2e04e04aaf2ad6..af0d7575dcfd92 100644 +--- a/arch/arm64/kernel/entry-common.c ++++ b/arch/arm64/kernel/entry-common.c +@@ -508,6 +508,15 @@ static void noinstr el1_bti(struct pt_regs *regs, unsigned long esr) + exit_to_kernel_mode(regs); + } + ++static void noinstr el1_breakpt(struct pt_regs *regs, unsigned long esr) ++{ ++ arm64_enter_el1_dbg(regs); ++ debug_exception_enter(regs); ++ do_breakpoint(esr, regs); ++ debug_exception_exit(regs); ++ arm64_exit_el1_dbg(regs); ++} ++ + static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr) + { + unsigned long far = read_sysreg(far_el1); +@@ -551,6 +560,8 @@ asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs) + el1_bti(regs, esr); + break; + case ESR_ELx_EC_BREAKPT_CUR: ++ el1_breakpt(regs, esr); ++ break; + case ESR_ELx_EC_SOFTSTP_CUR: + case ESR_ELx_EC_WATCHPT_CUR: + case ESR_ELx_EC_BRK64: +@@ -737,6 +748,19 @@ static void noinstr el0_inv(struct pt_regs *regs, unsigned long esr) + exit_to_user_mode(regs); + } + ++static void noinstr el0_breakpt(struct pt_regs *regs, unsigned long esr) ++{ ++ if (!is_ttbr0_addr(regs->pc)) ++ arm64_apply_bp_hardening(); ++ ++ enter_from_user_mode(regs); ++ debug_exception_enter(regs); ++ do_breakpoint(esr, regs); ++ debug_exception_exit(regs); ++ local_daif_restore(DAIF_PROCCTX); ++ exit_to_user_mode(regs); ++} ++ + static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr) + { + /* Only watchpoints write FAR_EL1, otherwise its UNKNOWN */ +@@ -813,6 +837,8 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs) + el0_mops(regs, esr); + break; + case ESR_ELx_EC_BREAKPT_LOW: ++ el0_breakpt(regs, esr); ++ break; + case ESR_ELx_EC_SOFTSTP_LOW: + case ESR_ELx_EC_WATCHPT_LOW: + case ESR_ELx_EC_BRK64: +@@ -933,6 +959,8 @@ asmlinkage void noinstr el0t_32_sync_handler(struct pt_regs *regs) + el0_cp15(regs, esr); + break; + case ESR_ELx_EC_BREAKPT_LOW: ++ el0_breakpt(regs, esr); ++ break; + case ESR_ELx_EC_SOFTSTP_LOW: + case ESR_ELx_EC_WATCHPT_LOW: + case ESR_ELx_EC_BKPT32: +diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c +index 722ac45f9f7b16..d7eede5d869c2b 100644 +--- a/arch/arm64/kernel/hw_breakpoint.c ++++ b/arch/arm64/kernel/hw_breakpoint.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -618,8 +619,7 @@ NOKPROBE_SYMBOL(toggle_bp_registers); + /* + * Debug exception handlers. + */ +-static int breakpoint_handler(unsigned long unused, unsigned long esr, +- struct pt_regs *regs) ++void do_breakpoint(unsigned long esr, struct pt_regs *regs) + { + int i, step = 0, *kernel_step; + u32 ctrl_reg; +@@ -662,7 +662,7 @@ static int breakpoint_handler(unsigned long unused, unsigned long esr, + } + + if (!step) +- return 0; ++ return; + + if (user_mode(regs)) { + debug_info->bps_disabled = 1; +@@ -670,7 +670,7 @@ static int breakpoint_handler(unsigned long unused, unsigned long esr, + + /* If we're already stepping a watchpoint, just return. */ + if (debug_info->wps_disabled) +- return 0; ++ return; + + if (test_thread_flag(TIF_SINGLESTEP)) + debug_info->suspended_step = 1; +@@ -681,7 +681,7 @@ static int breakpoint_handler(unsigned long unused, unsigned long esr, + kernel_step = this_cpu_ptr(&stepping_kernel_bp); + + if (*kernel_step != ARM_KERNEL_STEP_NONE) +- return 0; ++ return; + + if (kernel_active_single_step()) { + *kernel_step = ARM_KERNEL_STEP_SUSPEND; +@@ -690,10 +690,8 @@ static int breakpoint_handler(unsigned long unused, unsigned long esr, + kernel_enable_single_step(regs); + } + } +- +- return 0; + } +-NOKPROBE_SYMBOL(breakpoint_handler); ++NOKPROBE_SYMBOL(do_breakpoint); + + /* + * Arm64 hardware does not always report a watchpoint hit address that matches +@@ -988,8 +986,6 @@ static int __init arch_hw_breakpoint_init(void) + core_num_brps, core_num_wrps); + + /* Register debug fault handlers. */ +- hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP, +- TRAP_HWBKPT, "hw-breakpoint handler"); + hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP, + TRAP_HWBKPT, "hw-watchpoint handler"); + +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-split-hardware-watchpoint-exception-entr.patch b/queue-6.12/arm64-debug-split-hardware-watchpoint-exception-entr.patch new file mode 100644 index 0000000000..30f89e72e4 --- /dev/null +++ b/queue-6.12/arm64-debug-split-hardware-watchpoint-exception-entr.patch @@ -0,0 +1,197 @@ +From 6c640c1850f7bb22d42145f3660fde62fd0eb849 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:50 +0200 +Subject: arm64: debug: split hardware watchpoint exception entry + +From: Ada Couprie Diaz + +[ Upstream commit 413f0bba005dacf2484bb8ecce212fab9be79d81 ] + +Currently all debug exceptions share common entry code and are routed +to `do_debug_exception()`, which calls dynamically-registered +handlers for each specific debug exception. This is unfortunate as +different debug exceptions have different entry handling requirements, +and it would be better to handle these distinct requirements earlier. + +Hardware watchpoints are the only debug exceptions that will write +FAR_EL1, so we need to preserve it and pass it down. +However, they cannot be used to maliciously train branch predictors, so +we can omit calling `arm64_bp_hardening()`, nor do they need to handle +the Cortex-A76 erratum #1463225, as it only applies to single stepping +exceptions. + +As the hardware watchpoint handler only returns 0 and never triggers +the call to `arm64_notify_die()`, we can call it directly from +`entry-common.c`. +Split the hardware watchpoint exception entry and adjust the behaviour +to match the lack of needed mitigations. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-11-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/exception.h | 4 ++++ + arch/arm64/kernel/entry-common.c | 31 ++++++++++++++++++++++++++++++ + arch/arm64/kernel/hw_breakpoint.c | 17 +++++----------- + 3 files changed, 40 insertions(+), 12 deletions(-) + +diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h +index 6d40efc28be401..594350e552e112 100644 +--- a/arch/arm64/include/asm/exception.h ++++ b/arch/arm64/include/asm/exception.h +@@ -61,8 +61,12 @@ void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr, + struct pt_regs *regs); + #ifdef CONFIG_HAVE_HW_BREAKPOINT + void do_breakpoint(unsigned long esr, struct pt_regs *regs); ++void do_watchpoint(unsigned long addr, unsigned long esr, ++ struct pt_regs *regs); + #else + static inline void do_breakpoint(unsigned long esr, struct pt_regs *regs) {} ++static inline void do_watchpoint(unsigned long addr, unsigned long esr, ++ struct pt_regs *regs) {} + #endif /* CONFIG_HAVE_HW_BREAKPOINT */ + void do_el0_softstep(unsigned long esr, struct pt_regs *regs); + void do_el1_softstep(unsigned long esr, struct pt_regs *regs); +diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c +index c22cc4d0052d54..b90babcf2e2b10 100644 +--- a/arch/arm64/kernel/entry-common.c ++++ b/arch/arm64/kernel/entry-common.c +@@ -535,6 +535,18 @@ static void noinstr el1_softstp(struct pt_regs *regs, unsigned long esr) + arm64_exit_el1_dbg(regs); + } + ++static void noinstr el1_watchpt(struct pt_regs *regs, unsigned long esr) ++{ ++ /* Watchpoints are the only debug exception to write FAR_EL1 */ ++ unsigned long far = read_sysreg(far_el1); ++ ++ arm64_enter_el1_dbg(regs); ++ debug_exception_enter(regs); ++ do_watchpoint(far, esr, regs); ++ debug_exception_exit(regs); ++ arm64_exit_el1_dbg(regs); ++} ++ + static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr) + { + unsigned long far = read_sysreg(far_el1); +@@ -584,6 +596,8 @@ asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs) + el1_softstp(regs, esr); + break; + case ESR_ELx_EC_WATCHPT_CUR: ++ el1_watchpt(regs, esr); ++ break; + case ESR_ELx_EC_BRK64: + el1_dbg(regs, esr); + break; +@@ -800,6 +814,19 @@ static void noinstr el0_softstp(struct pt_regs *regs, unsigned long esr) + exit_to_user_mode(regs); + } + ++static void noinstr el0_watchpt(struct pt_regs *regs, unsigned long esr) ++{ ++ /* Watchpoints are the only debug exception to write FAR_EL1 */ ++ unsigned long far = read_sysreg(far_el1); ++ ++ enter_from_user_mode(regs); ++ debug_exception_enter(regs); ++ do_watchpoint(far, esr, regs); ++ debug_exception_exit(regs); ++ local_daif_restore(DAIF_PROCCTX); ++ exit_to_user_mode(regs); ++} ++ + static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr) + { + /* Only watchpoints write FAR_EL1, otherwise its UNKNOWN */ +@@ -882,6 +909,8 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs) + el0_softstp(regs, esr); + break; + case ESR_ELx_EC_WATCHPT_LOW: ++ el0_watchpt(regs, esr); ++ break; + case ESR_ELx_EC_BRK64: + el0_dbg(regs, esr); + break; +@@ -1006,6 +1035,8 @@ asmlinkage void noinstr el0t_32_sync_handler(struct pt_regs *regs) + el0_softstp(regs, esr); + break; + case ESR_ELx_EC_WATCHPT_LOW: ++ el0_watchpt(regs, esr); ++ break; + case ESR_ELx_EC_BKPT32: + el0_dbg(regs, esr); + break; +diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c +index 8a80e13347c88f..ab76b36dce820b 100644 +--- a/arch/arm64/kernel/hw_breakpoint.c ++++ b/arch/arm64/kernel/hw_breakpoint.c +@@ -750,8 +750,7 @@ static int watchpoint_report(struct perf_event *wp, unsigned long addr, + return step; + } + +-static int watchpoint_handler(unsigned long addr, unsigned long esr, +- struct pt_regs *regs) ++void do_watchpoint(unsigned long addr, unsigned long esr, struct pt_regs *regs) + { + int i, step = 0, *kernel_step, access, closest_match = 0; + u64 min_dist = -1, dist; +@@ -806,7 +805,7 @@ static int watchpoint_handler(unsigned long addr, unsigned long esr, + rcu_read_unlock(); + + if (!step) +- return 0; ++ return; + + /* + * We always disable EL0 watchpoints because the kernel can +@@ -819,7 +818,7 @@ static int watchpoint_handler(unsigned long addr, unsigned long esr, + + /* If we're already stepping a breakpoint, just return. */ + if (debug_info->bps_disabled) +- return 0; ++ return; + + if (test_thread_flag(TIF_SINGLESTEP)) + debug_info->suspended_step = 1; +@@ -830,7 +829,7 @@ static int watchpoint_handler(unsigned long addr, unsigned long esr, + kernel_step = this_cpu_ptr(&stepping_kernel_bp); + + if (*kernel_step != ARM_KERNEL_STEP_NONE) +- return 0; ++ return; + + if (kernel_active_single_step()) { + *kernel_step = ARM_KERNEL_STEP_SUSPEND; +@@ -839,10 +838,8 @@ static int watchpoint_handler(unsigned long addr, unsigned long esr, + kernel_enable_single_step(regs); + } + } +- +- return 0; + } +-NOKPROBE_SYMBOL(watchpoint_handler); ++NOKPROBE_SYMBOL(do_watchpoint); + + /* + * Handle single-step exception. +@@ -984,10 +981,6 @@ static int __init arch_hw_breakpoint_init(void) + pr_info("found %d breakpoint and %d watchpoint registers.\n", + core_num_brps, core_num_wrps); + +- /* Register debug fault handlers. */ +- hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP, +- TRAP_HWBKPT, "hw-watchpoint handler"); +- + /* + * Reset the breakpoint resources. We assume that a halting + * debugger will leave the world in a nice state for us. +-- +2.53.0 + diff --git a/queue-6.12/arm64-debug-split-single-stepping-exception-entry.patch b/queue-6.12/arm64-debug-split-single-stepping-exception-entry.patch new file mode 100644 index 0000000000..d98e76a07b --- /dev/null +++ b/queue-6.12/arm64-debug-split-single-stepping-exception-entry.patch @@ -0,0 +1,296 @@ +From 4f0e01d33f85d69272c4340964178d2b507620be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:49 +0200 +Subject: arm64: debug: split single stepping exception entry + +From: Ada Couprie Diaz + +[ Upstream commit 0ac7584c08ceff13fc1e3082a0104548688d6b00 ] + +Currently all debug exceptions share common entry code and are routed +to `do_debug_exception()`, which calls dynamically-registered +handlers for each specific debug exception. This is unfortunate as +different debug exceptions have different entry handling requirements, +and it would be better to handle these distinct requirements earlier. + +The single stepping exception has the most constraints : it can be +exploited to train branch predictors and it needs special handling at EL1 +for the Cortex-A76 erratum #1463225. We need to conserve all those +mitigations. +However, it does not write an address at FAR_EL1, as only hardware +watchpoints do so. + +The single-step handler does its own signaling if it needs to and only +returns 0, so we can call it directly from `entry-common.c`. + +Split the single stepping exception entry, adjust the function signature, +keep the security mitigation and erratum handling. +Further, as the EL0 and EL1 code paths are cleanly separated, we can split +`do_softstep()` into `do_el0_softstep()` and `do_el1_softstep()` and +call them directly from the relevant entry paths. +We can also remove `NOKPROBE_SYMBOL` for the EL0 path, as it cannot +lead to a kprobe recursion. + +Move the call to `arm64_apply_bp_hardening()` to `entry-common.c` so that +we can do it as early as possible, and only for the exceptions coming +from EL0, where it is needed. +This is safe to do as it is `noinstr`, as are all the functions it +may call. `el0_ia()` and `el0_pc()` already call it this way. + +When taking a soft-step exception from EL0, most of the single stepping +handling is safely preemptible : the only possible handler is +`uprobe_single_step_handler()`. It only operates on task-local data and +properly checks its validity, then raises a Thread Information Flag, +processed before returning to userspace in `do_notify_resume()`, which +is already preemptible. +However, the soft-step handler first calls `reinstall_suspended_bps()` +to check if there is any hardware breakpoint or watchpoint pending +or already stepped through. +This cannot be preempted as it manipulates the hardware breakpoint and +watchpoint registers. + +Move the call to `try_step_suspended_breakpoints()` to `entry-common.c` +and adjust the relevant comments. +We can now safely unmask interrupts before handling the step itself, +fixing a PREEMPT_RT issue where the handler could call a sleeping function +with preemption disabled. + +Signed-off-by: Ada Couprie Diaz +Closes: https://lore.kernel.org/linux-arm-kernel/Z6YW_Kx4S2tmj2BP@uudg.org/ +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-10-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/exception.h | 2 + + arch/arm64/kernel/debug-monitors.c | 73 +++++++++++------------------- + arch/arm64/kernel/entry-common.c | 43 ++++++++++++++++++ + arch/arm64/kernel/hw_breakpoint.c | 2 +- + 4 files changed, 73 insertions(+), 47 deletions(-) + +diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h +index 94f46e96515160..6d40efc28be401 100644 +--- a/arch/arm64/include/asm/exception.h ++++ b/arch/arm64/include/asm/exception.h +@@ -64,6 +64,8 @@ void do_breakpoint(unsigned long esr, struct pt_regs *regs); + #else + static inline void do_breakpoint(unsigned long esr, struct pt_regs *regs) {} + #endif /* CONFIG_HAVE_HW_BREAKPOINT */ ++void do_el0_softstep(unsigned long esr, struct pt_regs *regs); ++void do_el1_softstep(unsigned long esr, struct pt_regs *regs); + void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs); + void do_sve_acc(unsigned long esr, struct pt_regs *regs); + void do_sme_acc(unsigned long esr, struct pt_regs *regs); +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index b95a135ef10a99..10d2bc51a32f7c 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -159,21 +160,6 @@ NOKPROBE_SYMBOL(clear_user_regs_spsr_ss); + #define set_regs_spsr_ss(r) set_user_regs_spsr_ss(&(r)->user_regs) + #define clear_regs_spsr_ss(r) clear_user_regs_spsr_ss(&(r)->user_regs) + +-/* +- * Call single step handlers +- * There is no Syndrome info to check for determining the handler. +- * However, there is only one possible handler for user and kernel modes, so +- * check and call the appropriate one. +- */ +-static int call_step_hook(struct pt_regs *regs, unsigned long esr) +-{ +- if (user_mode(regs)) +- return uprobe_single_step_handler(regs, esr); +- +- return kgdb_single_step_handler(regs, esr); +-} +-NOKPROBE_SYMBOL(call_step_hook); +- + static void send_user_sigtrap(int si_code) + { + struct pt_regs *regs = current_pt_regs(); +@@ -188,41 +174,38 @@ static void send_user_sigtrap(int si_code) + "User debug trap"); + } + +-static int single_step_handler(unsigned long unused, unsigned long esr, +- struct pt_regs *regs) ++/* ++ * We have already unmasked interrupts and enabled preemption ++ * when calling do_el0_softstep() from entry-common.c. ++ */ ++void do_el0_softstep(unsigned long esr, struct pt_regs *regs) + { ++ if (uprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED) ++ return; ++ ++ send_user_sigtrap(TRAP_TRACE); + /* +- * If we are stepping a pending breakpoint, call the hw_breakpoint +- * handler first. ++ * ptrace will disable single step unless explicitly ++ * asked to re-enable it. For other clients, it makes ++ * sense to leave it enabled (i.e. rewind the controls ++ * to the active-not-pending state). + */ +- if (try_step_suspended_breakpoints(regs)) +- return 0; +- +- if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED) +- return 0; ++ user_rewind_single_step(current); ++} + +- if (user_mode(regs)) { +- send_user_sigtrap(TRAP_TRACE); +- +- /* +- * ptrace will disable single step unless explicitly +- * asked to re-enable it. For other clients, it makes +- * sense to leave it enabled (i.e. rewind the controls +- * to the active-not-pending state). +- */ +- user_rewind_single_step(current); +- } else { +- pr_warn("Unexpected kernel single-step exception at EL1\n"); +- /* +- * Re-enable stepping since we know that we will be +- * returning to regs. +- */ +- set_regs_spsr_ss(regs); +- } ++void do_el1_softstep(unsigned long esr, struct pt_regs *regs) ++{ ++ if (kgdb_single_step_handler(regs, esr) == DBG_HOOK_HANDLED) ++ return; + +- return 0; ++ pr_warn("Unexpected kernel single-step exception at EL1\n"); ++ /* ++ * Re-enable stepping since we know that we will be ++ * returning to regs. ++ */ ++ set_regs_spsr_ss(regs); + } +-NOKPROBE_SYMBOL(single_step_handler); ++NOKPROBE_SYMBOL(do_el1_softstep); + + static int call_break_hook(struct pt_regs *regs, unsigned long esr) + { +@@ -329,8 +312,6 @@ NOKPROBE_SYMBOL(try_handle_aarch32_break); + + void __init debug_traps_init(void) + { +- hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP, +- TRAP_TRACE, "single-step handler"); + hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP, + TRAP_BRKPT, "BRK handler"); + } +diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c +index af0d7575dcfd92..c22cc4d0052d54 100644 +--- a/arch/arm64/kernel/entry-common.c ++++ b/arch/arm64/kernel/entry-common.c +@@ -517,6 +517,24 @@ static void noinstr el1_breakpt(struct pt_regs *regs, unsigned long esr) + arm64_exit_el1_dbg(regs); + } + ++static void noinstr el1_softstp(struct pt_regs *regs, unsigned long esr) ++{ ++ arm64_enter_el1_dbg(regs); ++ if (!cortex_a76_erratum_1463225_debug_handler(regs)) { ++ debug_exception_enter(regs); ++ /* ++ * After handling a breakpoint, we suspend the breakpoint ++ * and use single-step to move to the next instruction. ++ * If we are stepping a suspended breakpoint there's nothing more to do: ++ * the single-step is complete. ++ */ ++ if (!try_step_suspended_breakpoints(regs)) ++ do_el1_softstep(esr, regs); ++ debug_exception_exit(regs); ++ } ++ arm64_exit_el1_dbg(regs); ++} ++ + static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr) + { + unsigned long far = read_sysreg(far_el1); +@@ -563,6 +581,8 @@ asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs) + el1_breakpt(regs, esr); + break; + case ESR_ELx_EC_SOFTSTP_CUR: ++ el1_softstp(regs, esr); ++ break; + case ESR_ELx_EC_WATCHPT_CUR: + case ESR_ELx_EC_BRK64: + el1_dbg(regs, esr); +@@ -761,6 +781,25 @@ static void noinstr el0_breakpt(struct pt_regs *regs, unsigned long esr) + exit_to_user_mode(regs); + } + ++static void noinstr el0_softstp(struct pt_regs *regs, unsigned long esr) ++{ ++ if (!is_ttbr0_addr(regs->pc)) ++ arm64_apply_bp_hardening(); ++ ++ enter_from_user_mode(regs); ++ /* ++ * After handling a breakpoint, we suspend the breakpoint ++ * and use single-step to move to the next instruction. ++ * If we are stepping a suspended breakpoint there's nothing more to do: ++ * the single-step is complete. ++ */ ++ if (!try_step_suspended_breakpoints(regs)) { ++ local_daif_restore(DAIF_PROCCTX); ++ do_el0_softstep(esr, regs); ++ } ++ exit_to_user_mode(regs); ++} ++ + static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr) + { + /* Only watchpoints write FAR_EL1, otherwise its UNKNOWN */ +@@ -840,6 +879,8 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs) + el0_breakpt(regs, esr); + break; + case ESR_ELx_EC_SOFTSTP_LOW: ++ el0_softstp(regs, esr); ++ break; + case ESR_ELx_EC_WATCHPT_LOW: + case ESR_ELx_EC_BRK64: + el0_dbg(regs, esr); +@@ -962,6 +1003,8 @@ asmlinkage void noinstr el0t_32_sync_handler(struct pt_regs *regs) + el0_breakpt(regs, esr); + break; + case ESR_ELx_EC_SOFTSTP_LOW: ++ el0_softstp(regs, esr); ++ break; + case ESR_ELx_EC_WATCHPT_LOW: + case ESR_ELx_EC_BKPT32: + el0_dbg(regs, esr); +diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c +index 309ae24d454805..8a80e13347c88f 100644 +--- a/arch/arm64/kernel/hw_breakpoint.c ++++ b/arch/arm64/kernel/hw_breakpoint.c +@@ -854,7 +854,7 @@ bool try_step_suspended_breakpoints(struct pt_regs *regs) + bool handled_exception = false; + + /* +- * Called from single-step exception handler. ++ * Called from single-step exception entry. + * Return true if we stepped a breakpoint and can resume execution, + * false if we need to handle a single-step. + */ +-- +2.53.0 + diff --git a/queue-6.12/arm64-entry-add-entry-and-exit-functions-for-debug-e.patch b/queue-6.12/arm64-entry-add-entry-and-exit-functions-for-debug-e.patch new file mode 100644 index 0000000000..eb55ced38c --- /dev/null +++ b/queue-6.12/arm64-entry-add-entry-and-exit-functions-for-debug-e.patch @@ -0,0 +1,114 @@ +From 7218b03de6b3f9077424926feccd628d2cd218a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:46 +0200 +Subject: arm64: entry: Add entry and exit functions for debug exceptions + +From: Ada Couprie Diaz + +[ Upstream commit eaff68b3286116d499a3d4e513a36d772faba587 ] + +Move the `debug_exception_enter()` and `debug_exception_exit()` +functions from mm/fault.c, as they are needed to split +the debug exceptions entry paths from the current unified one. + +Make them externally visible in include/asm/exception.h until +the caller in mm/fault.c is cleaned up. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Anshuman Khandual +Reviewed-by: Will Deacon +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20250707114109.35672-7-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/exception.h | 4 ++++ + arch/arm64/kernel/entry-common.c | 22 ++++++++++++++++++++++ + arch/arm64/mm/fault.c | 22 ---------------------- + 3 files changed, 26 insertions(+), 22 deletions(-) + +diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h +index f296662590c7f8..b1d6a65f6d2256 100644 +--- a/arch/arm64/include/asm/exception.h ++++ b/arch/arm64/include/asm/exception.h +@@ -77,4 +77,8 @@ void do_serror(struct pt_regs *regs, unsigned long esr); + void do_signal(struct pt_regs *regs); + + void __noreturn panic_bad_stack(struct pt_regs *regs, unsigned long esr, unsigned long far); ++ ++void debug_exception_enter(struct pt_regs *regs); ++void debug_exception_exit(struct pt_regs *regs); ++ + #endif /* __ASM_EXCEPTION_H */ +diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c +index d23315ef7b679b..2e04e04aaf2ad6 100644 +--- a/arch/arm64/kernel/entry-common.c ++++ b/arch/arm64/kernel/entry-common.c +@@ -441,6 +441,28 @@ static __always_inline void fpsimd_syscall_exit(void) + __this_cpu_write(fpsimd_last_state.to_save, FP_STATE_CURRENT); + } + ++/* ++ * In debug exception context, we explicitly disable preemption despite ++ * having interrupts disabled. ++ * This serves two purposes: it makes it much less likely that we would ++ * accidentally schedule in exception context and it will force a warning ++ * if we somehow manage to schedule by accident. ++ */ ++void debug_exception_enter(struct pt_regs *regs) ++{ ++ preempt_disable(); ++ ++ /* This code is a bit fragile. Test it. */ ++ RCU_LOCKDEP_WARN(!rcu_is_watching(), "exception_enter didn't work"); ++} ++NOKPROBE_SYMBOL(debug_exception_enter); ++ ++void debug_exception_exit(struct pt_regs *regs) ++{ ++ preempt_enable_no_resched(); ++} ++NOKPROBE_SYMBOL(debug_exception_exit); ++ + UNHANDLED(el1t, 64, sync) + UNHANDLED(el1t, 64, irq) + UNHANDLED(el1t, 64, fiq) +diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c +index 2d1ebc0c3437f2..7c87d2b3b06eaa 100644 +--- a/arch/arm64/mm/fault.c ++++ b/arch/arm64/mm/fault.c +@@ -939,28 +939,6 @@ void __init hook_debug_fault_code(int nr, + debug_fault_info[nr].name = name; + } + +-/* +- * In debug exception context, we explicitly disable preemption despite +- * having interrupts disabled. +- * This serves two purposes: it makes it much less likely that we would +- * accidentally schedule in exception context and it will force a warning +- * if we somehow manage to schedule by accident. +- */ +-static void debug_exception_enter(struct pt_regs *regs) +-{ +- preempt_disable(); +- +- /* This code is a bit fragile. Test it. */ +- RCU_LOCKDEP_WARN(!rcu_is_watching(), "exception_enter didn't work"); +-} +-NOKPROBE_SYMBOL(debug_exception_enter); +- +-static void debug_exception_exit(struct pt_regs *regs) +-{ +- preempt_enable_no_resched(); +-} +-NOKPROBE_SYMBOL(debug_exception_exit); +- + void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr, + struct pt_regs *regs) + { +-- +2.53.0 + diff --git a/queue-6.12/arm64-introduce-esr_is_ubsan_brk.patch b/queue-6.12/arm64-introduce-esr_is_ubsan_brk.patch new file mode 100644 index 0000000000..be964a87a5 --- /dev/null +++ b/queue-6.12/arm64-introduce-esr_is_ubsan_brk.patch @@ -0,0 +1,57 @@ +From 0015fe8d4fb74bfd8db7b5546545adc5bcb392d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:40 +0200 +Subject: arm64: Introduce esr_is_ubsan_brk() + +From: Mostafa Saleh + +[ Upstream commit dc1fd37a7f501731e488c1c6f86b2f591632a4ad ] + +Soon, KVM is going to use this logic for hypervisor panics, +so add it in a wrapper that can be used by the hypervisor exit +handler to decode hyp panics. + +Signed-off-by: Mostafa Saleh +Reviewed-by: Kees Cook +Link: https://lore.kernel.org/r/20250430162713.1997569-2-smostafa@google.com +Signed-off-by: Marc Zyngier +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/esr.h | 5 +++++ + arch/arm64/kernel/traps.c | 2 +- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h +index 5f4dc6364dbb9d..b0520b18192c5a 100644 +--- a/arch/arm64/include/asm/esr.h ++++ b/arch/arm64/include/asm/esr.h +@@ -409,6 +409,11 @@ static inline bool esr_is_cfi_brk(unsigned long esr) + (esr_brk_comment(esr) & ~CFI_BRK_IMM_MASK) == CFI_BRK_IMM_BASE; + } + ++static inline bool esr_is_ubsan_brk(unsigned long esr) ++{ ++ return (esr_brk_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM; ++} ++ + static inline bool esr_fsc_is_translation_fault(unsigned long esr) + { + esr = esr & ESR_ELx_FSC; +diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c +index e2e8ffa65aa586..5e138cf5d4ade3 100644 +--- a/arch/arm64/kernel/traps.c ++++ b/arch/arm64/kernel/traps.c +@@ -1136,7 +1136,7 @@ int __init early_brk64(unsigned long addr, unsigned long esr, + return kasan_handler(regs, esr) != DBG_HOOK_HANDLED; + #endif + #ifdef CONFIG_UBSAN_TRAP +- if ((esr_brk_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM) ++ if (esr_is_ubsan_brk(esr)) + return ubsan_handler(regs, esr) != DBG_HOOK_HANDLED; + #endif + return bug_handler(regs, esr) != DBG_HOOK_HANDLED; +-- +2.53.0 + diff --git a/queue-6.12/arm64-refactor-aarch32_break_handler.patch b/queue-6.12/arm64-refactor-aarch32_break_handler.patch new file mode 100644 index 0000000000..43a8ae5ad6 --- /dev/null +++ b/queue-6.12/arm64-refactor-aarch32_break_handler.patch @@ -0,0 +1,106 @@ +From fbce8389712b338c681afcdbaf131ecf23e15da4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:25:42 +0200 +Subject: arm64: refactor aarch32_break_handler() + +From: Ada Couprie Diaz + +[ Upstream commit b1e2d95524e4d0f5b643394c739212869e95cf6a ] + +`aarch32_break_handler()` is called in `do_el0_undef()` when we +are trying to handle an exception whose Exception Syndrome is unknown. +It checks if the instruction hit might be a 32-bit arm break (be it +A32 or T2), and sends a SIGTRAP to userspace if it is so that it can +be handled. + +However, this is badly represented in the naming of the function, and +is not consistent with the other functions called with the same logic +in `do_el0_undef()`. + +Rename it `try_handle_aarch32_break()` and change the return value to +a boolean to align with the logic of the other tentative handlers in +`do_el0_undef()`, the previous error code being ignored anyway. + +Signed-off-by: Ada Couprie Diaz +Tested-by: Luis Claudio R. Goncalves +Reviewed-by: Anshuman Khandual +Acked-by: Mark Rutland +Reviewed-by: Will Deacon +Link: https://lore.kernel.org/r/20250707114109.35672-3-ada.coupriediaz@arm.com +Signed-off-by: Will Deacon +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Ada Couprie Diaz +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/debug-monitors.h | 2 +- + arch/arm64/kernel/debug-monitors.c | 10 +++++----- + arch/arm64/kernel/traps.c | 2 +- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h +index 13d437bcbf58c2..3eeea1c9f06664 100644 +--- a/arch/arm64/include/asm/debug-monitors.h ++++ b/arch/arm64/include/asm/debug-monitors.h +@@ -115,7 +115,7 @@ static inline int reinstall_suspended_bps(struct pt_regs *regs) + } + #endif + +-int aarch32_break_handler(struct pt_regs *regs); ++bool try_handle_aarch32_break(struct pt_regs *regs); + + void debug_traps_init(void); + +diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c +index b7a2155bca42b1..8275b7f5754626 100644 +--- a/arch/arm64/kernel/debug-monitors.c ++++ b/arch/arm64/kernel/debug-monitors.c +@@ -335,7 +335,7 @@ static int brk_handler(unsigned long unused, unsigned long esr, + } + NOKPROBE_SYMBOL(brk_handler); + +-int aarch32_break_handler(struct pt_regs *regs) ++bool try_handle_aarch32_break(struct pt_regs *regs) + { + u32 arm_instr; + u16 thumb_instr; +@@ -343,7 +343,7 @@ int aarch32_break_handler(struct pt_regs *regs) + void __user *pc = (void __user *)instruction_pointer(regs); + + if (!compat_user_mode(regs)) +- return -EFAULT; ++ return false; + + if (compat_thumb_mode(regs)) { + /* get 16-bit Thumb instruction */ +@@ -367,12 +367,12 @@ int aarch32_break_handler(struct pt_regs *regs) + } + + if (!bp) +- return -EFAULT; ++ return false; + + send_user_sigtrap(TRAP_BRKPT); +- return 0; ++ return true; + } +-NOKPROBE_SYMBOL(aarch32_break_handler); ++NOKPROBE_SYMBOL(try_handle_aarch32_break); + + void __init debug_traps_init(void) + { +diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c +index 5e138cf5d4ade3..c38ebf715be764 100644 +--- a/arch/arm64/kernel/traps.c ++++ b/arch/arm64/kernel/traps.c +@@ -462,7 +462,7 @@ void do_el0_undef(struct pt_regs *regs, unsigned long esr) + u32 insn; + + /* check for AArch32 breakpoint instructions */ +- if (!aarch32_break_handler(regs)) ++ if (try_handle_aarch32_break(regs)) + return; + + if (user_insn_read(regs, &insn)) +-- +2.53.0 + diff --git a/queue-6.12/bcache-fix-uninitialized-closure-object.patch b/queue-6.12/bcache-fix-uninitialized-closure-object.patch new file mode 100644 index 0000000000..3bca96189a --- /dev/null +++ b/queue-6.12/bcache-fix-uninitialized-closure-object.patch @@ -0,0 +1,47 @@ +From 545ac76f1abc68e59dd9a70bd8c62e4f25e4e305 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:21:35 +0800 +Subject: bcache: fix uninitialized closure object + +From: Mingzhe Zou + +[ Upstream commit 20a8e451ec1c7e99060b1bbaaad03ce88c39ddb8 ] + +In the previous patch ("bcache: fix cached_dev.sb_bio use-after-free and +crash"), we adopted a simple modification suggestion from AI to fix the +use-after-free. + +But in actual testing, we found an extreme case where the device is +stopped before calling bch_write_bdev_super(). + +At this point, struct closure sb_write has not been initialized yet. +For this patch, we ensure that sb_bio has been completed via +sb_write_mutex. + +Signed-off-by: Mingzhe Zou +Signed-off-by: Coly Li +Link: https://patch.msgid.link/20260403042135.2221247-1-colyli@fnnas.com +Fixes: fec114a98b87 ("bcache: fix cached_dev.sb_bio use-after-free and crash") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/md/bcache/super.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index 6e0ac0958c10b5..f969ea43492531 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -1378,7 +1378,8 @@ static CLOSURE_CALLBACK(cached_dev_free) + * The sb_bio is embedded in struct cached_dev, so we must + * ensure no I/O is in progress. + */ +- closure_sync(&dc->sb_write); ++ down(&dc->sb_write_mutex); ++ up(&dc->sb_write_mutex); + + if (dc->sb_disk) + put_page(virt_to_page(dc->sb_disk)); +-- +2.53.0 + diff --git a/queue-6.12/drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-o.patch b/queue-6.12/drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-o.patch new file mode 100644 index 0000000000..89f00f072e --- /dev/null +++ b/queue-6.12/drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-o.patch @@ -0,0 +1,130 @@ +From 437dc0ec19a0c2c386662a1033fd7055d9a92a8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 18:02:01 -0300 +Subject: drm/v3d: Fix use-after-free of CPU job query arrays on error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maíra Canal + +[ Upstream commit b0fe80c0b9250b35e2211bf3117e7aca814a21b0 ] + +The CPU job ioctl's fail label calls kvfree() on cpu_job's timestamp and +performance query arrays after v3d_job_cleanup(), which drops the job's +last reference and frees cpu_job. Reading cpu_job at that point is a +use-after-free. Also, on the early v3d_job_init() failure path, it is a +NULL dereference, since v3d_job_deallocate() zeroes the local pointer. + +In the success path, the arrays are released from the scheduler's +.free_job callback, but on the error path, they are freed manually, as +the job was never pushed to the scheduler. While the success path deals +with this correctly, the fail path doesn't. + +On top of that, the manual kvfree() calls only free the array storage; +they don't drm_syncobj_put() the per-query syncobjs that +v3d_timestamp_query_info_free() and v3d_performance_query_info_free() +release on the success path. So the same fail path that triggers the +use-after-free also leaks one syncobj reference per query. + +Unify the CPU job teardown into the CPU job's kref destructor, mirroring +v3d_render_job_free(). The scheduler's .free_job slot reverts to the +generic v3d_sched_job_free() and the fail label drops the manual +kvfree() calls, leaving a single teardown path that is reached from both +the scheduler and the ioctl error path. That removes the use-after-free, +the NULL dereference, and the syncobj leak by construction. + +Cc: stable@vger.kernel.org +Fixes: 9ba0ff3e083f ("drm/v3d: Create a CPU job extension for the timestamp query job") +Assisted-by: Claude:claude-opus-4.7 +Reviewed-by: Iago Toral Quiroga +Link: https://patch.msgid.link/20260515-v3d-cpu-job-leaks-v1-1-7f147cbbf935@igalia.com +Signed-off-by: Maíra Canal +Signed-off-by: Maíra Canal +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/v3d/v3d_sched.c | 16 +--------------- + drivers/gpu/drm/v3d/v3d_submit.c | 19 ++++++++++++++++--- + 2 files changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c +index c9c88d3ad6698f..90eef062766c8d 100644 +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -103,20 +103,6 @@ v3d_performance_query_info_free(struct v3d_performance_query_info *query_info, + } + } + +-static void +-v3d_cpu_job_free(struct drm_sched_job *sched_job) +-{ +- struct v3d_cpu_job *job = to_cpu_job(sched_job); +- +- v3d_timestamp_query_info_free(&job->timestamp_query, +- job->timestamp_query.count); +- +- v3d_performance_query_info_free(&job->performance_query, +- job->performance_query.count); +- +- v3d_job_cleanup(&job->base); +-} +- + static void + v3d_switch_perfmon(struct v3d_dev *v3d, struct v3d_job *job) + { +@@ -846,7 +832,7 @@ static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = { + static const struct drm_sched_backend_ops v3d_cpu_sched_ops = { + .run_job = v3d_cpu_job_run, + .timedout_job = v3d_generic_job_timedout, +- .free_job = v3d_cpu_job_free ++ .free_job = v3d_sched_job_free + }; + + int +diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c +index ddc20191a1ceef..40c21aaade0d67 100644 +--- a/drivers/gpu/drm/v3d/v3d_submit.c ++++ b/drivers/gpu/drm/v3d/v3d_submit.c +@@ -118,6 +118,21 @@ v3d_render_job_free(struct kref *ref) + v3d_job_free(ref); + } + ++static void ++v3d_cpu_job_free(struct kref *ref) ++{ ++ struct v3d_cpu_job *job = container_of(ref, struct v3d_cpu_job, ++ base.refcount); ++ ++ v3d_timestamp_query_info_free(&job->timestamp_query, ++ job->timestamp_query.count); ++ ++ v3d_performance_query_info_free(&job->performance_query, ++ job->performance_query.count); ++ ++ v3d_job_free(ref); ++} ++ + void v3d_job_cleanup(struct v3d_job *job) + { + if (!job) +@@ -1310,7 +1325,7 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, + trace_v3d_submit_cpu_ioctl(&v3d->drm, cpu_job->job_type); + + ret = v3d_job_init(v3d, file_priv, &cpu_job->base, +- v3d_job_free, 0, &se, V3D_CPU); ++ v3d_cpu_job_free, 0, &se, V3D_CPU); + if (ret) { + v3d_job_deallocate((void *)&cpu_job); + goto fail; +@@ -1393,8 +1408,6 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, + v3d_job_cleanup((void *)csd_job); + v3d_job_cleanup(clean_job); + v3d_put_multisync_post_deps(&se); +- kvfree(cpu_job->timestamp_query.queries); +- kvfree(cpu_job->performance_query.queries); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.12/drm-v3d-release-indirect-csd-gem-reference-on-cpu-jo.patch b/queue-6.12/drm-v3d-release-indirect-csd-gem-reference-on-cpu-jo.patch new file mode 100644 index 0000000000..2976b4aa26 --- /dev/null +++ b/queue-6.12/drm-v3d-release-indirect-csd-gem-reference-on-cpu-jo.patch @@ -0,0 +1,48 @@ +From ac324089f2969ff248d230dd8c5057d3833bc969 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 18:02:02 -0300 +Subject: drm/v3d: Release indirect CSD GEM reference on CPU job free +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maíra Canal + +[ Upstream commit 6eb6e5acafa46854d4363e6c34981289995f3ace ] + +v3d_get_cpu_indirect_csd_params() takes a reference to the indirect BO via +drm_gem_object_lookup() and stashes it in cpu_job->indirect_csd.indirect, +but nothing on the CPU job teardown path ever drops that reference. + +Drop the extra reference in v3d_cpu_job_free(). The NULL check covers ioctl +errors before the lookup ran and CPU job types other than +V3D_CPU_JOB_TYPE_INDIRECT_CSD, which leave the field zero-initialised. + +Cc: stable@vger.kernel.org +Fixes: 18b8413b25b7 ("drm/v3d: Create a CPU job extension for a indirect CSD job") +Assisted-by: Claude:claude-opus-4.7 +Reviewed-by: Iago Toral Quiroga +Link: https://patch.msgid.link/20260515-v3d-cpu-job-leaks-v1-2-7f147cbbf935@igalia.com +Signed-off-by: Maíra Canal +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/v3d/v3d_submit.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c +index 40c21aaade0d67..23472c7af41a96 100644 +--- a/drivers/gpu/drm/v3d/v3d_submit.c ++++ b/drivers/gpu/drm/v3d/v3d_submit.c +@@ -130,6 +130,9 @@ v3d_cpu_job_free(struct kref *ref) + v3d_performance_query_info_free(&job->performance_query, + job->performance_query.count); + ++ if (job->indirect_csd.indirect) ++ drm_gem_object_put(job->indirect_csd.indirect); ++ + v3d_job_free(ref); + } + +-- +2.53.0 + diff --git a/queue-6.12/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch b/queue-6.12/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch new file mode 100644 index 0000000000..869eb9d388 --- /dev/null +++ b/queue-6.12/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch @@ -0,0 +1,55 @@ +From ce9afcfe3b2fbb17ba1b8c32a9af013c3770474c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 15:37:08 +0800 +Subject: net: cpsw_new: Fix potential unregister of netdev that has not been + registered yet + +From: Kevin Hao + +[ Upstream commit 9d724b34fbe13b71865ad0906a4be97571f19cf5 ] + +If an error occurs during register_netdev() for the first MAC in +cpsw_register_ports(), even though cpsw->slaves[0].ndev is set to NULL, +cpsw->slaves[1].ndev would remain unchanged. This could later cause +cpsw_unregister_ports() to attempt unregistering the second MAC. +To address this, add a check for ndev->reg_state before calling +unregister_netdev(). With this change, setting cpsw->slaves[i].ndev +to NULL becomes unnecessary and can be removed accordingly. + +Fixes: ed3525eda4c4 ("net: ethernet: ti: introduce cpsw switchdev based driver part 1 - dual-emac") +Signed-off-by: Kevin Hao +Cc: stable@vger.kernel.org +Reviewed-by: Alexander Sverdlin +Link: https://patch.msgid.link/20260205-cpsw-error-path-v1-2-6e58bae6b299@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Wenshan Lan +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/cpsw_new.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index a74caaca94d110..fa161a10960459 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -1443,7 +1443,8 @@ static void cpsw_unregister_ports(struct cpsw_common *cpsw) + int i = 0; + + for (i = 0; i < cpsw->data.slaves; i++) { +- if (!cpsw->slaves[i].ndev) ++ if (!cpsw->slaves[i].ndev || ++ cpsw->slaves[i].ndev->reg_state != NETREG_REGISTERED) + continue; + + unregister_netdev(cpsw->slaves[i].ndev); +@@ -1463,7 +1464,6 @@ static int cpsw_register_ports(struct cpsw_common *cpsw) + if (ret) { + dev_err(cpsw->dev, + "cpsw: err registering net device%d\n", i); +- cpsw->slaves[i].ndev = NULL; + break; + } + } +-- +2.53.0 + diff --git a/queue-6.12/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch b/queue-6.12/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch new file mode 100644 index 0000000000..41df7619c0 --- /dev/null +++ b/queue-6.12/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch @@ -0,0 +1,71 @@ +From 817d04a6ee8eb3b53cb5c3d93cf7712429210558 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:35:48 +0800 +Subject: net: mctp: ensure our nlmsg responses are initialised + +From: Jeremy Kerr + +[ Upstream commit a6a9bc544b675d8b5180f2718ec985ad267b5cbf ] + +Syed Faraz Abrar (@farazsth98) from Zellic, and Pumpkin (@u1f383) from +DEVCORE Research Team working with Trend Micro Zero Day Initiative +report that a RTM_GETNEIGH will return uninitalised data in the pad +bytes of the ndmsg data. + +Ensure we're initialising the netlink data to zero, in the link, addr +and neigh response messages. + +Fixes: 831119f88781 ("mctp: Add neighbour netlink interface") +Fixes: 06d2f4c583a7 ("mctp: Add netlink route management") +Fixes: 583be982d934 ("mctp: Add device handling and netlink interface") +Signed-off-by: Jeremy Kerr +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260209-dev-mctp-nlmsg-v1-1-f1e30c346a43@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Li hongliang <1468888505@139.com> +Signed-off-by: Sasha Levin +--- + net/mctp/device.c | 1 + + net/mctp/neigh.c | 1 + + net/mctp/route.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/net/mctp/device.c b/net/mctp/device.c +index 8d1386601bbe06..67576cb2728ece 100644 +--- a/net/mctp/device.c ++++ b/net/mctp/device.c +@@ -70,6 +70,7 @@ static int mctp_fill_addrinfo(struct sk_buff *skb, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ifa_family = AF_MCTP; + hdr->ifa_prefixlen = 0; + hdr->ifa_flags = 0; +diff --git a/net/mctp/neigh.c b/net/mctp/neigh.c +index 590f642413e4ef..c0151a69d2b7c2 100644 +--- a/net/mctp/neigh.c ++++ b/net/mctp/neigh.c +@@ -218,6 +218,7 @@ static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ndm_family = AF_MCTP; + hdr->ndm_ifindex = dev->ifindex; + hdr->ndm_state = 0; // TODO other state bits? +diff --git a/net/mctp/route.c b/net/mctp/route.c +index ccba2abbbbfbcc..35a0681123a33f 100644 +--- a/net/mctp/route.c ++++ b/net/mctp/route.c +@@ -1405,6 +1405,7 @@ static int mctp_fill_rtinfo(struct sk_buff *skb, struct mctp_route *rt, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->rtm_family = AF_MCTP; + + /* we use the _len fields as a number of EIDs, rather than +-- +2.53.0 + diff --git a/queue-6.12/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch b/queue-6.12/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch new file mode 100644 index 0000000000..1c3603e554 --- /dev/null +++ b/queue-6.12/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch @@ -0,0 +1,122 @@ +From 18d804eba01a851c9be8784ff63557dc0d9a044f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 17:24:36 +0200 +Subject: net/sched: cls_fw: fix NULL dereference of "old" filters before + change() + +From: Davide Caratti + +[ Upstream commit 65782b2db7321d5f97c16718c4c7f6c7205a56be ] + +Like pointed out by Sashiko [1], since commit ed76f5edccc9 ("net: sched: +protect filter_chain list with filter_chain_lock mutex") TC filters are +added to a shared block and published to datapath before their ->change() +function is called. This is a problem for cls_fw: an invalid filter +created with the "old" method can still classify some packets before it +is destroyed by the validation logic added by Xiang. +Therefore, insisting with repeated runs of the following script: + + # ip link add dev crash0 type dummy + # ip link set dev crash0 up + # mausezahn crash0 -c 100000 -P 10 \ + > -A 4.3.2.1 -B 1.2.3.4 -t udp "dp=1234" -q & + # sleep 1 + # tc qdisc add dev crash0 egress_block 1 clsact + # tc filter add block 1 protocol ip prio 1 matchall \ + > action skbedit mark 65536 continue + # tc filter add block 1 protocol ip prio 2 fw + # ip link del dev crash0 + +can still make fw_classify() hit the WARN_ON() in [2]: + + WARNING: ./include/net/pkt_cls.h:88 at fw_classify+0x244/0x250 [cls_fw], CPU#18: mausezahn/1399 + Modules linked in: cls_fw(E) act_skbedit(E) + CPU: 18 UID: 0 PID: 1399 Comm: mausezahn Tainted: G E 7.0.0-rc6-virtme #17 PREEMPT(full) + Tainted: [E]=UNSIGNED_MODULE + Hardware name: Red Hat KVM, BIOS 1.16.3-2.el9 04/01/2014 + RIP: 0010:fw_classify+0x244/0x250 [cls_fw] + Code: 5c 49 c7 45 00 00 00 00 00 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 5b b8 ff ff ff ff 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 90 <0f> 0b 90 eb a0 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 + RSP: 0018:ffffd1b7026bf8a8 EFLAGS: 00010202 + RAX: ffff8c5ac9c60800 RBX: ffff8c5ac99322c0 RCX: 0000000000000004 + RDX: 0000000000000001 RSI: ffff8c5b74d7a000 RDI: ffff8c5ac8284f40 + RBP: ffffd1b7026bf8d0 R08: 0000000000000000 R09: ffffd1b7026bf9b0 + R10: 00000000ffffffff R11: 0000000000000000 R12: 0000000000010000 + R13: ffffd1b7026bf930 R14: ffff8c5ac8284f40 R15: 0000000000000000 + FS: 00007fca40c37740(0000) GS:ffff8c5b74d7a000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007fca40e822a0 CR3: 0000000005ca0001 CR4: 0000000000172ef0 + Call Trace: + + tcf_classify+0x17d/0x5c0 + tc_run+0x9d/0x150 + __dev_queue_xmit+0x2ab/0x14d0 + ip_finish_output2+0x340/0x8f0 + ip_output+0xa4/0x250 + raw_sendmsg+0x147d/0x14b0 + __sys_sendto+0x1cc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x126/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7fca40e822ba + Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89 + RSP: 002b:00007ffc248a42c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 000055ef233289d0 RCX: 00007fca40e822ba + RDX: 000000000000001e RSI: 000055ef23328c30 RDI: 0000000000000003 + RBP: 000055ef233289d0 R08: 00007ffc248a42d0 R09: 0000000000000010 + R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000001e + R13: 00000000000186a0 R14: 0000000000000000 R15: 00007fca41043000 + + irq event stamp: 1045778 + hardirqs last enabled at (1045784): [] __up_console_sem+0x52/0x60 + hardirqs last disabled at (1045789): [] __up_console_sem+0x37/0x60 + softirqs last enabled at (1045426): [] __alloc_skb+0x207/0x260 + softirqs last disabled at (1045434): [] __dev_queue_xmit+0x78/0x14d0 + +Then, because of the value in the packet's mark, dereference on 'q->handle' +with NULL 'q' occurs: + + BUG: kernel NULL pointer dereference, address: 0000000000000038 + [...] + RIP: 0010:fw_classify+0x1fe/0x250 [cls_fw] + [...] + +Skip "old-style" classification on shared blocks, so that the NULL +dereference is fixed and WARN_ON() is not hit anymore in the short +lifetime of invalid cls_fw "old-style" filters. + +[1] https://sashiko.dev/#/patchset/20260331050217.504278-1-xmei5%40asu.edu +[2] https://elixir.bootlin.com/linux/v7.0-rc6/source/include/net/pkt_cls.h#L86 + +Fixes: faeea8bbf6e9 ("net/sched: cls_fw: fix NULL pointer dereference on shared blocks") +Fixes: ed76f5edccc9 ("net: sched: protect filter_chain list with filter_chain_lock mutex") +Acked-by: Jamal Hadi Salim +Signed-off-by: Davide Caratti +Link: https://patch.msgid.link/e39cbd3103a337f1e515d186fe697b4459d24757.1775661704.git.dcaratti@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_fw.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c +index 83a7372ea15c2a..fd9c6c2815a1c2 100644 +--- a/net/sched/cls_fw.c ++++ b/net/sched/cls_fw.c +@@ -74,9 +74,13 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb, + } + } + } else { +- struct Qdisc *q = tcf_block_q(tp->chain->block); ++ struct Qdisc *q; + + /* Old method: classify the packet using its skb mark. */ ++ if (tcf_block_shared(tp->chain->block)) ++ return -1; ++ ++ q = tcf_block_q(tp->chain->block); + if (id && (TC_H_MAJ(id) == 0 || + !(TC_H_MAJ(id ^ q->handle)))) { + res->classid = id; +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch b/queue-6.12/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch new file mode 100644 index 0000000000..38f9c9d82a --- /dev/null +++ b/queue-6.12/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch @@ -0,0 +1,79 @@ +From aa6d397b43eb8ec02f2bdc53da51b59add84fed0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 11:29:56 -0400 +Subject: net/sched: sch_sfb: Replace direct dequeue call with peek and + qdisc_dequeue_peeked + +From: Victor Nogueria + +[ Upstream commit 1b9bc71153b01dbde8045b9edede4240f4f5520e ] + +When sfb has children (eg qfq qdisc) whose peek() callback is +qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such +qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from +its child (sfb in this case), it will do the following: + 1a. do a peek() - and when sensing there's an skb the child can offer, then + - the child in this case(sfb) calls its child's (qfq) peek. + qfq does the right thing and will return the gso_skb queue packet. + Note: if there wasnt a gso_skb entry then qfq will store it there. + 1b. invoke a dequeue() on the child (sfb). And herein lies the problem. + - sfb will call the child's dequeue() which will essentially just + try to grab something of qfq's queue. + +[ 127.594489][ T453] KASAN: null-ptr-deref in range [0x0000000000000048-0x000000000000004f] +[ 127.594741][ T453] CPU: 2 UID: 0 PID: 453 Comm: ping Not tainted 7.1.0-rc1-00035-gac961974495b-dirty #793 PREEMPT(full) +[ 127.595059][ T453] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +[ 127.595254][ T453] RIP: 0010:qfq_dequeue+0x35c/0x1650 [sch_qfq] +[ 127.595461][ T453] Code: 00 fc ff df 80 3c 02 00 0f 85 17 0e 00 00 4c 8d 73 48 48 89 9d b8 02 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 76 0c 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b +[ 127.596081][ T453] RSP: 0018:ffff88810e5af440 EFLAGS: 00010216 +[ 127.596337][ T453] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: dffffc0000000000 +[ 127.596623][ T453] RDX: 0000000000000009 RSI: 0000001880000000 RDI: ffff888104fd82b0 +[ 127.596917][ T453] RBP: ffff888104fd8000 R08: ffff888104fd8280 R09: 1ffff110211893a3 +[ 127.597165][ T453] R10: 1ffff110211893a6 R11: 1ffff110211893a7 R12: 0000001880000000 +[ 127.597404][ T453] R13: ffff888104fd82b8 R14: 0000000000000048 R15: 0000000040000000 +[ 127.597644][ T453] FS: 00007fc380cbfc40(0000) GS:ffff88816f2a8000(0000) knlGS:0000000000000000 +[ 127.597956][ T453] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 127.598160][ T453] CR2: 00005610aa9890a8 CR3: 000000010369e000 CR4: 0000000000750ef0 +[ 127.598390][ T453] PKRU: 55555554 +[ 127.598509][ T453] Call Trace: +[ 127.598629][ T453] +[ 127.598718][ T453] ? mark_held_locks+0x40/0x70 +[ 127.598890][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599053][ T453] sfb_dequeue+0x88/0x4d0 +[ 127.599174][ T453] ? ktime_get+0x137/0x230 +[ 127.599328][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599480][ T453] ? qdisc_peek_dequeued+0x7b/0x350 [sch_qfq] +[ 127.599670][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599831][ T453] tbf_dequeue+0x6b1/0x1098 [sch_tbf] +[ 127.599988][ T453] __qdisc_run+0x169/0x1900 + +The right thing to do in #1b is to grab the skb off gso_skb queue. +This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked() +method instead. + +Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler") +Signed-off-by: Victor Nogueria +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260430152957.194015-3-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index c36725f0870d46..9a2edaf8352adc 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -439,7 +439,7 @@ static struct sk_buff *sfb_dequeue(struct Qdisc *sch) + struct Qdisc *child = q->qdisc; + struct sk_buff *skb; + +- skb = child->dequeue(q->qdisc); ++ skb = qdisc_dequeue_peeked(child); + + if (skb) { + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series new file mode 100644 index 0000000000..b5232c9bf7 --- /dev/null +++ b/queue-6.12/series @@ -0,0 +1,23 @@ +drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-o.patch +drm-v3d-release-indirect-csd-gem-reference-on-cpu-jo.patch +net-sched-cls_fw-fix-null-dereference-of-old-filters.patch +net-mctp-ensure-our-nlmsg-responses-are-initialised.patch +xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch +net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch +bcache-fix-uninitialized-closure-object.patch +net-cpsw_new-fix-potential-unregister-of-netdev-that.patch +arm64-introduce-esr_is_ubsan_brk.patch +arm64-debug-clean-up-single_step_handler-logic.patch +arm64-refactor-aarch32_break_handler.patch +arm64-debug-call-software-breakpoint-handlers-static.patch +arm64-debug-call-step-handlers-statically.patch +arm64-debug-remove-break-step-handler-registration-i.patch +arm64-entry-add-entry-and-exit-functions-for-debug-e.patch +arm64-debug-split-hardware-breakpoint-exception-entr.patch +arm64-debug-refactor-reinstall_suspended_bps.patch +arm64-debug-split-single-stepping-exception-entry.patch +arm64-debug-split-hardware-watchpoint-exception-entr.patch +arm64-debug-split-brk64-exception-entry.patch +arm64-debug-split-bkpt32-exception-entry.patch +arm64-debug-remove-debug-exception-registration-infr.patch +arm64-debug-always-unmask-interrupts-in-el0_softstp.patch diff --git a/queue-6.12/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch b/queue-6.12/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch new file mode 100644 index 0000000000..c554fe9328 --- /dev/null +++ b/queue-6.12/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch @@ -0,0 +1,93 @@ +From 3da1eccc11d9fc9d5eaec90cffe24e5603d30b5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 03:29:26 -0700 +Subject: xfrm: move policy_bydst RCU sync from per-netns .exit to .pre_exit + +From: Usama Arif + +[ Upstream commit 3e52417318473782012b236d0325bf7d2266a597 ] + +The struct pernet_operations docstring in include/net/net_namespace.h +explicitly warns against blocking RCU primitives in .exit handlers: + + Exit methods using blocking RCU primitives, such as + synchronize_rcu(), should be implemented via exit_batch. + [...] + Please, avoid synchronize_rcu() at all, where it's possible. + + Note that a combination of pre_exit() and exit() can + be used, since a synchronize_rcu() is guaranteed between + the calls. + +xfrm_policy_fini() violates this: it calls synchronize_rcu() before +freeing the policy_bydst hash tables (so no RCU reader is mid- +traversal at free time), but runs from xfrm_net_ops.exit -- once per +namespace -- so a cleanup_net() of N namespaces pays N full RCU +grace periods serially. + +Use the documented pre_exit/exit split. Move the policy flush (and +the workqueue drains it depends on) into a new .pre_exit handler; +xfrm_policy_fini() then runs in .exit and frees the hash tables +after the synchronize_rcu_expedited() that cleanup_net() guarantees +between the two phases. Providing O(1) RCU grace periods per batch +instead of O(N). + +Observed on Linux 6.18 with a workload doing unshare(CLONE_NEWNET) +at ~13/sec sustained: cleanup_net() and the netns_wq rescuer kthread +both stuck in xfrm_policy_fini()'s synchronize_rcu(), >300k struct +net accumulated in the cleanup queue, Percpu in /proc/meminfo climbed +to 130+ GB on 256-CPU hosts, and memcg OOMs followed. setup_net and +__put_net counts were balanced, ruling out a refcount leak. + +Fixes: 069daad4f2ae ("xfrm: Wait for RCU readers during policy netns exit") +Signed-off-by: Usama Arif +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index fca07f8e60749a..863e37d3d7f0f7 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -4264,21 +4264,21 @@ static int __net_init xfrm_policy_init(struct net *net) + return -ENOMEM; + } + +-static void xfrm_policy_fini(struct net *net) ++static void __net_exit xfrm_net_pre_exit(struct net *net) + { +- struct xfrm_pol_inexact_bin *b, *t; +- unsigned int sz; +- int dir; +- + disable_work_sync(&net->xfrm.policy_hthresh.work); +- + flush_work(&net->xfrm.policy_hash_work); + #ifdef CONFIG_XFRM_SUB_POLICY + xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false); + #endif + xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false); ++} + +- synchronize_rcu(); ++static void xfrm_policy_fini(struct net *net) ++{ ++ struct xfrm_pol_inexact_bin *b, *t; ++ unsigned int sz; ++ int dir; + + WARN_ON(!list_empty(&net->xfrm.policy_all)); + +@@ -4356,6 +4356,7 @@ static void __net_exit xfrm_net_exit(struct net *net) + + static struct pernet_operations __net_initdata xfrm_net_ops = { + .init = xfrm_net_init, ++ .pre_exit = xfrm_net_pre_exit, + .exit = xfrm_net_exit, + }; + +-- +2.53.0 + diff --git a/queue-6.18/bcache-fix-uninitialized-closure-object.patch b/queue-6.18/bcache-fix-uninitialized-closure-object.patch new file mode 100644 index 0000000000..df7b11de85 --- /dev/null +++ b/queue-6.18/bcache-fix-uninitialized-closure-object.patch @@ -0,0 +1,47 @@ +From 2ec0dc826a72242ecdea8d0ec183a6684d00e40a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:21:35 +0800 +Subject: bcache: fix uninitialized closure object + +From: Mingzhe Zou + +[ Upstream commit 20a8e451ec1c7e99060b1bbaaad03ce88c39ddb8 ] + +In the previous patch ("bcache: fix cached_dev.sb_bio use-after-free and +crash"), we adopted a simple modification suggestion from AI to fix the +use-after-free. + +But in actual testing, we found an extreme case where the device is +stopped before calling bch_write_bdev_super(). + +At this point, struct closure sb_write has not been initialized yet. +For this patch, we ensure that sb_bio has been completed via +sb_write_mutex. + +Signed-off-by: Mingzhe Zou +Signed-off-by: Coly Li +Link: https://patch.msgid.link/20260403042135.2221247-1-colyli@fnnas.com +Fixes: fec114a98b87 ("bcache: fix cached_dev.sb_bio use-after-free and crash") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/md/bcache/super.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index 2f06945533d673..d4ebd13a59f820 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -1378,7 +1378,8 @@ static CLOSURE_CALLBACK(cached_dev_free) + * The sb_bio is embedded in struct cached_dev, so we must + * ensure no I/O is in progress. + */ +- closure_sync(&dc->sb_write); ++ down(&dc->sb_write_mutex); ++ up(&dc->sb_write_mutex); + + if (dc->sb_disk) + folio_put(virt_to_folio(dc->sb_disk)); +-- +2.53.0 + diff --git a/queue-6.18/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch b/queue-6.18/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch new file mode 100644 index 0000000000..536719018e --- /dev/null +++ b/queue-6.18/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch @@ -0,0 +1,71 @@ +From 653831a4cbf606d60c0f3e59418189975074a464 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:34:28 +0800 +Subject: net: mctp: ensure our nlmsg responses are initialised + +From: Jeremy Kerr + +[ Upstream commit a6a9bc544b675d8b5180f2718ec985ad267b5cbf ] + +Syed Faraz Abrar (@farazsth98) from Zellic, and Pumpkin (@u1f383) from +DEVCORE Research Team working with Trend Micro Zero Day Initiative +report that a RTM_GETNEIGH will return uninitalised data in the pad +bytes of the ndmsg data. + +Ensure we're initialising the netlink data to zero, in the link, addr +and neigh response messages. + +Fixes: 831119f88781 ("mctp: Add neighbour netlink interface") +Fixes: 06d2f4c583a7 ("mctp: Add netlink route management") +Fixes: 583be982d934 ("mctp: Add device handling and netlink interface") +Signed-off-by: Jeremy Kerr +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260209-dev-mctp-nlmsg-v1-1-f1e30c346a43@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Li hongliang <1468888505@139.com> +Signed-off-by: Sasha Levin +--- + net/mctp/device.c | 1 + + net/mctp/neigh.c | 1 + + net/mctp/route.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/net/mctp/device.c b/net/mctp/device.c +index 4d404edd7446e1..04c5570bacff69 100644 +--- a/net/mctp/device.c ++++ b/net/mctp/device.c +@@ -70,6 +70,7 @@ static int mctp_fill_addrinfo(struct sk_buff *skb, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ifa_family = AF_MCTP; + hdr->ifa_prefixlen = 0; + hdr->ifa_flags = 0; +diff --git a/net/mctp/neigh.c b/net/mctp/neigh.c +index 05b899f22d902b..fc85f0e6930143 100644 +--- a/net/mctp/neigh.c ++++ b/net/mctp/neigh.c +@@ -218,6 +218,7 @@ static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ndm_family = AF_MCTP; + hdr->ndm_ifindex = dev->ifindex; + hdr->ndm_state = 0; // TODO other state bits? +diff --git a/net/mctp/route.c b/net/mctp/route.c +index d4fdaac8037aba..eb817f1eb5c8eb 100644 +--- a/net/mctp/route.c ++++ b/net/mctp/route.c +@@ -1650,6 +1650,7 @@ static int mctp_fill_rtinfo(struct sk_buff *skb, struct mctp_route *rt, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->rtm_family = AF_MCTP; + + /* we use the _len fields as a number of EIDs, rather than +-- +2.53.0 + diff --git a/queue-6.18/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch b/queue-6.18/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch new file mode 100644 index 0000000000..c77d891b6c --- /dev/null +++ b/queue-6.18/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch @@ -0,0 +1,122 @@ +From f0db3e191c173b5275d4245a60ef47188965a717 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 17:24:36 +0200 +Subject: net/sched: cls_fw: fix NULL dereference of "old" filters before + change() + +From: Davide Caratti + +[ Upstream commit 65782b2db7321d5f97c16718c4c7f6c7205a56be ] + +Like pointed out by Sashiko [1], since commit ed76f5edccc9 ("net: sched: +protect filter_chain list with filter_chain_lock mutex") TC filters are +added to a shared block and published to datapath before their ->change() +function is called. This is a problem for cls_fw: an invalid filter +created with the "old" method can still classify some packets before it +is destroyed by the validation logic added by Xiang. +Therefore, insisting with repeated runs of the following script: + + # ip link add dev crash0 type dummy + # ip link set dev crash0 up + # mausezahn crash0 -c 100000 -P 10 \ + > -A 4.3.2.1 -B 1.2.3.4 -t udp "dp=1234" -q & + # sleep 1 + # tc qdisc add dev crash0 egress_block 1 clsact + # tc filter add block 1 protocol ip prio 1 matchall \ + > action skbedit mark 65536 continue + # tc filter add block 1 protocol ip prio 2 fw + # ip link del dev crash0 + +can still make fw_classify() hit the WARN_ON() in [2]: + + WARNING: ./include/net/pkt_cls.h:88 at fw_classify+0x244/0x250 [cls_fw], CPU#18: mausezahn/1399 + Modules linked in: cls_fw(E) act_skbedit(E) + CPU: 18 UID: 0 PID: 1399 Comm: mausezahn Tainted: G E 7.0.0-rc6-virtme #17 PREEMPT(full) + Tainted: [E]=UNSIGNED_MODULE + Hardware name: Red Hat KVM, BIOS 1.16.3-2.el9 04/01/2014 + RIP: 0010:fw_classify+0x244/0x250 [cls_fw] + Code: 5c 49 c7 45 00 00 00 00 00 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 5b b8 ff ff ff ff 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 90 <0f> 0b 90 eb a0 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 + RSP: 0018:ffffd1b7026bf8a8 EFLAGS: 00010202 + RAX: ffff8c5ac9c60800 RBX: ffff8c5ac99322c0 RCX: 0000000000000004 + RDX: 0000000000000001 RSI: ffff8c5b74d7a000 RDI: ffff8c5ac8284f40 + RBP: ffffd1b7026bf8d0 R08: 0000000000000000 R09: ffffd1b7026bf9b0 + R10: 00000000ffffffff R11: 0000000000000000 R12: 0000000000010000 + R13: ffffd1b7026bf930 R14: ffff8c5ac8284f40 R15: 0000000000000000 + FS: 00007fca40c37740(0000) GS:ffff8c5b74d7a000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007fca40e822a0 CR3: 0000000005ca0001 CR4: 0000000000172ef0 + Call Trace: + + tcf_classify+0x17d/0x5c0 + tc_run+0x9d/0x150 + __dev_queue_xmit+0x2ab/0x14d0 + ip_finish_output2+0x340/0x8f0 + ip_output+0xa4/0x250 + raw_sendmsg+0x147d/0x14b0 + __sys_sendto+0x1cc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x126/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7fca40e822ba + Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89 + RSP: 002b:00007ffc248a42c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 000055ef233289d0 RCX: 00007fca40e822ba + RDX: 000000000000001e RSI: 000055ef23328c30 RDI: 0000000000000003 + RBP: 000055ef233289d0 R08: 00007ffc248a42d0 R09: 0000000000000010 + R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000001e + R13: 00000000000186a0 R14: 0000000000000000 R15: 00007fca41043000 + + irq event stamp: 1045778 + hardirqs last enabled at (1045784): [] __up_console_sem+0x52/0x60 + hardirqs last disabled at (1045789): [] __up_console_sem+0x37/0x60 + softirqs last enabled at (1045426): [] __alloc_skb+0x207/0x260 + softirqs last disabled at (1045434): [] __dev_queue_xmit+0x78/0x14d0 + +Then, because of the value in the packet's mark, dereference on 'q->handle' +with NULL 'q' occurs: + + BUG: kernel NULL pointer dereference, address: 0000000000000038 + [...] + RIP: 0010:fw_classify+0x1fe/0x250 [cls_fw] + [...] + +Skip "old-style" classification on shared blocks, so that the NULL +dereference is fixed and WARN_ON() is not hit anymore in the short +lifetime of invalid cls_fw "old-style" filters. + +[1] https://sashiko.dev/#/patchset/20260331050217.504278-1-xmei5%40asu.edu +[2] https://elixir.bootlin.com/linux/v7.0-rc6/source/include/net/pkt_cls.h#L86 + +Fixes: faeea8bbf6e9 ("net/sched: cls_fw: fix NULL pointer dereference on shared blocks") +Fixes: ed76f5edccc9 ("net: sched: protect filter_chain list with filter_chain_lock mutex") +Acked-by: Jamal Hadi Salim +Signed-off-by: Davide Caratti +Link: https://patch.msgid.link/e39cbd3103a337f1e515d186fe697b4459d24757.1775661704.git.dcaratti@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_fw.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c +index 83a7372ea15c2a..fd9c6c2815a1c2 100644 +--- a/net/sched/cls_fw.c ++++ b/net/sched/cls_fw.c +@@ -74,9 +74,13 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb, + } + } + } else { +- struct Qdisc *q = tcf_block_q(tp->chain->block); ++ struct Qdisc *q; + + /* Old method: classify the packet using its skb mark. */ ++ if (tcf_block_shared(tp->chain->block)) ++ return -1; ++ ++ q = tcf_block_q(tp->chain->block); + if (id && (TC_H_MAJ(id) == 0 || + !(TC_H_MAJ(id ^ q->handle)))) { + res->classid = id; +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch b/queue-6.18/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch new file mode 100644 index 0000000000..0617a5396f --- /dev/null +++ b/queue-6.18/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch @@ -0,0 +1,79 @@ +From a15b332e17f6bb7b34e8929ff451e86ed4710d3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 11:29:56 -0400 +Subject: net/sched: sch_sfb: Replace direct dequeue call with peek and + qdisc_dequeue_peeked + +From: Victor Nogueria + +[ Upstream commit 1b9bc71153b01dbde8045b9edede4240f4f5520e ] + +When sfb has children (eg qfq qdisc) whose peek() callback is +qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such +qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from +its child (sfb in this case), it will do the following: + 1a. do a peek() - and when sensing there's an skb the child can offer, then + - the child in this case(sfb) calls its child's (qfq) peek. + qfq does the right thing and will return the gso_skb queue packet. + Note: if there wasnt a gso_skb entry then qfq will store it there. + 1b. invoke a dequeue() on the child (sfb). And herein lies the problem. + - sfb will call the child's dequeue() which will essentially just + try to grab something of qfq's queue. + +[ 127.594489][ T453] KASAN: null-ptr-deref in range [0x0000000000000048-0x000000000000004f] +[ 127.594741][ T453] CPU: 2 UID: 0 PID: 453 Comm: ping Not tainted 7.1.0-rc1-00035-gac961974495b-dirty #793 PREEMPT(full) +[ 127.595059][ T453] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +[ 127.595254][ T453] RIP: 0010:qfq_dequeue+0x35c/0x1650 [sch_qfq] +[ 127.595461][ T453] Code: 00 fc ff df 80 3c 02 00 0f 85 17 0e 00 00 4c 8d 73 48 48 89 9d b8 02 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 76 0c 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b +[ 127.596081][ T453] RSP: 0018:ffff88810e5af440 EFLAGS: 00010216 +[ 127.596337][ T453] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: dffffc0000000000 +[ 127.596623][ T453] RDX: 0000000000000009 RSI: 0000001880000000 RDI: ffff888104fd82b0 +[ 127.596917][ T453] RBP: ffff888104fd8000 R08: ffff888104fd8280 R09: 1ffff110211893a3 +[ 127.597165][ T453] R10: 1ffff110211893a6 R11: 1ffff110211893a7 R12: 0000001880000000 +[ 127.597404][ T453] R13: ffff888104fd82b8 R14: 0000000000000048 R15: 0000000040000000 +[ 127.597644][ T453] FS: 00007fc380cbfc40(0000) GS:ffff88816f2a8000(0000) knlGS:0000000000000000 +[ 127.597956][ T453] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 127.598160][ T453] CR2: 00005610aa9890a8 CR3: 000000010369e000 CR4: 0000000000750ef0 +[ 127.598390][ T453] PKRU: 55555554 +[ 127.598509][ T453] Call Trace: +[ 127.598629][ T453] +[ 127.598718][ T453] ? mark_held_locks+0x40/0x70 +[ 127.598890][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599053][ T453] sfb_dequeue+0x88/0x4d0 +[ 127.599174][ T453] ? ktime_get+0x137/0x230 +[ 127.599328][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599480][ T453] ? qdisc_peek_dequeued+0x7b/0x350 [sch_qfq] +[ 127.599670][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599831][ T453] tbf_dequeue+0x6b1/0x1098 [sch_tbf] +[ 127.599988][ T453] __qdisc_run+0x169/0x1900 + +The right thing to do in #1b is to grab the skb off gso_skb queue. +This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked() +method instead. + +Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler") +Signed-off-by: Victor Nogueria +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260430152957.194015-3-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index 00286c930b8de7..14ac8897784757 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -441,7 +441,7 @@ static struct sk_buff *sfb_dequeue(struct Qdisc *sch) + struct Qdisc *child = q->qdisc; + struct sk_buff *skb; + +- skb = child->dequeue(q->qdisc); ++ skb = qdisc_dequeue_peeked(child); + + if (skb) { + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series new file mode 100644 index 0000000000..003f0fd2a1 --- /dev/null +++ b/queue-6.18/series @@ -0,0 +1,5 @@ +net-sched-cls_fw-fix-null-dereference-of-old-filters.patch +net-mctp-ensure-our-nlmsg-responses-are-initialised.patch +xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch +net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch +bcache-fix-uninitialized-closure-object.patch diff --git a/queue-6.18/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch b/queue-6.18/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch new file mode 100644 index 0000000000..d1aa92b902 --- /dev/null +++ b/queue-6.18/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch @@ -0,0 +1,93 @@ +From fd4ed4eb53969b3f249dfaedd05b0edb148902e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 03:29:26 -0700 +Subject: xfrm: move policy_bydst RCU sync from per-netns .exit to .pre_exit + +From: Usama Arif + +[ Upstream commit 3e52417318473782012b236d0325bf7d2266a597 ] + +The struct pernet_operations docstring in include/net/net_namespace.h +explicitly warns against blocking RCU primitives in .exit handlers: + + Exit methods using blocking RCU primitives, such as + synchronize_rcu(), should be implemented via exit_batch. + [...] + Please, avoid synchronize_rcu() at all, where it's possible. + + Note that a combination of pre_exit() and exit() can + be used, since a synchronize_rcu() is guaranteed between + the calls. + +xfrm_policy_fini() violates this: it calls synchronize_rcu() before +freeing the policy_bydst hash tables (so no RCU reader is mid- +traversal at free time), but runs from xfrm_net_ops.exit -- once per +namespace -- so a cleanup_net() of N namespaces pays N full RCU +grace periods serially. + +Use the documented pre_exit/exit split. Move the policy flush (and +the workqueue drains it depends on) into a new .pre_exit handler; +xfrm_policy_fini() then runs in .exit and frees the hash tables +after the synchronize_rcu_expedited() that cleanup_net() guarantees +between the two phases. Providing O(1) RCU grace periods per batch +instead of O(N). + +Observed on Linux 6.18 with a workload doing unshare(CLONE_NEWNET) +at ~13/sec sustained: cleanup_net() and the netns_wq rescuer kthread +both stuck in xfrm_policy_fini()'s synchronize_rcu(), >300k struct +net accumulated in the cleanup queue, Percpu in /proc/meminfo climbed +to 130+ GB on 256-CPU hosts, and memcg OOMs followed. setup_net and +__put_net counts were balanced, ruling out a refcount leak. + +Fixes: 069daad4f2ae ("xfrm: Wait for RCU readers during policy netns exit") +Signed-off-by: Usama Arif +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index 29c94ee0ceb256..96e9262c4b482a 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -4276,21 +4276,21 @@ static int __net_init xfrm_policy_init(struct net *net) + return -ENOMEM; + } + +-static void xfrm_policy_fini(struct net *net) ++static void __net_exit xfrm_net_pre_exit(struct net *net) + { +- struct xfrm_pol_inexact_bin *b, *t; +- unsigned int sz; +- int dir; +- + disable_work_sync(&net->xfrm.policy_hthresh.work); +- + flush_work(&net->xfrm.policy_hash_work); + #ifdef CONFIG_XFRM_SUB_POLICY + xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false); + #endif + xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false); ++} + +- synchronize_rcu(); ++static void xfrm_policy_fini(struct net *net) ++{ ++ struct xfrm_pol_inexact_bin *b, *t; ++ unsigned int sz; ++ int dir; + + WARN_ON(!list_empty(&net->xfrm.policy_all)); + +@@ -4368,6 +4368,7 @@ static void __net_exit xfrm_net_exit(struct net *net) + + static struct pernet_operations __net_initdata xfrm_net_ops = { + .init = xfrm_net_init, ++ .pre_exit = xfrm_net_pre_exit, + .exit = xfrm_net_exit, + }; + +-- +2.53.0 + diff --git a/queue-6.6/bcache-fix-uninitialized-closure-object.patch b/queue-6.6/bcache-fix-uninitialized-closure-object.patch new file mode 100644 index 0000000000..8ce3fb4098 --- /dev/null +++ b/queue-6.6/bcache-fix-uninitialized-closure-object.patch @@ -0,0 +1,47 @@ +From ec99f33265443be31ab13be1e1ed366b65a77613 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:21:35 +0800 +Subject: bcache: fix uninitialized closure object + +From: Mingzhe Zou + +[ Upstream commit 20a8e451ec1c7e99060b1bbaaad03ce88c39ddb8 ] + +In the previous patch ("bcache: fix cached_dev.sb_bio use-after-free and +crash"), we adopted a simple modification suggestion from AI to fix the +use-after-free. + +But in actual testing, we found an extreme case where the device is +stopped before calling bch_write_bdev_super(). + +At this point, struct closure sb_write has not been initialized yet. +For this patch, we ensure that sb_bio has been completed via +sb_write_mutex. + +Signed-off-by: Mingzhe Zou +Signed-off-by: Coly Li +Link: https://patch.msgid.link/20260403042135.2221247-1-colyli@fnnas.com +Fixes: fec114a98b87 ("bcache: fix cached_dev.sb_bio use-after-free and crash") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/md/bcache/super.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index a66423cf12d0a7..6d9349f6f8fd75 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -1372,7 +1372,8 @@ static void cached_dev_free(struct closure *cl) + * The sb_bio is embedded in struct cached_dev, so we must + * ensure no I/O is in progress. + */ +- closure_sync(&dc->sb_write); ++ down(&dc->sb_write_mutex); ++ up(&dc->sb_write_mutex); + + if (dc->sb_disk) + put_page(virt_to_page(dc->sb_disk)); +-- +2.53.0 + diff --git a/queue-6.6/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch b/queue-6.6/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch new file mode 100644 index 0000000000..68c445a749 --- /dev/null +++ b/queue-6.6/drm-remove-plane-hsub-vsub-alignment-requirement-for.patch @@ -0,0 +1,66 @@ +From 6c80855c9061b4952f412d43f319cfb70b0a909f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Sep 2023 11:15:18 -0300 +Subject: drm: Remove plane hsub/vsub alignment requirement for core helpers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Carlos Eduardo Gallo Filho + +[ Upstream commit f2f455981a34ce8ca88a41458c09494b387d344f ] + +The drm_format_info_plane_{height,width} functions was implemented using +regular division for the plane size calculation, which cause issues [1][2] +when used on contexts where the dimensions are misaligned with relation +to the subsampling factors. So, replace the regular division by the +DIV_ROUND_UP macro. + +This allows these functions to be used in more drivers, making further +work to bring more core presence on them possible. + +[1] http://patchwork.freedesktop.org/patch/msgid/20170321181218.10042-3-ville.syrjala@linux.intel.com +[2] https://patchwork.freedesktop.org/patch/msgid/20211026225105.2783797-2-imre.deak@intel.com + +Signed-off-by: Carlos Eduardo Gallo Filho +Reviewed-by: André Almeida +Signed-off-by: Thomas Zimmermann +Link: https://patchwork.freedesktop.org/patch/msgid/20230926141519.9315-2-gcarlos@disroot.org +Signed-off-by: Sasha Levin +--- + include/drm/drm_fourcc.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h +index 532ae78ca747e6..ccf91daa430702 100644 +--- a/include/drm/drm_fourcc.h ++++ b/include/drm/drm_fourcc.h +@@ -22,6 +22,7 @@ + #ifndef __DRM_FOURCC_H__ + #define __DRM_FOURCC_H__ + ++#include + #include + #include + +@@ -279,7 +280,7 @@ int drm_format_info_plane_width(const struct drm_format_info *info, int width, + if (plane == 0) + return width; + +- return width / info->hsub; ++ return DIV_ROUND_UP(width, info->hsub); + } + + /** +@@ -301,7 +302,7 @@ int drm_format_info_plane_height(const struct drm_format_info *info, int height, + if (plane == 0) + return height; + +- return height / info->vsub; ++ return DIV_ROUND_UP(height, info->vsub); + } + + const struct drm_format_info *__drm_format_info(u32 format); +-- +2.53.0 + diff --git a/queue-6.6/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch b/queue-6.6/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch new file mode 100644 index 0000000000..2b42f5064b --- /dev/null +++ b/queue-6.6/net-cpsw_new-fix-potential-unregister-of-netdev-that.patch @@ -0,0 +1,55 @@ +From deff77ef684f0c438cf436e8d1a4b7b39215154d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 15:37:35 +0800 +Subject: net: cpsw_new: Fix potential unregister of netdev that has not been + registered yet + +From: Kevin Hao + +[ Upstream commit 9d724b34fbe13b71865ad0906a4be97571f19cf5 ] + +If an error occurs during register_netdev() for the first MAC in +cpsw_register_ports(), even though cpsw->slaves[0].ndev is set to NULL, +cpsw->slaves[1].ndev would remain unchanged. This could later cause +cpsw_unregister_ports() to attempt unregistering the second MAC. +To address this, add a check for ndev->reg_state before calling +unregister_netdev(). With this change, setting cpsw->slaves[i].ndev +to NULL becomes unnecessary and can be removed accordingly. + +Fixes: ed3525eda4c4 ("net: ethernet: ti: introduce cpsw switchdev based driver part 1 - dual-emac") +Signed-off-by: Kevin Hao +Cc: stable@vger.kernel.org +Reviewed-by: Alexander Sverdlin +Link: https://patch.msgid.link/20260205-cpsw-error-path-v1-2-6e58bae6b299@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Wenshan Lan +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/cpsw_new.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index 1f98044b3666ff..64f527ba9a4746 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -1442,7 +1442,8 @@ static void cpsw_unregister_ports(struct cpsw_common *cpsw) + int i = 0; + + for (i = 0; i < cpsw->data.slaves; i++) { +- if (!cpsw->slaves[i].ndev) ++ if (!cpsw->slaves[i].ndev || ++ cpsw->slaves[i].ndev->reg_state != NETREG_REGISTERED) + continue; + + unregister_netdev(cpsw->slaves[i].ndev); +@@ -1462,7 +1463,6 @@ static int cpsw_register_ports(struct cpsw_common *cpsw) + if (ret) { + dev_err(cpsw->dev, + "cpsw: err registering net device%d\n", i); +- cpsw->slaves[i].ndev = NULL; + break; + } + } +-- +2.53.0 + diff --git a/queue-6.6/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch b/queue-6.6/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch new file mode 100644 index 0000000000..2c4ced4a24 --- /dev/null +++ b/queue-6.6/net-mctp-ensure-our-nlmsg-responses-are-initialised.patch @@ -0,0 +1,71 @@ +From 1e2b2fd93ff3e8dc619a04c0e3b71938b52641c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:36:17 +0800 +Subject: net: mctp: ensure our nlmsg responses are initialised + +From: Jeremy Kerr + +[ Upstream commit a6a9bc544b675d8b5180f2718ec985ad267b5cbf ] + +Syed Faraz Abrar (@farazsth98) from Zellic, and Pumpkin (@u1f383) from +DEVCORE Research Team working with Trend Micro Zero Day Initiative +report that a RTM_GETNEIGH will return uninitalised data in the pad +bytes of the ndmsg data. + +Ensure we're initialising the netlink data to zero, in the link, addr +and neigh response messages. + +Fixes: 831119f88781 ("mctp: Add neighbour netlink interface") +Fixes: 06d2f4c583a7 ("mctp: Add netlink route management") +Fixes: 583be982d934 ("mctp: Add device handling and netlink interface") +Signed-off-by: Jeremy Kerr +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260209-dev-mctp-nlmsg-v1-1-f1e30c346a43@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Li hongliang <1468888505@139.com> +Signed-off-by: Sasha Levin +--- + net/mctp/device.c | 1 + + net/mctp/neigh.c | 1 + + net/mctp/route.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/net/mctp/device.c b/net/mctp/device.c +index 8d1386601bbe06..67576cb2728ece 100644 +--- a/net/mctp/device.c ++++ b/net/mctp/device.c +@@ -70,6 +70,7 @@ static int mctp_fill_addrinfo(struct sk_buff *skb, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ifa_family = AF_MCTP; + hdr->ifa_prefixlen = 0; + hdr->ifa_flags = 0; +diff --git a/net/mctp/neigh.c b/net/mctp/neigh.c +index 590f642413e4ef..c0151a69d2b7c2 100644 +--- a/net/mctp/neigh.c ++++ b/net/mctp/neigh.c +@@ -218,6 +218,7 @@ static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->ndm_family = AF_MCTP; + hdr->ndm_ifindex = dev->ifindex; + hdr->ndm_state = 0; // TODO other state bits? +diff --git a/net/mctp/route.c b/net/mctp/route.c +index a565cf2bc7330d..6d6e19c049396f 100644 +--- a/net/mctp/route.c ++++ b/net/mctp/route.c +@@ -1332,6 +1332,7 @@ static int mctp_fill_rtinfo(struct sk_buff *skb, struct mctp_route *rt, + return -EMSGSIZE; + + hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); + hdr->rtm_family = AF_MCTP; + + /* we use the _len fields as a number of EIDs, rather than +-- +2.53.0 + diff --git a/queue-6.6/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch b/queue-6.6/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch new file mode 100644 index 0000000000..6546e902c5 --- /dev/null +++ b/queue-6.6/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch @@ -0,0 +1,122 @@ +From c00564a7545ef50b432c28721bc42e3e244be12b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 17:24:36 +0200 +Subject: net/sched: cls_fw: fix NULL dereference of "old" filters before + change() + +From: Davide Caratti + +[ Upstream commit 65782b2db7321d5f97c16718c4c7f6c7205a56be ] + +Like pointed out by Sashiko [1], since commit ed76f5edccc9 ("net: sched: +protect filter_chain list with filter_chain_lock mutex") TC filters are +added to a shared block and published to datapath before their ->change() +function is called. This is a problem for cls_fw: an invalid filter +created with the "old" method can still classify some packets before it +is destroyed by the validation logic added by Xiang. +Therefore, insisting with repeated runs of the following script: + + # ip link add dev crash0 type dummy + # ip link set dev crash0 up + # mausezahn crash0 -c 100000 -P 10 \ + > -A 4.3.2.1 -B 1.2.3.4 -t udp "dp=1234" -q & + # sleep 1 + # tc qdisc add dev crash0 egress_block 1 clsact + # tc filter add block 1 protocol ip prio 1 matchall \ + > action skbedit mark 65536 continue + # tc filter add block 1 protocol ip prio 2 fw + # ip link del dev crash0 + +can still make fw_classify() hit the WARN_ON() in [2]: + + WARNING: ./include/net/pkt_cls.h:88 at fw_classify+0x244/0x250 [cls_fw], CPU#18: mausezahn/1399 + Modules linked in: cls_fw(E) act_skbedit(E) + CPU: 18 UID: 0 PID: 1399 Comm: mausezahn Tainted: G E 7.0.0-rc6-virtme #17 PREEMPT(full) + Tainted: [E]=UNSIGNED_MODULE + Hardware name: Red Hat KVM, BIOS 1.16.3-2.el9 04/01/2014 + RIP: 0010:fw_classify+0x244/0x250 [cls_fw] + Code: 5c 49 c7 45 00 00 00 00 00 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 5b b8 ff ff ff ff 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 90 <0f> 0b 90 eb a0 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 + RSP: 0018:ffffd1b7026bf8a8 EFLAGS: 00010202 + RAX: ffff8c5ac9c60800 RBX: ffff8c5ac99322c0 RCX: 0000000000000004 + RDX: 0000000000000001 RSI: ffff8c5b74d7a000 RDI: ffff8c5ac8284f40 + RBP: ffffd1b7026bf8d0 R08: 0000000000000000 R09: ffffd1b7026bf9b0 + R10: 00000000ffffffff R11: 0000000000000000 R12: 0000000000010000 + R13: ffffd1b7026bf930 R14: ffff8c5ac8284f40 R15: 0000000000000000 + FS: 00007fca40c37740(0000) GS:ffff8c5b74d7a000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007fca40e822a0 CR3: 0000000005ca0001 CR4: 0000000000172ef0 + Call Trace: + + tcf_classify+0x17d/0x5c0 + tc_run+0x9d/0x150 + __dev_queue_xmit+0x2ab/0x14d0 + ip_finish_output2+0x340/0x8f0 + ip_output+0xa4/0x250 + raw_sendmsg+0x147d/0x14b0 + __sys_sendto+0x1cc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x126/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7fca40e822ba + Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89 + RSP: 002b:00007ffc248a42c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 000055ef233289d0 RCX: 00007fca40e822ba + RDX: 000000000000001e RSI: 000055ef23328c30 RDI: 0000000000000003 + RBP: 000055ef233289d0 R08: 00007ffc248a42d0 R09: 0000000000000010 + R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000001e + R13: 00000000000186a0 R14: 0000000000000000 R15: 00007fca41043000 + + irq event stamp: 1045778 + hardirqs last enabled at (1045784): [] __up_console_sem+0x52/0x60 + hardirqs last disabled at (1045789): [] __up_console_sem+0x37/0x60 + softirqs last enabled at (1045426): [] __alloc_skb+0x207/0x260 + softirqs last disabled at (1045434): [] __dev_queue_xmit+0x78/0x14d0 + +Then, because of the value in the packet's mark, dereference on 'q->handle' +with NULL 'q' occurs: + + BUG: kernel NULL pointer dereference, address: 0000000000000038 + [...] + RIP: 0010:fw_classify+0x1fe/0x250 [cls_fw] + [...] + +Skip "old-style" classification on shared blocks, so that the NULL +dereference is fixed and WARN_ON() is not hit anymore in the short +lifetime of invalid cls_fw "old-style" filters. + +[1] https://sashiko.dev/#/patchset/20260331050217.504278-1-xmei5%40asu.edu +[2] https://elixir.bootlin.com/linux/v7.0-rc6/source/include/net/pkt_cls.h#L86 + +Fixes: faeea8bbf6e9 ("net/sched: cls_fw: fix NULL pointer dereference on shared blocks") +Fixes: ed76f5edccc9 ("net: sched: protect filter_chain list with filter_chain_lock mutex") +Acked-by: Jamal Hadi Salim +Signed-off-by: Davide Caratti +Link: https://patch.msgid.link/e39cbd3103a337f1e515d186fe697b4459d24757.1775661704.git.dcaratti@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_fw.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c +index 2e5e8df5ca55c4..bc007bb47432cd 100644 +--- a/net/sched/cls_fw.c ++++ b/net/sched/cls_fw.c +@@ -74,9 +74,13 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb, + } + } + } else { +- struct Qdisc *q = tcf_block_q(tp->chain->block); ++ struct Qdisc *q; + + /* Old method: classify the packet using its skb mark. */ ++ if (tcf_block_shared(tp->chain->block)) ++ return -1; ++ ++ q = tcf_block_q(tp->chain->block); + if (id && (TC_H_MAJ(id) == 0 || + !(TC_H_MAJ(id ^ q->handle)))) { + res->classid = id; +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch b/queue-6.6/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch new file mode 100644 index 0000000000..290d6e44cc --- /dev/null +++ b/queue-6.6/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch @@ -0,0 +1,79 @@ +From d4332c82eeae899732d2c35fe84130bfd2f1c093 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 11:29:56 -0400 +Subject: net/sched: sch_sfb: Replace direct dequeue call with peek and + qdisc_dequeue_peeked + +From: Victor Nogueria + +[ Upstream commit 1b9bc71153b01dbde8045b9edede4240f4f5520e ] + +When sfb has children (eg qfq qdisc) whose peek() callback is +qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such +qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from +its child (sfb in this case), it will do the following: + 1a. do a peek() - and when sensing there's an skb the child can offer, then + - the child in this case(sfb) calls its child's (qfq) peek. + qfq does the right thing and will return the gso_skb queue packet. + Note: if there wasnt a gso_skb entry then qfq will store it there. + 1b. invoke a dequeue() on the child (sfb). And herein lies the problem. + - sfb will call the child's dequeue() which will essentially just + try to grab something of qfq's queue. + +[ 127.594489][ T453] KASAN: null-ptr-deref in range [0x0000000000000048-0x000000000000004f] +[ 127.594741][ T453] CPU: 2 UID: 0 PID: 453 Comm: ping Not tainted 7.1.0-rc1-00035-gac961974495b-dirty #793 PREEMPT(full) +[ 127.595059][ T453] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +[ 127.595254][ T453] RIP: 0010:qfq_dequeue+0x35c/0x1650 [sch_qfq] +[ 127.595461][ T453] Code: 00 fc ff df 80 3c 02 00 0f 85 17 0e 00 00 4c 8d 73 48 48 89 9d b8 02 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 76 0c 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b +[ 127.596081][ T453] RSP: 0018:ffff88810e5af440 EFLAGS: 00010216 +[ 127.596337][ T453] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: dffffc0000000000 +[ 127.596623][ T453] RDX: 0000000000000009 RSI: 0000001880000000 RDI: ffff888104fd82b0 +[ 127.596917][ T453] RBP: ffff888104fd8000 R08: ffff888104fd8280 R09: 1ffff110211893a3 +[ 127.597165][ T453] R10: 1ffff110211893a6 R11: 1ffff110211893a7 R12: 0000001880000000 +[ 127.597404][ T453] R13: ffff888104fd82b8 R14: 0000000000000048 R15: 0000000040000000 +[ 127.597644][ T453] FS: 00007fc380cbfc40(0000) GS:ffff88816f2a8000(0000) knlGS:0000000000000000 +[ 127.597956][ T453] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 127.598160][ T453] CR2: 00005610aa9890a8 CR3: 000000010369e000 CR4: 0000000000750ef0 +[ 127.598390][ T453] PKRU: 55555554 +[ 127.598509][ T453] Call Trace: +[ 127.598629][ T453] +[ 127.598718][ T453] ? mark_held_locks+0x40/0x70 +[ 127.598890][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599053][ T453] sfb_dequeue+0x88/0x4d0 +[ 127.599174][ T453] ? ktime_get+0x137/0x230 +[ 127.599328][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599480][ T453] ? qdisc_peek_dequeued+0x7b/0x350 [sch_qfq] +[ 127.599670][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599831][ T453] tbf_dequeue+0x6b1/0x1098 [sch_tbf] +[ 127.599988][ T453] __qdisc_run+0x169/0x1900 + +The right thing to do in #1b is to grab the skb off gso_skb queue. +This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked() +method instead. + +Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler") +Signed-off-by: Victor Nogueria +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260430152957.194015-3-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index ce67826fdf9b6d..58bf4c803f7fee 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -439,7 +439,7 @@ static struct sk_buff *sfb_dequeue(struct Qdisc *sch) + struct Qdisc *child = q->qdisc; + struct sk_buff *skb; + +- skb = child->dequeue(q->qdisc); ++ skb = qdisc_dequeue_peeked(child); + + if (skb) { + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series new file mode 100644 index 0000000000..3a056ff01a --- /dev/null +++ b/queue-6.6/series @@ -0,0 +1,6 @@ +net-sched-cls_fw-fix-null-dereference-of-old-filters.patch +net-mctp-ensure-our-nlmsg-responses-are-initialised.patch +net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch +drm-remove-plane-hsub-vsub-alignment-requirement-for.patch +bcache-fix-uninitialized-closure-object.patch +net-cpsw_new-fix-potential-unregister-of-netdev-that.patch diff --git a/queue-7.0/acpi-button-enable-wakeup-gpes-for-acpi-buttons-at-p.patch b/queue-7.0/acpi-button-enable-wakeup-gpes-for-acpi-buttons-at-p.patch new file mode 100644 index 0000000000..5fd0e01848 --- /dev/null +++ b/queue-7.0/acpi-button-enable-wakeup-gpes-for-acpi-buttons-at-p.patch @@ -0,0 +1,194 @@ +From 8d04ca0065c7a3c7aea2569b52af6e6a33b4b10f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:52:10 +0200 +Subject: ACPI: button: Enable wakeup GPEs for ACPI buttons at probe time + +From: Rafael J. Wysocki + +[ Upstream commit a004b8f0d3bc5d82d3f2c91ff93f4b4b7ccb8f76 ] + +Prior to commit 57c31e6d620f ("ACPI: scan: Use acpi_setup_gpe_for_wake() +for buttons"), ACPI button wakeup GPEs having handler methods remained +enabled after acpi_wakeup_gpe_init(), but currently they are not enabled +because acpi_setup_gpe_for_wake() disables them. + +That causes function keys to stop working on some systems [1] and there +may be other related issues elsewhere. + +To address that, make the ACPI button driver enable wakeup GPEs for ACPI +buttons so long as they have handler methods. While this does not +restore the old behavior exactly (the ACPI button driver needs to be +bound to the button devices for the GPEs to be enabled), it should be +sufficient to restore the missing functionality. + +For this purpose, introduce acpi_enable_gpe_cond() that enables +a GPE if its dispatch type matches the supplied one and modify +acpi_button_probe() to use that function for enabling the GPEs in +question. + +Fixes: 57c31e6d620f ("ACPI: scan: Use acpi_setup_gpe_for_wake() for buttons") +Reported-by: Nick +Closes: https://lore.kernel.org/linux-acpi/E2OXET.4X5GTP37VTNC3@kousu.ca/ [1] +Signed-off-by: Rafael J. Wysocki +Tested-by: Nick +Cc: 7.0+ # 7.0+ +Link: https://patch.msgid.link/9629117.CDJkKcVGEf@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/evxfgpe.c | 50 ++++++++++++++++++++++++++++------- + drivers/acpi/button.c | 22 +++++++++++++++ + include/acpi/acpixf.h | 5 ++++ + 3 files changed, 68 insertions(+), 9 deletions(-) + +diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c +index 60dacec1b121fd..4074b5908db308 100644 +--- a/drivers/acpi/acpica/evxfgpe.c ++++ b/drivers/acpi/acpica/evxfgpe.c +@@ -78,18 +78,22 @@ ACPI_EXPORT_SYMBOL(acpi_update_all_gpes) + + /******************************************************************************* + * +- * FUNCTION: acpi_enable_gpe ++ * FUNCTION: acpi_enable_gpe_cond + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block ++ * dispatch_type - GPE dispatch type to match + * + * RETURN: Status + * +- * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is +- * hardware-enabled. ++ * DESCRIPTION: Add a reference to a GPE so long as its dispatch type matches ++ * the supplied one, or it is different from ACPI_GPE_DISPATCH_NONE ++ * if the supplied one is ACPI_GPE_DISPATCH_MASK. On the first ++ * reference, the GPE is hardware-enabled. + * + ******************************************************************************/ +-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) ++acpi_status acpi_enable_gpe_cond(acpi_handle gpe_device, u32 gpe_number, ++ u8 dispatch_type) + { + acpi_status status = AE_BAD_PARAMETER; + struct acpi_gpe_event_info *gpe_event_info; +@@ -100,14 +104,18 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* +- * Ensure that we have a valid GPE number and that there is some way +- * of handling the GPE (handler or a GPE method). In other words, we +- * won't allow a valid GPE to be enabled if there is no way to handle it. ++ * Ensure that we have a valid GPE number and that the dispatch type of ++ * the GPE matches the supplied one (or it is not ACPI_GPE_DISPATCH_NONE ++ * if the supplied one is ACPI_GPE_DISPATCH_MASK). + */ + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (gpe_event_info) { +- if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != +- ACPI_GPE_DISPATCH_NONE) { ++ if (dispatch_type == ACPI_GPE_DISPATCH_MASK) ++ dispatch_type = ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags); ++ else if (dispatch_type != ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) ++ dispatch_type = ACPI_GPE_DISPATCH_NONE; ++ ++ if (dispatch_type != ACPI_GPE_DISPATCH_NONE) { + status = acpi_ev_add_gpe_reference(gpe_event_info, TRUE); + if (ACPI_SUCCESS(status) && + ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) { +@@ -128,6 +136,30 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); + } ++ACPI_EXPORT_SYMBOL(acpi_enable_gpe_cond) ++ ++/******************************************************************************* ++ * ++ * FUNCTION: acpi_enable_gpe ++ * ++ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 ++ * gpe_number - GPE level within the GPE block ++ * ++ * RETURN: Status ++ * ++ * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is ++ * hardware-enabled. ++ * ++ ******************************************************************************/ ++acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) ++{ ++ /* ++ * Ensure that there is some way of handling the GPE (handler or a GPE ++ * method). In other words, we won't allow a valid GPE to be enabled if ++ * there is no way to handle it. ++ */ ++ return acpi_enable_gpe_cond(gpe_device, gpe_number, ACPI_GPE_DISPATCH_MASK); ++} + ACPI_EXPORT_SYMBOL(acpi_enable_gpe) + + /******************************************************************************* +diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c +index 22f26d8fdb1f6e..0ddbcfd0b1040a 100644 +--- a/drivers/acpi/button.c ++++ b/drivers/acpi/button.c +@@ -179,6 +179,7 @@ struct acpi_button { + ktime_t last_time; + bool suspended; + bool lid_state_initialized; ++ bool gpe_enabled; + }; + + static struct acpi_device *lid_device; +@@ -647,6 +648,21 @@ static int acpi_button_probe(struct platform_device *pdev) + status = acpi_install_notify_handler(device->handle, + ACPI_ALL_NOTIFY, handler, + button); ++ if (ACPI_SUCCESS(status) && device->wakeup.flags.valid) { ++ acpi_status st; ++ ++ /* ++ * If the wakeup GPE has a handler method, enable it in ++ * case it is also used for signaling runtime events. ++ */ ++ st = acpi_enable_gpe_cond(device->wakeup.gpe_device, ++ device->wakeup.gpe_number, ++ ACPI_GPE_DISPATCH_METHOD); ++ button->gpe_enabled = ACPI_SUCCESS(st); ++ if (button->gpe_enabled) ++ dev_dbg(button->dev, "Enabled ACPI GPE%02llx\n", ++ device->wakeup.gpe_number); ++ } + break; + } + if (ACPI_FAILURE(status)) { +@@ -690,6 +706,12 @@ static void acpi_button_remove(struct platform_device *pdev) + acpi_button_event); + break; + default: ++ if (button->gpe_enabled) { ++ dev_dbg(button->dev, "Disabling ACPI GPE%02llx\n", ++ adev->wakeup.gpe_number); ++ acpi_disable_gpe(adev->wakeup.gpe_device, ++ adev->wakeup.gpe_number); ++ } + acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, + button->type == ACPI_BUTTON_TYPE_LID ? + acpi_lid_notify : +diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h +index 49d1749f30bbc9..a4b56270015161 100644 +--- a/include/acpi/acpixf.h ++++ b/include/acpi/acpixf.h +@@ -725,6 +725,11 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status + */ + ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_update_all_gpes(void)) + ++ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status ++ acpi_enable_gpe_cond(acpi_handle gpe_device, ++ u32 gpe_number, ++ u8 dispatch_type)) ++ + ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status + acpi_enable_gpe(acpi_handle gpe_device, + u32 gpe_number)) +-- +2.53.0 + diff --git a/queue-7.0/acpi-button-fix-acpi-gpe-handler-leak-during-removal.patch b/queue-7.0/acpi-button-fix-acpi-gpe-handler-leak-during-removal.patch new file mode 100644 index 0000000000..9db88020f4 --- /dev/null +++ b/queue-7.0/acpi-button-fix-acpi-gpe-handler-leak-during-removal.patch @@ -0,0 +1,46 @@ +From 44bd83bc081a7c89932ec792c9a77a1b37d84ca1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:49:44 +0200 +Subject: ACPI: button: Fix ACPI GPE handler leak during removal + +From: Rafael J. Wysocki + +[ Upstream commit fe80251152fed5b185f795ef2cd9f7fe9c3162e0 ] + +Commit a7e23ec17fee ("ACPI: button: Install notifier for system events +as well") changed the ACPI notify handler type for ACPI buttons to +ACPI_ALL_NOTIFY, but it forgot to update acpi_button_remove() to reflect +that change. This leads to leaking the notify handler past driver +removal, which may cause a kernel crash to occur if ACPI notify on +the given device is triggered after removing the driver, and causes a +subsequent probe of the given device with the same driver to fail. + +Address this by updating the acpi_remove_notify_handler() call in +acpi_button_remove() as appropriate. + +Fixes: a7e23ec17fee ("ACPI: button: Install notifier for system events as well") +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Mario Limonciello (AMD) +Cc: 6.15+ # 6.15+ +Link: https://patch.msgid.link/7954431.EvYhyI6sBW@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/button.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c +index ff30f993b15062..22f26d8fdb1f6e 100644 +--- a/drivers/acpi/button.c ++++ b/drivers/acpi/button.c +@@ -690,7 +690,7 @@ static void acpi_button_remove(struct platform_device *pdev) + acpi_button_event); + break; + default: +- acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, ++ acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, + button->type == ACPI_BUTTON_TYPE_LID ? + acpi_lid_notify : + acpi_button_notify); +-- +2.53.0 + diff --git a/queue-7.0/bcache-fix-uninitialized-closure-object.patch b/queue-7.0/bcache-fix-uninitialized-closure-object.patch new file mode 100644 index 0000000000..16fb48a927 --- /dev/null +++ b/queue-7.0/bcache-fix-uninitialized-closure-object.patch @@ -0,0 +1,47 @@ +From f55c2f9a2c213a2ea0e96d3b7fe50cb58fd79be5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:21:35 +0800 +Subject: bcache: fix uninitialized closure object + +From: Mingzhe Zou + +[ Upstream commit 20a8e451ec1c7e99060b1bbaaad03ce88c39ddb8 ] + +In the previous patch ("bcache: fix cached_dev.sb_bio use-after-free and +crash"), we adopted a simple modification suggestion from AI to fix the +use-after-free. + +But in actual testing, we found an extreme case where the device is +stopped before calling bch_write_bdev_super(). + +At this point, struct closure sb_write has not been initialized yet. +For this patch, we ensure that sb_bio has been completed via +sb_write_mutex. + +Signed-off-by: Mingzhe Zou +Signed-off-by: Coly Li +Link: https://patch.msgid.link/20260403042135.2221247-1-colyli@fnnas.com +Fixes: fec114a98b87 ("bcache: fix cached_dev.sb_bio use-after-free and crash") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/md/bcache/super.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index 6627a381f65ae7..97d9adb0bf96b0 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -1378,7 +1378,8 @@ static CLOSURE_CALLBACK(cached_dev_free) + * The sb_bio is embedded in struct cached_dev, so we must + * ensure no I/O is in progress. + */ +- closure_sync(&dc->sb_write); ++ down(&dc->sb_write_mutex); ++ up(&dc->sb_write_mutex); + + if (dc->sb_disk) + folio_put(virt_to_folio(dc->sb_disk)); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch b/queue-7.0/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch new file mode 100644 index 0000000000..b30aae1701 --- /dev/null +++ b/queue-7.0/net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch @@ -0,0 +1,79 @@ +From b4054f008dc9126b448ebf9f02cf81d1f0a2049b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 11:29:56 -0400 +Subject: net/sched: sch_sfb: Replace direct dequeue call with peek and + qdisc_dequeue_peeked + +From: Victor Nogueria + +[ Upstream commit 1b9bc71153b01dbde8045b9edede4240f4f5520e ] + +When sfb has children (eg qfq qdisc) whose peek() callback is +qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such +qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from +its child (sfb in this case), it will do the following: + 1a. do a peek() - and when sensing there's an skb the child can offer, then + - the child in this case(sfb) calls its child's (qfq) peek. + qfq does the right thing and will return the gso_skb queue packet. + Note: if there wasnt a gso_skb entry then qfq will store it there. + 1b. invoke a dequeue() on the child (sfb). And herein lies the problem. + - sfb will call the child's dequeue() which will essentially just + try to grab something of qfq's queue. + +[ 127.594489][ T453] KASAN: null-ptr-deref in range [0x0000000000000048-0x000000000000004f] +[ 127.594741][ T453] CPU: 2 UID: 0 PID: 453 Comm: ping Not tainted 7.1.0-rc1-00035-gac961974495b-dirty #793 PREEMPT(full) +[ 127.595059][ T453] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +[ 127.595254][ T453] RIP: 0010:qfq_dequeue+0x35c/0x1650 [sch_qfq] +[ 127.595461][ T453] Code: 00 fc ff df 80 3c 02 00 0f 85 17 0e 00 00 4c 8d 73 48 48 89 9d b8 02 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 76 0c 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b +[ 127.596081][ T453] RSP: 0018:ffff88810e5af440 EFLAGS: 00010216 +[ 127.596337][ T453] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: dffffc0000000000 +[ 127.596623][ T453] RDX: 0000000000000009 RSI: 0000001880000000 RDI: ffff888104fd82b0 +[ 127.596917][ T453] RBP: ffff888104fd8000 R08: ffff888104fd8280 R09: 1ffff110211893a3 +[ 127.597165][ T453] R10: 1ffff110211893a6 R11: 1ffff110211893a7 R12: 0000001880000000 +[ 127.597404][ T453] R13: ffff888104fd82b8 R14: 0000000000000048 R15: 0000000040000000 +[ 127.597644][ T453] FS: 00007fc380cbfc40(0000) GS:ffff88816f2a8000(0000) knlGS:0000000000000000 +[ 127.597956][ T453] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 127.598160][ T453] CR2: 00005610aa9890a8 CR3: 000000010369e000 CR4: 0000000000750ef0 +[ 127.598390][ T453] PKRU: 55555554 +[ 127.598509][ T453] Call Trace: +[ 127.598629][ T453] +[ 127.598718][ T453] ? mark_held_locks+0x40/0x70 +[ 127.598890][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599053][ T453] sfb_dequeue+0x88/0x4d0 +[ 127.599174][ T453] ? ktime_get+0x137/0x230 +[ 127.599328][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599480][ T453] ? qdisc_peek_dequeued+0x7b/0x350 [sch_qfq] +[ 127.599670][ T453] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 127.599831][ T453] tbf_dequeue+0x6b1/0x1098 [sch_tbf] +[ 127.599988][ T453] __qdisc_run+0x169/0x1900 + +The right thing to do in #1b is to grab the skb off gso_skb queue. +This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked() +method instead. + +Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler") +Signed-off-by: Victor Nogueria +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260430152957.194015-3-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index 00286c930b8de7..14ac8897784757 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -441,7 +441,7 @@ static struct sk_buff *sfb_dequeue(struct Qdisc *sch) + struct Qdisc *child = q->qdisc; + struct sk_buff *skb; + +- skb = child->dequeue(q->qdisc); ++ skb = qdisc_dequeue_peeked(child); + + if (skb) { + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-7.0/series b/queue-7.0/series new file mode 100644 index 0000000000..646d508915 --- /dev/null +++ b/queue-7.0/series @@ -0,0 +1,5 @@ +acpi-button-fix-acpi-gpe-handler-leak-during-removal.patch +acpi-button-enable-wakeup-gpes-for-acpi-buttons-at-p.patch +xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch +net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch +bcache-fix-uninitialized-closure-object.patch diff --git a/queue-7.0/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch b/queue-7.0/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch new file mode 100644 index 0000000000..9a9283a900 --- /dev/null +++ b/queue-7.0/xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch @@ -0,0 +1,93 @@ +From eedaa7f770f77730fe2ac4a1e66ea906b244ceab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 03:29:26 -0700 +Subject: xfrm: move policy_bydst RCU sync from per-netns .exit to .pre_exit + +From: Usama Arif + +[ Upstream commit 3e52417318473782012b236d0325bf7d2266a597 ] + +The struct pernet_operations docstring in include/net/net_namespace.h +explicitly warns against blocking RCU primitives in .exit handlers: + + Exit methods using blocking RCU primitives, such as + synchronize_rcu(), should be implemented via exit_batch. + [...] + Please, avoid synchronize_rcu() at all, where it's possible. + + Note that a combination of pre_exit() and exit() can + be used, since a synchronize_rcu() is guaranteed between + the calls. + +xfrm_policy_fini() violates this: it calls synchronize_rcu() before +freeing the policy_bydst hash tables (so no RCU reader is mid- +traversal at free time), but runs from xfrm_net_ops.exit -- once per +namespace -- so a cleanup_net() of N namespaces pays N full RCU +grace periods serially. + +Use the documented pre_exit/exit split. Move the policy flush (and +the workqueue drains it depends on) into a new .pre_exit handler; +xfrm_policy_fini() then runs in .exit and frees the hash tables +after the synchronize_rcu_expedited() that cleanup_net() guarantees +between the two phases. Providing O(1) RCU grace periods per batch +instead of O(N). + +Observed on Linux 6.18 with a workload doing unshare(CLONE_NEWNET) +at ~13/sec sustained: cleanup_net() and the netns_wq rescuer kthread +both stuck in xfrm_policy_fini()'s synchronize_rcu(), >300k struct +net accumulated in the cleanup queue, Percpu in /proc/meminfo climbed +to 130+ GB on 256-CPU hosts, and memcg OOMs followed. setup_net and +__put_net counts were balanced, ruling out a refcount leak. + +Fixes: 069daad4f2ae ("xfrm: Wait for RCU readers during policy netns exit") +Signed-off-by: Usama Arif +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index a872af5610dc95..71bdb781cb0292 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -4276,21 +4276,21 @@ static int __net_init xfrm_policy_init(struct net *net) + return -ENOMEM; + } + +-static void xfrm_policy_fini(struct net *net) ++static void __net_exit xfrm_net_pre_exit(struct net *net) + { +- struct xfrm_pol_inexact_bin *b, *t; +- unsigned int sz; +- int dir; +- + disable_work_sync(&net->xfrm.policy_hthresh.work); +- + flush_work(&net->xfrm.policy_hash_work); + #ifdef CONFIG_XFRM_SUB_POLICY + xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false); + #endif + xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false); ++} + +- synchronize_rcu(); ++static void xfrm_policy_fini(struct net *net) ++{ ++ struct xfrm_pol_inexact_bin *b, *t; ++ unsigned int sz; ++ int dir; + + WARN_ON(!list_empty(&net->xfrm.policy_all)); + +@@ -4368,6 +4368,7 @@ static void __net_exit xfrm_net_exit(struct net *net) + + static struct pernet_operations __net_initdata xfrm_net_ops = { + .init = xfrm_net_init, ++ .pre_exit = xfrm_net_pre_exit, + .exit = xfrm_net_exit, + }; + +-- +2.53.0 +