Technical Advisory – Multiple Vulnerabilities in U-Boot (CVE-2022-30790, CVE-2022-30552)

By Nicolas Bidron, and Nicolas Guigo.

U-boot is a popular boot loader for embedded systems with implementations for a large number of architectures and prominent in most Linux based embedded systems such as ChromeOS and Android Devices.

Two vulnerabilities were uncovered in the IP Defragmentation algorithm implemented in U-Boot, with the associated technical advisories below:

  • Technical Advisory – Hole Descriptor Overwrite in U-Boot IP Packet Defragmentation Leads to Arbitrary Out of Bounds Write Primitive (CVE-2022-30790)
  • Technical Advisory – Large buffer overflow leads to DoS in U-Boot IP Packet Defragmentation Code (CVE-2022-30552)

Proof of concept code will be made available once the fixes have been published.

Technical Advisories:

Hole Descriptor Overwrite in U-Boot IP Packet Defragmentation Leads to Arbitrary Out of Bounds Write Primitive (CVE-2022-30790)

ProjectU-Boot
Project URLhttps://github.com/u-boot/u-boot
Versions affectedall versions up to commit TBD
Systems affectedAll systems defining CONFIG_IP_DEFRAG
CVE identifierCVE-2022-30790
Advisory URLTBD
RiskCritical 9.6 (CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
AuthorsNicolas Guigo, Nicolas Bidron

Summary

U-boot is a popular boot loader for embedded systems with implementations for a large number of architectures and prominent in most linux based embedded systems.

Location

In u-boot/net/net.c the __net_defragment function line 900 through 1018.

Impact

The U-Boot implementation of RFC815 IP DATAGRAM REASSEMBLY ALGORITHMS is susceptible to a Hole Descriptor overwrite attack which ultimately leads to an arbitrary write primitive.

Description

In compiled versions of U-Boot that define CONFIG_IP_DEFRAG, a value of ip->ip_len (IP packet header’s total Length) higher than IP_HDR_SIZE and strictly lower than IP_HDR_SIZE+8 leads to a value for len comprised between 0 and 7. This ultimately results in a truncated division by 8 resulting in a value of 0, forcing the hole metadata and fragment to point to the same location. The subsequent memcpy then overwrites the hole metadata with the fragment data. Through a second fragment, this attacker-controlled metadata can be exploited to perform a controlled write to an arbitrary offset.

This bug is only exploitable from the local network as it requires crafting a malformed packet which would most likely be dropped during routing. However, this it can be effectively leveraged to root linux based embedded devices locally.

static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
{
	static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
	static u16 first_hole, total_len;
	struct hole *payload, *thisfrag, *h, *newh;
	struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
	uchar *indata = (uchar *)ip;
	int offset8, start, len, done = 0;
	u16 ip_off = ntohs(ip->ip_off);

	/* payload starts after IP header, this fragment is in there */
	payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
	offset8 =  (ip_off & IP_OFFS);
	thisfrag = payload + offset8;
	start = offset8 * 8;
	len = ntohs(ip->ip_len) - IP_HDR_SIZE;

The last line of the previous excerpt from u-boot/net/net.c shows how the attacker can control the value of len to be strictly lower than 8 by issuing a packet with ip_len between 21 and 27 (IP_HDR_SIZE has a value of 20).

Also note that offset8 here is 0 which leads to thisfrag = payload.

	} else if (h >= thisfrag) {
		/* overlaps with initial part of the hole: move this hole */
		newh = thisfrag + (len / 8);
		*newh = *h;
		h = newh;
		if (h->next_hole)
			payload[h->next_hole].prev_hole = (h - payload);
		if (h->prev_hole)
			payload[h->prev_hole].next_hole = (h - payload);
		else
			first_hole = (h - payload);

	} else {

Later in the same function, execution reaches the above code path. Here, len / 8 evaluates to 0 leading to newh = thisfrag. Also note that first_hole here is 0 since h and payload point to the same location.

	/* finally copy this fragment and possibly return whole packet */
	memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);

In the above excerpt the call to memcpy() overwrites the hole metadata (since thisfrag and h both point to the same location) with arbitrary data from the fragmented IP packet data. With a len value of 6, last_byte, next_hole, and prev_hole of the first_hole all end- up attacker-controlled.

Finally the arbitrary write is triggered by sending a second fragment packet, whose offset and length only need to fit within the hole pointed to by the previously controlled metadata (next_hole) set from the first packet.

Recommendation

This bug was disclosed to U-Boot support team and will be fixed in an upcoming patch. Update to the latest master branch version once the fix has been committed.

Large buffer overflow leads to DoS in U-Boot IP Packet Defragmentation Code (CVE-2022-30552)

ProjectU-Boot
Project URLhttps://github.com/u-boot/u-boot
Versions affectedall versions up to commit TBD
Systems affectedAll systems defining CONFIG_IP_DEFRAG
CVE identifierCVE-2022-30552
Advisory URLTBD
RiskHigh 7.1 (CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H)
AuthorsNicolas Guigo, Nicolas Bidron

Summary

U-boot is a popular boot loader for embedded systems with implementations for a large number of architectures and prominent in most linux based embedded systems.

Location

u-boot/net/net.c lines 915 and 1011.

Impact

The U-Boot implementation of RFC815 IP DATAGRAM REASSEMBLY ALGORITHMS is susceptible to a buffer overflow through a specially crafted fragmented IP Datagram with an invalid total length which causes a denial of service.

Description

In compiled versions of U-Boot that define CONFIG_IP_DEFRAG, a value of ip->ip_len (IP packet header’s total length) lower than IP_HDR_SIZE leads to len taking a negative value, which ultimately results in a buffer overflow during the subsequent call to memcpy() that uses len as its count parameter.

This bug is only exploitable from the local network as it requires crafting a malformed packet with an ip_len value lower than the minimum accepted total length (21 as defined in the IP specification document: RFC791) which would most likely be dropped during routing.

static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
{
	static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
	static u16 first_hole, total_len;
	struct hole *payload, *thisfrag, *h, *newh;
	struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
	uchar *indata = (uchar *)ip;
	int offset8, start, len, done = 0;
	u16 ip_off = ntohs(ip->ip_off);

	/* payload starts after IP header, this fragment is in there */
	payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
	offset8 =  (ip_off & IP_OFFS);
	thisfrag = payload + offset8;
	start = offset8 * 8;
	len = ntohs(ip->ip_len) - IP_HDR_SIZE;

The last line of the previous excerpt from u-boot/net/net.c shows where the underflow to a negative len value occurs if ip_len is set to a value strictly lower than 20 (IP_HDR_SIZE being 20). Also note that in the above excerpt the pkt_buff buffer has a size of CONFIG_NET_MAXDEFRAG which defaults to 16 KB but can range from 1KB to 64 KB depending on configurations.

	/* finally copy this fragment and possibly return whole packet */
	memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);

In the above excerpt the memcpy() overflows the destination by attempting to make a copy of nearly 4 gigabytes in a buffer that’s designed to hold CONFIG_NET_MAXDEFRAG bytes at most, which leads to a DoS.

Recommendation

This bug was disclosed to U-Boot support team and will be fixed in an upcoming patch. Update to the latest master branch version once the fix has been committed.

Disclosure Timeline

May 18th 2022: Initial e-mail from NCC to U-boot maintainers announcing two vulnerabilities were identified. U-Boot maintainers responded indicating that the disclosure process is to be handled publicly through U-Boot’s mailing list.

May 18th 2022: NCC posted a full writeup of the two vulnerabilities identified to U-Boot’s public mailing list.

May 25th 2022: a U-Boot maintainer indicated on the mailing list that they will implement a fix to the two findings.

May 26th 2022: a patch has been proposed by U-Boot maintainers to fix both CVEs through the mailing list.

May 31st 2022: U-boot maintainers and NCC Group agree to publishing the advisories in advance of patch deployment, given the public mailing-list-based discussion of the vulnerability and proposed fixes.

Thanks to

Jennifer Fernick, and Dave Goldsmith for their support through the disclosure process.

U-Boot’s maintainers.

Authors

Nicolas Guigo, and Nicolas Bidron