__net_defragment() reassembles IP fragments into the static buffer
pkt_buff[CONFIG_NET_MAXDEFRAG].  The bounds check

        if (start + len > IP_MAXUDP)
                return NULL;

only covers the fragment data copy.  The split-hole and move-hole
branches additionally write an 8-byte struct hole via "*newh = *h" at
newh = thisfrag + len / 8, which can land up to sizeof(struct hole)
bytes past the end of pkt_buff.  A single fragment with a non-zero
fragment offset and the More-Fragments flag set reaches this path, so
a crafted fragment received during netboot overflows the buffer.

Reject any fragment whose trailing hole descriptor would fall outside
pkt_buff.

Signed-off-by: Shahriyar Jalayeri <[email protected]>
Acked-by: Jerome Forissier <[email protected]>
---
 net/net.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/net.c b/net/net.c
index 61c5a6ef6c4..71666eb1113 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1076,6 +1076,8 @@ static struct ip_udp_hdr *__net_defragment(struct 
ip_udp_hdr *ip, int *lenp)
        } else if (h >= thisfrag) {
                /* overlaps with initial part of the hole: move this hole */
                newh = thisfrag + (len / 8);
+               if ((uchar *)(newh + 1) > pkt_buff + IP_PKTSIZE)
+                       return NULL;    /* hole descriptor would overflow 
pkt_buff */
                *newh = *h;
                h = newh;
                if (h->next_hole)
@@ -1088,6 +1090,8 @@ static struct ip_udp_hdr *__net_defragment(struct 
ip_udp_hdr *ip, int *lenp)
        } else {
                /* fragment sits in the middle: split the hole */
                newh = thisfrag + (len / 8);
+               if ((uchar *)(newh + 1) > pkt_buff + IP_PKTSIZE)
+                       return NULL;    /* hole descriptor would overflow 
pkt_buff */
                *newh = *h;
                h->last_byte = start;
                h->next_hole = (newh - payload);

-- 
2.43.0

Reply via email to