From: 徐晗翔 <xuhx@hust.edu.cn>
To: tglx@kernel.org
Cc: linux-kernel@vger.kernel.org
Subject: genirq: NMI dispatch reads struct irqaction with no quiescence -- use-after-free across free_nmi()'s kfree (x86 verification on the arch-independent core path)
Date: Wed, 11 Nov 2026 15:17:38 +0800 (GMT+08:00) [thread overview]
Message-ID: <57077c85.24251.1a1c9782b17.Coremail.xuhx@hust.edu.cn> (raw)
In-Reply-To: <2026102727-data-sequel-ce41@gregkh>
[-- Attachment #1: Type: text/plain, Size: 6922 bytes --]
handle_fasteoi_nmi() (kernel/irq/chip.c:792-810), the SPI-NMI flow
handler, snapshots desc->action at entry with no lock (:795) and then
uses that pointer in NMI context: the tracepoint(s) (:801/:806), the
indirect call action->handler(irq, action->dev_id) (:805) and the
trailing irq_eoi. The unregister path free_nmi() -> __cleanup_nmi()
(kernel/irq/manage.c:2032-2065) removes the publication under
desc->lock, then kfree()s the action OUTSIDE the lock (:2057) --
there is no mechanism anywhere that waits for an in-flight NMI
handler: the flow handler never sets IRQD_IRQ_INPROGRESS (no
IRQD_IRQ_INPROGRESS in the whole function, so __synchronize_hardirq's
spin can never observe an in-flight NMI), there is no reference
count, no RCU, and no in-flight counter on struct irqaction. When
the remove side and an in-flight NMI run concurrently, the in-flight
handler keeps dereferencing the kfree()d action -- including reading
the function pointer and indirect-calling it -- which happens in NMI
context (panic or hard lockup; no safe recovery). I verified this
one-shot on a pristine Linux 7.3 KASAN kernel by driving the
arch-independent genirq core with a fake NMI-capable irqchip module
(IRQCHIP_SUPPORTS_NMI, mirroring the GIC driver's nmi_setup/teardown
semantics): with the dispatch thread held by kprobe right after the
snapshot (handle_fasteoi_nmi+0x56) and free_nmi completing its kfree
on another CPU, the release produced exactly the two predicted
slab-use-after-free reports (action->handler load at +0x5e, dev_id
load at +0x6b -- matching the objdump-decoded load offsets byte for
byte), followed by an indirect call through the garbage function
pointer (Oops RIP 0x0) from NMI context. The sibling drivers
pciehp-style comparison does not exist here, but the plain-IRQ path
has the complete quiescence machinery (IRQD_IRQ_INPROGRESS +
__synchronize_hardirq + request_mutex + dev_id matching) that the NMI
paths lack entirely -- the defect is that NMI dispatch bypasses all
of it.
The detailed description:
* The two paths (Linux 7.3 line numbers)
Dispatch (SPI-NMI): generic_handle_domain_nmi() -> handle_irq_desc()
-> desc->handle_irq = handle_fasteoi_nmi (kernel/irq/chip.c:792-810):
:795 snapshot; :799 kstat; :801/:806 tracepoints; :805
action->handler(irq, action->dev_id); :808-809 irq_eoi.
Unregister: free_nmi() (manage.c:2067-2082) -> __cleanup_nmi()
(manage.c:2032-2065): lock :2037, irq_nmi_teardown :2038 (flow
handler switched back by the irqchip driver, gic-v3.c:646),
desc->action = NULL :2047, irq_shutdown_and_deactivate :2050,
unlock, kfree(action) :2057, irq_release_resources :2059,
irq_chip_pm_put :2061, module_put :2062. No wait of any kind
before the kfree.
* Why the depth/mask handling is not protection (closed)
free_nmi() on an enabled NMI (depth==0) only WARNs and disables
(manage.c:2077-2079); disable_nmi_nosync() documents that it does
not wait for running instances (manage.c:755-768) and a synchronous
disable_nmi() does not exist in the tree; a GICv3-level mask stops
NEW deliveries but SPI pending state survives disable (GICv3 spec:
only PPI pending is cleared on disable), so "disabled but still
deliverable" widens the window. struct irqaction has no refcount
and no RCU field (include/linux/interrupt.h:123-139); the kfree is
direct.
The plain free_irq() path, by contrast, has the full machinery:
IRQD_IRQ_INPROGRESS (handle.c:255-267) + __synchronize_hardirq
(manage.c:50-82) + request_mutex (manage.c:1868) + dev_id matching
with an already-free early return (manage.c:1881-1889). NMI
dispatch bypasses handle_irq_event(), so it never participates.
* Reachability (upstream form)
Requires arm64 + GICv3 pseudo-NMI (irqchip.gicv3_pseudo_nmi=1) and
an SPI-type NMI registration; in-tree registrants: ACPI AGDI
(frees without disabling first, agdi.c:150-151), Fujitsu A64FX diag,
and arm_pmu's SPI overflow (its probe-failure path removes the
cpuhp instance with _nocalls -- teardown callbacks do not run, NMI
stays enabled -- then frees, arm_pmu.c:858-859/243/51). Trigger
pairs an admin remove with any in-flight firmware/PMU NMI; the
window is microseconds, and NMI frequency scales it linearly.
Alternative delivery paths (resend, software re-trigger, injection,
suspend/resume) were exhaustively ruled out for NMI descs -- the
only execution of handle_fasteoi_nmi is the NMI entry itself, so
the exposure is exactly this window.
* Evidence (pristine 7.3 KASAN, x86_64 QEMU; instruments attached)
nmi_race.ko registers a fake NMI irqchip (the GIC mirror) and a
dispatch kthread on the exported-equivalent paths; nmi_stall.ko
parks the dispatcher at handle_fasteoi_nmi+0x56 (after the
snapshot, before the handler/dev_id loads). free_nmi from another
CPU completes inside the stall:
BUG: KASAN: slab-use-after-free in handle_fasteoi_nmi+0x5e
(action->handler load) <- objdump-decoded offsets match
BUG: KASAN: slab-use-after-free in handle_fasteoi_nmi+0x6b
(action->dev_id load)
Oops: 0010 RIP: 0010:0x0 <- indirect call through the garbage
function pointer read from freed
memory, in NMI context
three stacks closed: use handle_fasteoi_nmi+0x5e <- handle_irq_desc
(CPU 2); alloc __kmalloc_cache_noprof <- request_nmi (task 112);
free kfree <- __cleanup_nmi <- free_thread (CPU 3);
object kmalloc-128 (struct irqaction)
Fidelity, stated plainly: the audited defect code (chip.c:792-810
snapshot/use and manage.c:2032-2065 unlock-and-free) is the
architecture-independent genirq core and executes unmodified; the
delivery ENTRY (GIC pseudo-NMI exception path) is platform code and
is replaced in the x86 VM by a module irqchip whose setup/teardown
mirror the GIC semantics -- the racing pair (dispatch snapshot vs
unregister free) is unaffected by which entry raises the interrupt.
* Suggested fix direction
Option A (minimal): in __cleanup_nmi(), after removing the
publication and before the out-of-lock kfree, wait for in-flight
NMIs: __synchronize_hardirq(desc, true) covers the active window
(EOI clears it), plus a per-desc in-flight counter incremented/
decremented by handle_fasteoi_nmi (atomic; spin-waited to zero)
to close the small ack-then-sample blind spot; a pre-wait
PENDING clear accounts for the GICv3 SPI pending-survival rule.
Option B (structural): make struct irqaction RCU-freed for NMI
flows (rcu_dereference at the snapshot, kfree_rcu at cleanup) --
consistent with the sparse-irq RCU direction and it also fixes the
percpu variant (my separate observation). Either way, free_nmi()
deserves a kernel-doc stating the quiescence contract (none exists
today).
Please keep me in Cc; I am not subscribed to the lists.
Regards,
Hanxiang Xu
xuhx@hust.edu.cn
[-- Attachment #2: nmi_stall.c --]
[-- Type: text/plain, Size: 2814 bytes --]
// SPDX-License-Identifier: GPL-2.0
/*
* nmi_stall.c - generic kprobe controlled-window staller for the
* kernel/irq NMI verification (2026-11-09), following the r4_stall
* methodology (controlled window; does not measure natural hit rates).
*
* Params:
* symbol= function to probe (required)
* off= kprobe offset inside symbol (instruction offset, hex ok)
* stall_us= max busy-wait duration once armed+hit (default 40s)
* arm= sysfs gate (0600): stall only while armed
* release= sysfs gate (0600): end the stall
*
* The pre_handler stalls the FIRST armed hit until release=1 (or timeout).
* Later hits are counted only.
*/
#define pr_fmt(fmt) "NMI1STALL: " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/delay.h>
#include <linux/atomic.h>
static char *symbol = "";
module_param(symbol, charp, 0400);
MODULE_PARM_DESC(symbol, "kprobe target symbol");
static unsigned long off;
module_param(off, ulong, 0400);
MODULE_PARM_DESC(off, "kprobe offset inside symbol");
static int stall_us = 40000000;
module_param(stall_us, int, 0600);
MODULE_PARM_DESC(stall_us, "max stall duration in us");
static int arm;
module_param(arm, int, 0600);
MODULE_PARM_DESC(arm, "1 = stall next hit");
static int release;
module_param(release, int, 0600);
MODULE_PARM_DESC(release, "1 = end the stall");
static atomic_t hits = ATOMIC_INIT(0);
static bool consumed;
static int stall_pre(struct kprobe *p, struct pt_regs *regs)
{
int h = atomic_inc_return(&hits);
if (!READ_ONCE(arm) || consumed) {
if (h <= 5)
pr_warn("hit #%d (not stalled, arm=%d)\n", h, READ_ONCE(arm));
return 0;
}
WRITE_ONCE(consumed, true);
pr_warn("STALL HIT at %s+0x%lx stall_us=%d\n", p->symbol_name, off,
stall_us);
/* hard deadline so a dead orchestrator cannot hang the VM forever */
for (int waited = 0; waited < stall_us && !READ_ONCE(release);
waited += 1000)
udelay(1000);
pr_warn("RELEASED (release=%d waited_hits=%d)\n", READ_ONCE(release),
atomic_read(&hits));
return 0;
}
static struct kprobe kp;
static int __init nmi_stall_init(void)
{
if (!symbol[0]) {
pr_err("no symbol given\n");
return -EINVAL;
}
kp.symbol_name = symbol;
kp.offset = off;
kp.pre_handler = stall_pre;
if (register_kprobe(&kp)) {
pr_err("cannot register kprobe on %s+0x%lx\n", symbol, off);
return -EINVAL;
}
pr_warn("armed-able: %s+0x%lx stall_us=%d (waiting for arm=1)\n",
symbol, off, stall_us);
return 0;
}
static void __exit nmi_stall_exit(void)
{
unregister_kprobe(&kp);
pr_warn("removed hits=%d stalled=%d\n", atomic_read(&hits), consumed);
}
module_init(nmi_stall_init);
module_exit(nmi_stall_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("generic kprobe stall for kernel/irq NMI verification");
[-- Attachment #3: nmi_race.c --]
[-- Type: text/plain, Size: 10724 bytes --]
// SPDX-License-Identifier: GPL-2.0
/*
* nmi_race.c - driver module for the kernel/irq NMI race verification
* (2026-11-09). It exercises the REAL genirq NMI core paths
* (request_nmi/free_nmi/enable_irq + handle_fasteoi_nmi) on a fake
* NMI-capable irq_chip, mirroring what GICv3 pseudo-NMI does on arm64.
*
* request_nmi()/free_nmi() are not exported, so they are resolved with the
* kprobe-addr trick (same technique as r4_stall's symbol lookup).
*
* modes:
* 1 Case-1 controlled window: dispatch thread enters handle_fasteoi_nmi
* and is stalled by nmi_stall.ko (kprobe at +0x56 in build-kasan-7.3,
* after the desc->action snapshot, before the action->handler /
* action->dev_id loads); free thread frees the action meanwhile; the
* released dispatcher then reads freed memory -> KASAN.
* 3 natural hammer: writer request/sleep/free/sleep cycles + dense
* dispatcher (READ_ONCE(installed) pre-check to dodge the NULL window;
* residual NULL / freed reads are captured by KASAN/KCSAN).
* churn=1 variant: writer only cycles enable/disable (negative control,
* desc->action untouched).
* 5 W5 double-free: two threads call free_nmi() concurrently on an
* installed line; the loser passes the irq_is_nmi() gate before the
* winner clears IRQS_NMI, then serializes behind desc->lock and runs
* a SECOND cleanup (WARN_ON(desc->action==NULL) + unconditional
* release tail) -> teardown/release_resources counted twice, module
* refcount goes negative in /proc/modules.
*/
#define pr_fmt(fmt) "NMI1RACE: " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/atomic.h>
#include <linux/sched/task.h>
typedef int (*request_nmi_t)(unsigned int, irq_handler_t, unsigned long,
const char *, void *);
typedef const void *(*free_nmi_t)(unsigned int, void *);
static int mode = 1;
module_param(mode, int, 0400);
MODULE_PARM_DESC(mode, "1=case1 controlled, 3=hammer, 5=W5 double-free");
static int secs = 60;
module_param(secs, int, 0400);
MODULE_PARM_DESC(secs, "hammer duration (mode 3)");
static int hold_ms = 1500;
module_param(hold_ms, int, 0400);
MODULE_PARM_DESC(hold_ms, "installed hold time per cycle (mode 3)");
static int gap_ms = 100;
module_param(gap_ms, int, 0400);
MODULE_PARM_DESC(gap_ms, "freed gap time per cycle (mode 3)");
static int churn;
module_param(churn, int, 0400);
MODULE_PARM_DESC(churn, "mode3 control: writer cycles enable/disable only");
static unsigned int cpu_disp = 2, cpu_free = 3;
module_param(cpu_disp, uint, 0400);
module_param(cpu_free, uint, 0400);
static request_nmi_t request_nmi_fn;
static free_nmi_t free_nmi_fn;
static unsigned int virq;
static void *cookie;
static atomic_t installed = ATOMIC_INIT(0);
static atomic_t go = ATOMIC_INIT(0);
static atomic_t teardown_cnt = ATOMIC_INIT(0);
static atomic_t relres_cnt = ATOMIC_INIT(0);
static atomic_t dispatches = ATOMIC_INIT(0);
static atomic_t disp_null = ATOMIC_INIT(0);
static struct task_struct *t_disp, *t_free;
/* ---- fake NMI-capable chip (core sees the same callbacks as GICv3) ---- */
static int fake_nmi_setup(struct irq_data *d)
{
pr_warn("chip: irq_nmi_setup irq=%u\n", d->irq);
return 0;
}
static void fake_nmi_teardown(struct irq_data *d)
{
pr_warn("chip: irq_nmi_teardown #%d irq=%u\n",
atomic_inc_return(&teardown_cnt), d->irq);
}
static void fake_relres(struct irq_data *d)
{
pr_warn("chip: irq_release_resources #%d irq=%u\n",
atomic_inc_return(&relres_cnt), d->irq);
}
static void fake_mask(struct irq_data *d) {}
static void fake_unmask(struct irq_data *d) {}
static void fake_eoi(struct irq_data *d) {}
static struct irq_chip fake_chip = {
.name = "nmi-fake",
.flags = IRQCHIP_SUPPORTS_NMI,
.irq_mask = fake_mask,
.irq_unmask = fake_unmask,
.irq_eoi = fake_eoi,
.irq_nmi_setup = fake_nmi_setup,
.irq_nmi_teardown = fake_nmi_teardown,
.irq_release_resources = fake_relres,
};
static atomic_t handler_calls = ATOMIC_INIT(0);
static irqreturn_t fake_nmi_handler(int irq, void *dev_id)
{
/* print sparsely: printk-path accesses would dilute KCSAN sampling */
if (atomic_inc_return(&handler_calls) % 512 == 1)
pr_warn("HANDLER CALLED #%d irq=%d dev_id=%px\n",
atomic_read(&handler_calls), irq, dev_id);
return IRQ_HANDLED;
}
static void park(void)
{
while (!kthread_should_stop())
msleep(100);
}
static unsigned long sym_addr(const char *name)
{
struct kprobe p = { .symbol_name = name };
unsigned long addr = 0;
if (!register_kprobe(&p)) {
addr = (unsigned long)p.addr;
unregister_kprobe(&p);
}
return addr;
}
static int do_request(void)
{
int ret;
ret = request_nmi_fn(virq, fake_nmi_handler,
IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_AUTOEN |
IRQF_NO_THREAD,
"nmi-race", &cookie);
if (!ret) {
atomic_inc(&installed);
enable_irq(virq); /* == enable_nmi */
/*
* The GIC driver installs handle_fasteoi_nmi from its
* irq_nmi_setup callback (desc->lock held); the core does not
* do it. struct irq_desc is opaque to modules, so we install
* the audited flow handler via the exported API instead.
*/
__irq_set_handler(virq, handle_fasteoi_nmi, 0, NULL);
}
pr_warn("request_nmi -> %d (installed=%d)\n", ret,
atomic_read(&installed));
return ret;
}
static void do_free(void)
{
const void *devname;
atomic_dec(&installed);
devname = free_nmi_fn(virq, &cookie);
pr_warn("free_nmi -> %p (installed=%d)\n", devname,
atomic_read(&installed));
}
/* mode 1: dispatcher stalls inside handle_fasteoi_nmi via nmi_stall.ko */
static int disp_thread_m1(void *arg)
{
while (!atomic_read(&go))
cpu_relax();
pr_warn("DISPATCH_BEGIN (cpu=%u)\n", smp_processor_id());
generic_handle_irq(virq);
pr_warn("DISPATCH_DONE\n");
park();
return 0;
}
static int free_thread_m1(void *arg)
{
msleep(2000);
pr_warn("release go -> dispatch enters handle_fasteoi_nmi\n");
atomic_inc(&go);
msleep(3000); /* dispatcher is stalled inside handle_fasteoi_nmi now */
do_free();
pr_warn("FREE side finished (dispatcher still stalled on freed action)\n");
park();
return 0;
}
/* mode 3: natural hammer */
static int writer_thread(void *arg)
{
unsigned long deadline = jiffies + secs * HZ;
int cycles = 0;
while (time_before(jiffies, deadline)) {
if (churn) {
/* control: no management writes at all */
msleep_interruptible(hold_ms);
} else {
if (do_request())
break;
msleep_interruptible(hold_ms);
do_free();
msleep_interruptible(gap_ms);
}
cycles++;
}
if (churn)
cycles = 0;
pr_warn("writer done: cycles=%d churn=%d teardown=%d relres=%d\n",
cycles, churn, atomic_read(&teardown_cnt),
atomic_read(&relres_cnt));
park();
return 0;
}
static int disp_thread_m3(void *arg)
{
unsigned long deadline = jiffies + secs * HZ;
while (time_before(jiffies, deadline)) {
if (atomic_read(&installed)) {
generic_handle_irq(virq);
atomic_inc(&dispatches);
} else {
atomic_inc(&disp_null);
cpu_relax();
}
}
pr_warn("dispatcher done: dispatches=%d null-skips=%d\n",
atomic_read(&dispatches), atomic_read(&disp_null));
park();
return 0;
}
/* mode 5: concurrent double free_nmi (W5) */
static int w5_thread(void *arg)
{
int id = (int)(long)arg;
const void *ret;
int i;
/* rendezvous so BOTH threads pass free_nmi's irq_is_nmi() gate before
* either one clears IRQS_NMI inside the cleanup lock region */
atomic_inc(&go);
while (atomic_read(&go) < 2)
cpu_relax();
ret = free_nmi_fn(virq, &cookie);
pr_warn("W5 thread %d free -> %p teardown=%d relres=%d\n", id, ret,
atomic_read(&teardown_cnt), atomic_read(&relres_cnt));
/* fallback retries in case this thread lost the istate race */
for (i = 0; i < 30 && atomic_read(&teardown_cnt) < 2; i++)
udelay(500);
pr_warn("W5 thread %d done: teardown=%d relres=%d (expect 2/2)\n", id,
atomic_read(&teardown_cnt), atomic_read(&relres_cnt));
park();
return 0;
}
static int __init nmi_race_init(void)
{
unsigned long a_req = sym_addr("request_nmi");
unsigned long a_free = sym_addr("free_nmi");
int ret = -EINVAL;
request_nmi_fn = (request_nmi_t)a_req;
free_nmi_fn = (free_nmi_t)a_free;
if (!request_nmi_fn || !free_nmi_fn) {
pr_err("cannot resolve request_nmi=%lx free_nmi=%lx\n", a_req,
a_free);
return -EINVAL;
}
pr_warn("resolved request_nmi=%px free_nmi=%px mode=%d\n",
request_nmi_fn, free_nmi_fn, mode);
virq = __irq_alloc_descs(-1, 0, 1, NUMA_NO_NODE, THIS_MODULE, NULL);
if (virq < 0) {
pr_err("irq_alloc_descs failed %d\n", virq);
return virq;
}
pr_warn("allocated virq=%u (desc owner=this module)\n", virq);
irq_set_chip(virq, &fake_chip);
switch (mode) {
case 1:
ret = do_request();
if (ret)
return ret;
t_free = kthread_create_on_cpu(free_thread_m1, NULL, cpu_free,
"nmi1_free");
t_disp = kthread_create_on_cpu(disp_thread_m1, NULL, cpu_disp,
"nmi1_disp");
if (IS_ERR(t_free) || IS_ERR(t_disp))
return -EINVAL;
wake_up_process(t_free);
wake_up_process(t_disp);
break;
case 3:
/* experiment: the writer installs in its first cycle.
* churn control: install once here so the dispatch density
* matches the experiment, and the writer only sleeps. */
if (churn && do_request())
return ret;
t_free = kthread_create_on_cpu(writer_thread, NULL, cpu_free,
"nmi1_writer");
t_disp = kthread_create_on_cpu(disp_thread_m3, NULL, cpu_disp,
"nmi1_disp");
if (IS_ERR(t_free) || IS_ERR(t_disp))
return -EINVAL;
wake_up_process(t_free);
wake_up_process(t_disp);
break;
case 5:
ret = do_request();
if (ret)
return ret;
t_free = kthread_create_on_cpu(w5_thread, (void *)1L, cpu_free,
"nmi_w5a");
t_disp = kthread_create_on_cpu(w5_thread, (void *)2L, cpu_disp,
"nmi_w5b");
if (IS_ERR(t_free) || IS_ERR(t_disp))
return -EINVAL;
wake_up_process(t_free);
wake_up_process(t_disp);
break;
default:
pr_err("bad mode %d\n", mode);
return -EINVAL;
}
return 0;
}
static void __exit nmi_race_exit(void)
{
if (t_free && !IS_ERR(t_free))
kthread_stop(t_free);
if (t_disp && !IS_ERR(t_disp))
kthread_stop(t_disp);
/* best-effort cleanup of a still-installed action (mode 3 churn off) */
if (atomic_read(&installed) && mode == 3 && !churn)
do_free();
pr_warn("removed mode=%d teardown=%d relres=%d\n", mode,
atomic_read(&teardown_cnt), atomic_read(&relres_cnt));
}
module_init(nmi_race_init);
module_exit(nmi_race_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("kernel/irq NMI race verification driver");
next prev parent reply other threads:[~2026-11-11 7:17 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 12:35 usb: devio: usbdev_release() has no barrier against an in-flight async_completed() callback (use-after-free window on struct usb_dev_state)gregkh@linuxfoundation.org 徐晗翔
2026-10-27 14:12 ` Greg KH
2026-11-03 11:21 ` mm/slub: has_pcs_used() reads remote per-CPU sheaf state from flush_all_cpus_locked() without synchronization (data race; KCSAN blind spot: slub.o is uninstrumented) 徐晗翔
2026-11-04 9:41 ` Qing Wang
2026-11-04 10:07 ` Qing Wang
2026-11-03 11:30 ` futex/hrtimer: hrtimer_sleeper::task is read unsynchronized in 16 places on v7.3 -- the accessor series that fixes this is not in 7.3; please make sure it reaches the affected trees (backport nudge + stock-kernel KCSAN evidence) 徐晗翔
2026-11-03 11:48 ` cgroup: fork vs cgroup.procs write race in favordynmods mode -- v7.3 is affected; please make sure bf6fbf46b5ff reaches the stable trees (repro incl. uninstrumented natural hit) 徐晗翔
2026-11-03 14:51 ` Sasha Levin
2026-11-03 11:57 ` net: rtnetlink: rtnl_link_unregister() vs in-flight RTM_GETLINK dump readers -- v7.3 lacks the synchronize_rcu() fix (Fixes: 6b57ff21a310 family); A/B reproduction on stock 7.3 徐晗翔
2026-11-03 15:49 ` Eric Dumazet
2026-11-04 15:03 ` Sasha Levin
2026-11-03 12:07 ` wifi: wilc1000: SDIO/SPI remove destroys the srcu_struct before wiphy_unregister() -- late cfg80211 callbacks write through dangling srcu state (unfixed upstream; controlled + natural Oops) 徐晗翔
2026-11-03 12:10 ` gpio: gpiolib: final put of the gpio_device happens inside the SRCU read critical section on the setup-failure path -- deterministic use-after-free read at guard release (unfixed upstream) 徐晗翔
2026-11-05 8:52 ` Linus Walleij
2026-11-04 12:54 ` soc: qcom: pmic_glink_altmode: fix use-after-free on unbind (no cancel_work_sync for port work and enable_work) 徐晗翔
2026-11-04 13:04 ` Greg KH
2026-11-04 12:57 ` usb: typec: anx7411: unregister partner/altmodes before stopping the IRQ work -- use-after-free, double unregister, orphan partner on remove 徐晗翔
2026-11-04 13:28 ` Greg KH
2026-11-04 12:58 ` usb: typec: ucsi: deadlock on cros_ec unbind -- connector lock held across cancel_delayed_work_sync vs the mode-selection work's unbounded trylock polling 徐晗翔
2026-11-04 13:00 ` usb: typec: stusb160x/rt1719/hd3ss3220: IRQ thread vs remove -- double unregister / use-after-free on the partner and port 徐晗翔
2026-11-04 13:01 ` usb: typec: ucsi: displayport: data race on dp->header/ vdo_data/vdo_size -- work reads them unlocked while writers hold con->lock (VDM mismatch) 徐晗翔
2026-11-04 13:02 ` usb: typec: class: three lifetime/locking gaps around the mux/switch handles and mode_selection (drvdata UAF after provider unbind; no concurrent protocol for set/put; unlocked state_update vs delete) 徐晗翔
2026-11-10 12:56 ` driver core: uevent: netns teardown frees uevent_sock while a tagged uevent is still being broadcast (UAF) 徐晗翔
2026-11-10 13:00 ` 徐晗翔
2026-11-10 18:48 ` Greg KH
2026-11-10 13:05 ` ACPI: CPPC: per-CPU cpc_desc is freed on processor unbind without clearing the published pointer, causing UAF in cpufreq accessors 徐晗翔
2026-11-10 13:07 ` ACPI: CPPC: shared PCC subspace data can be freed while another CPU probes, reads, or tears it down 徐晗翔
2026-11-10 14:47 ` Christian Loehle
2026-11-10 13:11 ` ACPI: ACPICA: Reset can delete an event semaphore while another thread is blocked in Wait 徐晗翔
2026-11-10 13:14 ` power: supply: bq25890: pump-express work can call power_supply_changed after the psy is unregistered 徐晗翔
2026-11-10 13:17 ` power: supply: core: get/set property callbacks can run after unregister and read freed driver data 徐晗翔
2026-11-10 13:18 ` power: supply: core: system-battery enumeration can return an unregistered battery 徐晗翔
2026-11-10 13:21 ` power: supply: core: changed work can run after unregister and use freed LED triggers 徐晗翔
2026-11-10 13:23 ` power: supply: bq24190: IRQ handler can call power_supply_changed after the psy is unregistered 徐晗翔
2026-11-10 13:34 ` 徐晗翔
2026-11-11 7:17 ` 徐晗翔 [this message]
2026-11-11 7:26 ` genirq: NMI API lacks the request_mutex / dev_id matching / idempotency semantics that free_irq() has -- double free_nmi releases chip PM and module references twice (verified) 徐晗翔
2026-11-11 7:30 ` kernfs: kernfs_drain()'s fast-path decision reads the active count without acquire ordering -- on weakly-ordered architectures the forced ->release()/unmap can be skipped 徐晗翔
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=57077c85.24251.1a1c9782b17.Coremail.xuhx@hust.edu.cn \
--to=xuhx@hust.edu.cn \
--cc=linux-kernel@vger.kernel.org \
--cc=tglx@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®