Skip to content

Commit 2a73b2c

Browse files
Qihang Tanggregkh
authored andcommitted
packet: use consistent hard_header_len in TX_RING send path
[ Upstream commit 21b5953 ] tpacket_snd() reads dev->hard_header_len independently for skb allocation and header construction in tpacket_fill_skb(). Concurrent netdevice reconfiguration can therefore make the reserved headroom smaller than the amount later pushed, or make copylen - hard_header_len negative. Snapshot hard_header_len once before processing ring frames and use it for the frame limit, headroom allocation, copy length, and skb construction. Pass the snapshot to tpacket_fill_skb(). The separate SOCK_DGRAM consistency problem between hard_header_len and header_ops->create is not addressed here. Fixes: 69e3c75 ("net: TX_RING and packet mmap") Cc: stable@vger.kernel.org Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/20260805125729.19220-4-q.h.hack.winter@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> [ Applied cleanly after amending the prerequisite that adds `LL_RESERVED_SPACE_EX()`; no target-side adaptation was needed. ] Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 78a4712 commit 2a73b2c

1 file changed

Lines changed: 11 additions & 8 deletions

File tree

‎net/packet/af_packet.c‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,6 +2586,7 @@ static int packet_snd_vnet_parse(struct msghdr *msg, size_t *len,
25862586
static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
25872587
void *frame, struct net_device *dev, void *data, int tp_len,
25882588
__be16 proto, unsigned char *addr, int hlen, int copylen,
2589+
int hard_header_len,
25892590
const struct sockcm_cookie *sockc)
25902591
{
25912592
union tpacket_uhdr ph;
@@ -2617,8 +2618,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
26172618
} else if (copylen) {
26182619
int hdrlen = min_t(int, copylen, tp_len);
26192620

2620-
skb_push(skb, dev->hard_header_len);
2621-
skb_put(skb, copylen - dev->hard_header_len);
2621+
skb_push(skb, hard_header_len);
2622+
skb_put(skb, copylen - hard_header_len);
26222623
err = skb_store_bits(skb, 0, data, hdrlen);
26232624
if (unlikely(err))
26242625
return err;
@@ -2751,7 +2752,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
27512752
void *data;
27522753
int len_sum = 0;
27532754
int status = TP_STATUS_AVAILABLE;
2754-
int hlen, tlen, copylen = 0;
2755+
int hard_header_len, hlen, tlen, copylen = 0;
27552756
long timeo;
27562757

27572758
mutex_lock(&po->pg_vec_lock);
@@ -2798,8 +2799,9 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
27982799
goto out_put;
27992800
}
28002801

2802+
hard_header_len = READ_ONCE(dev->hard_header_len);
28012803
if (po->sk.sk_socket->type == SOCK_RAW)
2802-
reserve = dev->hard_header_len;
2804+
reserve = hard_header_len;
28032805
size_max = po->tx_ring.frame_size
28042806
- (po->tp_hdrlen - sizeof(struct sockaddr_ll));
28052807

@@ -2836,7 +2838,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
28362838
goto tpacket_error;
28372839

28382840
status = TP_STATUS_SEND_REQUEST;
2839-
hlen = LL_RESERVED_SPACE(dev);
2841+
hlen = LL_RESERVED_SPACE_EX(dev, hard_header_len);
28402842
tlen = dev->needed_tailroom;
28412843
if (po->has_vnet_hdr) {
28422844
data += sizeof(vnet_hdr);
@@ -2854,10 +2856,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
28542856
vnet_hdr.hdr_len);
28552857
has_vnet_hdr = true;
28562858
}
2857-
copylen = max_t(int, copylen, dev->hard_header_len);
2859+
copylen = max_t(int, copylen, hard_header_len);
28582860
skb = sock_alloc_send_skb(&po->sk,
28592861
hlen + tlen + sizeof(struct sockaddr_ll) +
2860-
(copylen - dev->hard_header_len),
2862+
(copylen - hard_header_len),
28612863
!need_wait, &err);
28622864

28632865
if (unlikely(skb == NULL)) {
@@ -2867,7 +2869,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
28672869
goto out_status;
28682870
}
28692871
tp_len = tpacket_fill_skb(po, skb, ph, dev, data, tp_len, proto,
2870-
addr, hlen, copylen, &sockc);
2872+
addr, hlen, copylen, hard_header_len,
2873+
&sockc);
28712874
if (likely(tp_len >= 0) &&
28722875
tp_len > dev->mtu + reserve &&
28732876
!po->has_vnet_hdr &&

0 commit comments

Comments
 (0)