* [PATCH net v5 0/2] packet: use consistent hard_header_len in send paths
@ 2026-07-30 8:29 Qihang
2026-07-30 8:29 ` [PATCH net v5 1/2] packet: use consistent hard_header_len in non-ring " Qihang
` (4 more replies)
0 siblings, 5 replies; 14+ messages in thread
From: Qihang @ 2026-07-30 8:29 UTC (permalink / raw)
To: netdev
Cc: willemdebruijn.kernel, daniel.zahka, davem, edumazet, kuba,
pabeni, horms, stable, Qihang
AF_PACKET send paths read dev->hard_header_len at several stages of skb
allocation and construction. Concurrent netdevice reconfiguration can
make those reads inconsistent and cause skb headroom underflow.
Split the regular and TX_RING paths so each patch has one Fixes tag.
The separate SOCK_DGRAM consistency issue between hard_header_len and
header_ops->create remains outside this series.
Changes in v5:
- Drop the unnecessary per-frame copylen reset from patch 2.
Changes in v4:
- Use one hard_header_len snapshot throughout tpacket_snd(), including
reserve and per-frame skb construction.
- Carry Willem's Reviewed-by on patch 1.
Link to v4: https://lore.kernel.org/netdev/20260729030122.21462-1-q.h.hack.winter@gmail.com/
Link to v3: https://lore.kernel.org/netdev/20260728031345.49562-1-q.h.hack.winter@gmail.com/
Qihang (2):
packet: use consistent hard_header_len in non-ring send paths
packet: use consistent hard_header_len in TX_RING send path
include/linux/netdevice.h | 6 ++++--
net/packet/af_packet.c | 45 +++++++++++++++++++++++----------------
2 files changed, 31 insertions(+), 20 deletions(-)
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net v5 1/2] packet: use consistent hard_header_len in non-ring send paths
2026-07-30 8:29 [PATCH net v5 0/2] packet: use consistent hard_header_len in send paths Qihang
@ 2026-07-30 8:29 ` Qihang
2026-07-30 8:29 ` [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path Qihang
` (3 subsequent siblings)
4 siblings, 0 replies; 14+ messages in thread
From: Qihang @ 2026-07-30 8:29 UTC (permalink / raw)
To: netdev
Cc: willemdebruijn.kernel, daniel.zahka, davem, edumazet, kuba,
pabeni, horms, stable, Qihang, Willem de Bruijn
packet_snd() reads dev->hard_header_len multiple times while allocating
and constructing an skb. Device reconfiguration can change this value
concurrently, for example through bonding device type changes.
For SOCK_RAW, packet_snd() can save a larger value in reserve and later
allocate headroom using a smaller value. Moving skb->data back by reserve
then places it before skb->head, and the following copy from userspace can
attempt an out-of-bounds write.
packet_sendmsg_spkt() has the same issue because it calculates its
reservation and header offset from separate reads before dropping the RCU
read lock to allocate the skb.
Add LL_RESERVED_SPACE_EX() for callers that already saved a header length.
Read hard_header_len once in packet_snd() and use it for allocation and
construction. In packet_sendmsg_spkt(), preserve the allocation-time value
through the device lookup retry.
The separate SOCK_DGRAM consistency problem between hard_header_len and
header_ops->create is not addressed here.
Fixes: b84bbaf7a6c8 ("packet: in packet_snd start writing at link layer allocation")
Cc: stable@vger.kernel.org
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
include/linux/netdevice.h | 6 ++++--
net/packet/af_packet.c | 26 ++++++++++++++++----------
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9981d637f8b5..e50e8abc1392 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -300,9 +300,11 @@ struct hh_cache {
* We could use other alignment values, but we must maintain the
* relationship HH alignment <= LL alignment.
*/
-#define LL_RESERVED_SPACE(dev) \
- ((((dev)->hard_header_len + READ_ONCE((dev)->needed_headroom)) \
+#define LL_RESERVED_SPACE_EX(dev, hlen) \
+ ((((hlen) + READ_ONCE((dev)->needed_headroom)) \
& ~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+#define LL_RESERVED_SPACE(dev) \
+ LL_RESERVED_SPACE_EX(dev, (dev)->hard_header_len)
#define LL_RESERVED_SPACE_EXTRA(dev,extra) \
((((dev)->hard_header_len + READ_ONCE((dev)->needed_headroom) + (extra)) \
& ~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index e75d2932475a..88674a6e868c 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1953,8 +1953,9 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
struct net_device *dev;
struct sockcm_cookie sockc;
__be16 proto = 0;
- int err;
+ int hard_header_len;
int extra_len = 0;
+ int err;
/*
* Get and verify the address.
@@ -1997,14 +1998,18 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
extra_len = 4; /* We're doing our own CRC */
}
+ /* Keep the allocation-time header length across retry. */
+ if (!skb)
+ hard_header_len = READ_ONCE(dev->hard_header_len);
+
err = -EMSGSIZE;
- if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN + extra_len)
+ if (len > dev->mtu + hard_header_len + VLAN_HLEN + extra_len)
goto out_unlock;
if (!skb) {
- size_t reserved = LL_RESERVED_SPACE(dev);
+ size_t reserved = LL_RESERVED_SPACE_EX(dev, hard_header_len);
int tlen = dev->needed_tailroom;
- unsigned int hhlen = dev->header_ops ? dev->hard_header_len : 0;
+ unsigned int hhlen = dev->header_ops ? hard_header_len : 0;
rcu_read_unlock();
skb = sock_wmalloc(sk, len + reserved + tlen, 0, GFP_KERNEL);
@@ -2034,7 +2039,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
err = -EINVAL;
goto out_unlock;
}
- if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
+ if (len > (dev->mtu + hard_header_len + extra_len) &&
!packet_extra_vlan_len_allowed(dev, skb)) {
err = -EMSGSIZE;
goto out_unlock;
@@ -2956,7 +2961,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
int offset = 0;
struct packet_sock *po = pkt_sk(sk);
int vnet_hdr_sz = READ_ONCE(po->vnet_hdr_sz);
- int hlen, tlen, linear;
+ int hard_header_len, hlen, tlen, linear;
int extra_len = 0;
/*
@@ -2996,8 +3001,9 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
goto out_unlock;
}
+ hard_header_len = READ_ONCE(dev->hard_header_len);
if (sock->type == SOCK_RAW)
- reserve = dev->hard_header_len;
+ reserve = hard_header_len;
if (vnet_hdr_sz) {
err = packet_snd_vnet_parse(msg, &len, &vnet_hdr, vnet_hdr_sz);
if (err)
@@ -3018,10 +3024,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
goto out_unlock;
err = -ENOBUFS;
- hlen = LL_RESERVED_SPACE(dev);
+ hlen = LL_RESERVED_SPACE_EX(dev, hard_header_len);
tlen = dev->needed_tailroom;
linear = __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len);
- linear = max(linear, min_t(int, len, dev->hard_header_len));
+ linear = max(linear, min_t(int, len, hard_header_len));
skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, linear,
msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
@@ -3037,7 +3043,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
} else if (reserve) {
skb_reserve(skb, -reserve);
if (len < reserve + sizeof(struct ipv6hdr) &&
- dev->min_header_len != dev->hard_header_len)
+ dev->min_header_len != hard_header_len)
skb_reset_network_header(skb);
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path
2026-07-30 8:29 [PATCH net v5 0/2] packet: use consistent hard_header_len in send paths Qihang
2026-07-30 8:29 ` [PATCH net v5 1/2] packet: use consistent hard_header_len in non-ring " Qihang
@ 2026-07-30 8:29 ` Qihang
2026-07-30 9:22 ` Willem de Bruijn
2026-08-04 9:00 ` [PATCH net v6 0/3] net: fix hard_header_len races in packet send paths Qihang
` (2 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Qihang @ 2026-07-30 8:29 UTC (permalink / raw)
To: netdev
Cc: willemdebruijn.kernel, daniel.zahka, davem, edumazet, kuba,
pabeni, horms, stable, Qihang
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: 69e3c75f4d54 ("net: TX_RING and packet mmap")
Cc: stable@vger.kernel.org
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
---
net/packet/af_packet.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 88674a6e868c..e9b6810c885e 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2574,6 +2574,7 @@ static int packet_snd_vnet_parse(struct msghdr *msg, size_t *len,
static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
void *frame, struct net_device *dev, void *data, int tp_len,
__be16 proto, unsigned char *addr, int hlen, int copylen,
+ int hard_header_len,
const struct sockcm_cookie *sockc)
{
union tpacket_uhdr ph;
@@ -2605,8 +2606,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
} else if (copylen) {
int hdrlen = min_t(int, copylen, tp_len);
- skb_push(skb, dev->hard_header_len);
- skb_put(skb, copylen - dev->hard_header_len);
+ skb_push(skb, hard_header_len);
+ skb_put(skb, copylen - hard_header_len);
err = skb_store_bits(skb, 0, data, hdrlen);
if (unlikely(err))
return err;
@@ -2737,7 +2738,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
void *data;
int len_sum = 0;
int status = TP_STATUS_AVAILABLE;
- int hlen, tlen, copylen = 0;
+ int hard_header_len, hlen, tlen, copylen = 0;
long timeo;
mutex_lock(&po->pg_vec_lock);
@@ -2784,8 +2785,9 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
goto out_put;
}
+ hard_header_len = READ_ONCE(dev->hard_header_len);
if (po->sk.sk_socket->type == SOCK_RAW)
- reserve = dev->hard_header_len;
+ reserve = hard_header_len;
size_max = po->tx_ring.frame_size
- (po->tp_hdrlen - sizeof(struct sockaddr_ll));
@@ -2822,7 +2824,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
goto tpacket_error;
status = TP_STATUS_SEND_REQUEST;
- hlen = LL_RESERVED_SPACE(dev);
+ hlen = LL_RESERVED_SPACE_EX(dev, hard_header_len);
tlen = dev->needed_tailroom;
if (vnet_hdr_sz) {
data += vnet_hdr_sz;
@@ -2840,10 +2842,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
vnet_hdr.hdr_len);
has_vnet_hdr = true;
}
- copylen = max_t(int, copylen, dev->hard_header_len);
+ copylen = max_t(int, copylen, hard_header_len);
skb = sock_alloc_send_skb(&po->sk,
hlen + tlen + sizeof(struct sockaddr_ll) +
- (copylen - dev->hard_header_len),
+ (copylen - hard_header_len),
!need_wait, &err);
if (unlikely(skb == NULL)) {
@@ -2853,7 +2855,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
goto out_status;
}
tp_len = tpacket_fill_skb(po, skb, ph, dev, data, tp_len, proto,
- addr, hlen, copylen, &sockc);
+ addr, hlen, copylen, hard_header_len,
+ &sockc);
if (likely(tp_len >= 0) &&
tp_len > dev->mtu + reserve &&
!vnet_hdr_sz &&
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path
2026-07-30 8:29 ` [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path Qihang
@ 2026-07-30 9:22 ` Willem de Bruijn
2026-08-04 2:22 ` Jakub Kicinski
0 siblings, 1 reply; 14+ messages in thread
From: Willem de Bruijn @ 2026-07-30 9:22 UTC (permalink / raw)
To: Qihang, netdev
Cc: willemdebruijn.kernel, daniel.zahka, davem, edumazet, kuba,
pabeni, horms, stable, Qihang
Qihang wrote:
> 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: 69e3c75f4d54 ("net: TX_RING and packet mmap")
> Cc: stable@vger.kernel.org
> Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path
2026-07-30 9:22 ` Willem de Bruijn
@ 2026-08-04 2:22 ` Jakub Kicinski
2026-08-04 3:04 ` Willem de Bruijn
0 siblings, 1 reply; 14+ messages in thread
From: Jakub Kicinski @ 2026-08-04 2:22 UTC (permalink / raw)
To: Willem de Bruijn
Cc: Qihang, netdev, daniel.zahka, davem, edumazet, pabeni, horms,
stable
On Thu, 30 Jul 2026 05:22:21 -0400 Willem de Bruijn wrote:
> Qihang wrote:
> > 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: 69e3c75f4d54 ("net: TX_RING and packet mmap")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
>
> Reviewed-by: Willem de Bruijn <willemb@google.com>
Willem, does the *shiko feedback look like false positives?
Both instances seem to provide different feedback, if I'm reading my own
tea leaves right Claude discarded the Gemini feedback about a panic
as a hallucination..
https://sashiko.dev/#/patchset/20260730082925.93759-2-q.h.hack.winter@gmail.com
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260730082925.93759-2-q.h.hack.winter@gmail.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path
2026-08-04 2:22 ` Jakub Kicinski
@ 2026-08-04 3:04 ` Willem de Bruijn
2026-08-04 23:43 ` Jakub Kicinski
0 siblings, 1 reply; 14+ messages in thread
From: Willem de Bruijn @ 2026-08-04 3:04 UTC (permalink / raw)
To: Jakub Kicinski, Willem de Bruijn
Cc: Qihang, netdev, daniel.zahka, davem, edumazet, pabeni, horms,
stable
Jakub Kicinski wrote:
> On Thu, 30 Jul 2026 05:22:21 -0400 Willem de Bruijn wrote:
> > Qihang wrote:
> > > 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: 69e3c75f4d54 ("net: TX_RING and packet mmap")
> > > Cc: stable@vger.kernel.org
> > > Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
I missed this before, but Qihang is that your full name?
https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
> >
> > Reviewed-by: Willem de Bruijn <willemb@google.com>
>
> Willem, does the *shiko feedback look like false positives?
> Both instances seem to provide different feedback, if I'm reading my own
> tea leaves right Claude discarded the Gemini feedback about a panic
> as a hallucination..
>
> https://sashiko.dev/#/patchset/20260730082925.93759-2-q.h.hack.winter@gmail.com
>
> https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260730082925.93759-2-q.h.hack.winter@gmail.com
If I read Gemini feedback correctly, all reports are about the current
solution falling short of fixing the instance of this race condition
with dev_hard_header(), which reads dev->hard_header_len directly.
The patch indeed mentions this limitation.
As well as the same issue with dev_validate_header(), which the commit
does not list as limitation. But that one is only reached with variable
length L2 protocols.
Side note, in net-next I can probably remove header_ops.validate now
that ax25 is gone, and with that all of dev_validate_header. No other
variable length L2 protocol ever implemented that callback.
But that won't help older kernels, of course. I think it's fine to
remove that CAP_SYS_RAWIO branch in the fix, which never had much
value anyway. It was there to allow testing purposely bad input or so.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net v6 0/3] net: fix hard_header_len races in packet send paths
2026-07-30 8:29 [PATCH net v5 0/2] packet: use consistent hard_header_len in send paths Qihang
2026-07-30 8:29 ` [PATCH net v5 1/2] packet: use consistent hard_header_len in non-ring " Qihang
2026-07-30 8:29 ` [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path Qihang
@ 2026-08-04 9:00 ` Qihang
2026-08-04 9:00 ` [PATCH net v6 1/3] net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header Qihang
2026-08-04 9:32 ` [PATCH net v6 2/3] packet: use consistent hard_header_len in non-ring send paths Qihang
2026-08-04 9:33 ` [PATCH net v6 3/3] packet: use consistent hard_header_len in TX_RING send path Qihang
4 siblings, 1 reply; 14+ messages in thread
From: Qihang @ 2026-08-04 9:00 UTC (permalink / raw)
To: netdev
Cc: willemdebruijn.kernel, willemb, daniel.zahka, davem, edumazet,
kuba, pabeni, horms, stable, Qihang Tang
From: Qihang Tang <q.h.hack.winter@gmail.com>
The packet socket TX paths read dev->hard_header_len independently for
skb allocation and header construction. Concurrent netdevice
reconfiguration (e.g. bonding device type changes) can change this value
in between, leading to mismatched headroom and copy length, and in the
SOCK_RAW case to out-of-bounds writes.
Patch 1 removes the CAP_SYS_RAWIO zero-padding branch in
dev_validate_header(). That branch sizes a memset against the live
dev->hard_header_len while operating on an skb whose headroom was
allocated from an earlier hard_header_len read, so a concurrent increase
can write past the reserved buffer. Removing it first keeps the later
snapshot fixes bisect-safe: they do not replace an earlier skb_under_panic
with a silent overwrite.
Patches 2 and 3 snapshot hard_header_len once per send and use it
consistently for allocation and construction, in the non-ring and TX_RING
paths respectively. The separate SOCK_DGRAM consistency problem between
hard_header_len and header_ops->create remains out of scope, as noted in
the commit messages.
v5 -> v6:
- Fix Signed-off-by to use full name (DCO).
- Add patch 1: remove CAP_SYS_RAWIO zero-padding in dev_validate_header,
before the snapshot fixes for per-commit safety. Suggested by Willem de
Bruijn.
- Add Reviewed-by from Willem de Bruijn to the TX_RING patch (given on v5).
v5: https://lore.kernel.org/netdev/20260730082925.93759-1-q.h.hack.winter@gmail.com/
Qihang Tang (3):
net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header
packet: use consistent hard_header_len in non-ring send paths
packet: use consistent hard_header_len in TX_RING send path
include/linux/netdevice.h | 11 ++++------
net/packet/af_packet.c | 45 +++++++++++++++++++++++----------------
2 files changed, 31 insertions(+), 25 deletions(-)
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net v6 1/3] net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header
2026-08-04 9:00 ` [PATCH net v6 0/3] net: fix hard_header_len races in packet send paths Qihang
@ 2026-08-04 9:00 ` Qihang
2026-08-04 12:16 ` Willem de Bruijn
0 siblings, 1 reply; 14+ messages in thread
From: Qihang @ 2026-08-04 9:00 UTC (permalink / raw)
To: netdev
Cc: willemdebruijn.kernel, willemb, daniel.zahka, davem, edumazet,
kuba, pabeni, horms, stable, Qihang Tang
From: Qihang Tang <q.h.hack.winter@gmail.com>
dev_validate_header() reads dev->hard_header_len directly when
zero-padding short link layer headers for CAP_SYS_RAWIO holders:
if (capable(CAP_SYS_RAWIO)) {
memset(ll_header + len, 0, dev->hard_header_len - len);
return true;
}
Packet send paths call dev_validate_header() on skbs whose headroom was
allocated from an earlier hard_header_len read. If the device is
reconfigured so that dev->hard_header_len increases before validation,
the memset writes past the reserved buffer, an out-of-bounds write.
This out-of-bounds write is masked in some SOCK_RAW paths today because
the same concurrent increase can first make skb_push() exceed the
reserved headroom and trigger skb_under_panic(). Remove the zero-padding
branch before making those hard_header_len reads consistent, so the
snapshot fixes do not turn a loud panic into a silent overwrite.
This path is only reached for variable length L2 protocols, where
len < hard_header_len but len >= min_header_len. No remaining in-tree
variable length L2 protocol implements header_ops->validate, and the
CAP_SYS_RAWIO bypass that zero-pads and accepts short headers has no
real value beyond allowing testing of intentionally malformed input.
Drop the CAP_SYS_RAWIO branch. The remaining reads of
dev->hard_header_len in dev_validate_header() are comparisons only and
have no memory safety impact.
Suggested-by: Willem de Bruijn <willemb@google.com>
Fixes: 2793a23aacbd ("net: validate variable length ll headers")
Cc: stable@vger.kernel.org
Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
---
include/linux/netdevice.h | 5 -----
1 file changed, 5 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9981d637f8b5..9a770eb823ce 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3531,11 +3531,6 @@ static inline bool dev_validate_header(const struct net_device *dev,
if (len < dev->min_header_len)
return false;
- if (capable(CAP_SYS_RAWIO)) {
- memset(ll_header + len, 0, dev->hard_header_len - len);
- return true;
- }
-
if (dev->header_ops && dev->header_ops->validate)
return dev->header_ops->validate(ll_header, len);
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net v6 2/3] packet: use consistent hard_header_len in non-ring send paths
2026-07-30 8:29 [PATCH net v5 0/2] packet: use consistent hard_header_len in send paths Qihang
` (2 preceding siblings ...)
2026-08-04 9:00 ` [PATCH net v6 0/3] net: fix hard_header_len races in packet send paths Qihang
@ 2026-08-04 9:32 ` Qihang
2026-08-04 9:33 ` [PATCH net v6 3/3] packet: use consistent hard_header_len in TX_RING send path Qihang
4 siblings, 0 replies; 14+ messages in thread
From: Qihang @ 2026-08-04 9:32 UTC (permalink / raw)
To: netdev
Cc: willemdebruijn.kernel, willemb, daniel.zahka, davem, edumazet,
kuba, pabeni, horms, stable, Qihang Tang
From: Qihang Tang <q.h.hack.winter@gmail.com>
packet_snd() reads dev->hard_header_len multiple times while allocating
and constructing an skb. Device reconfiguration can change this value
concurrently, for example through bonding device type changes.
For SOCK_RAW, packet_snd() can save a larger value in reserve and later
allocate headroom using a smaller value. Moving skb->data back by reserve
then places it before skb->head, and the following copy from userspace can
attempt an out-of-bounds write.
packet_sendmsg_spkt() has the same issue because it calculates its
reservation and header offset from separate reads before dropping the RCU
read lock to allocate the skb.
Add LL_RESERVED_SPACE_EX() for callers that already saved a header length.
Read hard_header_len once in packet_snd() and use it for allocation and
construction. In packet_sendmsg_spkt(), preserve the allocation-time value
through the device lookup retry.
The separate SOCK_DGRAM consistency problem between hard_header_len and
header_ops->create is not addressed here.
Fixes: b84bbaf7a6c8 ("packet: in packet_snd start writing at link layer allocation")
Cc: stable@vger.kernel.org
Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
include/linux/netdevice.h | 6 ++++--
net/packet/af_packet.c | 26 ++++++++++++++++----------
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9a770eb823ce..8840b126979f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -300,9 +300,11 @@ struct hh_cache {
* We could use other alignment values, but we must maintain the
* relationship HH alignment <= LL alignment.
*/
-#define LL_RESERVED_SPACE(dev) \
- ((((dev)->hard_header_len + READ_ONCE((dev)->needed_headroom)) \
+#define LL_RESERVED_SPACE_EX(dev, hlen) \
+ ((((hlen) + READ_ONCE((dev)->needed_headroom)) \
& ~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+#define LL_RESERVED_SPACE(dev) \
+ LL_RESERVED_SPACE_EX(dev, (dev)->hard_header_len)
#define LL_RESERVED_SPACE_EXTRA(dev,extra) \
((((dev)->hard_header_len + READ_ONCE((dev)->needed_headroom) + (extra)) \
& ~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index e75d2932475a..88674a6e868c 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1953,8 +1953,9 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
struct net_device *dev;
struct sockcm_cookie sockc;
__be16 proto = 0;
- int err;
+ int hard_header_len;
int extra_len = 0;
+ int err;
/*
* Get and verify the address.
@@ -1997,14 +1998,18 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
extra_len = 4; /* We're doing our own CRC */
}
+ /* Keep the allocation-time header length across retry. */
+ if (!skb)
+ hard_header_len = READ_ONCE(dev->hard_header_len);
+
err = -EMSGSIZE;
- if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN + extra_len)
+ if (len > dev->mtu + hard_header_len + VLAN_HLEN + extra_len)
goto out_unlock;
if (!skb) {
- size_t reserved = LL_RESERVED_SPACE(dev);
+ size_t reserved = LL_RESERVED_SPACE_EX(dev, hard_header_len);
int tlen = dev->needed_tailroom;
- unsigned int hhlen = dev->header_ops ? dev->hard_header_len : 0;
+ unsigned int hhlen = dev->header_ops ? hard_header_len : 0;
rcu_read_unlock();
skb = sock_wmalloc(sk, len + reserved + tlen, 0, GFP_KERNEL);
@@ -2034,7 +2039,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
err = -EINVAL;
goto out_unlock;
}
- if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
+ if (len > (dev->mtu + hard_header_len + extra_len) &&
!packet_extra_vlan_len_allowed(dev, skb)) {
err = -EMSGSIZE;
goto out_unlock;
@@ -2956,7 +2961,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
int offset = 0;
struct packet_sock *po = pkt_sk(sk);
int vnet_hdr_sz = READ_ONCE(po->vnet_hdr_sz);
- int hlen, tlen, linear;
+ int hard_header_len, hlen, tlen, linear;
int extra_len = 0;
/*
@@ -2996,8 +3001,9 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
goto out_unlock;
}
+ hard_header_len = READ_ONCE(dev->hard_header_len);
if (sock->type == SOCK_RAW)
- reserve = dev->hard_header_len;
+ reserve = hard_header_len;
if (vnet_hdr_sz) {
err = packet_snd_vnet_parse(msg, &len, &vnet_hdr, vnet_hdr_sz);
if (err)
@@ -3018,10 +3024,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
goto out_unlock;
err = -ENOBUFS;
- hlen = LL_RESERVED_SPACE(dev);
+ hlen = LL_RESERVED_SPACE_EX(dev, hard_header_len);
tlen = dev->needed_tailroom;
linear = __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len);
- linear = max(linear, min_t(int, len, dev->hard_header_len));
+ linear = max(linear, min_t(int, len, hard_header_len));
skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, linear,
msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
@@ -3037,7 +3043,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
} else if (reserve) {
skb_reserve(skb, -reserve);
if (len < reserve + sizeof(struct ipv6hdr) &&
- dev->min_header_len != dev->hard_header_len)
+ dev->min_header_len != hard_header_len)
skb_reset_network_header(skb);
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net v6 3/3] packet: use consistent hard_header_len in TX_RING send path
2026-07-30 8:29 [PATCH net v5 0/2] packet: use consistent hard_header_len in send paths Qihang
` (3 preceding siblings ...)
2026-08-04 9:32 ` [PATCH net v6 2/3] packet: use consistent hard_header_len in non-ring send paths Qihang
@ 2026-08-04 9:33 ` Qihang
4 siblings, 0 replies; 14+ messages in thread
From: Qihang @ 2026-08-04 9:33 UTC (permalink / raw)
To: netdev
Cc: willemdebruijn.kernel, willemb, daniel.zahka, davem, edumazet,
kuba, pabeni, horms, stable, Qihang Tang
From: Qihang Tang <q.h.hack.winter@gmail.com>
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: 69e3c75f4d54 ("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>
---
net/packet/af_packet.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 88674a6e868c..e9b6810c885e 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2574,6 +2574,7 @@ static int packet_snd_vnet_parse(struct msghdr *msg, size_t *len,
static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
void *frame, struct net_device *dev, void *data, int tp_len,
__be16 proto, unsigned char *addr, int hlen, int copylen,
+ int hard_header_len,
const struct sockcm_cookie *sockc)
{
union tpacket_uhdr ph;
@@ -2605,8 +2606,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
} else if (copylen) {
int hdrlen = min_t(int, copylen, tp_len);
- skb_push(skb, dev->hard_header_len);
- skb_put(skb, copylen - dev->hard_header_len);
+ skb_push(skb, hard_header_len);
+ skb_put(skb, copylen - hard_header_len);
err = skb_store_bits(skb, 0, data, hdrlen);
if (unlikely(err))
return err;
@@ -2737,7 +2738,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
void *data;
int len_sum = 0;
int status = TP_STATUS_AVAILABLE;
- int hlen, tlen, copylen = 0;
+ int hard_header_len, hlen, tlen, copylen = 0;
long timeo;
mutex_lock(&po->pg_vec_lock);
@@ -2784,8 +2785,9 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
goto out_put;
}
+ hard_header_len = READ_ONCE(dev->hard_header_len);
if (po->sk.sk_socket->type == SOCK_RAW)
- reserve = dev->hard_header_len;
+ reserve = hard_header_len;
size_max = po->tx_ring.frame_size
- (po->tp_hdrlen - sizeof(struct sockaddr_ll));
@@ -2822,7 +2824,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
goto tpacket_error;
status = TP_STATUS_SEND_REQUEST;
- hlen = LL_RESERVED_SPACE(dev);
+ hlen = LL_RESERVED_SPACE_EX(dev, hard_header_len);
tlen = dev->needed_tailroom;
if (vnet_hdr_sz) {
data += vnet_hdr_sz;
@@ -2840,10 +2842,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
vnet_hdr.hdr_len);
has_vnet_hdr = true;
}
- copylen = max_t(int, copylen, dev->hard_header_len);
+ copylen = max_t(int, copylen, hard_header_len);
skb = sock_alloc_send_skb(&po->sk,
hlen + tlen + sizeof(struct sockaddr_ll) +
- (copylen - dev->hard_header_len),
+ (copylen - hard_header_len),
!need_wait, &err);
if (unlikely(skb == NULL)) {
@@ -2853,7 +2855,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
goto out_status;
}
tp_len = tpacket_fill_skb(po, skb, ph, dev, data, tp_len, proto,
- addr, hlen, copylen, &sockc);
+ addr, hlen, copylen, hard_header_len,
+ &sockc);
if (likely(tp_len >= 0) &&
tp_len > dev->mtu + reserve &&
!vnet_hdr_sz &&
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH net v6 1/3] net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header
2026-08-04 9:00 ` [PATCH net v6 1/3] net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header Qihang
@ 2026-08-04 12:16 ` Willem de Bruijn
2026-08-04 23:44 ` Jakub Kicinski
0 siblings, 1 reply; 14+ messages in thread
From: Willem de Bruijn @ 2026-08-04 12:16 UTC (permalink / raw)
To: Qihang, netdev
Cc: willemdebruijn.kernel, willemb, daniel.zahka, davem, edumazet,
kuba, pabeni, horms, stable, Qihang Tang
Qihang wrote:
> From: Qihang Tang <q.h.hack.winter@gmail.com>
>
> dev_validate_header() reads dev->hard_header_len directly when
> zero-padding short link layer headers for CAP_SYS_RAWIO holders:
>
> if (capable(CAP_SYS_RAWIO)) {
> memset(ll_header + len, 0, dev->hard_header_len - len);
> return true;
> }
>
> Packet send paths call dev_validate_header() on skbs whose headroom was
> allocated from an earlier hard_header_len read. If the device is
> reconfigured so that dev->hard_header_len increases before validation,
> the memset writes past the reserved buffer, an out-of-bounds write.
>
> This out-of-bounds write is masked in some SOCK_RAW paths today because
> the same concurrent increase can first make skb_push() exceed the
> reserved headroom and trigger skb_under_panic(). Remove the zero-padding
> branch before making those hard_header_len reads consistent, so the
> snapshot fixes do not turn a loud panic into a silent overwrite.
>
> This path is only reached for variable length L2 protocols, where
> len < hard_header_len but len >= min_header_len. No remaining in-tree
> variable length L2 protocol implements header_ops->validate, and the
> CAP_SYS_RAWIO bypass that zero-pads and accepts short headers has no
> real value beyond allowing testing of intentionally malformed input.
>
> Drop the CAP_SYS_RAWIO branch. The remaining reads of
> dev->hard_header_len in dev_validate_header() are comparisons only and
> have no memory safety impact.
>
> Suggested-by: Willem de Bruijn <willemb@google.com>
> Fixes: 2793a23aacbd ("net: validate variable length ll headers")
> Cc: stable@vger.kernel.org
> Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
For future patches: don't send new revisions as replies to existing threads.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path
2026-08-04 3:04 ` Willem de Bruijn
@ 2026-08-04 23:43 ` Jakub Kicinski
0 siblings, 0 replies; 14+ messages in thread
From: Jakub Kicinski @ 2026-08-04 23:43 UTC (permalink / raw)
To: Willem de Bruijn
Cc: Qihang, netdev, daniel.zahka, davem, edumazet, pabeni, horms,
stable
On Mon, 03 Aug 2026 23:04:54 -0400 Willem de Bruijn wrote:
> If I read Gemini feedback correctly, all reports are about the current
> solution falling short of fixing the instance of this race condition
> with dev_hard_header(), which reads dev->hard_header_len directly.
> The patch indeed mentions this limitation.
To be clear -- prefer looking that the netdev-ai instance.
It cross reviews the feedback with different LLMs
> As well as the same issue with dev_validate_header(), which the commit
> does not list as limitation. But that one is only reached with variable
> length L2 protocols.
>
> Side note, in net-next I can probably remove header_ops.validate now
> that ax25 is gone, and with that all of dev_validate_header. No other
> variable length L2 protocol ever implemented that callback.
Let's do it.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net v6 1/3] net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header
2026-08-04 12:16 ` Willem de Bruijn
@ 2026-08-04 23:44 ` Jakub Kicinski
0 siblings, 0 replies; 14+ messages in thread
From: Jakub Kicinski @ 2026-08-04 23:44 UTC (permalink / raw)
To: Qihang
Cc: Willem de Bruijn, netdev, willemb, daniel.zahka, davem, edumazet,
pabeni, horms, stable
On Tue, 04 Aug 2026 08:16:35 -0400 Willem de Bruijn wrote:
> For future patches: don't send new revisions as replies to existing threads.
Unfortunately, in this case patchwork was not able to process
the posting due to the incorrect threading. A repost (after 24h)
will be need.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net v6 2/3] packet: use consistent hard_header_len in non-ring send paths
2026-08-05 12:57 [PATCH net v6 0/3] net: fix hard_header_len races in packet send paths Qihang
@ 2026-08-05 12:57 ` Qihang
0 siblings, 0 replies; 14+ messages in thread
From: Qihang @ 2026-08-05 12:57 UTC (permalink / raw)
To: netdev
Cc: willemdebruijn.kernel, willemb, daniel.zahka, davem, edumazet,
kuba, pabeni, horms, stable, Qihang Tang
From: Qihang Tang <q.h.hack.winter@gmail.com>
packet_snd() reads dev->hard_header_len multiple times while allocating
and constructing an skb. Device reconfiguration can change this value
concurrently, for example through bonding device type changes.
For SOCK_RAW, packet_snd() can save a larger value in reserve and later
allocate headroom using a smaller value. Moving skb->data back by reserve
then places it before skb->head, and the following copy from userspace can
attempt an out-of-bounds write.
packet_sendmsg_spkt() has the same issue because it calculates its
reservation and header offset from separate reads before dropping the RCU
read lock to allocate the skb.
Add LL_RESERVED_SPACE_EX() for callers that already saved a header length.
Read hard_header_len once in packet_snd() and use it for allocation and
construction. In packet_sendmsg_spkt(), preserve the allocation-time value
through the device lookup retry.
The separate SOCK_DGRAM consistency problem between hard_header_len and
header_ops->create is not addressed here.
Fixes: b84bbaf7a6c8 ("packet: in packet_snd start writing at link layer allocation")
Cc: stable@vger.kernel.org
Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
include/linux/netdevice.h | 6 ++++--
net/packet/af_packet.c | 26 ++++++++++++++++----------
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9a770eb823ce..8840b126979f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -300,9 +300,11 @@ struct hh_cache {
* We could use other alignment values, but we must maintain the
* relationship HH alignment <= LL alignment.
*/
-#define LL_RESERVED_SPACE(dev) \
- ((((dev)->hard_header_len + READ_ONCE((dev)->needed_headroom)) \
+#define LL_RESERVED_SPACE_EX(dev, hlen) \
+ ((((hlen) + READ_ONCE((dev)->needed_headroom)) \
& ~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+#define LL_RESERVED_SPACE(dev) \
+ LL_RESERVED_SPACE_EX(dev, (dev)->hard_header_len)
#define LL_RESERVED_SPACE_EXTRA(dev,extra) \
((((dev)->hard_header_len + READ_ONCE((dev)->needed_headroom) + (extra)) \
& ~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index e75d2932475a..88674a6e868c 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1953,8 +1953,9 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
struct net_device *dev;
struct sockcm_cookie sockc;
__be16 proto = 0;
- int err;
+ int hard_header_len;
int extra_len = 0;
+ int err;
/*
* Get and verify the address.
@@ -1997,14 +1998,18 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
extra_len = 4; /* We're doing our own CRC */
}
+ /* Keep the allocation-time header length across retry. */
+ if (!skb)
+ hard_header_len = READ_ONCE(dev->hard_header_len);
+
err = -EMSGSIZE;
- if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN + extra_len)
+ if (len > dev->mtu + hard_header_len + VLAN_HLEN + extra_len)
goto out_unlock;
if (!skb) {
- size_t reserved = LL_RESERVED_SPACE(dev);
+ size_t reserved = LL_RESERVED_SPACE_EX(dev, hard_header_len);
int tlen = dev->needed_tailroom;
- unsigned int hhlen = dev->header_ops ? dev->hard_header_len : 0;
+ unsigned int hhlen = dev->header_ops ? hard_header_len : 0;
rcu_read_unlock();
skb = sock_wmalloc(sk, len + reserved + tlen, 0, GFP_KERNEL);
@@ -2034,7 +2039,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
err = -EINVAL;
goto out_unlock;
}
- if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
+ if (len > (dev->mtu + hard_header_len + extra_len) &&
!packet_extra_vlan_len_allowed(dev, skb)) {
err = -EMSGSIZE;
goto out_unlock;
@@ -2956,7 +2961,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
int offset = 0;
struct packet_sock *po = pkt_sk(sk);
int vnet_hdr_sz = READ_ONCE(po->vnet_hdr_sz);
- int hlen, tlen, linear;
+ int hard_header_len, hlen, tlen, linear;
int extra_len = 0;
/*
@@ -2996,8 +3001,9 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
goto out_unlock;
}
+ hard_header_len = READ_ONCE(dev->hard_header_len);
if (sock->type == SOCK_RAW)
- reserve = dev->hard_header_len;
+ reserve = hard_header_len;
if (vnet_hdr_sz) {
err = packet_snd_vnet_parse(msg, &len, &vnet_hdr, vnet_hdr_sz);
if (err)
@@ -3018,10 +3024,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
goto out_unlock;
err = -ENOBUFS;
- hlen = LL_RESERVED_SPACE(dev);
+ hlen = LL_RESERVED_SPACE_EX(dev, hard_header_len);
tlen = dev->needed_tailroom;
linear = __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len);
- linear = max(linear, min_t(int, len, dev->hard_header_len));
+ linear = max(linear, min_t(int, len, hard_header_len));
skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, linear,
msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
@@ -3037,7 +3043,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
} else if (reserve) {
skb_reserve(skb, -reserve);
if (len < reserve + sizeof(struct ipv6hdr) &&
- dev->min_header_len != dev->hard_header_len)
+ dev->min_header_len != hard_header_len)
skb_reset_network_header(skb);
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-08-05 12:58 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 8:29 [PATCH net v5 0/2] packet: use consistent hard_header_len in send paths Qihang
2026-07-30 8:29 ` [PATCH net v5 1/2] packet: use consistent hard_header_len in non-ring " Qihang
2026-07-30 8:29 ` [PATCH net v5 2/2] packet: use consistent hard_header_len in TX_RING send path Qihang
2026-07-30 9:22 ` Willem de Bruijn
2026-08-04 2:22 ` Jakub Kicinski
2026-08-04 3:04 ` Willem de Bruijn
2026-08-04 23:43 ` Jakub Kicinski
2026-08-04 9:00 ` [PATCH net v6 0/3] net: fix hard_header_len races in packet send paths Qihang
2026-08-04 9:00 ` [PATCH net v6 1/3] net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header Qihang
2026-08-04 12:16 ` Willem de Bruijn
2026-08-04 23:44 ` Jakub Kicinski
2026-08-04 9:32 ` [PATCH net v6 2/3] packet: use consistent hard_header_len in non-ring send paths Qihang
2026-08-04 9:33 ` [PATCH net v6 3/3] packet: use consistent hard_header_len in TX_RING send path Qihang
-- strict thread matches above, loose matches on Subject: below --
2026-08-05 12:57 [PATCH net v6 0/3] net: fix hard_header_len races in packet send paths Qihang
2026-08-05 12:57 ` [PATCH net v6 2/3] packet: use consistent hard_header_len in non-ring " Qihang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox