oss-sec mailing list archives

[CVE-2023-42752] integer overflow in Linux kernel leading to exploitable memory access


From: Kyle Zeng <zengyhkyle () gmail com>
Date: Mon, 18 Sep 2023 13:54:03 -0700

Hi there,

I recently found an integer overflow in the Linux kernel, which leads
to the kernel allocating `skb_shared_info` in the userspace, which is
exploitable in systems without SMAP protection since `skb_shared_info`
contains references to function pointers.

I verified the existence of the vulnerability on both the main tree
and v6.1.y, more versions may be affected (potentially all stable
trees).

[Root Cause]

The root cause of the vulnerability is an insufficient check for
integer overflow in `__alloc_skb`. As shown below:
```
struct sk_buff *__alloc_skb(unsigned int size, ...)
{
        ......
        data = kmalloc_reserve(&size, gfp_mask, node, &pfmemalloc);
        if (unlikely(!data))
                goto nodata;
        ......
}
```
`size` is an `unsigned int` and it is potentially controlled by users.
In `kmalloc_reserve`, it will round up the size by `PAGE_SIZE <<
get_order(size);` in `kmalloc_size_roundup`. Since `size` is `unsigned
int`, the roundup logic will make it 0 if the original value is
something huge such as 0xfffffed0. As a result, `data` will actually
become `ZERO_SIZE_PTR`, which is 0x10 instead of 0. Since the check
does not consider the case, the kernel will happily continue
processing the `data` as if it is a valid kernel pointer.

Later when the kernel tries to finalize the skb object in
`__finalize_skb_around`, it has the code: `shinfo = skb_shinfo(skb);`,
which is `skb->head+skb->end` where `skb->head` is 0x10 and `skb->end`
is a large size such as 0xfffffed0. As a result, `shinfo` points to a
userspace pointer.

The kernel crashes at `memset(shinfo, 0, offsetof(struct
skb_shared_info, dataref));` in systems with SMAP enabled.

The root cause of the bug was introduced in v6.2-rc1 in
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=12d6c1d3a2ad.
But it gets backported to all stable trees, which may potentially
introduce the bug to stable trees (that's why I could trigger the bug
in v6.1.y). According to Vegard Nossum, this is the backported buggy
patch: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=0dbc898f5917

[Impact]

* The vulnerability is likely exploitable in systems without SMAP
protection since `shinfo` has a function pointer member
`destructor_arg`. Attackers can overwrite it to obtain code execution
in kernel space.
* The vulnerability can lead to local DoS from a user having access to
user namespace
* The vulnerability cannot be triggered remotely according to Eric Dumazet

[Patch]

I already contacted the linux kernel security team and assisted them
in fixing the vulnerability.
The patch consists of two commits:
[1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=915d975b2ffa
[2] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=c3b704d4a4a2

[Proof-of-Concept]

A crashing poc is attached.

Thanks,
Kyle Zeng

=================[Crashing Splash]==========================

[    4.367486] BUG: unable to handle page fault for address: 00000000fffffed0
[    4.367792] #PF: supervisor write access in kernel mode
[    4.368029] #PF: error_code(0x0002) - not-present page
[    4.368260] PGD da2f067 P4D da2f067 PUD 0
[    4.368447] Oops: 0002 [#1] PREEMPT SMP KASAN NOPTI
[    4.368668] CPU: 0 PID: 440 Comm: poc Tainted: G        W          6.5.0+ #47
[    4.368987] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS 1.15.0-1 04/01/2014
[    4.369355] RIP: 0010:memset_orig+0x72/0xac
[    4.369546] Code: 47 28 48 89 47 30 48 89 47 38 48 8d 7f 40 75 d8
0f 1f 84 00 00 00 00 00 89 d1 83 e1 38 74 14 c1 e9 03 66 0f 1f 44 00
00 ff c9 <48> 89 07 48 8d 7f 08 75 f5 83 e2 07 74 0a ff ca 88 07 48 8d
7f 01
[    4.370379] RSP: 0000:ffff88800e627a48 EFLAGS: 00010206
[    4.370626] RAX: 0000000000000000 RBX: 0000000000000010 RCX: 0000000000000003
[    4.370947] RDX: 0000000000000020 RSI: 0000000000000000 RDI: 00000000fffffed0
[    4.371263] RBP: 00000000fffffec0 R08: ffff88800d8faad7 R09: 0000000000000000
[    4.371580] R10: 00000000fffffed0 R11: ffffed1001b1f55b R12: 1ffff11001b1f557
[    4.371896] R13: ffff88800d8faac0 R14: dffffc0000000000 R15: 1ffff11001b1f558
[    4.372212] FS:  000000000207a3c0(0000) GS:ffff888036000000(0000)
knlGS:0000000000000000
[    4.372568] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    4.372825] CR2: 00000000fffffed0 CR3: 000000001115c005 CR4: 0000000000770ef0
[    4.373147] PKRU: 55555554
[    4.373278] Call Trace:
[    4.373392]  <TASK>
[    4.373491]  ? __die_body+0x67/0xb0
[    4.373653]  ? page_fault_oops+0x65a/0x7f0
[    4.373839]  ? exc_page_fault+0x76/0xe0
[    4.374013]  ? asm_exc_page_fault+0x22/0x30
[    4.374202]  ? memset_orig+0x72/0xac
[    4.374371]  __build_skb_around+0x202/0x3c0
[    4.374560]  __alloc_skb+0x214/0x4e0
[    4.374724]  igmpv3_newpack+0xf8/0xfb0
[    4.374895]  add_grhead+0x6e/0x2b0
[    4.375051]  add_grec+0xfcf/0x12d0
[    4.375216]  igmp_ifc_timer_expire+0x72c/0xd20
[    4.375412]  ? igmp_gq_timer_expire+0x90/0x90
[    4.375614]  call_timer_fn+0xb9/0x1c0
[    4.375781]  ? igmp_gq_timer_expire+0x90/0x90
[    4.375984]  __run_timers+0x683/0x790
[    4.376148]  run_timer_softirq+0x46/0x80
[    4.376330]  __do_softirq+0x22e/0x51e
[    4.376497]  __irq_exit_rcu+0x6f/0x120
[    4.376673]  sysvec_apic_timer_interrupt+0x43/0xb0
[    4.376884]  asm_sysvec_apic_timer_interrupt+0x16/0x20
[    4.377119] RIP: 0033:0x401e38
[    4.377260] Code: 53 07 00 89 45 bc 8b 05 3a 36 10 00 48 8d 55 b8
41 b8 08 00 00 00 48 89 d1 ba 23 00 00 00 be 00 00 00 00 89 c7 e8 c8
32 07 00 <eb> fe f3 0f 1e fa 55 48 89 e5 48 83 ec 70 48 89 7d 98 48 89
75 90
[    4.378101] RSP: 002b:00007ffc1f22b390 EFLAGS: 00000207
[    4.378370] RAX: 0000000000000000 RBX: 00007ffc1f22b5d8 RCX: 000000000047510e
[    4.378725] RDX: 0000000000000023 RSI: 0000000000000000 RDI: 0000000000000006
[    4.379060] RBP: 00007ffc1f22b3e0 R08: 0000000000000008 R09: 0000000000000000
[    4.379385] R10: 00007ffc1f22b398 R11: 0000000000000206 R12: 0000000000000001
[    4.379717] R13: 00007ffc1f22b5c8 R14: 00000000004ff740 R15: 0000000000000002
[    4.380048]  </TASK>
[    4.380152] Modules linked in:
[    4.380296] CR2: 00000000fffffed0
[    4.380451] ---[ end trace 0000000000000000 ]---
[    4.380661] RIP: 0010:memset_orig+0x72/0xac
[    4.380851] Code: 47 28 48 89 47 30 48 89 47 38 48 8d 7f 40 75 d8
0f 1f 84 00 00 00 00 00 89 d1 83 e1 38 74 14 c1 e9 03 66 0f 1f 44 00
00 ff c9 <48> 89 07 48 8d 7f 08 75 f5 83 e2 07 74 0a ff ca 88 07 48 8d
7f 01
[    4.381706] RSP: 0000:ffff88800e627a48 EFLAGS: 00010206
[    4.381949] RAX: 0000000000000000 RBX: 0000000000000010 RCX: 0000000000000003
[    4.382275] RDX: 0000000000000020 RSI: 0000000000000000 RDI: 00000000fffffed0
[    4.382607] RBP: 00000000fffffec0 R08: ffff88800d8faad7 R09: 0000000000000000
[    4.382926] R10: 00000000fffffed0 R11: ffffed1001b1f55b R12: 1ffff11001b1f557
[    4.383271] R13: ffff88800d8faac0 R14: dffffc0000000000 R15: 1ffff11001b1f558
[    4.383590] FS:  000000000207a3c0(0000) GS:ffff888036000000(0000)
knlGS:0000000000000000
[    4.384012] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    4.384298] CR2: 00000000fffffed0 CR3: 000000001115c005 CR4: 0000000000770ef0
[    4.384635] PKRU: 55555554
[    4.384763] Kernel panic - not syncing: Fatal exception in interrupt
[    4.385239] Kernel Offset: disabled
[    4.385413] Rebooting in 1000 seconds..

Attachment: poc.c
Description:


Current thread: