Bug 1715501 (CVE-2019-12381)

Summary: CVE-2019-12381 kernel: unchecked kmalloc of new_ra in ip_ra_control leads to denial of service
Product: [Other] Security Response Reporter: msiddiqu
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED NOTABUG QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: acaringi, airlied, bhu, blc, brdeoliv, bskeggs, dhoward, dongyang626, dvlasenk, esammons, fhrbata, hdegoede, hkrzesin, iboverma, ichavero, itamar, jarodwilson, jeremy, jforbes, jglisse, jkacur, john.j5live, jonathan, josef, jross, jstancek, jwboyer, kernel-maint, kernel-mgr, labbott, lgoncalv, linville, matt, mchehab, mcressma, mjg59, mlangsdo, nmurray, plougher, rt-maint, rvrbovsk, steved, williams, wmealing
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
A flaw was discovered in the Linux kernel that allows an attacker to crash a system under low-memory free conditions in the ipv4 router advertisement code. The attacker must be able to send 'router advertisements' which limits the attack vector to be on the same physical segment.
Story Points: ---
Clone Of: Environment:
Last Closed: 2019-11-20 14:12:35 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 1715502    
Bug Blocks: 1715562    

Description msiddiqu 2019-05-30 13:57:46 UTC
An issue was discovered in ip_ra_control in net/ipv4/ip_sockglue.c in the Linux kernel.  During low memory conditions a memory allocation may fail which could allow an attacker to cause a denial of service (NULL pointer dereference and possibly a system crash).

Upstream patch: 

https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git/commit/?id=425aa0e1d01513437668fa3d4a971168bbaa8515

References:  

https://lkml.org/lkml/2019/5/25/230

Comment 1 msiddiqu 2019-05-30 13:58:04 UTC
Created kernel tracking bugs for this issue:

Affects: fedora-all [bug 1715502]

Comment 5 Wade Mealing 2019-06-20 06:27:50 UTC
Investigation (Paraphrased):

The declared NULL ptr dereference within this function can not happen.

Reporting below the relevant code (pretty much unchanged since Red Hat Enterprise Linux 5  at its introduction):

        new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
	/* ^^^^ this is where it apparently can fail */

        mutex_lock(&net->ipv4.ra_mutex);
        for (rap = &net->ipv4.ra_chain;
             (ra = rcu_dereference_protected(*rap,
                        lockdep_is_held(&net->ipv4.ra_mutex))) != NULL;
             rap = &ra->next) {
                if (ra->sk == sk) {
                        if (on) {
                                mutex_unlock(&net->ipv4.ra_mutex);
                                kfree(new_ra); /* *************** kfree() would deal with a null here */
                                return -EADDRINUSE;
                        }
                        /* dont let ip_call_ra_chain() use sk again */
                        ra->sk = NULL;
                        RCU_INIT_POINTER(*rap, ra->next);
                        mutex_unlock(&net->ipv4.ra_mutex);

                        if (ra->destructor)
                                ra->destructor(sk);
                        /*
                         * Delay sock_put(sk) and kfree(ra) after one rcu grace
                         * period. This guarantee ip_call_ra_chain() dont need
                         * to mess with socket refcounts.
                         */
                        ra->saved_sk = sk;
                        call_rcu(&ra->rcu, ip_ra_destroy_rcu);
                        return 0;
                }
        }
        if (!new_ra) { /* ******* this is the null check that was believed to be missing, it bails here if null*/
                mutex_unlock(&net->ipv4.ra_mutex);
                return -ENOBUFS;
        }
        new_ra->sk = sk; /* THis part will never be executed/run if new_ra is null */
        new_ra->destructor = destructor; /* this part will never be dereferenced if new_ra is null */


Since kfree() is designed to handle correctly even NULL ptr, the above derefences of new_ra can not happen as they are protected by the immediate check above them.

Red Hat is open to discussion on this flaw if you have an an additional vector within the code please dont hesitate to put a discussion here and set NEEDINFO on wmealing.

Thanks!

Comment 6 dongyang626 2019-07-23 06:02:02 UTC
Hi Wade,

I have the same question with you. I can't find the risk from the new_ra as a C developer, if the 'new_ra = NULL', it will be checked before it is used. 
But I saw the linux-stable had merged this patch. The kernel maintainers may have a reason to do this. 
I'm not familiar about the 'NULL pointer dereference', maybe the attacker can use this?  

I really want to know the risk of this CVE. 
Anyone can help to explain?  Thanks a lot!

Best Regards,
Dongyang