All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ramon Fried <rfried.dev@gmail.com>
To: Nicolas Bidron <nicolas.bidron@nccgroup.com>
Cc: "u-boot@lists.denx.de" <u-boot@lists.denx.de>,
	"joe.hershberger@ni.com" <joe.hershberger@ni.com>,
	 "trini@konsulko.com" <trini@konsulko.com>
Subject: Re: Vulnerability Disclosure in net/
Date: Thu, 26 May 2022 05:46:08 +0300	[thread overview]
Message-ID: <CAGi-RUJZwY197Tp5NKdOW8OYMBHvw453ZiwpG_1Y7wzh6wxADw@mail.gmail.com> (raw)
In-Reply-To: <c043a092-ab03-585c-2ce2-7531389acb27@nccgroup.com>

On Wed, May 18, 2022 at 7:14 PM Nicolas Bidron
<nicolas.bidron@nccgroup.com> wrote:
>
> Hello,
>
> We found a couple of bugs in net/net.s in the IP defragmentation
> function __net_defragment(). Below the writeup for the 2 bugs:
>
> -----------BUG 1-----------
>
> # Hole Descriptor Overwrite in U-Boot IP Packet Defragmentation Leads to
> Arbitrary Out of Bounds Write Primitive (CVE-TBD)
>
> |  |  |
> | --- | --- |
> |Project | U-Boot |
> |Project URL | https://github.com/u-boot/u-boot |
> |Versions affected | all versions up to commit TBD |
> |Systems affected | All systems defining `CONFIG_IP_DEFRAG` |
> |CVE identifier | TBD |
> |Advisory URL | TBD |
> |Risk | Critical 9.6 (CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
> |Authors | Nicolas 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](https://datatracker.ietf.org/doc/html/rfc815) IP DATAGRAM
> REASSEMBLY ALGORITHMS is susceptible to a Hole Descriptor overwrite
> attack which ultimately leads to an arbitrary write primitve.
>
> ### 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` will lead to a value for `len`
> comprised between `0` and `7`. This will ultimately result in a
> truncated division by `8` resulting value of `0` forcing the hole
> metadata and fragment to point to the same location. The subsequent
> memcopy will overwrite the hole metadata with the fragment data. Through
> a second fragment, this can be exploited to write to an arbitrary offset
> controlled by that overwritten hole metadata value.
>
> This bug is only exploitable locally as it requires crafting two packets
> the first of which would most likely be dropped through routing due to
> its unexpectedly low Total Length. However, this bug can potentially be
> exploited to root linux based embedded devices locally.
>
> ```C
> 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`.
>
> ```C
>      } 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 {
> ```
>
> Lower down 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.
>
> ```C
>      /* finally copy this fragment and possibly return whole packet */
>      memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);
> ```
>
> Finally, in the above excerpt the `memcpy` overwrites the hole metadata
> since `thisfrag` and `h` both point to the same location. The hole
> metadata is effectively overwritten with arbitrary data from the
> fragmented IP packet data. If `len` was crafted to be `6`, `last_byte`,
> `next_hole`, and `prev_hole` of the `first_hole` can be controlled by
> the attacker.
>
> Finally the arbitrary offset write occurs through a second fragment that
> only needs to be crafted to write data in the hole pointed to by the
> previously controlled hole metadata (`next_hole`) from the first packet.
>
> ### Recommendation
>
> Handle cases where `len` is strictly lower than 8 by preventing the
> overwrite of the hole metadata during the memcpy of the fragment. This
> could be achieved by either:
> * Moving the location where the hole metadata is stored when `len` is
> lower than `8`.
> * Or outright rejecting fragmented IP datagram with a Total Length
> (`ip_len`) lower than 28 bytes which is the minimum valid fragmented IP
> datagram size (as defined as the minimum fragment of 8 octets in the IP
> Specification Document:
> [RFC791](https://datatracker.ietf.org/doc/html/rfc791) page 25).
>
> ----------BUG 2----------
>
> # Large buffer overflow leads to DoS in U-Boot IP Packet Defragmentation
> Code (CVE-TBD)
>
> |  |  |
> | --- | --- |
> |Project | U-Boot |
> |Project URL | https://github.com/u-boot/u-boot |
> |Versions affected | all versions up to commit TBD |
> |Systems affected | All systems defining `CONFIG_IP_DEFRAG` |
> |CVE identifier | TBD |
> |Advisory URL | TBD |
> |Risk | High 7.1 (CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H) |
> |Authors | Nicolas 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](https://datatracker.ietf.org/doc/html/rfc815) IP DATAGRAM
> REASSEMBLY ALGORITHMS is susceptible to a buffer overflow through a
> specially crafted fragmented IP Datagram with an invalid Total Length
> which creates Denial of Service conditions.
>
> ### 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`
> will lead to a negative value for `len` which will ultimately result in
> a buffer overflow during the subsequent `memcpy` that uses `len` as it's
> `count` parameter.
>
> This bug is only exploitable on local ethernet as it requires crafting
> an invalid packet to include an unexpected `ip_len` value in the IP UDP
> header that's lower than the minimum accepted Total Length of a packet
> (21 as defined in the IP Specification Document:
> [RFC791](https://datatracker.ietf.org/doc/html/rfc791)). Such packet
> would in all likelihood be dropped while being routed to its final
> destination through most routing equipment and as such requires the
> attacker to be in a local position in order to be exploited.
>
> ```C
> 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 undeflow 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.
>
> ```C
>      /* 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
>
> Stop processing of the packet if `ip_len` is lower than 21 (as defined
> by the minimum length of a data carrying datagram in the IP
> Specification Document:
> [RFC791](https://datatracker.ietf.org/doc/html/rfc791) page 34).
>
>
> Nicolas Bidron, Nicolas Guigo
>
Hi Nicolas,
Thanks for the research.
I have read your description thoroughly, very interesting.
I will implement fixes to the findings.
Thanks.
Ramon.

  reply	other threads:[~2022-05-26  2:46 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-18 16:14 Vulnerability Disclosure in net/ Nicolas Bidron
2022-05-26  2:46 ` Ramon Fried [this message]
2022-05-26 11:48   ` Matthias Brugger
2022-05-26 12:13   ` Fabio Estevam
2022-05-26 12:20     ` Michael Nazzareno Trimarchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAGi-RUJZwY197Tp5NKdOW8OYMBHvw453ZiwpG_1Y7wzh6wxADw@mail.gmail.com \
    --to=rfried.dev@gmail.com \
    --cc=joe.hershberger@ni.com \
    --cc=nicolas.bidron@nccgroup.com \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.