[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    Re: [oss-security] CVE-2020-10708 kernel: race condition in kernel/audit.c may allow low privilege u
From:       Steve Grubb <sgrubb () redhat ! com>
Date:       2020-04-17 13:24:42
Message-ID: 7526463.NqbLCg6IT0 () x2
[Download RAW message or body]

On Friday, April 17, 2020 12:40:10 AM EDT 陈伟宸(田各) wrote:
> "A race condition was found in the Linux kernel audit subsystem. When the
> system is configured to panic on events being dropped, an attacker who is
> able to trigger an audit event that starts while auditd is in the process
> of starting may be able to cause the system to panic by exploiting a race
> condition in audit event handling. This creates a denial of service by
> causing a panic."

While this is theoretically possible, starting the audit daemon requires 
privileges. As root, you can do many worse things. Or just call panic 
yourself. In practice, there isn't really a problem because the audit daemon 
starts, registers the pid, then the rules get loaded. So, I'd say yes there 
is a race that should get fixed. But you're shooting yourself in the foot for 
looping on restarting the audit daemon as root.

Also, there is a configuration option, --backlog_wait_time, which also has 
something to do with whether or not panic will get called.

-Steve

> https://bugzilla.redhat.com/show_bug.cgi?id=1822593
> 
> Env:
>     Red Hat Enterprise Linux Server release 7.7 (Maipo)
>     3.10.0-1062.12.1.el7.x86_64
> 
> Details:
> Function audit_log_end and audit_panic may have race conditions when auditd
> is restarting because audit_pid can be NULL in audit_log_end and then
> become not NULL in audit_panic, which may allow attackers to trigger
> kernel panic. Here is panic call stack:
> 
> 
> void audit_log_end(struct audit_buffer *ab)
> {
>     if (!ab)
>         return;
>     if (!audit_rate_check()) {
>         audit_log_lost("rate limit exceeded");
>     } else {
>         struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
>         nlh->nlmsg_len = ab->skb->len - NLMSG_HDRLEN;
> 
>         if (audit_pid) {
>             skb_queue_tail(&audit_skb_queue, ab->skb);
>             wake_up_interruptible(&kauditd_wait);
>         } else {
>             audit_printk_skb(ab->skb); // <- audit_pid == NULL when auditd
> is killed }
>         ab->skb = NULL;
>     }
>     audit_buffer_free(ab);
> }
> -> audit_printk_skb -> audit_log_lost ->
> void audit_panic(const char *message)
> {
>     switch (audit_failure)
>     {
>     case AUDIT_FAIL_SILENT:
>         break;
>     case AUDIT_FAIL_PRINTK:
>         if (printk_ratelimit())
>             printk(KERN_ERR "audit: %s\n", message);
>         break;
>     case AUDIT_FAIL_PANIC:
>         /* test audit_pid since printk is always losey, why bother? */
>         if (audit_pid) // <- audit_pid not NULL because auditd is
> restarting panic("audit: %s\n", message);
>         break;
>     }
> }
> 
> How to reproduce:
> 1. set audit-failure to AUDIT_FAIL_PANIC(2) and add a random audit rule
> like: [root@test ~]# cat /etc/audit/rules.d/audit.rules
> -D
> -b 8192
> -f 2
> -w /etc/hosts -p rwa -k hosts
> 2. keep killing auditd and then starting auditd, for example:
> while true; do ps aux | grep "/sbin/auditd" | grep -v "grep" | awk '{print
> $2}' | xargs kill; service auditd start; systemctl reset-failed
> auditd.service; done 3. log in a low privilege user and keep reading
> /etc/hosts, for example: while true; do cat /etc/hosts > /dev/null; done
> 4. kernel panic will happen within several minutes
> 
> Thanks.




[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic