FAILED: patch "[PATCH] packet: use consistent hard_header_len in non-ring send paths" failed to apply to 5.10-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x 03390aa32e669cc4ecd7d34108e2e1afc13d689d
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026081702-flagstone-product-2e6e@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 03390aa32e669cc4ecd7d34108e2e1afc13d689d Mon Sep 17 00:00:00 2001
From: Qihang Tang <[email protected]>
Date: Wed, 5 Aug 2026 20:57:28 +0800
Subject: [PATCH] packet: use consistent hard_header_len in non-ring send paths
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.
include/linux/netdevice.h +4 -2
@@ -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)
net/packet/af_packet.c +16 -10
@@ -1966,8 +1966,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.
@@ -2010,14 +2011,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 );
@@ -2047,7 +2052,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;
@@ -2969,7 +2974,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 ;/*
@@ -3009,8 +3014,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)
@@ -3031,10 +3037,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 )
@@ -3050,7 +3056,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); }
Sasha Levin
maintainerPATCH 1/1 packet: use consistent hard_header_len in non-ring send paths
From: Qihang Tang <[email protected]>
[ Upstream commit 03390aa32e669cc4ecd7d34108e2e1afc13d689d ]
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.
--- include/linux/netdevice.h | 6 ++++-- net/packet/af_packet.c | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-)
include/linux/netdevice.h +4 -2
@@ -269,9 +269,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)
net/packet/af_packet.c +16 -10
@@ -1968,8 +1968,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.
@@ -2012,14 +2013,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 );
@@ -2049,7 +2054,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;
@@ -2962,7 +2967,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)int offset =0 ;struct packet_sock *po =pkt_sk (sk);bool has_vnet_hdr = false; -int hlen, tlen, linear; +int hard_header_len, hlen, tlen, linear;int extra_len =0 ;/*
@@ -3003,8 +3008,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 (po->has_vnet_hdr) { err =packet_snd_vnet_parse (msg, &len, &vnet_hdr);if (err)
@@ -3026,10 +3032,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 )
@@ -3045,7 +3051,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); }
Signature · 1 line
2.53.0