summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorRasmus Villemoes <rasmus.villemoes@prevas.dk>2022-10-17 09:52:51 +0200
committerTom Rini <trini@konsulko.com>2022-11-28 13:06:39 -0500
commit068696863980f86504934bdb1e4d0d6359b76092 (patch)
tree95d094e506bcf1e1780fadf671968fcfae000dda /net
parent087648b5df8db0d4786ff86e61e7616ebc181cf4 (diff)
net: deal with fragment-overlapping-two-holes case
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@prevas.dk>
Diffstat (limited to 'net')
-rw-r--r--net/net.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/net/net.c b/net/net.c
index 073fb681e5..6f0a48361c 100644
--- a/net/net.c
+++ b/net/net.c
@@ -985,10 +985,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 */