diff options
author | Paolo Abeni <pabeni@redhat.com> | 2024-10-01 11:47:08 +0200 |
---|---|---|
committer | Paolo Abeni <pabeni@redhat.com> | 2024-10-01 11:47:08 +0200 |
commit | 23e19f2473c8762438baa1bcf3f71ee16dfcd535 (patch) | |
tree | a1459d6153629dc225628a0994b929b7251e227a | |
parent | e9d591b16c0ed8489aedc86cac237145815d14dc (diff) | |
parent | ab9a9a9e9647392a19e7a885b08000e89c86b535 (diff) | |
download | linux-23e19f2473c8762438baa1bcf3f71ee16dfcd535.tar.gz linux-23e19f2473c8762438baa1bcf3f71ee16dfcd535.tar.bz2 linux-23e19f2473c8762438baa1bcf3f71ee16dfcd535.zip |
Merge branch 'net-two-fixes-for-qdisc_pkt_len_init'
Eric Dumazet says:
====================
net: two fixes for qdisc_pkt_len_init()
Inspired by one syzbot report.
At least one qdisc (fq_codel) depends on qdisc_skb_cb(skb)->pkt_len
having a sane value (not zero)
With the help of af_packet, syzbot was able to fool qdisc_pkt_len_init()
to precisely set qdisc_skb_cb(skb)->pkt_len to zero.
First patch fixes this issue.
Second one (a separate one to help future bisections) adds
more sanity check to SKB_GSO_DODGY users.
====================
Link: https://patch.msgid.link/20240924150257.1059524-1-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r-- | net/core/dev.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 74cf78a6b512..ea5fbcd133ae 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3758,7 +3758,7 @@ static void qdisc_pkt_len_init(struct sk_buff *skb) sizeof(_tcphdr), &_tcphdr); if (likely(th)) hdr_len += __tcp_hdrlen(th); - } else { + } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { struct udphdr _udphdr; if (skb_header_pointer(skb, hdr_len, @@ -3766,10 +3766,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; } } |