u-boot/net
Rasmus Villemoes 1817c3824a net: (actually/better) deal with CVE-2022-{30790,30552}
I hit a strange problem with v2022.10: Sometimes my tftp transfer
would seemingly just hang. It only happened for some files. Moreover,
changing tftpblocksize from 65464 to 65460 or 65000 made it work again
for all the files I tried. So I started suspecting it had something to
do with the file sizes and in particular the way the tftp blocks get
fragmented and reassembled.

v2022.01 showed no problems with any of the files or any value of
tftpblocksize.

Looking at what had changed in net.c or tftp.c since January showed
only one remotely interesting thing, b85d130ea0.

So I fired up wireshark on my host to see if somehow one of the
packets would be too small. But no, with both v2022.01 and v2022.10,
the exact same sequence of packets were sent, all but the last of size
1500, and the last being 1280 bytes.

But then it struck me that 1280 is 5*256, so one of the two bytes
on-the-wire is 0 and the other is 5, and when then looking at the code
again the lack of endianness conversion becomes obvious. [ntohs is
both applied to ip->ip_off just above, as well as to ip->ip_len just a
little further down when the "len" is actually computed].

IOWs the current code would falsely reject any packet which happens to
be a multiple of 256 bytes in size, breaking tftp transfers somewhat
randomly, and if it did get one of those "malicious" packets with
ip_len set to, say, 27, it would be seen by this check as being 6912
and hence not rejected.

====

Now, just adding the missing ntohs() would make my initial problem go
away, in that I can now download the file where the last fragment ends
up being 1280 bytes. But there's another bug in the code and/or
analysis: The right-hand side is too strict, in that it is ok for the
last fragment not to have a multiple of 8 bytes as payload - it really
must be ok, because nothing in the IP spec says that IP datagrams must
have a multiple of 8 bytes as payload. And comments in the code also
mention this.

To fix that, replace the comparison with <= IP_HDR_SIZE and add
another check that len is actually a multiple of 8 when the "more
fragments" bit is set - which it necessarily is for the case where
offset8 ends up being 0, since we're only called when

  (ip_off & (IP_OFFS | IP_FLAGS_MFRAG)).

====

So, does this fix CVE-2022-30790 for real? It certainly correctly
rejects the POC code which relies on sending a packet of size 27 with
the MFRAG flag set. Can the attack be carried out with a size 27
packet that doesn't set MFRAG (hence must set a non-zero fragment
offset)? I dunno. If we get a packet without MFRAG, we update
h->last_byte in the hole we've found to be start+len, hence we'd enter
one of

	if ((h >= thisfrag) && (h->last_byte <= start + len)) {

or

	} else if (h->last_byte <= start + len) {

and thus won't reach any of the

		/* overlaps with initial part of the hole: move this hole */
		newh = thisfrag + (len / 8);

		/* fragment sits in the middle: split the hole */
		newh = thisfrag + (len / 8);

IOW these division are now guaranteed to be exact, and thus I think
the scenario in CVE-2022-30790 cannot happen anymore.

====

However, there's a big elephant in the room, which has always been
spelled out in the comments, and which makes me believe that one can
still cause mayhem even with packets whose payloads are all 8-byte
aligned:

    This code doesn't deal with a fragment that overlaps with two
    different holes (thus being a superset of a previously-received
    fragment).

Suppose each character below represents 8 bytes, with D being already
received data, H being a hole descriptor (struct hole), h being
non-populated chunks, and P representing where the payload of a just
received packet should go:

  DDDHhhhhDDDDHhhhDDDD
        PPPPPPPPP

I'm pretty sure in this case we'd end up with h being the first hole,
enter the simple

	} else if (h->last_byte <= start + len) {
		/* overlaps with final part of the hole: shorten this hole */
		h->last_byte = start;

case, and thus in the memcpy happily overwrite the second H with our
chosen payload. This is probably worth fixing...

Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
2022-11-28 10:25:18 -05:00
..
arp.c Convert CONFIG_NET_RETRY_COUNT to Kconfig 2022-03-18 12:48:17 -04:00
arp.h net: Don't overwrite waiting packets with asynchronous replies 2018-10-10 12:29:01 -05:00
bootp.c efi_loader: Let networking support depend on NETDEVICES 2022-11-06 10:50:04 +01:00
bootp.h net: Use packed structures for networking 2017-08-07 15:18:31 -05:00
cdp.c Remove #include <timestamp.h> from files which do not need it 2021-09-17 12:10:44 -04:00
cdp.h SPDX: Convert a few files that were missed before 2018-05-10 20:38:35 -04:00
dns.c net: move random_port() to dns 2020-06-12 13:17:23 -04:00
dns.h SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
dsa-uclass.c dm: core: Drop ofnode_is_available() 2022-09-29 16:11:31 -04:00
eth_bootdev.c bootstd: ethernet: Add a bootdev driver 2022-04-25 10:00:04 -04:00
eth_common.c net: Move network rules to drivers/net 2021-09-04 12:51:47 -04:00
eth_internal.h doc: replace @return by Return: 2022-01-19 18:11:34 +01:00
eth_legacy.c net: uclass: Save generated ethernet MAC addresses to the environment 2022-01-11 10:33:42 +01:00
eth-uclass.c net: eth-uclass: Do not set device on error 2022-10-17 21:17:12 -06:00
fastboot.c net: fastboot: make UDP port net: configurable 2022-01-15 18:54:21 +02:00
Kconfig net: bootp: Make root path (option 17) length configurable 2022-08-08 10:49:51 -04:00
link_local.c common: Drop log.h from common header 2020-05-18 21:19:18 -04:00
link_local.h net: Add link-local addressing support 2012-05-23 17:53:08 -05:00
Makefile bootstd: ethernet: Add a bootdev driver 2022-04-25 10:00:04 -04:00
mdio-mux-uclass.c treewide: use dm_mdio_read/write/reset() wrappers 2022-04-10 08:44:12 +03:00
mdio-uclass.c net: mdio-uclass: add dm_phy_find_by_ofnode() helper 2022-05-04 07:05:51 +02:00
net_rand.h net: Use NDRNG device in srand_mac() 2021-01-19 09:15:02 -05:00
net.c net: (actually/better) deal with CVE-2022-{30790,30552} 2022-11-28 10:25:18 -05:00
nfs.c common: Drop display_options.h from common header 2022-08-10 13:46:55 -04:00
nfs.h net: nfs: remove superfluous packed attribute 2019-09-04 11:37:19 -05:00
pcap.c net: introduce packet capture support 2019-09-04 11:37:19 -05:00
ping.c net: Do not respond to ICMP_ECHO_REQUEST if we do not have an IP address 2021-01-19 09:15:02 -05:00
ping.h SPDX: Convert a few files that were missed before 2018-05-10 20:38:35 -04:00
rarp.c Convert CONFIG_NET_RETRY_COUNT to Kconfig 2022-03-18 12:48:17 -04:00
rarp.h SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
sntp.c net: sntp: remove CONFIG_TIMESTAMP constraint 2020-12-01 14:12:28 -05:00
tftp.c common: Drop display_options.h from common header 2022-08-10 13:46:55 -04:00
udp.c net: add a generic udp protocol 2020-09-30 16:55:03 -04:00
wol.c env: Drop environment.h header file where not needed 2019-08-11 16:43:41 -04:00
wol.h net: Add new wol command - Wake on LAN 2018-07-02 14:14:20 -05:00