Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Syzkaller hit 'memory leak in prepare_creds' bug.
- executing program
- executing program
- BUG: memory leak
- unreferenced object 0xffff88800de0f400 (size 176):
- comm "syz-executor221", pid 232, jiffies 4294806347 (age 19.226s)
- hex dump (first 32 bytes):
- 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
- backtrace:
- [<00000000d7267485>] prepare_creds+0x2b/0x6f0 kernel/cred.c:260
- [<00000000944a3848>] copy_creds+0x72/0x930 kernel/cred.c:365
- [<000000002be529b9>] copy_process+0x1091/0x6e80 kernel/fork.c:2063
- [<00000000c9ac28da>] kernel_clone+0xe7/0x1050 kernel/fork.c:2582
- [<0000000094b79658>] __do_sys_clone+0xc8/0x110 kernel/fork.c:2699
- [<00000000ccb88a3f>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
- [<00000000ccb88a3f>] do_syscall_64+0x3b/0x90 arch/x86/entry/common.c:80
- [<000000007042bd37>] entry_SYSCALL_64_after_hwframe+0x44/0xae
- BUG: memory leak
- unreferenced object 0xffff88800e436900 (size 32):
- comm "syz-executor221", pid 232, jiffies 4294806347 (age 19.226s)
- hex dump (first 32 bytes):
- 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
- backtrace:
- [<0000000001439cb7>] slab_alloc_node mm/slub.c:3234 [inline]
- [<0000000001439cb7>] slab_alloc mm/slub.c:3242 [inline]
- [<0000000001439cb7>] __kmalloc+0x166/0x350 mm/slub.c:4419
- [<0000000014e9e082>] kmalloc include/linux/slab.h:595 [inline]
- [<0000000014e9e082>] kzalloc include/linux/slab.h:724 [inline]
- [<0000000014e9e082>] lsm_cred_alloc security/security.c:537 [inline]
- [<0000000014e9e082>] security_prepare_creds+0x10a/0x180 security/security.c:1692
- [<000000009629e28f>] prepare_creds+0x505/0x6f0 kernel/cred.c:291
- [<00000000944a3848>] copy_creds+0x72/0x930 kernel/cred.c:365
- [<000000002be529b9>] copy_process+0x1091/0x6e80 kernel/fork.c:2063
- [<00000000c9ac28da>] kernel_clone+0xe7/0x1050 kernel/fork.c:2582
- [<0000000094b79658>] __do_sys_clone+0xc8/0x110 kernel/fork.c:2699
- [<00000000ccb88a3f>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
- [<00000000ccb88a3f>] do_syscall_64+0x3b/0x90 arch/x86/entry/common.c:80
- [<000000007042bd37>] entry_SYSCALL_64_after_hwframe+0x44/0xae
- BUG: memory leak
- unreferenced object 0xffff88800db5b000 (size 1024):
- comm "syz-executor221", pid 234, jiffies 4294806357 (age 19.216s)
- hex dump (first 32 bytes):
- 60 ec 4f 84 ff ff ff ff 01 00 00 00 00 00 00 00 `.O.............
- 00 00 00 00 ad 4e ad de ff ff ff ff 00 00 00 00 .....N..........
- backtrace:
- [<000000001eb98443>] slab_alloc_node mm/slub.c:3234 [inline]
- [<000000001eb98443>] slab_alloc mm/slub.c:3242 [inline]
- [<000000001eb98443>] kmem_cache_alloc_trace+0x1b1/0x410 mm/slub.c:3259
- [<0000000019cd7692>] kmalloc include/linux/slab.h:590 [inline]
- [<0000000019cd7692>] kzalloc include/linux/slab.h:724 [inline]
- [<0000000019cd7692>] __fsnotify_alloc_group+0x87/0x2e0 fs/notify/group.c:119
- [<00000000c784e765>] inotify_new_group fs/notify/inotify/inotify_user.c:639 [inline]
- [<00000000c784e765>] do_inotify_init+0x44/0x5f0 fs/notify/inotify/inotify_user.c:687
- [<0000000092552d66>] __do_sys_inotify_init1 fs/notify/inotify/inotify_user.c:701 [inline]
- [<0000000092552d66>] __se_sys_inotify_init1 fs/notify/inotify/inotify_user.c:699 [inline]
- [<0000000092552d66>] __x64_sys_inotify_init1+0x2d/0x40 fs/notify/inotify/inotify_user.c:699
- [<00000000ccb88a3f>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
- [<00000000ccb88a3f>] do_syscall_64+0x3b/0x90 arch/x86/entry/common.c:80
- [<000000007042bd37>] entry_SYSCALL_64_after_hwframe+0x44/0xae
- BUG: memory leak
- unreferenced object 0xffff88800d034e80 (size 32):
- comm "syz-executor221", pid 234, jiffies 4294806357 (age 19.216s)
- hex dump (first 32 bytes):
- 80 4e 03 0d 80 88 ff ff 80 4e 03 0d 80 88 ff ff .N.......N......
- 00 40 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 .@..............
- backtrace:
- [<000000001eb98443>] slab_alloc_node mm/slub.c:3234 [inline]
- [<000000001eb98443>] slab_alloc mm/slub.c:3242 [inline]
- [<000000001eb98443>] kmem_cache_alloc_trace+0x1b1/0x410 mm/slub.c:3259
- [<00000000a23d1d08>] kmalloc include/linux/slab.h:590 [inline]
- [<00000000a23d1d08>] inotify_new_group fs/notify/inotify/inotify_user.c:643 [inline]
- [<00000000a23d1d08>] do_inotify_init+0x9d/0x5f0 fs/notify/inotify/inotify_user.c:687
- [<0000000092552d66>] __do_sys_inotify_init1 fs/notify/inotify/inotify_user.c:701 [inline]
- [<0000000092552d66>] __se_sys_inotify_init1 fs/notify/inotify/inotify_user.c:699 [inline]
- [<0000000092552d66>] __x64_sys_inotify_init1+0x2d/0x40 fs/notify/inotify/inotify_user.c:699
- [<00000000ccb88a3f>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
- [<00000000ccb88a3f>] do_syscall_64+0x3b/0x90 arch/x86/entry/common.c:80
- [<000000007042bd37>] entry_SYSCALL_64_after_hwframe+0x44/0xae
- BUG: memory leak
- unreferenced object 0xffff88800e0aaf00 (size 464):
- comm "syz-executor221", pid 234, jiffies 4294806363 (age 19.210s)
- hex dump (first 32 bytes):
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
- a0 a4 e5 07 80 88 ff ff 48 ea 81 1a 80 88 ff ff ........H.......
- backtrace:
- [<00000000cec63102>] kmem_cache_zalloc include/linux/slab.h:714 [inline]
- [<00000000cec63102>] __alloc_file+0x21/0x240 fs/file_table.c:101
- [<000000001782d092>] alloc_empty_file+0x6d/0x170 fs/file_table.c:150
- [<00000000f746e44b>] alloc_file+0x59/0x590 fs/file_table.c:192
- [<00000000dc119180>] alloc_file_pseudo+0x16a/0x250 fs/file_table.c:232
- [<00000000a53ee9f9>] __anon_inode_getfile+0x137/0x3d0 fs/anon_inodes.c:109
- [<00000000aa7e1319>] __anon_inode_getfd+0x61/0xc0 fs/anon_inodes.c:194
- [<00000000fbe857a6>] do_inotify_init+0x493/0x5f0 fs/notify/inotify/inotify_user.c:691
- [<0000000092552d66>] __do_sys_inotify_init1 fs/notify/inotify/inotify_user.c:701 [inline]
- [<0000000092552d66>] __se_sys_inotify_init1 fs/notify/inotify/inotify_user.c:699 [inline]
- [<0000000092552d66>] __x64_sys_inotify_init1+0x2d/0x40 fs/notify/inotify/inotify_user.c:699
- [<00000000ccb88a3f>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
- [<00000000ccb88a3f>] do_syscall_64+0x3b/0x90 arch/x86/entry/common.c:80
- [<000000007042bd37>] entry_SYSCALL_64_after_hwframe+0x44/0xae
- Syzkaller reproducer:
- # {Threaded:true Repeat:true RepeatTimes:0 Procs:1 Slowdown:1 Sandbox: Leak:true NetInjection:false NetDevices:false NetReset:false Cgroups:false BinfmtMisc:false CloseFDs:false KCSAN:false DevlinkPCI:false USB:false VhciInjection:false Wifi:false IEEE802154:false Sysctl:false UseTmpDir:false HandleSegv:false Repro:false Trace:false LegacyOptions:{Collide:false Fault:false FaultCall:0 FaultNth:0}}
- inotify_init1(0x0) (rerun: 64)
- r0 = fsopen(&(0x7f0000000000)='sysfs\x00', 0x0)
- close_range(r0, 0xffffffffffffffff, 0x2)
- C reproducer:
- // autogenerated by syzkaller (https://github.com/google/syzkaller)
- #define _GNU_SOURCE
- #include <dirent.h>
- #include <endian.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <pthread.h>
- #include <signal.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/prctl.h>
- #include <sys/stat.h>
- #include <sys/syscall.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <time.h>
- #include <unistd.h>
- #include <linux/futex.h>
- #ifndef __NR_close_range
- #define __NR_close_range 436
- #endif
- #ifndef SYS_gettid
- #error "SYS_gettid unavailable on this system"
- #endif
- #define gettid() ((pid_t)syscall(SYS_gettid))
- static void sleep_ms(uint64_t ms)
- {
- usleep(ms * 1000);
- }
- static uint64_t current_time_ms(void)
- {
- struct timespec ts;
- if (clock_gettime(CLOCK_MONOTONIC, &ts))
- exit(1);
- return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
- }
- static void thread_start(void* (*fn)(void*), void* arg)
- {
- pid_t pid = getpid();
- pid_t tid = gettid();
- pthread_t th;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, 128 << 10);
- int i = 0;
- for (; i < 100; i++) {
- if (pthread_create(&th, &attr, fn, arg) == 0) {
- pthread_attr_destroy(&attr);
- printf("%d %d created thread\n", pid, tid);
- return;
- }
- if (errno == EAGAIN) {
- usleep(50);
- continue;
- }
- break;
- }
- exit(1);
- }
- 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 (ev->state)
- 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);
- }
- static int event_isset(event_t* ev)
- {
- return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
- }
- static int event_timedwait(event_t* ev, uint64_t timeout)
- {
- uint64_t start = current_time_ms();
- uint64_t now = start;
- for (;;) {
- uint64_t remain = timeout - (now - start);
- struct timespec ts;
- ts.tv_sec = remain / 1000;
- ts.tv_nsec = (remain % 1000) * 1000 * 1000;
- syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
- if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
- return 1;
- now = current_time_ms();
- if (now - start > timeout)
- return 0;
- }
- }
- static bool write_file(const char* file, const char* what, ...)
- {
- char buf[1024];
- va_list args;
- va_start(args, what);
- vsnprintf(buf, sizeof(buf), what, args);
- va_end(args);
- buf[sizeof(buf) - 1] = 0;
- int len = strlen(buf);
- int fd = open(file, O_WRONLY | O_CLOEXEC);
- if (fd == -1)
- return false;
- if (write(fd, buf, len) != len) {
- int err = errno;
- close(fd);
- errno = err;
- return false;
- }
- close(fd);
- return true;
- }
- static void kill_and_wait(int pid, int* status)
- {
- kill(-pid, SIGKILL);
- kill(pid, SIGKILL);
- for (int i = 0; i < 100; i++) {
- if (waitpid(-1, status, WNOHANG | __WALL) == pid)
- return;
- usleep(1000);
- }
- DIR* dir = opendir("/sys/fs/fuse/connections");
- if (dir) {
- for (;;) {
- struct dirent* ent = readdir(dir);
- if (!ent)
- break;
- if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
- continue;
- char abort[300];
- snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort", ent->d_name);
- int fd = open(abort, O_WRONLY);
- if (fd == -1) {
- continue;
- }
- if (write(fd, abort, 1) < 0) {
- }
- close(fd);
- }
- closedir(dir);
- } else {
- }
- while (waitpid(-1, status, __WALL) != pid) {
- }
- }
- static void setup_test()
- {
- prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
- setpgrp();
- write_file("/proc/self/oom_score_adj", "1000");
- }
- #define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
- static void setup_leak()
- {
- if (!write_file(KMEMLEAK_FILE, "scan"))
- exit(1);
- sleep(5);
- if (!write_file(KMEMLEAK_FILE, "scan"))
- exit(1);
- if (!write_file(KMEMLEAK_FILE, "clear"))
- exit(1);
- }
- static void check_leaks(void)
- {
- int fd = open(KMEMLEAK_FILE, O_RDWR);
- if (fd == -1)
- exit(1);
- uint64_t start = current_time_ms();
- if (write(fd, "scan", 4) != 4)
- exit(1);
- sleep(1);
- while (current_time_ms() - start < 4 * 1000)
- sleep(1);
- if (write(fd, "scan", 4) != 4)
- exit(1);
- static char buf[128 << 10];
- ssize_t n = read(fd, buf, sizeof(buf) - 1);
- if (n < 0)
- exit(1);
- int nleaks = 0;
- if (n != 0) {
- sleep(1);
- if (write(fd, "scan", 4) != 4)
- exit(1);
- if (lseek(fd, 0, SEEK_SET) < 0)
- exit(1);
- n = read(fd, buf, sizeof(buf) - 1);
- if (n < 0)
- exit(1);
- buf[n] = 0;
- char* pos = buf;
- char* end = buf + n;
- while (pos < end) {
- char* next = strstr(pos + 1, "unreferenced object");
- if (!next)
- next = end;
- char prev = *next;
- *next = 0;
- fprintf(stderr, "BUG: memory leak\n%s\n", pos);
- *next = prev;
- pos = next;
- nleaks++;
- }
- }
- if (write(fd, "clear", 5) != 5)
- exit(1);
- close(fd);
- if (nleaks)
- exit(1);
- }
- struct thread_t {
- int created, call;
- event_t ready, done;
- };
- static struct thread_t threads[16];
- static void execute_call(int call);
- static int running;
- static void* thr(void* arg)
- {
- struct thread_t* th = (struct thread_t*)arg;
- for (;;) {
- event_wait(&th->ready);
- event_reset(&th->ready);
- execute_call(th->call);
- __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
- event_set(&th->done);
- }
- return 0;
- }
- static void execute_one(void)
- {
- sleep_ms(100);
- int i, call, thread;
- for (call = 0; call < 2; call++) {
- for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) {
- struct thread_t* th = &threads[thread];
- if (!th->created) {
- th->created = 1;
- event_init(&th->ready);
- event_init(&th->done);
- event_set(&th->done);
- thread_start(thr, th);
- }
- if (!event_isset(&th->done))
- continue;
- event_reset(&th->done);
- th->call = call;
- __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
- event_set(&th->ready);
- event_timedwait(&th->done, 50);
- break;
- }
- }
- for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
- sleep_ms(1);
- }
- static void execute_one(void);
- #define WAIT_FLAGS __WALL
- static void loop(void)
- {
- pid_t parentPID = getpid();
- pid_t parentTID = gettid();
- int iter = 0;
- for (;; iter++) {
- printf("%d %d forking\n", parentPID, parentTID);
- int pid = fork();
- if (pid < 0)
- exit(1);
- if (pid == 0) {
- setup_test();
- execute_one();
- exit(0);
- }
- printf("%d %d forked child %d\n", parentPID, parentTID, pid);
- int status = 0;
- uint64_t start = current_time_ms();
- for (;;) {
- if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
- break;
- sleep_ms(1);
- if (current_time_ms() - start < 5000)
- continue;
- kill_and_wait(pid, &status);
- break;
- }
- printf("%d %d checking leak after executor exited\n", parentPID, parentTID);
- check_leaks();
- }
- }
- uint64_t r[1] = {0xffffffffffffffff};
- void execute_call(int call)
- {
- pid_t pid = getpid();
- pid_t tid = gettid();
- intptr_t res = 0;
- switch (call) {
- case 0:
- printf("%d %d pipe2\n", pid, tid);
- res = syscall(__NR_pipe2, 0x20000080ul, 0ul);
- {
- int i;
- for(i = 0; i < 64 /* 32 also triggers the bug, but 16 doesn't */; i++) {
- syscall(__NR_pipe2, 0x20000080ul, 0ul);
- }
- }
- if (res != -1)
- r[0] = *(uint32_t*)0x20000080;
- break;
- case 1:
- printf("%d %d close_range\n", pid, tid);
- syscall(__NR_close_range, r[0], -1, 2ul /* CLOSE_RANGE_UNSHARE */);
- break;
- }
- }
- int main(void)
- {
- syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);
- syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul);
- syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);
- setup_leak();
- printf("%d %d starting loop\n", getpid(), gettid());
- loop();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement