* memory leak in posix_clock_open
@ 2024-03-11 8:12 柳菁峰
2024-03-11 9:46 ` Z qiang
0 siblings, 1 reply; 6+ messages in thread
From: 柳菁峰 @ 2024-03-11 8:12 UTC (permalink / raw)
To: richardcochran@gmail.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Cc: syzkaller@googlegroups.com, secalert@redhat.com
There is a memory leak in posix_clock_open,it was found by syzkaller when I tested it with linux-6.7(commit: 0dd3ee31125508cd67f7e7172247f05b7fd1753a).
When the ptp_open function (in driver/ptp/ptp.chardev. c) is called in posix_clock_open and the ptp_open function returns an error, it appears to crash, posix_clock_release has not been called to free pccontext.
Here is crash info:
BUG: memory leak
unreferenced object 0xffff8881065327c0 (size 16):
comm "syz-executor.7", pid 8994, jiffies 4295144661 (age 17.222s)
hex dump (first 16 bytes):
00 20 79 01 81 88 ff ff 00 00 00 00 00 00 00 00 . y.............
backtrace:
[<00000000fba736c4>] kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
[<00000000fba736c4>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<00000000fba736c4>] slab_alloc_node mm/slub.c:3478 [inline]
[<00000000fba736c4>] __kmem_cache_alloc_node+0x1ee/0x250 mm/slub.c:3517
[<00000000f8fcb419>] kmalloc_trace+0x22/0xc0 mm/slab_common.c:1098
[<00000000afc910b4>] kmalloc include/linux/slab.h:600 [inline]
[<00000000afc910b4>] kzalloc include/linux/slab.h:721 [inline]
[<00000000afc910b4>] posix_clock_open+0xd3/0x250 kernel/time/posix-clock.c:126
[<00000000b1a43627>] chrdev_open+0x24b/0x6a0 fs/char_dev.c:414
[<00000000364febd5>] do_dentry_open+0x630/0x1580 fs/open.c:948
[<00000000ac62c8f4>] do_open fs/namei.c:3622 [inline]
[<00000000ac62c8f4>] path_openat+0x13f1/0x1c30 fs/namei.c:3779
[<0000000087bfc1bc>] do_filp_open+0x1c5/0x410 fs/namei.c:3809
[<0000000044db899a>] do_sys_openat2+0x139/0x190 fs/open.c:1437
[<00000000ee967f42>] do_sys_open fs/open.c:1452 [inline]
[<00000000ee967f42>] __do_sys_openat fs/open.c:1468 [inline]
[<00000000ee967f42>] __se_sys_openat fs/open.c:1463 [inline]
[<00000000ee967f42>] __x64_sys_openat+0x13d/0x1f0 fs/open.c:1463
[<000000004fad64b5>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<000000004fad64b5>] do_syscall_64+0x3e/0xf0 arch/x86/entry/common.c:83
[<00000000c2701c13>] entry_SYSCALL_64_after_hwframe+0x6e/0x76
BUG: leak checking failed
Here is the C code reproducer by syzkaller,It used inject fault to make ptp_open returns a error:
// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <dirent.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.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>
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 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 int inject_fault(int nth)
{
int fd;
fd = open("/proc/thread-self/fail-nth", O_RDWR);
if (fd == -1)
exit(1);
char buf[16];
sprintf(buf, "%d", nth);
if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
exit(1);
return fd;
}
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");
}
static void setup_fault()
{
static struct {
const char* file;
const char* val;
bool fatal;
} files[] = {
{"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
{"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
{"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
{"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
{"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
};
unsigned i;
for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
if (!write_file(files[i].file, files[i].val)) {
if (files[i].fatal)
exit(1);
}
}
}
#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);
}
static void execute_one(void);
#define WAIT_FLAGS __WALL
static void loop(void)
{
int iter = 0;
for (;; iter++) {
int pid = fork();
if (pid < 0)
exit(1);
if (pid == 0) {
setup_test();
execute_one();
exit(0);
}
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;
}
check_leaks();
}
}
void execute_one(void)
{
memcpy((void*)0x20001180, "/dev/ptp0\000", 10);
inject_fault(7);
syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x20001180ul, /*flags=*/0ul, /*mode=*/0ul);
}
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
setup_leak();
setup_fault();
loop();
return 0;
}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: memory leak in posix_clock_open
2024-03-11 8:12 memory leak in posix_clock_open 柳菁峰
@ 2024-03-11 9:46 ` Z qiang
2024-03-14 10:20 ` Thomas Gleixner
0 siblings, 1 reply; 6+ messages in thread
From: Z qiang @ 2024-03-11 9:46 UTC (permalink / raw)
To: 柳菁峰
Cc: richardcochran@gmail.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, syzkaller@googlegroups.com,
secalert@redhat.com
>
> There is a memory leak in posix_clock_open,it was found by syzkaller when I tested it with linux-6.7(commit: 0dd3ee31125508cd67f7e7172247f05b7fd1753a).
>
> When the ptp_open function (in driver/ptp/ptp.chardev. c) is called in posix_clock_open and the ptp_open function returns an error, it appears to crash, posix_clock_release has not been called to free pccontext.
>
> Here is crash info:
>
> BUG: memory leak
> unreferenced object 0xffff8881065327c0 (size 16):
> comm "syz-executor.7", pid 8994, jiffies 4295144661 (age 17.222s)
> hex dump (first 16 bytes):
> 00 20 79 01 81 88 ff ff 00 00 00 00 00 00 00 00 . y.............
> backtrace:
> [<00000000fba736c4>] kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
> [<00000000fba736c4>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<00000000fba736c4>] slab_alloc_node mm/slub.c:3478 [inline]
> [<00000000fba736c4>] __kmem_cache_alloc_node+0x1ee/0x250 mm/slub.c:3517
> [<00000000f8fcb419>] kmalloc_trace+0x22/0xc0 mm/slab_common.c:1098
> [<00000000afc910b4>] kmalloc include/linux/slab.h:600 [inline]
> [<00000000afc910b4>] kzalloc include/linux/slab.h:721 [inline]
> [<00000000afc910b4>] posix_clock_open+0xd3/0x250 kernel/time/posix-clock.c:126
> [<00000000b1a43627>] chrdev_open+0x24b/0x6a0 fs/char_dev.c:414
> [<00000000364febd5>] do_dentry_open+0x630/0x1580 fs/open.c:948
> [<00000000ac62c8f4>] do_open fs/namei.c:3622 [inline]
> [<00000000ac62c8f4>] path_openat+0x13f1/0x1c30 fs/namei.c:3779
> [<0000000087bfc1bc>] do_filp_open+0x1c5/0x410 fs/namei.c:3809
> [<0000000044db899a>] do_sys_openat2+0x139/0x190 fs/open.c:1437
> [<00000000ee967f42>] do_sys_open fs/open.c:1452 [inline]
> [<00000000ee967f42>] __do_sys_openat fs/open.c:1468 [inline]
> [<00000000ee967f42>] __se_sys_openat fs/open.c:1463 [inline]
> [<00000000ee967f42>] __x64_sys_openat+0x13d/0x1f0 fs/open.c:1463
> [<000000004fad64b5>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<000000004fad64b5>] do_syscall_64+0x3e/0xf0 arch/x86/entry/common.c:83
> [<00000000c2701c13>] entry_SYSCALL_64_after_hwframe+0x6e/0x76
>
> BUG: leak checking failed
Hi, jingfeng
Please try the following modifications:
diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
index 9de66bbbb3d1..71d9d8c394fa 100644
--- a/kernel/time/posix-clock.c
+++ b/kernel/time/posix-clock.c
@@ -137,6 +137,8 @@ static int posix_clock_open(struct inode *inode,
struct file *fp)
if (!err) {
get_device(clk->dev);
+ } else {
+ kfree(pccontext);
}
out:
up_read(&clk->rwsem);
Thanks
Zqiang
>
>
>
>
> Here is the C code reproducer by syzkaller,It used inject fault to make ptp_open returns a error:
>
> // autogenerated by syzkaller (https://github.com/google/syzkaller)
>
> #define _GNU_SOURCE
>
> #include <dirent.h>
> #include <endian.h>
> #include <errno.h>
> #include <fcntl.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>
>
> 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 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 int inject_fault(int nth)
> {
> int fd;
> fd = open("/proc/thread-self/fail-nth", O_RDWR);
> if (fd == -1)
> exit(1);
> char buf[16];
> sprintf(buf, "%d", nth);
> if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
> exit(1);
> return fd;
> }
>
> 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");
> }
>
> static void setup_fault()
> {
> static struct {
> const char* file;
> const char* val;
> bool fatal;
> } files[] = {
> {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
> {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
> {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
> {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
> {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
> };
> unsigned i;
> for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
> if (!write_file(files[i].file, files[i].val)) {
> if (files[i].fatal)
> exit(1);
> }
> }
> }
>
> #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);
> }
>
> static void execute_one(void);
>
> #define WAIT_FLAGS __WALL
>
> static void loop(void)
> {
> int iter = 0;
> for (;; iter++) {
> int pid = fork();
> if (pid < 0)
> exit(1);
> if (pid == 0) {
> setup_test();
> execute_one();
> exit(0);
> }
> 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;
> }
> check_leaks();
> }
> }
>
> void execute_one(void)
> {
> memcpy((void*)0x20001180, "/dev/ptp0\000", 10);
> inject_fault(7);
> syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x20001180ul, /*flags=*/0ul, /*mode=*/0ul);
>
> }
> int main(void)
> {
> syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> setup_leak();
> setup_fault();
> loop();
> return 0;
> }
>
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: memory leak in posix_clock_open
@ 2024-03-11 9:48 Red Hat Product Security
0 siblings, 0 replies; 6+ messages in thread
From: Red Hat Product Security @ 2024-03-11 9:48 UTC (permalink / raw)
To: richardcochran, syzkaller, liujingfeng, netdev, linux-kernel
[-- Attachment #1.1: Type: text/plain, Size: 8459 bytes --]
Hello!
INC2889741 (memory leak in posix_clock_open) has been updated.
Opened for: liujingfeng@qianxin.com
Followers: richardcochran@gmail.com, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, syzkaller@googlegroups.com
A Guest updated your request with the following comments:
Reply from: qiang.zhang1211@gmail.com [mailto:qiang.zhang1211@gmail.com]
>
> There is a memory leak in posix_clock_open,it was found by syzkaller when I tested it with linux-6.7(commit: 0dd3ee31125508cd67f7e7172247f05b7fd1753a).
>
> When the ptp_open function (in driver/ptp/ptp.chardev. c) is called in posix_clock_open and the ptp_open function returns an error, it appears to crash, posix_clock_release has not been called to free pccontext.
>
> Here is crash info:
>
> BUG: memory leak
> unreferenced object 0xffff8881065327c0 (size 16):
> comm "syz-executor.7", pid 8994, jiffies 4295144661 (age 17.222s)
> hex dump (first 16 bytes):
> 00 20 79 01 81 88 ff ff 00 00 00 00 00 00 00 00 . y.............
> backtrace:
> [<00000000fba736c4>] kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
> [<00000000fba736c4>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<00000000fba736c4>] slab_alloc_node mm/slub.c:3478 [inline]
> [<00000000fba736c4>] __kmem_cache_alloc_node+0x1ee/0x250 mm/slub.c:3517
> [<00000000f8fcb419>] kmalloc_trace+0x22/0xc0 mm/slab_common.c:1098
> [<00000000afc910b4>] kmalloc include/linux/slab.h:600 [inline]
> [<00000000afc910b4>] kzalloc include/linux/slab.h:721 [inline]
> [<00000000afc910b4>] posix_clock_open+0xd3/0x250 kernel/time/posix-clock.c:126
> [<00000000b1a43627>] chrdev_open+0x24b/0x6a0 fs/char_dev.c:414
> [<00000000364febd5>] do_dentry_open+0x630/0x1580 fs/open.c:948
> [<00000000ac62c8f4>] do_open fs/namei.c:3622 [inline]
> [<00000000ac62c8f4>] path_openat+0x13f1/0x1c30 fs/namei.c:3779
> [<0000000087bfc1bc>] do_filp_open+0x1c5/0x410 fs/namei.c:3809
> [<0000000044db899a>] do_sys_openat2+0x139/0x190 fs/open.c:1437
> [<00000000ee967f42>] do_sys_open fs/open.c:1452 [inline]
> [<00000000ee967f42>] __do_sys_openat fs/open.c:1468 [inline]
> [<00000000ee967f42>] __se_sys_openat fs/open.c:1463 [inline]
> [<00000000ee967f42>] __x64_sys_openat+0x13d/0x1f0 fs/open.c:1463
> [<000000004fad64b5>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<000000004fad64b5>] do_syscall_64+0x3e/0xf0 arch/x86/entry/common.c:83
> [<00000000c2701c13>] entry_SYSCALL_64_after_hwframe+0x6e/0x76
>
> BUG: leak checking failed
Hi, jingfeng
Please try the following modifications:
diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
index 9de66bbbb3d1..71d9d8c394fa 100644
--- a/kernel/time/posix-clock.c
+++ b/kernel/time/posix-clock.c
@@ -137,6 +137,8 @@ static int posix_clock_open(struct inode *inode,
struct file *fp)
if (!err) {
get_device(clk->dev);
+ } else {
+ kfree(pccontext);
}
out:
up_read(&clk->rwsem);
Thanks
Zqiang
>
>
>
>
> Here is the C code reproducer by syzkaller,It used inject fault to make ptp_open returns a error:
>
> // autogenerated by syzkaller (https://github.com/google/syzkaller [https://github.com/google/syzkaller])
>
> #define _GNU_SOURCE
>
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
> #include
>
> 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 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 int inject_fault(int nth)
> {
> int fd;
> fd = open("/proc/thread-self/fail-nth", O_RDWR);
> if (fd == -1)
> exit(1);
> char buf[16];
> sprintf(buf, "%d", nth);
> if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
> exit(1);
> return fd;
> }
>
> 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");
> }
>
> static void setup_fault()
> {
> static struct {
> const char* file;
> const char* val;
> bool fatal;
> } files[] = {
> {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
> {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
> {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
> {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
> {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
> };
> unsigned i;
> for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
> if (!write_file(files[i].file, files[i].val)) {
> if (files[i].fatal)
> exit(1);
> }
> }
> }
>
> #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);
> }
>
> static void execute_one(void);
>
> #define WAIT_FLAGS __WALL
>
> static void loop(void)
> {
> int iter = 0;
> for (;; iter++) {
> int pid = fork();
> if (pid < 0)
> exit(1);
> if (pid == 0) {
> setup_test();
> execute_one();
> exit(0);
> }
> 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;
> }
> check_leaks();
> }
> }
>
> void execute_one(void)
> {
> memcpy((void*)0x20001180, "/dev/ptp0\000", 10);
> inject_fault(7);
> syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x20001180ul, /*flags=*/0ul, /*mode=*/0ul);
>
> }
> int main(void)
> {
> syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> setup_leak();
> setup_fault();
> loop();
> return 0;
> }
>
How can I track and update my request?
To respond, reply to this email. You may also create a new email and include the request number (INC2889741) in the subject.
Thank you,
Product Security
Ref:MSG86490725
[-- Attachment #1.2: Type: text/html, Size: 15502 bytes --]
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: memory leak in posix_clock_open
2024-03-11 9:46 ` Z qiang
@ 2024-03-14 10:20 ` Thomas Gleixner
2024-03-15 2:13 ` Z qiang
0 siblings, 1 reply; 6+ messages in thread
From: Thomas Gleixner @ 2024-03-14 10:20 UTC (permalink / raw)
To: Z qiang, 柳菁峰
Cc: richardcochran@gmail.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, syzkaller@googlegroups.com,
secalert@redhat.com
On Mon, Mar 11 2024 at 17:46, Z qiang wrote:
>
> diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
> index 9de66bbbb3d1..71d9d8c394fa 100644
> --- a/kernel/time/posix-clock.c
> +++ b/kernel/time/posix-clock.c
> @@ -137,6 +137,8 @@ static int posix_clock_open(struct inode *inode,
> struct file *fp)
>
> if (!err) {
> get_device(clk->dev);
> + } else {
> + kfree(pccontext);
> }
> out:
> up_read(&clk->rwsem);
Looks about right. Can you please send a proper patch?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: memory leak in posix_clock_open
2024-03-14 10:20 ` Thomas Gleixner
@ 2024-03-15 2:13 ` Z qiang
0 siblings, 0 replies; 6+ messages in thread
From: Z qiang @ 2024-03-15 2:13 UTC (permalink / raw)
To: Thomas Gleixner
Cc: 柳菁峰, richardcochran@gmail.com,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
syzkaller@googlegroups.com, secalert@redhat.com
>
> On Mon, Mar 11 2024 at 17:46, Z qiang wrote:
> >
> > diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
> > index 9de66bbbb3d1..71d9d8c394fa 100644
> > --- a/kernel/time/posix-clock.c
> > +++ b/kernel/time/posix-clock.c
> > @@ -137,6 +137,8 @@ static int posix_clock_open(struct inode *inode,
> > struct file *fp)
> >
> > if (!err) {
> > get_device(clk->dev);
> > + } else {
> > + kfree(pccontext);
> > }
> > out:
> > up_read(&clk->rwsem);
>
> Looks about right. Can you please send a proper patch?
I will send a patch.
Thanks,
Zqiang
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: memory leak in posix_clock_open
@ 2024-03-15 2:15 Red Hat Product Security
0 siblings, 0 replies; 6+ messages in thread
From: Red Hat Product Security @ 2024-03-15 2:15 UTC (permalink / raw)
To: richardcochran, syzkaller, liujingfeng, netdev, linux-kernel
[-- Attachment #1.1: Type: text/plain, Size: 1128 bytes --]
Hello!
INC2889741 (memory leak in posix_clock_open) has been updated.
Opened for: liujingfeng@qianxin.com
Followers: richardcochran@gmail.com, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, syzkaller@googlegroups.com
A Guest updated your request with the following comments:
Reply from: qiang.zhang1211@gmail.com [mailto:qiang.zhang1211@gmail.com]
>
> On Mon, Mar 11 2024 at 17:46, Z qiang wrote:
> >
> > diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
> > index 9de66bbbb3d1..71d9d8c394fa 100644
> > --- a/kernel/time/posix-clock.c
> > +++ b/kernel/time/posix-clock.c
> > @@ -137,6 +137,8 @@ static int posix_clock_open(struct inode *inode,
> > struct file *fp)
> >
> > if (!err) {
> > get_device(clk->dev);
> > + } else {
> > + kfree(pccontext);
> > }
> > out:
> > up_read(&clk->rwsem);
>
> Looks about right. Can you please send a proper patch?
I will send a patch.
Thanks,
Zqiang
How can I track and update my request?
To respond, reply to this email. You may also create a new email and include the request number (INC2889741) in the subject.
Thank you,
Product Security
Ref:MSG86727590
[-- Attachment #1.2: Type: text/html, Size: 2199 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-03-15 2:15 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-11 8:12 memory leak in posix_clock_open 柳菁峰
2024-03-11 9:46 ` Z qiang
2024-03-14 10:20 ` Thomas Gleixner
2024-03-15 2:13 ` Z qiang
-- strict thread matches above, loose matches on Subject: below --
2024-03-11 9:48 Red Hat Product Security
2024-03-15 2:15 Red Hat Product Security
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.