Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-pull-gso-packet-headers-in-core-stack'

Eric Dumazet says:

====================
net: pull gso packet headers in core stack

Most ndo_start_xmit() methods expects headers of gso packets
to be already in skb->head.

net/core/tso.c users are particularly at risk, because tso_build_hdr()
does a memcpy(hdr, skb->data, hdr_len);

qdisc_pkt_len_segs_init() already does a dissection of gso packets.

Use pskb_may_pull() instead of skb_header_pointer() to make
sure drivers do not have to reimplement this.

First patch is a small cleanup to ease second patch review.
====================

Link: https://patch.msgid.link/20260403221540.3297753-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+53 -39
+3
include/net/dropreason-core.h
··· 74 74 FN(UNHANDLED_PROTO) \ 75 75 FN(SKB_CSUM) \ 76 76 FN(SKB_GSO_SEG) \ 77 + FN(SKB_BAD_GSO) \ 77 78 FN(SKB_UCOPY_FAULT) \ 78 79 FN(DEV_HDR) \ 79 80 FN(DEV_READY) \ ··· 393 392 SKB_DROP_REASON_SKB_CSUM, 394 393 /** @SKB_DROP_REASON_SKB_GSO_SEG: gso segmentation error */ 395 394 SKB_DROP_REASON_SKB_GSO_SEG, 395 + /** @SKB_DROP_REASON_SKB_BAD_GSO: malicious gso packet. */ 396 + SKB_DROP_REASON_SKB_BAD_GSO, 396 397 /** 397 398 * @SKB_DROP_REASON_SKB_UCOPY_FAULT: failed to copy data from user space, 398 399 * e.g., via zerocopy_sg_from_iter() or skb_orphan_frags_rx()
+50 -39
net/core/dev.c
··· 4101 4101 } 4102 4102 EXPORT_SYMBOL_GPL(validate_xmit_skb_list); 4103 4103 4104 - static void qdisc_pkt_len_segs_init(struct sk_buff *skb) 4104 + static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb) 4105 4105 { 4106 4106 struct skb_shared_info *shinfo = skb_shinfo(skb); 4107 + unsigned int hdr_len, tlen; 4107 4108 u16 gso_segs; 4108 4109 4109 4110 qdisc_skb_cb(skb)->pkt_len = skb->len; 4110 4111 if (!shinfo->gso_size) { 4111 4112 qdisc_skb_cb(skb)->pkt_segs = 1; 4112 - return; 4113 + return SKB_NOT_DROPPED_YET; 4113 4114 } 4114 4115 4115 4116 qdisc_skb_cb(skb)->pkt_segs = gso_segs = shinfo->gso_segs; ··· 4118 4117 /* To get more precise estimation of bytes sent on wire, 4119 4118 * we add to pkt_len the headers size of all segments 4120 4119 */ 4121 - if (skb_transport_header_was_set(skb)) { 4122 - unsigned int hdr_len; 4123 4120 4124 - /* mac layer + network layer */ 4125 - if (!skb->encapsulation) 4126 - hdr_len = skb_transport_offset(skb); 4127 - else 4128 - hdr_len = skb_inner_transport_offset(skb); 4129 - 4130 - /* + transport layer */ 4131 - if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { 4132 - const struct tcphdr *th; 4133 - struct tcphdr _tcphdr; 4134 - 4135 - th = skb_header_pointer(skb, hdr_len, 4136 - sizeof(_tcphdr), &_tcphdr); 4137 - if (likely(th)) 4138 - hdr_len += __tcp_hdrlen(th); 4139 - } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { 4140 - struct udphdr _udphdr; 4141 - 4142 - if (skb_header_pointer(skb, hdr_len, 4143 - sizeof(_udphdr), &_udphdr)) 4144 - hdr_len += sizeof(struct udphdr); 4145 - } 4146 - 4147 - if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) { 4148 - int payload = skb->len - hdr_len; 4149 - 4150 - /* Malicious packet. */ 4151 - if (payload <= 0) 4152 - return; 4153 - gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size); 4154 - shinfo->gso_segs = gso_segs; 4155 - qdisc_skb_cb(skb)->pkt_segs = gso_segs; 4156 - } 4157 - qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len; 4121 + /* mac layer + network layer */ 4122 + if (!skb->encapsulation) { 4123 + if (unlikely(!skb_transport_header_was_set(skb))) 4124 + return SKB_NOT_DROPPED_YET; 4125 + hdr_len = skb_transport_offset(skb); 4126 + } else { 4127 + hdr_len = skb_inner_transport_offset(skb); 4158 4128 } 4129 + /* + transport layer */ 4130 + if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { 4131 + const struct tcphdr *th; 4132 + 4133 + if (!pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr))) 4134 + return SKB_DROP_REASON_SKB_BAD_GSO; 4135 + 4136 + th = (const struct tcphdr *)(skb->data + hdr_len); 4137 + tlen = __tcp_hdrlen(th); 4138 + if (tlen < sizeof(*th)) 4139 + return SKB_DROP_REASON_SKB_BAD_GSO; 4140 + hdr_len += tlen; 4141 + if (!pskb_may_pull(skb, hdr_len)) 4142 + return SKB_DROP_REASON_SKB_BAD_GSO; 4143 + } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { 4144 + if (!pskb_may_pull(skb, hdr_len + sizeof(struct udphdr))) 4145 + return SKB_DROP_REASON_SKB_BAD_GSO; 4146 + hdr_len += sizeof(struct udphdr); 4147 + } 4148 + 4149 + /* prior pskb_may_pull() might have changed skb->head. */ 4150 + shinfo = skb_shinfo(skb); 4151 + if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) { 4152 + int payload = skb->len - hdr_len; 4153 + 4154 + /* Malicious packet. */ 4155 + if (payload <= 0) 4156 + return SKB_DROP_REASON_SKB_BAD_GSO; 4157 + gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size); 4158 + shinfo->gso_segs = gso_segs; 4159 + qdisc_skb_cb(skb)->pkt_segs = gso_segs; 4160 + } 4161 + qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len; 4162 + return SKB_NOT_DROPPED_YET; 4159 4163 } 4160 4164 4161 4165 static int dev_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *q, ··· 4777 4771 (SKBTX_SCHED_TSTAMP | SKBTX_BPF))) 4778 4772 __skb_tstamp_tx(skb, NULL, NULL, skb->sk, SCM_TSTAMP_SCHED); 4779 4773 4774 + reason = qdisc_pkt_len_segs_init(skb); 4775 + if (unlikely(reason)) { 4776 + dev_core_stats_tx_dropped_inc(dev); 4777 + kfree_skb_reason(skb, reason); 4778 + return -EINVAL; 4779 + } 4780 4780 /* Disable soft irqs for various locks below. Also 4781 4781 * stops preemption for RCU. 4782 4782 */ ··· 4790 4778 4791 4779 skb_update_prio(skb); 4792 4780 4793 - qdisc_pkt_len_segs_init(skb); 4794 4781 tcx_set_ingress(skb, false); 4795 4782 #ifdef CONFIG_NET_EGRESS 4796 4783 if (static_branch_unlikely(&egress_needed_key)) {