mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: 徐晗翔 <xuhx@hust.edu.cn>
To: tj@kernel.org
Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: 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
Date: Wed, 11 Nov 2026 15:30:11 +0800 (GMT+08:00)	[thread overview]
Message-ID: <61919bed.2429b.1a1c983aa11.Coremail.xuhx@hust.edu.cn> (raw)
In-Reply-To: <2026102727-data-sequel-ce41@gregkh>

[-- Attachment #1: Type: text/plain, Size: 6825 bytes --]

kernfs_drain() (fs/kernfs/dir.c:508-551) decides whether it must
drain open files with the fast-path test "atomic_read(&kn->active)
== KN_DEACTIVATED_BIAS && !kernfs_should_drain_open_files(kn)" --
both a plain atomic_read (relaxed) and an unlocked read of
kn->attr.open / on->nr_mmapped / on->nr_to_release.  The writer side
(the last active holder) releases correctly -- its writes to
attr.open/counter happen under the hash lock, followed by the fully
ordered atomic_dec_return() that wakes the drain waiter
(dir.c:491-495) -- but on the READER side there is no acquire edge
on any fast path: the early-return branch (:522-524), the
wait_event's non-sleeping first check (:537-538), and the slow-loop
checks where the waker has not yet touched the queue lock.  The
phase-1 BIAS add is itself a relaxed atomic_add (:1563), and the
kernfs_rwsem write lock the remover holds has no intersection with
the putter.  On a weakly-ordered architecture (arm64, powerpc,
riscv; x86-TSO is immune because plain load-load does not reorder),
the remover can therefore observe "active drained" WITHOUT observing
the racing opener's attr.open/nr_to_release/nr_mmapped updates, skip
kernfs_drain_open_files() entirely, and leave the mandatory
->release() and unmap_mapping_range() to be deferred to the last fd
close.  Consequences under current semantics: no memory corruption
(of->kn/inode stay pinned through the dentry chain; the close path
performs the release and decrements then, and the accounting WARN
never fires) -- the observable effects are a delayed
cgroup_file_release()/put_cgroup_ns() (a cgroup-namespace reference
pinned for the lifetime of a leaked-open fd) and a skipped
unmap_mapping_range() (mmap'ed vmas survive until their next fault
takes the kernfs fault path and SIGBUSes, safely).  I verified the
RACE itself dynamically on a stock Linux 7.3 KCSAN kernel: a
cgroup2-slot hammer (attached) produced 17 captures of exactly the
target race pair -- kernfs_fop_release (the nr_to_release--
writer, inlined in the close path) vs kernfs_should_drain_open_files
(read), with the reader stack at kernfs_drain+0xba, which I mapped
back to dir.c:522-524 (the early-return decision) via objdump (the
cmp $0x80000001 / KN_DEACTIVATED_BIAS immediate).  The consequence
itself needs a weakly-ordered machine plus a microsecond window, so
I did not and could not trigger it on x86 -- the report is therefore
a memory-ordering fix with (a) the race pair proven to occur as a
matter of course on x86, (b) an LKMM litmus showing the outcome is
Allowed on linux-kernel.cat and Never on x86-TSO (available; please
run it), and (c) a one-line fix that closes all three fast paths.

The detailed description:

* The ordering gap (Linux 7.3)

  Writer (last active holder of a HAS_RELEASE file):
      mutex(attr.open = on); on->nr_to_release = 1   <- plain writes,
                                                        hash-locked
      ... ops->open() ...
      kernfs_put_active(): atomic_dec_return(active)  <- fully ordered
                                                        RMW (release
                                                        for the writer)
                                                        + wake_up_all
                                                        (dir.c:491-495)

  Reader (the remover, holding kernfs_rwsem write since phase 1 --
  itself a relaxed atomic_add(BIAS) at dir.c:1563):
      kernfs_drain():
        if (atomic_read(&kn->active) == KN_DEACTIVATED_BIAS &&   /* :522,
                                                    relaxed */
            !kernfs_should_drain_open_files(kn))     /* :784-802 plain
                                                        loads */
                return;                              /* :522-524 early
                                                        out */
        wait_event(root->deactivate_waitq,
                   atomic_read(&kn->active) == BIAS) /* :537-538 first
                                                        check also
                                                        relaxed */

  No lock edge (the fast paths never take the queue lock), no data
  or address dependency between active and attr.open/on->, and
  control dependencies do not order subsequent loads
  (Documentation/memory-barriers.txt).  Only the fully-sleeping path
  is ordered today (putter's RMW -> wake_up_all's queue lock ->
  waiter's recheck under that lock).

* Evidence (stock 7.3 KCSAN kernel; hammer attached)

  kfshammer.c drives synchronized cgroup2 slot rmdir/open/close
  traffic (the cgroup release path is the HAS_RELEASE consumer).
  300 s: 10,287 rmdirs x 185,310 open/close -> the exact target race
  pair captured 17 times:

    BUG: KCSAN: data-race in kernfs_fop_release /
         kernfs_should_drain_open_files
    reader stack at kernfs_drain+0xba   <- mapped to dir.c:522-524
      (objdump: cmp $0x80000001 == KN_DEACTIVATED_BIAS; also +0x1ab =
       dir.c:545)
    writer stack: the close path's inlined nr_to_release--
    plus 7 same-root reports (__kernfs_remove /
    kernfs_unlink_open_file family)

  Attribution controls: a sequential-cleanup control (kfs1ctl2) also
  captures the pair (plain rmdir chains reach it); a TRUE
  zero-rmdir control (kfs1ctl4, 692,469 open+close, zero rmdirs)
  shows should_drain never executing and zero target-family
  reports -- the pair is specific to rmdir-vs-close concurrency.
  The stale-READ consequence (skipped drain) is architecturally
  impossible on this x86 guest; the race itself is not.

* The fix (one line, both decision sites)

  --- a/fs/kernfs/dir.c
  +++ b/fs/kernfs/dir.c

  @@ -519
  -	if (atomic_read(&kn->active) == KN_DEACTIVATED_BIAS &&
  -	    !kernfs_should_drain_open_files(kn))
  +	/* acquire pairs with the fully-ordered dec_return in
  +	 * kernfs_put_active() so that the skip decision observes the
  +	 * racing opener's attr.open/counter updates */
  +	if (atomic_read_acquire(&kn->active) == KN_DEACTIVATED_BIAS &&
  +	    !kernfs_should_drain_open_files(kn))
   		return;
  @@ -537
  -	wait_event(root->deactivate_waitq,
  -		   atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);
  +	wait_event(root->deactivate_waitq,
  +		   atomic_read_acquire(&kn->active) == KN_DEACTIVATED_BIAS);

  atomic_read_acquire() is available in this tree (include/linux/
  atomic/atomic-instrumented.h:47) and covers all three fast paths;
  the sleeping path was already ordered and is unaffected.
  smp_load_acquire() is an equivalent alternative.

  A herd7 litmus test for the pair (Expected: Allowed on
  linux-kernel.cat, Never on x86-TSO) is available and will be
  provided with the patch -- please run it, as no herd7 exists on my
  side.



  Please keep me in Cc; I am not subscribed to the lists.


Regards,
Hanxiang Xu
xuhx@hust.edu.cn

[-- Attachment #2: kfshammer.c --]
[-- Type: text/plain, Size: 9682 bytes --]

// SPDX-License-Identifier: GPL-2.0
/* kfshammer.c - user-space hammer for fs__kernfs audit verification (v3).
 *
 * Target: kernfs open-file accounting vs drain decision (fs/kernfs/file.c,
 * fs/kernfs/dir.c), exercised on cgroup2 attribute files.
 *
 * Synchronized slot design (structurally forces the races instead of
 * relying on timing luck):
 *
 *   slot states: 0 empty -> 1 prepared (subtree t_i/{x,y} created, 12 fds
 *   open) -> 2 removing (rmdir(2) in-kernel, recursive kernfs_remove over
 *   ~33 nodes) -> 0.
 *
 *   On seeing state 2, the prep thread closes its fds one by one with
 *   microsecond gaps, so kernfs_unlink_open_file (plain stores under the
 *   hashed per-node mutex) executes inside / right after the removal,
 *   concurrent with kernfs_drain's kernfs_should_drain_open_files loads
 *   (plain loads, no acquire: audit Case 5).  fd[0] closes last, often
 *   after the forced release, exercising kernfs_release_file exactly-once
 *   and the close-after-release WARN tripwire (file.c:586).
 *
 * Plans:
 *   kfs1 (KCSAN): expect data-race reports naming
 *        kernfs_should_drain_open_files / kernfs_unlink_open_file /
 *        kernfs_get_open_node / kernfs_drain_open_files
 *   kfs1ctl: ctrl=1, rmdir disabled -> drain never runs -> accounting is
 *            mutex-protected -> expect zero drain/accounting reports
 *   kfs2 (KASAN): heavier negative control; in-kernel tripwires
 *        (file.c:586, file.c:830, dir.c:602) must stay silent and KASAN
 *        must see no use-after-free (any hit refutes the Case 2/3 loop)
 *
 * usage: kfshammer <cg2-mount> <slots> <rmdir-threads> <seconds> [ctrl]
 */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <time.h>
#include <sys/stat.h>

#define MAXSLOTS 32
#define NF_TOP	 10
#define NF_CHILD 4

static char mount_[256];
static int slots = 8, rmdirs = 3, secs = 120, ctrl = 0;
static volatile int running = 1;

/* per-slot state: 0 empty, 1 prepared (fds open), 2 removing */
static volatile int slot_state[MAXSLOTS];
static int slot_fd[MAXSLOTS][NF_TOP + 2 * NF_CHILD];
static int slot_nopen[MAXSLOTS];

static const char *files_top[NF_TOP] = {
	"cgroup.procs", "cgroup.type", "cgroup.stat", "cgroup.events",
	"cgroup.controllers", "cgroup.subtree_control", "cgroup.threads",
	"cgroup.max.descendants", "cgroup.max.depth", "cgroup.freeze",
};
static const char *files_child[NF_CHILD] = {
	"cgroup.procs", "cgroup.type", "cgroup.stat", "cgroup.events",
};

enum { E_MKDIR_OK, E_MKDIR_FAIL, E_OPEN_OK, E_OPEN_FAIL, E_CLOSE,
       E_RMDIR_OK, E_RMDIR_FAIL, E_MAX };
static long st[E_MAX];
static int last_rmdir_errno, last_open_errno;
#define ATOMIC_INC(x) __atomic_add_fetch(&(x), 1, __ATOMIC_RELAXED)

/* nanosleep with us ranges from 50us to 500ms - all < 1s, tv_nsec safe */
static int usleep_(long us)
{
	struct timespec ts = { .tv_sec = 0, .tv_nsec = us * 1000L };
	if (ts.tv_nsec >= 1000000000L) {	/* paranoia */
		ts.tv_sec += ts.tv_nsec / 1000000000L;
		ts.tv_nsec %= 1000000000L;
	}
	return nanosleep(&ts, NULL);
}

static void mkpath(char *buf, size_t len, int slot, const char *sub,
		   const char *f)
{
	snprintf(buf, len, "%s/t%d%s%s%s%s", mount_, slot, sub ? "/" : "",
		 sub ?: "", f ? "/" : "", f ?: "");
}

/* prep thread: owns one slot */
static void *th_prep(void *arg)
{
	long id = (long)(intptr_t)arg;
	char path[512];
	unsigned seed = id * 7919u + 7;
	int n = 0;

	while (running) {
		mkpath(path, sizeof(path), (int)id, NULL, NULL);
		if (mkdir(path, 0755) == 0) {
			ATOMIC_INC(st[E_MKDIR_OK]);
		} else if (!ctrl) {
			ATOMIC_INC(st[E_MKDIR_FAIL]);
			/* stale dir from a failed cycle: best-effort cleanup
			 * (bottom-up), then retry */
			mkpath(path, sizeof(path), (int)id, "x", NULL);
			rmdir(path);
			mkpath(path, sizeof(path), (int)id, "y", NULL);
			rmdir(path);
			mkpath(path, sizeof(path), (int)id, NULL, NULL);
			rmdir(path);
			usleep_(2000);
			continue;
		} else {
			/* ctrl: dir persists - churn on it, zero rmdir calls */
			ATOMIC_INC(st[E_MKDIR_FAIL]);
		}
		mkpath(path, sizeof(path), (int)id, "x", NULL);
		mkdir(path, 0755);
		mkpath(path, sizeof(path), (int)id, "y", NULL);
		mkdir(path, 0755);

		/* fd[0] = top cgroup.procs; closes LAST (after forced release) */
		n = 0;
		mkpath(path, sizeof(path), (int)id, NULL, files_top[0]);
		int fd = open(path, O_RDONLY);
		if (fd >= 0) { slot_fd[id][n++] = fd; ATOMIC_INC(st[E_OPEN_OK]); }
		else { last_open_errno = errno; ATOMIC_INC(st[E_OPEN_FAIL]); }

		for (int i = 1; i < NF_TOP; i++) {
			mkpath(path, sizeof(path), (int)id, NULL, files_top[i]);
			fd = open(path, O_RDONLY);
			if (fd < 0) { last_open_errno = errno; ATOMIC_INC(st[E_OPEN_FAIL]); continue; }
			ATOMIC_INC(st[E_OPEN_OK]);
			slot_fd[id][n++] = fd;
		}
		for (int c = 0; c < 2; c++) {
			const char *sub = c ? "y" : "x";
			for (int i = 0; i < NF_CHILD; i++) {
				mkpath(path, sizeof(path), (int)id, sub, files_child[i]);
				fd = open(path, O_RDONLY);
				if (fd < 0) { last_open_errno = errno; ATOMIC_INC(st[E_OPEN_FAIL]); continue; }
				ATOMIC_INC(st[E_OPEN_OK]);
				slot_fd[id][n++] = fd;
			}
		}
		slot_nopen[id] = n;
		if (ctrl) {
			/* control mode (churn-only): open/read/poll/close on
			 * persistent dirs, NO removal ever -> kernfs_drain /
			 * kernfs_should_drain_open_files never execute, so
			 * the target race site is unreachable by construction;
			 * accounting stays under the hashed mutex */
			for (int i = 0; i < n; i++) {
				close(slot_fd[id][i]);
				ATOMIC_INC(st[E_CLOSE]);
			}
			slot_nopen[id] = 0;
			usleep_(500);
			continue;
		}
		if (n >= 2) {
			slot_state[id] = 1;

			/* short poll on fd0: exercises kernfs_generic_poll;
			 * (kernfs releases the active ref before poll sleeps,
			 * so this does NOT lengthen the drain window) */
			if ((rand_r(&seed) & 3) == 0) {
				struct pollfd pf = { .fd = slot_fd[id][0],
						     .events = POLLPRI };
				poll(&pf, 1, 0);
			}

			/* wait for the remover to mark state 2 */
			int spins = 0;
			while (running && slot_state[id] == 1 && spins < 3000) {
				usleep_(100);
				spins++;
			}

			/* close fds INSIDE the rmdir(2) kernel window, with
			 * gaps so stores land across the whole removal */
			for (int i = 1; i < slot_nopen[id]; i++) {
				close(slot_fd[id][i]);
				ATOMIC_INC(st[E_CLOSE]);
				usleep_(100 + (long)(rand_r(&seed) % 300));
			}
			/* fd[0] closes last: often after the forced release */
			close(slot_fd[id][0]);
			ATOMIC_INC(st[E_CLOSE]);
		} else {
			for (int i = 0; i < n; i++)
				close(slot_fd[id][i]);
		}
		slot_nopen[id] = 0;
		slot_state[id] = 0;
		usleep_(500);
	}
	return NULL;
}

/* remover thread: drive slots through state 2; bottom-up (children first,
 * each child rmdir runs its own drain window, then the top removal runs
 * with the top-level fds still open) */
static void *th_rmdir(void *arg)
{
	long id = (long)(intptr_t)arg;
	char path[512];
	unsigned seed = id * 104729u + 1;
	int i = (int)id;

	while (running) {
		if (slot_state[i] == 1) {
			slot_state[i] = 2;
			int ok = 1;
			mkpath(path, sizeof(path), i, "x", NULL);
			if (rmdir(path) != 0)
				ok = 0;
			mkpath(path, sizeof(path), i, "y", NULL);
			if (rmdir(path) != 0)
				ok = 0;
			mkpath(path, sizeof(path), i, NULL, NULL);
			if (rmdir(path) != 0)
				ok = 0;
			if (ok)
				ATOMIC_INC(st[E_RMDIR_OK]);
			else {
				last_rmdir_errno = errno;
				ATOMIC_INC(st[E_RMDIR_FAIL]);
			}
		}
		i = (i + 1) % slots;
		usleep_(rand_r(&seed) % 400);
	}
	return NULL;
}

static void *th_report(void *arg)
{
	(void)arg;
	/* exactly 3 progress lines per run to avoid serial flooding */
	long wait[] = { 30, 90, 0 };
	for (int k = 0; k < 3 && running; k++) {
		struct timespec ts = { .tv_sec = wait[k] ? wait[k] : secs,
				       .tv_nsec = 0 };
		if (nanosleep(&ts, NULL) && !running)
			break;
		fprintf(stderr,
			"KFSHAMMER-PROGRESS[%d]: mkdir_ok=%ld open_ok=%ld "
			"close=%ld rmdir_ok=%ld rmdir_fail=%ld "
			"last_rmdir_errno=%d last_open_errno=%d\n",
			k + 1, st[E_MKDIR_OK], st[E_OPEN_OK], st[E_CLOSE],
			st[E_RMDIR_OK], st[E_RMDIR_FAIL],
			last_rmdir_errno, last_open_errno);
	}
	return NULL;
}

int main(int argc, char **argv)
{
	if (argc < 5) {
		fprintf(stderr,
			"usage: %s <mount> <slots> <rmdir-threads> <secs> [ctrl]\n",
			argv[0]);
		return 1;
	}
	snprintf(mount_, sizeof(mount_), "%s", argv[1]);
	slots = atoi(argv[2]);
	rmdirs = atoi(argv[3]);
	secs = atoi(argv[4]);
	if (argc > 5)
		ctrl = atoi(argv[5]);
	if (slots > MAXSLOTS)
		slots = MAXSLOTS;

	int nthreads = slots + (ctrl ? 0 : rmdirs) + 1;
	pthread_t *t = calloc(nthreads, sizeof(*t));
	for (long i = 0; i < slots; i++)
		pthread_create(&t[i], NULL, th_prep, (void *)i);
	for (long i = 0; i < (long)(ctrl ? 0u : (unsigned)rmdirs); i++)
		pthread_create(&t[slots + i], NULL, th_rmdir, (void *)(long)i);
	pthread_create(&t[nthreads - 1], NULL, th_report, NULL);

	struct timespec ts = { .tv_sec = secs, .tv_nsec = 0 };
	nanosleep(&ts, &ts);
	running = 0;
	for (int i = 0; i < nthreads; i++)
		pthread_join(t[i], NULL);

	printf("KFSHAMMER-FINAL: mkdir_ok=%ld mkdir_fail=%ld open_ok=%ld "
	       "open_fail=%ld close=%ld rmdir_ok=%ld rmdir_fail=%ld "
	       "last_rmdir_errno=%d last_open_errno=%d\n",
	       st[E_MKDIR_OK], st[E_MKDIR_FAIL], st[E_OPEN_OK],
	       st[E_OPEN_FAIL], st[E_CLOSE], st[E_RMDIR_OK],
	       st[E_RMDIR_FAIL], last_rmdir_errno, last_open_errno);
	fflush(stdout);
	printf("KFSHAMMER-FINAL2: rmdir_ok=%ld rmdir_fail=%ld close=%ld "
	       "open_ok=%ld mkdir_ok=%ld\n",
	       st[E_RMDIR_OK], st[E_RMDIR_FAIL], st[E_CLOSE], st[E_OPEN_OK],
	       st[E_MKDIR_OK]);
	fflush(stdout);
	return 0;
}

      parent reply	other threads:[~2026-11-11  7:30 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   ` 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) 徐晗翔
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   ` 徐晗翔 [this message]

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=61919bed.2429b.1a1c983aa11.Coremail.xuhx@hust.edu.cn \
    --to=xuhx@hust.edu.cn \
    --cc=driver-core@lists.linux.dev \
    --cc=linux-kernel@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®