From: Alexei Starovoitov qdisc_pkt_len_segs_init() stores skb_transport_offset(), or the inner offset, in the unsigned hdr_len. A header in front of skb->data gives a negative offset. For an offset a little below zero, pskb_may_pull() gets a small length and succeeds. Then a 64-bit kernel reads the TCP header far after the skb and can crash. Further below zero pskb_may_pull() fails. Commit 28a57fb2c5df ("net: iptunnel: fix stale transport header during tunnel decapsulation") fixed one source of such offsets. Other code that removes bytes from the front of a packet can leave the same stale header. Return SKB_DROP_REASON_SKB_BAD_GSO for a negative offset in the TCP branch. SKB_GSO_UDP_L4 and the other GSO types read no header and still get a wrong qdisc_pkt_len(). On a 64-bit kernel only packets that cause the read after the skb today get a new result. Then __dev_queue_xmit() drops them and returns -EINVAL, but sch_handle_ingress() ignores the result. Their content can be valid. Thus the code that leaves the header stale needs its own fix. Fixes: 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()") Signed-off-by: Alexei Starovoitov --- net/core/dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 3ac700d37e59..ccf4b02e08de 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4320,7 +4320,9 @@ static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb) if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { const struct tcphdr *th; - if (!pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr))) + /* A header in front of skb->data gives a negative offset. */ + if ((int)hdr_len < 0 || + !pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr))) return SKB_DROP_REASON_SKB_BAD_GSO; th = (const struct tcphdr *)(skb->data + hdr_len); -- 2.55.0