summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSakib Sajal <sakib.sajal@windriver.com>2022-08-19 17:59:06 -0400
committerRichard Purdie <richard.purdie@linuxfoundation.org>2022-08-28 07:51:29 +0100
commitc78d028649c0684e61977d4d78c39195cb370990 (patch)
tree1ac1c9bfa1b1e8f7ff37ccf945c32c2b7b0608dc
parentee16bcef39ed7f97edbf53c97a7b087e0904af0b (diff)
downloadpoky-c78d028649c0684e61977d4d78c39195cb370990.tar.gz
u-boot: fix CVE-2022-30552
Backport patch to fix CVE-2022-30552. (From OE-Core rev: db5212cbe7537036108682f0f3a9316ca3c06fc1) Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/recipes-bsp/u-boot/files/0001-net-Check-for-the-minimum-IP-fragmented-datagram-siz.patch207
-rw-r--r--meta/recipes-bsp/u-boot/u-boot_2022.01.bb1
2 files changed, 208 insertions, 0 deletions
diff --git a/meta/recipes-bsp/u-boot/files/0001-net-Check-for-the-minimum-IP-fragmented-datagram-siz.patch b/meta/recipes-bsp/u-boot/files/0001-net-Check-for-the-minimum-IP-fragmented-datagram-siz.patch
new file mode 100644
index 0000000000..3f9cc7776b
--- /dev/null
+++ b/meta/recipes-bsp/u-boot/files/0001-net-Check-for-the-minimum-IP-fragmented-datagram-siz.patch
@@ -0,0 +1,207 @@
1From c7cab39de5e4b22620248a190b3d2ee46cff38c2 Mon Sep 17 00:00:00 2001
2From: Fabio Estevam <festevam@denx.de>
3Date: Thu, 26 May 2022 11:14:37 -0300
4Subject: [PATCH] net: Check for the minimum IP fragmented datagram size
5
6Nicolas Bidron and Nicolas Guigo reported the two bugs below:
7
8"
9----------BUG 1----------
10
11In compiled versions of U-Boot that define CONFIG_IP_DEFRAG, a value of
12`ip->ip_len` (IP packet header's Total Length) higher than `IP_HDR_SIZE`
13and strictly lower than `IP_HDR_SIZE+8` will lead to a value for `len`
14comprised between `0` and `7`. This will ultimately result in a
15truncated division by `8` resulting value of `0` forcing the hole
16metadata and fragment to point to the same location. The subsequent
17memcopy will overwrite the hole metadata with the fragment data. Through
18a second fragment, this can be exploited to write to an arbitrary offset
19controlled by that overwritten hole metadata value.
20
21This bug is only exploitable locally as it requires crafting two packets
22the first of which would most likely be dropped through routing due to
23its unexpectedly low Total Length. However, this bug can potentially be
24exploited to root linux based embedded devices locally.
25
26```C
27static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
28{
29 static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
30 static u16 first_hole, total_len;
31 struct hole *payload, *thisfrag, *h, *newh;
32 struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
33 uchar *indata = (uchar *)ip;
34 int offset8, start, len, done = 0;
35 u16 ip_off = ntohs(ip->ip_off);
36
37 /* payload starts after IP header, this fragment is in there */
38 payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
39 offset8 = (ip_off & IP_OFFS);
40 thisfrag = payload + offset8;
41 start = offset8 * 8;
42 len = ntohs(ip->ip_len) - IP_HDR_SIZE;
43```
44
45The last line of the previous excerpt from `u-boot/net/net.c` shows how
46the attacker can control the value of `len` to be strictly lower than
47`8` by issuing a packet with `ip_len` between `21` and `27`
48(`IP_HDR_SIZE` has a value of `20`).
49
50Also note that `offset8` here is `0` which leads to `thisfrag = payload`.
51
52```C
53 } else if (h >= thisfrag) {
54 /* overlaps with initial part of the hole: move this hole */
55 newh = thisfrag + (len / 8);
56 *newh = *h;
57 h = newh;
58 if (h->next_hole)
59 payload[h->next_hole].prev_hole = (h - payload);
60 if (h->prev_hole)
61 payload[h->prev_hole].next_hole = (h - payload);
62 else
63 first_hole = (h - payload);
64
65 } else {
66```
67
68Lower down the same function, execution reaches the above code path.
69Here, `len / 8` evaluates to `0` leading to `newh = thisfrag`. Also note
70that `first_hole` here is `0` since `h` and `payload` point to the same
71location.
72
73```C
74 /* finally copy this fragment and possibly return whole packet */
75 memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);
76```
77
78Finally, in the above excerpt the `memcpy` overwrites the hole metadata
79since `thisfrag` and `h` both point to the same location. The hole
80metadata is effectively overwritten with arbitrary data from the
81fragmented IP packet data. If `len` was crafted to be `6`, `last_byte`,
82`next_hole`, and `prev_hole` of the `first_hole` can be controlled by
83the attacker.
84
85Finally the arbitrary offset write occurs through a second fragment that
86only needs to be crafted to write data in the hole pointed to by the
87previously controlled hole metadata (`next_hole`) from the first packet.
88
89 ### Recommendation
90
91Handle cases where `len` is strictly lower than 8 by preventing the
92overwrite of the hole metadata during the memcpy of the fragment. This
93could be achieved by either:
94* Moving the location where the hole metadata is stored when `len` is
95lower than `8`.
96* Or outright rejecting fragmented IP datagram with a Total Length
97(`ip_len`) lower than 28 bytes which is the minimum valid fragmented IP
98datagram size (as defined as the minimum fragment of 8 octets in the IP
99Specification Document:
100[RFC791](https://datatracker.ietf.org/doc/html/rfc791) page 25).
101
102----------BUG 2----------
103
104In compiled versions of U-Boot that define CONFIG_IP_DEFRAG, a value of
105`ip->ip_len` (IP packet header's Total Length) lower than `IP_HDR_SIZE`
106will lead to a negative value for `len` which will ultimately result in
107a buffer overflow during the subsequent `memcpy` that uses `len` as it's
108`count` parameter.
109
110This bug is only exploitable on local ethernet as it requires crafting
111an invalid packet to include an unexpected `ip_len` value in the IP UDP
112header that's lower than the minimum accepted Total Length of a packet
113(21 as defined in the IP Specification Document:
114[RFC791](https://datatracker.ietf.org/doc/html/rfc791)). Such packet
115would in all likelihood be dropped while being routed to its final
116destination through most routing equipment and as such requires the
117attacker to be in a local position in order to be exploited.
118
119```C
120static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
121{
122 static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
123 static u16 first_hole, total_len;
124 struct hole *payload, *thisfrag, *h, *newh;
125 struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
126 uchar *indata = (uchar *)ip;
127 int offset8, start, len, done = 0;
128 u16 ip_off = ntohs(ip->ip_off);
129
130 /* payload starts after IP header, this fragment is in there */
131 payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
132 offset8 = (ip_off & IP_OFFS);
133 thisfrag = payload + offset8;
134 start = offset8 * 8;
135 len = ntohs(ip->ip_len) - IP_HDR_SIZE;
136```
137
138The last line of the previous excerpt from `u-boot/net/net.c` shows
139where the underflow to a negative `len` value occurs if `ip_len` is set
140to a value strictly lower than 20 (`IP_HDR_SIZE` being 20). Also note
141that in the above excerpt the `pkt_buff` buffer has a size of
142`CONFIG_NET_MAXDEFRAG` which defaults to 16 KB but can range from 1KB to
14364 KB depending on configurations.
144
145```C
146 /* finally copy this fragment and possibly return whole packet */
147 memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);
148```
149
150In the above excerpt the `memcpy` overflows the destination by
151attempting to make a copy of nearly 4 gigabytes in a buffer that's
152designed to hold `CONFIG_NET_MAXDEFRAG` bytes at most which leads to a DoS.
153
154 ### Recommendation
155
156Stop processing of the packet if `ip_len` is lower than 21 (as defined
157by the minimum length of a data carrying datagram in the IP
158Specification Document:
159[RFC791](https://datatracker.ietf.org/doc/html/rfc791) page 34)."
160
161Add a check for ip_len lesser than 28 and stop processing the packet
162in this case.
163
164Such a check covers the two reported bugs.
165
166Reported-by: Nicolas Bidron <nicolas.bidron@nccgroup.com>
167Signed-off-by: Fabio Estevam <festevam@denx.de>
168
169Upstream-Status: Backport [b85d130ea0cac152c21ec38ac9417b31d41b5552]
170CVE: CVE-2022-30552
171
172Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
173---
174 include/net.h | 2 ++
175 net/net.c | 3 +++
176 2 files changed, 5 insertions(+)
177
178diff --git a/include/net.h b/include/net.h
179index cec8c98618..09d7e9b9e8 100644
180--- a/include/net.h
181+++ b/include/net.h
182@@ -397,6 +397,8 @@ struct ip_hdr {
183
184 #define IP_HDR_SIZE (sizeof(struct ip_hdr))
185
186+#define IP_MIN_FRAG_DATAGRAM_SIZE (IP_HDR_SIZE + 8)
187+
188 /*
189 * Internet Protocol (IP) + UDP header.
190 */
191diff --git a/net/net.c b/net/net.c
192index c2992a0908..f5400e6dbc 100644
193--- a/net/net.c
194+++ b/net/net.c
195@@ -907,6 +907,9 @@ static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
196 int offset8, start, len, done = 0;
197 u16 ip_off = ntohs(ip->ip_off);
198
199+ if (ip->ip_len < IP_MIN_FRAG_DATAGRAM_SIZE)
200+ return NULL;
201+
202 /* payload starts after IP header, this fragment is in there */
203 payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
204 offset8 = (ip_off & IP_OFFS);
205--
2062.33.0
207
diff --git a/meta/recipes-bsp/u-boot/u-boot_2022.01.bb b/meta/recipes-bsp/u-boot/u-boot_2022.01.bb
index a6a15d698f..04f60adaa5 100644
--- a/meta/recipes-bsp/u-boot/u-boot_2022.01.bb
+++ b/meta/recipes-bsp/u-boot/u-boot_2022.01.bb
@@ -5,6 +5,7 @@ SRC_URI:append = " file://0001-riscv32-Use-double-float-ABI-for-rv32.patch \
5 file://0001-riscv-fix-build-with-binutils-2.38.patch \ 5 file://0001-riscv-fix-build-with-binutils-2.38.patch \
6 file://0001-i2c-fix-stack-buffer-overflow-vulnerability-in-i2c-m.patch \ 6 file://0001-i2c-fix-stack-buffer-overflow-vulnerability-in-i2c-m.patch \
7 file://0001-fs-squashfs-sqfs_read-Prevent-arbitrary-code-executi.patch \ 7 file://0001-fs-squashfs-sqfs_read-Prevent-arbitrary-code-executi.patch \
8 file://0001-net-Check-for-the-minimum-IP-fragmented-datagram-siz.patch \
8 " 9 "
9 10
10DEPENDS += "bc-native dtc-native python3-setuptools-native" 11DEPENDS += "bc-native dtc-native python3-setuptools-native"