oss-sec mailing list archives
[CVE-2023-42753] Array Indexing error in Linux kernel
From: Kyle Zeng <zengyhkyle () gmail com>
Date: Fri, 22 Sep 2023 13:15:43 -0700
Hi there, I recently found an array indexing vulnerability in the netfilter ipset subsystem in Linux, which I believe is exploitable in some systems because of its nature to increment/decrement pointers out-of-bound. I confirm that this bug affects at least upstream, 6.1, 5.15, and 5.10. [Root Cause] The root cause of the vulnerability is a missing IP_SET_HASH_WITH_NET0 macro in `ip_set_hash_netportnet`, which leads it to use the wrong wrong `CIDR_POS(c)` macro for calulating array offsets. More specifically, IP_SET_HASH_WITH_NET0 decides how to calculate the the index to access `h->nets`. ~~~ #ifdef IP_SET_HASH_WITH_NET0 /* cidr from 0 to HOST_MASK value and c = cidr + 1 */ #define NLEN (HOST_MASK + 1) #define CIDR_POS(c) ((c) - 1) #else /* cidr from 1 to HOST_MASK value and c = cidr + 1 */ #define NLEN HOST_MASK #define CIDR_POS(c) ((c) - 2) #endif ~~~ Previously when IP_SET_HASH_WITH_NET0 was missing, users can pass in a cidr == 0, which leads to `NCIDR_PUT(DCIDR_GET(d->cidr, i))` in `hash_netportnet6_add` (generated by `mtype_add`) resolved to 1. This will lead to `cidr=1` passed to `hash_netportnet6_add_cidr` (generated by `mtype_add_cidr`). And finally, depending on the compiler, `CIDR_POS(cidr)` may be resolved to one of (-1, 0xff, 0xffffffff), leading to out-of-bound access in `h->nets[CIDR_POS(cidr)].nets[n]`. Notice that `cidr`'s type is `u8`, which means the expected value here is 0xff. But depending on the compiler, it can be resolved to different values. Vegard Nossum let me know that they could only make it -1 indexing on amd64 systems. I expect the value to be different on different architectures. In the worst case, it can lead to slab-out-of-bound access, which is likely exploitable as demonstrated as follows. [Severity] mtype_add_cidr/mtype_del_cidr contain snippets like the following: ~~~ static void mtype_add_cidr(...) { ... h->nets[CIDR_POS(cidr)].nets[n]++; ... } static void mtype_del_cidr(...) { ... h->nets[CIDR_POS(cidr)].nets[n]--; ... } ~~~ This provides attackers with the primitive to arbitrarily increment/decrement a memory out-of-bound, which is likely exploitable. For example, attackers can manipulate a buffer pointer to obtain OOB read/write primitive; or increase the length of a buffer, to read/write out of bound. [Patch] I already contacted the linux kernel security and a patch can be found here: https://git.kernel.org/linus/050d91c03b28ca479df13dfb02bcd2c60dd6a878 [Proof-of-Concept] A proof-of-concept code to trigger the bug is attached to this email. Thanks, Kyle Zeng ===================== [Splash] ======================== [ 6.059960] UBSAN: array-index-out-of-bounds in net/netfilter/ipset/ip_set_hash_gen.h:344:2 [ 6.061493] index -1 is out of range for type 'struct net_prefixes[128]' [ 6.062601] CPU: 0 PID: 452 Comm: poc Not tainted 6.5.0+ #56 [ 6.063538] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [ 6.064455] Call Trace: [ 6.064570] <TASK> [ 6.064675] dump_stack_lvl+0x54/0x70 [ 6.064848] __ubsan_handle_out_of_bounds+0xd6/0x100 [ 6.065064] hash_netportnet6_add+0x1667/0x26d0 [ 6.065264] hash_netportnet6_uadt+0xa81/0x1250 [ 6.065462] ? hash_netportnet6_uadt+0x1250/0x1250 [ 6.065671] call_ad+0x1c6/0x850 [ 6.065836] ? ip_set_create+0x9a1/0x1120 [ 6.066019] ? deref_stack_reg+0x17f/0x210 [ 6.066202] ip_set_ad+0x68e/0x7d0 [ 6.066358] ? mutex_lock+0x76/0xc0 [ 6.066515] nfnetlink_rcv_msg+0x6a7/0x830 [ 6.066704] netlink_rcv_skb+0x166/0x340 [ 6.066882] ? nfnetlink_unbind+0x180/0x180 [ 6.067077] nfnetlink_rcv+0x22d/0x1e70 [ 6.067266] ? kasan_set_track+0x5e/0x70 [ 6.067450] ? kasan_set_track+0x4c/0x70 [ 6.067692] ? __kasan_slab_alloc+0x47/0x60 [ 6.067920] ? slab_post_alloc_hook+0x94/0x300 [ 6.068150] ? kmem_cache_alloc_node+0x13b/0x2d0 [ 6.068386] ? kmalloc_reserve+0x73/0x1f0 [ 6.068581] ? __alloc_skb+0x111/0x360 [ 6.068758] ? netlink_sendmsg+0x513/0x9f0 [ 6.068951] ? sock_sendmsg+0x24e/0x270 [ 6.069133] ? __sys_sendto+0x29f/0x390 [ 6.069340] ? __x64_sys_sendto+0xda/0xf0 [ 6.069534] ? do_syscall_64+0x67/0x90 [ 6.069762] ? entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 6.070046] ? __kasan_slab_alloc+0x47/0x60 [ 6.070305] ? slab_post_alloc_hook+0x94/0x300 [ 6.070551] ? __netlink_lookup+0x2fa/0x310 [ 6.070787] netlink_unicast+0x690/0x880 [ 6.070996] netlink_sendmsg+0x690/0x9f0 [ 6.071220] ? netlink_getsockopt+0x3c0/0x3c0 [ 6.071443] sock_sendmsg+0x24e/0x270 [ 6.071638] __sys_sendto+0x29f/0x390 [ 6.071833] __x64_sys_sendto+0xda/0xf0 [ 6.072029] do_syscall_64+0x67/0x90 [ 6.072212] ? exit_to_user_mode_prepare+0x12/0xa0 [ 6.072458] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 6.072729] RIP: 0033:0x474100 [ 6.072893] Code: 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 1d 45 31 c9 45 31 c0 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 68 c3 0f 1f 80 00 00 00 00 41 54 48 83 ec 20 [ 6.074338] RSP: 002b:00007ffcec95abf8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c [ 6.074747] RAX: ffffffffffffffda RBX: 00007ffcec95af08 RCX: 0000000000474100 [ 6.075128] RDX: 0000000000000074 RSI: 0000000002f10490 RDI: 0000000000000005 [ 6.075515] RBP: 00007ffcec95ad10 R08: 0000000000000000 R09: 0000000000000000 [ 6.075881] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001 [ 6.076241] R13: 00007ffcec95aef8 R14: 00000000004fd740 R15: 0000000000000002 [ 6.076619] </TASK> [ 6.076755] ================================================================================ [ 6.077187] Kernel panic - not syncing: UBSAN: panic_on_warn set ... [ 6.077511] CPU: 0 PID: 452 Comm: poc Not tainted 6.5.0+ #56 [ 6.077803] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [ 6.078221] Call Trace: [ 6.078358] <TASK> [ 6.078479] dump_stack_lvl+0x54/0x70 [ 6.078682] panic+0x192/0x4d0 [ 6.078854] check_panic_on_warn+0x5a/0x70 [ 6.079080] __ubsan_handle_out_of_bounds+0xf5/0x100 [ 6.079351] hash_netportnet6_add+0x1667/0x26d0 [ 6.079602] hash_netportnet6_uadt+0xa81/0x1250 [ 6.079896] ? hash_netportnet6_uadt+0x1250/0x1250 [ 6.080199] call_ad+0x1c6/0x850 [ 6.080400] ? ip_set_create+0x9a1/0x1120 [ 6.080654] ? deref_stack_reg+0x17f/0x210 [ 6.080886] ip_set_ad+0x68e/0x7d0 [ 6.081077] ? mutex_lock+0x76/0xc0 [ 6.081271] nfnetlink_rcv_msg+0x6a7/0x830 [ 6.081499] netlink_rcv_skb+0x166/0x340 [ 6.081714] ? nfnetlink_unbind+0x180/0x180 [ 6.081949] nfnetlink_rcv+0x22d/0x1e70 [ 6.082161] ? kasan_set_track+0x5e/0x70 [ 6.082375] ? kasan_set_track+0x4c/0x70 [ 6.082590] ? __kasan_slab_alloc+0x47/0x60 [ 6.082819] ? slab_post_alloc_hook+0x94/0x300 [ 6.083065] ? kmem_cache_alloc_node+0x13b/0x2d0 [ 6.083316] ? kmalloc_reserve+0x73/0x1f0 [ 6.083536] ? __alloc_skb+0x111/0x360 [ 6.083745] ? netlink_sendmsg+0x513/0x9f0 [ 6.083965] ? sock_sendmsg+0x24e/0x270 [ 6.084159] ? __sys_sendto+0x29f/0x390 [ 6.084355] ? __x64_sys_sendto+0xda/0xf0 [ 6.084561] ? do_syscall_64+0x67/0x90 [ 6.084774] ? entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 6.085041] ? __kasan_slab_alloc+0x47/0x60 [ 6.085253] ? slab_post_alloc_hook+0x94/0x300 [ 6.085479] ? __netlink_lookup+0x2fa/0x310 [ 6.085690] netlink_unicast+0x690/0x880 [ 6.085895] netlink_sendmsg+0x690/0x9f0 [ 6.086097] ? netlink_getsockopt+0x3c0/0x3c0 [ 6.086319] sock_sendmsg+0x24e/0x270 [ 6.086511] __sys_sendto+0x29f/0x390 [ 6.086701] __x64_sys_sendto+0xda/0xf0 [ 6.086914] do_syscall_64+0x67/0x90 [ 6.087098] ? exit_to_user_mode_prepare+0x12/0xa0 [ 6.087339] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 6.087593] RIP: 0033:0x474100 [ 6.087760] Code: 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 1d 45 31 c9 45 31 c0 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 68 c3 0f 1f 80 00 00 00 00 41 54 48 83 ec 20 [ 6.088707] RSP: 002b:00007ffcec95abf8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c [ 6.089087] RAX: ffffffffffffffda RBX: 00007ffcec95af08 RCX: 0000000000474100 [ 6.089439] RDX: 0000000000000074 RSI: 0000000002f10490 RDI: 0000000000000005 [ 6.089807] RBP: 00007ffcec95ad10 R08: 0000000000000000 R09: 0000000000000000 [ 6.090161] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001 [ 6.090524] R13: 00007ffcec95aef8 R14: 00000000004fd740 R15: 0000000000000002 [ 6.090894] </TASK> [ 6.091463] Kernel Offset: disabled [ 6.091676] Rebooting in 1000 seconds..
Attachment:
poc.c
Description:
Current thread:
- [CVE-2023-42753] Array Indexing error in Linux kernel Kyle Zeng (Sep 22)