Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Date: Fri, 22 Sep 2023 13:15:43 -0700
From: Kyle Zeng <zengyhkyle@...il.com>
To: oss-security@...ts.openwall.com
Subject: [CVE-2023-42753] Array Indexing error in Linux kernel

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..

View attachment "poc.c" of type "text/x-csrc" (3679 bytes)

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.