ASA-2019-00485 – Das U-Boot: Unbounded memcpy with a failed length check at nfs_read_reply()/store_block()


Allele Security Alert

ASA-2019-00485

Identifier(s)

ASA-2019-00485, CVE-2019-14198

Title

Unbounded memcpy with a failed length check at nfs_read_reply()/store_block()

Vendor(s)

DENX Software Engineering

Product(s)

Das U-Boot

Affected version(s)

Unknown

Fixed version(s)

Unknown

Proof of concept

Unknown

Description

The problem exists in the NFSv3 case in the function nfs_read_reply() when reading a file and storing it into another medium (flash or physical memory) for later processing. The data and length is fully controlled by the attacker and never validated.

Technical details

static int nfs_read_reply(uchar *pkt, unsigned len)
{        [...]

    if (supported_nfs_versions & NFSV2_FLAG) {
        rlen = ntohl(rpc_pkt.u.reply.data[18]); // <-- rlen is attacker-controlled could be 0xFFFFFFFF
        data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]);
    } else {  /* NFSV3_FLAG */
        int nfsv3_data_offset =
            nfs3_get_attributes_offset(rpc_pkt.u.reply.data);

        /* count value */
        rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]); // <-- rlen is attacker-controlled
        /* Skip unused values :
            EOF:        32 bits value,
            data_size:  32 bits value,
        */
        data_ptr = (uchar *)
            &(rpc_pkt.u.reply.data[4 + nfsv3_data_offset]);
    }

    if (store_block(data_ptr, nfs_offset, rlen)) // <-- We pass to store_block source and length controlled by the attacker
            return -9999;

    [...]
}

Focusing on physical memory part of the store_block() function, it attempts to reserve some memory using the arch specific function map_physmem(), ending up calling phys_to_virt(). As you can see in the x86 implementation, when reserving physical memory it clearly ignores length and gives you a raw pointer without checking if surrounding areas are reserved (or not) for other purposes.

static inline void *phys_to_virt(phys_addr_t paddr)
{
        return (void *)(unsigned long)paddr;
}
static inline int store_block(uchar *src, unsigned offset, unsigned len)
{

[...]

 void *ptr = map_sysmem(load_addr + offset, len); // <-- essentially this is ptr = load_addr + offset
 memcpy(ptr, src, len); // <-- unrestricted overflow happens here
 unmap_sysmem(ptr);

[...]

}

Credits

Fermín Serna, Pavel Avgustinov and Kevin Backhouse

Reference(s)

U-Boot RCE Vulnerabilities Affecting IoT Devices
https://blog.semmle.com/uboot-remote-code-execution-vulnerability/

U-Boot NFS RCE Vulnerabilities (CVE-2019-14192)
https://blog.semmle.com/uboot-rce-nfs-vulnerability/

[U-Boot] Remote code execution vulnerabilities in U-Boot’s NFS and other IP parsing code
https://lists.denx.de/pipermail/u-boot/2019-July/378001.html

CVE-2019-14198
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-14198

CVE-2019-14198
https://nvd.nist.gov/vuln/detail/CVE-2019-14198

If there is any error in this alert or you wish a comprehensive analysis, let us know.

Last modified: August 8, 2019

We are not responsible for any data loss, device corruption or any other type of issue due to the use of any information mentioned in our security alerts.