[PATCH 7/6] net: deal with fragment-overlapping-two-holes case

Rasmus Villemoes rasmus.villemoes at prevas.dk
Mon Oct 17 09:52:51 CEST 2022


With a suitable sequence of malicious packets, it's currently possible
to get a hole descriptor to contain arbitrary attacker-controlled
contents, and then with one more packet to use that as an arbitrary
write vector.

While one could possibly change the algorithm so we instead loop over
all holes, and in each hole puts as much of the current fragment as
belongs there (taking care to carefully update the hole list as
appropriate), it's not worth the complexity: In real, non-malicious
scenarios, one never gets overlapping fragments, and certainly not
fragments that would be supersets of one another.

So instead opt for this simple protection: Simply don't allow the
eventual memcpy() to write beyond the last_byte of the current hole.

Signed-off-by: Rasmus Villemoes <rasmus.villemoes at prevas.dk>
---

I've been mulling over this over the weekend, and concluded that this
should be enough for now. Even if I'm wrong about overlapping
fragments not happening in real life, this doesn't break something
that works currently, and does prevent the trivial attacker-controller
hole descriptor.

 net/net.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/net/net.c b/net/net.c
index d3ff871bca..5c6aea0c55 100644
--- a/net/net.c
+++ b/net/net.c
@@ -968,10 +968,14 @@ static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
 	}
 
 	/*
-	 * There is some overlap: fix the hole list. This code doesn't
-	 * deal with a fragment that overlaps with two different holes
-	 * (thus being a superset of a previously-received fragment).
+	 * There is some overlap: fix the hole list. This code deals
+	 * with a fragment that overlaps with two different holes
+	 * (thus being a superset of a previously-received fragment)
+	 * by only using the part of the fragment that fits in the
+	 * first hole.
 	 */
+	if (h->last_byte < start + len)
+		len = h->last_byte - start;
 
 	if ((h >= thisfrag) && (h->last_byte <= start + len)) {
 		/* complete overlap with hole: remove hole */
-- 
2.37.2



More information about the U-Boot mailing list