summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2024-09-24 18:02:57 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-10-17 16:11:21 +0300
commit2415f465730e48b6e38da1c7c097317bf5dd2d20 (patch)
tree871bf254f3d7ef393c711642032b2f4f121500a2 /net
parent939c88cbdc668dadd8cfa7a35d9066331239041c (diff)
downloadlinux-2415f465730e48b6e38da1c7c097317bf5dd2d20.tar.xz
net: add more sanity checks to qdisc_pkt_len_init()
[ Upstream commit ab9a9a9e9647392a19e7a885b08000e89c86b535 ] One path takes care of SKB_GSO_DODGY, assuming skb->len is bigger than hdr_len. virtio_net_hdr_to_skb() does not fully dissect TCP headers, it only make sure it is at least 20 bytes. It is possible for an user to provide a malicious 'GSO' packet, total length of 80 bytes. - 20 bytes of IPv4 header - 60 bytes TCP header - a small gso_size like 8 virtio_net_hdr_to_skb() would declare this packet as a normal GSO packet, because it would see 40 bytes of payload, bigger than gso_size. We need to make detect this case to not underflow qdisc_skb_cb(skb)->pkt_len. Fixes: 1def9238d4aa ("net_sched: more precise pkt_len computation") Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Reviewed-by: David Ahern <dsahern@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 96e093e2206f..8a22ce15b7f5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3795,10 +3795,14 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)
hdr_len += sizeof(struct udphdr);
}
- if (shinfo->gso_type & SKB_GSO_DODGY)
- gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
- shinfo->gso_size);
+ if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) {
+ int payload = skb->len - hdr_len;
+ /* Malicious packet. */
+ if (payload <= 0)
+ return;
+ gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size);
+ }
qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;
}
}