Yeqi Fu
unread,Nov 13, 2024, 3:46:44 AM11/13/24Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to ja...@cloudflare.com, john.fa...@gmail.com, da...@davemloft.net, edum...@google.com, ku...@kernel.org, pab...@redhat.com, net...@vger.kernel.org, b...@vger.kernel.org, linux-...@vger.kernel.org, syzk...@googlegroups.com, bonan...@u.nus.edu
Hi there,
A warning is triggered in lib/vsprintf.c due to an unsupported '%' in a format string. This issue occurs in the function format_decode at line 2659 of kernel version 6.12.0-rc3-gb22db8b8befe. A proof-of-concept is available, and I have manually reproduced this bug.
Report:
```
Please remove unsupported % in format string
WARNING: CPU: 1 PID: 29307 at lib/vsprintf.c:2659 format_decode+0x121a/0x1c00 lib/vsprintf.c:2659
Modules linked in:
CPU: 1 UID: 0 PID: 29307 Comm: syz.5.9298 Not tainted 6.12.0-rc3-gb22db8b8befe #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
RIP: 0010:format_decode+0x121a/0x1c00 lib/vsprintf.c:2659
Code: 8b 9c 24 80 00 00 00 48 89 d8 48 c1 e8 03 42 8a 04 30 84 c0 0f 85 d5 09 00 00 0f b6 33 48 c7 c7 00 bd eb 92 e8 b7 59 67 fc 90 <0f> 0b 90 90 4d 89 f7 48 8b 5c 24 18 e9 d7 fc ff ff 89 d1 80 e1 07
RSP: 0018:ffff888041197600 EFLAGS: 00010246
RAX: ea46d93351edcc00 RBX: ffff88804119792c RCX: ffff888009a78000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffff8880411976f0 R08: ffffffff8ebc8e3b R09: 1ffff1100d9e515a
R10: dffffc0000000000 R11: ffffed100d9e515b R12: ffff0000ffffff00
R13: ffff888041197700 R14: dffffc0000000000 R15: dffffc0000000000
FS: 00007fbe06321640(0000) GS:ffff88806cf00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000020a8c000 CR3: 00000000404b6005 CR4: 0000000000370ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<TASK>
bstr_printf+0x136/0x1260 lib/vsprintf.c:3232
____bpf_trace_printk kernel/trace/bpf_trace.c:389 [inline]
bpf_trace_printk+0x1a1/0x220 kernel/trace/bpf_trace.c:374
bpf_prog_7ee8fe4dad0c4460+0x4e/0x50
bpf_dispatcher_nop_func include/linux/bpf.h:1257 [inline]
__bpf_prog_run include/linux/filter.h:692 [inline]
bpf_prog_run include/linux/filter.h:708 [inline]
bpf_test_run+0x7a9/0x910 net/bpf/test_run.c:433
bpf_prog_test_run_skb+0xc47/0x1750 net/bpf/test_run.c:1094
bpf_prog_test_run+0x2df/0x350 kernel/bpf/syscall.c:4247
__sys_bpf+0x484/0x850 kernel/bpf/syscall.c:5652
__do_sys_bpf kernel/bpf/syscall.c:5741 [inline]
__se_sys_bpf kernel/bpf/syscall.c:5739 [inline]
__x64_sys_bpf+0x7c/0x90 kernel/bpf/syscall.c:5739
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xd8/0x1c0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x67/0x6f
RIP: 0033:0x7fbe07ccd72d
Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fbe06320f98 EFLAGS: 00000246 ORIG_RAX: 0000000000000141
RAX: ffffffffffffffda RBX: 00007fbe07ea5f80 RCX: 00007fbe07ccd72d
RDX: 0000000000000050 RSI: 0000000020000700 RDI: 000000000000000a
RBP: 00007fbe07d57584 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 0000000000000000 R14: 00007fbe07ea5f80 R15: 00007fbe06301000
</TASK>
irq event stamp: 39314
hardirqs last enabled at (39324): [<ffffffff8ed766cb>] __up_console_sem kernel/printk/printk.c:344 [inline]
hardirqs last enabled at (39324): [<ffffffff8ed766cb>] __console_unlock+0xfb/0x130 kernel/printk/printk.c:2844
hardirqs last disabled at (39335): [<ffffffff8ed766b0>] __up_console_sem kernel/printk/printk.c:342 [inline]
hardirqs last disabled at (39335): [<ffffffff8ed766b0>] __console_unlock+0xe0/0x130 kernel/printk/printk.c:2844
softirqs last enabled at (38482): [<ffffffff9195aaea>] bpf_test_run+0x31a/0x910
softirqs last disabled at (38484): [<ffffffff9195aaea>] bpf_test_run+0x31a/0x910
---[ end trace 0000000000000000 ]---
```
Poc.c:
```
#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>
#ifndef __NR_bpf
#define __NR_bpf 321
#endif
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 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_sysctl()
{
int cad_pid = fork();
if (cad_pid < 0)
exit(1);
if (cad_pid == 0) {
for (;;)
sleep(100);
}
char tmppid[32];
snprintf(tmppid, sizeof(tmppid), "%d", cad_pid);
struct {
const char* name;
const char* data;
} files[] = {
{"/sys/kernel/debug/x86/nmi_longest_ns", "10000000000"},
{"/proc/sys/kernel/hung_task_check_interval_secs", "20"},
{"/proc/sys/net/core/bpf_jit_kallsyms", "1"},
{"/proc/sys/net/core/bpf_jit_harden", "0"},
{"/proc/sys/kernel/kptr_restrict", "0"},
{"/proc/sys/kernel/softlockup_all_cpu_backtrace", "1"},
{"/proc/sys/fs/mount-max", "100"},
{"/proc/sys/vm/oom_dump_tasks", "0"},
{"/proc/sys/debug/exception-trace", "0"},
{"/proc/sys/kernel/printk", "7 4 1 3"},
{"/proc/sys/kernel/keys/gc_delay", "1"},
{"/proc/sys/vm/oom_kill_allocating_task", "1"},
{"/proc/sys/kernel/ctrl-alt-del", "0"},
{"/proc/sys/kernel/cad_pid", tmppid},
};
for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
if (!write_file(files[i].name, files[i].data)) {
}
}
kill(cad_pid, SIGKILL);
while (waitpid(cad_pid, NULL, 0) != cad_pid)
;
}
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 (;;) {
sleep_ms(10);
if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
break;
if (current_time_ms() - start < 5000)
continue;
kill_and_wait(pid, &status);
break;
}
}
}
uint64_t r[1] = {0xffffffffffffffff};
void execute_one(void)
{
intptr_t res = 0;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
}
*(uint32_t*)0x200013c0 = 4;
*(uint32_t*)0x200013c4 = 0xc;
*(uint64_t*)0x200013c8 = 0x20000600;
memcpy(
(void*)0x20000600,
"\x18\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x85\x00"
"\x00\x00\x07\x00\x00\x00\x18\x01\x00\x00\x78\x6c\x6c\x25\x00\x00\x00\x00"
"\x00\x20\x20\x20\x7b\x0a\xf8\xff\x00\x00\x00\x00\xbf\xa1\x00\x00\x00\x00"
"\x00\x00\x07\x01\x00\x00\xf8\xff\xff\xff\xb7\x02\x00\x00\x08\x00\x00\x00"
"\xb7\x03\x00\x00\x05\x00\x00\x00\x85\x00\x00\x00\x06\x00\x00\x00\x95",
89);
*(uint64_t*)0x200013d0 = 0x20000200;
memcpy((void*)0x20000200, "GPL\000", 4);
*(uint32_t*)0x200013d8 = 9;
*(uint32_t*)0x200013dc = 0;
*(uint64_t*)0x200013e0 = 0;
*(uint32_t*)0x200013e8 = 0x41000;
*(uint32_t*)0x200013ec = 0;
memset((void*)0x200013f0, 0, 16);
*(uint32_t*)0x20001400 = 0;
*(uint32_t*)0x20001404 = 6;
*(uint32_t*)0x20001408 = -1;
*(uint32_t*)0x2000140c = 0;
*(uint64_t*)0x20001410 = 0;
*(uint32_t*)0x20001418 = 0;
*(uint32_t*)0x2000141c = 0;
*(uint64_t*)0x20001420 = 0;
*(uint32_t*)0x20001428 = 0;
*(uint32_t*)0x2000142c = 0;
*(uint32_t*)0x20001430 = 0;
*(uint32_t*)0x20001434 = 0;
*(uint64_t*)0x20001438 = 0;
*(uint64_t*)0x20001440 = 0;
*(uint32_t*)0x20001448 = 0;
*(uint32_t*)0x2000144c = 1;
*(uint32_t*)0x20001450 = 0;
res = syscall(__NR_bpf, /*cmd=*/5ul, /*arg=*/0x200013c0ul, /*size=*/0x94ul);
if (res != -1)
r[0] = res;
syscall(__NR_bpf, /*cmd=*/0ul, /*arg=*/0ul, /*size=*/0x48ul);
*(uint32_t*)0x20000700 = r[0];
*(uint32_t*)0x20000704 = 0;
*(uint32_t*)0x20000708 = 0xe;
*(uint32_t*)0x2000070c = 0;
*(uint64_t*)0x20000710 = 0x20000300;
memcpy((void*)0x20000300,
"\x8f\x41\x3f\x07\x00\x00\x00\x7e\xfb\xe3\xd9\xb2\x48\xb6", 14);
*(uint64_t*)0x20000718 = 0;
*(uint32_t*)0x20000720 = 0x2a12;
*(uint32_t*)0x20000724 = 0;
*(uint32_t*)0x20000728 = 0;
*(uint32_t*)0x2000072c = 0;
*(uint64_t*)0x20000730 = 0;
*(uint64_t*)0x20000738 = 0;
*(uint32_t*)0x20000740 = 0;
*(uint32_t*)0x20000744 = 0;
*(uint32_t*)0x20000748 = 0;
syscall(__NR_bpf, /*cmd=*/0xaul, /*arg=*/0x20000700ul, /*size=*/0x50ul);
}
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
/*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
/*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul,
/*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
/*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
/*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
/*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
/*offset=*/0ul);
setup_sysctl();
const char* reason;
(void)reason;
loop();
return 0;
}
```