FAILED: patch "[PATCH] packet: use consistent hard_header_len in TX_RING send path" failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-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.15.y
git checkout FETCH_HEAD
git cherry-pick -x 21b5953e7494c16a42e6cd8cf110e18d13ae4a6b
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026081746-railing-baffling-3449@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 21b5953e7494c16a42e6cd8cf110e18d13ae4a6b Mon Sep 17 00:00:00 2001
From: Qihang Tang <[email protected]>
Date: Wed, 5 Aug 2026 20:57:29 +0800
Subject: [PATCH] packet: use consistent hard_header_len in TX_RING send path
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.
net/packet/af_packet.c +11 -8
@@ -2587,6 +2587,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;
@@ -2618,8 +2619,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;
@@ -2750,7 +2751,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);
@@ -2797,8 +2798,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 ));
@@ -2835,7 +2837,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;
@@ -2853,10 +2855,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 )) {
@@ -2866,7 +2868,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 &&
Sasha Levin
maintainerPATCH 1/2 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.
Stable-dep-of: 21b5953e7494 ("packet: use consistent hard_header_len in TX_RING send path")
--- include/linux/netdevice.h | 6 ++++-- net/packet/af_packet.c | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-)
include/linux/netdevice.h +4 -2
@@ -274,9 +274,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
@@ -1972,8 +1972,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.
@@ -2016,14 +2017,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 );
@@ -2053,7 +2058,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;
@@ -2966,7 +2971,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 ;/*
@@ -3007,8 +3012,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)
@@ -3030,10 +3036,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 )
@@ -3049,7 +3055,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
Sasha Levin
maintainerPATCH 2/2 packet: use consistent hard_header_len in TX_RING send path
From: Qihang Tang <[email protected]>
[ Upstream commit 21b5953e7494c16a42e6cd8cf110e18d13ae4a6b ]
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.
--- net/packet/af_packet.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
net/packet/af_packet.c +11 -8
@@ -2586,6 +2586,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;
@@ -2617,8 +2618,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;
@@ -2748,7 +2749,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);
@@ -2795,8 +2796,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 ));
@@ -2833,7 +2835,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 (po->has_vnet_hdr) { data +=sizeof (vnet_hdr);
@@ -2851,10 +2853,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 )) {
@@ -2864,7 +2866,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 && !po->has_vnet_hdr &&
Signature · 1 line
2.53.0