* [PATCH v6 0/2] bpf, sockmap: handle spurious tcp_msg_wait_data() wakeup
From: Nnamdi Onyeyiri @ 2026-07-20 17:15 UTC (permalink / raw)
To: nnamdio
Cc: bpf, davem, edumazet, horms, jakub, jiayuan.chen, john.fastabend,
kuba, kuniyu, ncardwell, netdev, pabeni, sashiko-reviews,
linux-kernel
Spurious wakeups in tcp_msg_wait_data() aren't being handled by
tcp_bpf_recvmsg() and tcp_bpf_recvmsg_parser(), leading to unexpected
EAGAIN errors returned by recvfrom()/recv(). Adding handling for the
wakeup and a selftest.
This issue was first discovered in an application that adds sockets to
a sockmap as a way to view the received data. No redirects or any
other operations are performed.
Sashiko has noted a few other pre-existing issues in the same area
(https://patch.msgid.link/20260714205118.17DB11F000E9@smtp.kernel.org)
that can lead to EAGAIN in tcp_bpf_recvmsg() and
tcp_bpf_recvmsg_parser(). A local run of Sashiko also identified a
potential issue in tcp_bpf_recvmsg() handling zero-data FIN packets when
the MSG_PEEK flag is set. To prevent this patchset from growing too
large, I intend to submit follow up patches to address these once this
one has been accepted.
Changes in v6:
- Closing the file descriptor in the selftest worker thread.
- Ensuring the selftest loop breaks early for an error in the worker
thread.
- Added comments to selftest regarding focus on EAGAIN error.
- Updated selftest commit message to imperative mood.
- Link to v5: https://patch.msgid.link/20260717155348.54975-1-nnamdio@gmail.com
Changes in v5:
- Move selftest from net into bpf/prog_tests/sockmap_basic.c
- Link to v4: https://patch.msgid.link/20260715213538.37229-1-nnamdio@gmail.com
Changes in v4:
- Fix potential data loss in tcp_bpf_recvmsg() when a FIN or RST has
been received.
- Check the return code of pthread_create() in the selftest.
- Fix race caused by using EXPECT macros in a thread in selftest.
- Link to v3: https://patch.msgid.link/20260714203927.32289-1-nnamdio@gmail.com
Changes in v3:
- Added the sockmap_recvfrom selftest.
- Link to v2: https://patch.msgid.link/alFRK66z45eDNZA7@localhost.localdomain
Changes in v2:
- In tcp_bpf_recvmsg, handle signals and the socket closing in the loop.
- Fix spurious wakeups when SO_RCVTIMEO has been set on the socket.
- Link to v1: https://patch.msgid.link/ak_rR-Skd8Mvn4mH@localhost.localdomain
Signed-off-by: Nnamdi Onyeyiri <nnamdio@gmail.com>
---
Nnamdi Onyeyiri (2):
bpf, sockmap: handle spurious tcp_msg_wait_data() wakeup
selftests/bpf: add sockmap recvfrom EAGAIN selftest
net/ipv4/tcp_bpf.c | 69 ++++++++--
.../selftests/bpf/prog_tests/sockmap_basic.c | 124 ++++++++++++++++++
2 files changed, 184 insertions(+), 9 deletions(-)
--
2.52.0
^ permalink raw reply
* [PATCH net] net/smc: validate peer CDC cursor against RMBE size before accepting it
From: Ibrahim Hashimov @ 2026-07-20 17:07 UTC (permalink / raw)
To: alibuda, dust.li, wenjia, davem, edumazet, kuba, pabeni
Cc: tonylu, guwen, horms, linux-rdma, linux-s390, netdev,
linux-kernel, stable
smc_cdc_cursor_to_host() converts the wire-format producer/consumer
cursor of an incoming CDC message into a host smc_host_cursor. It rejects
a cursor that goes backwards, but never checks that the cursor's count is
inside the buffer it indexes. Per smc_host_cursor ("an offset in an
RMBE") and the invariant smc_curs_add() enforces for every local advance
(0 <= count < size), a valid cursor count must be < size; the wire cursor
is peer-controlled and was never checked against that.
smcr_cdc_msg_to_host() accepts the producer and consumer cursors, and the
unbounded value feeds smc_curs_diff() in smc_cdc_msg_recv_action(), which
computes new->count - old->count without clamping against size. A peer
that puts an out-of-range prod.count on the wire (e.g. 0x7fffffff) drives
bytes_to_rcv far past rmb_desc->len -- the very invariant the comment
above the atomic_add() claims but does not enforce.
smc_rx_recvmsg() then trusts bytes_to_rcv as the amount of valid RMB
data. Its first copy chunk is safely bounded by rmb_desc->len -
cons.count, but the second chunk copies (copylen - chunk_len) bytes from
offset 0, and copylen came from the inflated readable -- an out-of-bounds
read of the RMB's backing (v)malloc allocation, copied straight to the
receiving process via _copy_to_iter(). This is a remote kernel-memory
disclosure driven by a malicious SMC-R peer, needing no local privilege
on the victim. The same unbounded count also reaches
smc_cdc_handle_urg_data_arrival() (base + urg_curs.count - 1) -- a
second, narrower OOB read.
Fix it where the wire cursor is accepted, mirroring the cursor-sanity
idiom two lines above: reject any incoming cursor whose count is >= the
size of the buffer it will index. smc_cdc_cursor_to_host() gains a size
parameter; smcr_cdc_msg_to_host() passes conn->rmb_desc->len for the
producer cursor and conn->peer_rmbe_size for the consumer cursor. This
bounds it at its single origin instead of patching every downstream
consumer. SMC-D (smcd_cdc_msg_to_host()) does not use this helper and is
a separate, out-of-scope gap.
Reproduced on a v6.19 KASAN kernel (SMC-Rv2 over soft-RoCE): a peer
emitting prod.count=0x7fffffff triggers a vmalloc-out-of-bounds read in
_copy_to_iter() via smc_rx_recvmsg(), returning ~960 KB of RMB-adjacent
kernel heap to userspace; an in-range cursor transfers cleanly. With the
fix the out-of-range cursor is dropped before it reaches
conn->local_rx_ctrl.prod, and the reproducer returns rc=0 with no report.
Fixes: 5f08318f617b ("smc: connection data control (CDC)")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
---
net/smc/smc_cdc.h | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/net/smc/smc_cdc.h b/net/smc/smc_cdc.h
index 696cc11f2303..f07bbef47073 100644
--- a/net/smc/smc_cdc.h
+++ b/net/smc/smc_cdc.h
@@ -221,6 +221,7 @@ static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer,
static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local,
union smc_cdc_cursor *peer,
+ unsigned int size,
struct smc_connection *conn)
{
union smc_host_cursor temp, old;
@@ -235,6 +236,14 @@ static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local,
if ((old.wrap == temp.wrap) &&
(old.count > temp.count))
return;
+ /* count is an offset into the RMBE and must always stay inside
+ * it (see smc_curs_add()); the peer is untrusted, so reject an
+ * out-of-range wire cursor the same way an out-of-order one is
+ * already rejected above, instead of letting it drive
+ * bytes_to_rcv / the urgent-byte offset past the buffer end
+ */
+ if (temp.count >= size)
+ return;
smc_curs_copy(local, &temp, conn);
}
@@ -246,8 +255,10 @@ static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local,
local->len = peer->len;
local->seqno = ntohs(peer->seqno);
local->token = ntohl(peer->token);
- smc_cdc_cursor_to_host(&local->prod, &peer->prod, conn);
- smc_cdc_cursor_to_host(&local->cons, &peer->cons, conn);
+ smc_cdc_cursor_to_host(&local->prod, &peer->prod,
+ conn->rmb_desc->len, conn);
+ smc_cdc_cursor_to_host(&local->cons, &peer->cons,
+ conn->peer_rmbe_size, conn);
local->prod_flags = peer->prod_flags;
local->conn_state_flags = peer->conn_state_flags;
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* Re: [PATCH 4/8] net: bcmgenet: use platform_device_set_fwnode()
From: Florian Fainelli @ 2026-07-20 16:57 UTC (permalink / raw)
To: Andrew Lunn, Bartosz Golaszewski
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Andi Shyti, Joerg Roedel (AMD),
Will Deacon, Robin Murphy, Andy Shevchenko, Doug Berger,
Broadcom internal kernel review list, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Ulf Hansson, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Lee Jones, Sebastian Hesselbarth,
Srinivas Kandagatla, brgl, driver-core, linuxppc-dev,
linux-kernel, linux-i2c, iommu, netdev, linux-pm, imx,
linux-arm-kernel, mfd, linux-arm-msm, linux-sound
In-Reply-To: <ae9da5dd-3528-4270-ada0-d17ed14478e0@lunn.ch>
[-- Attachment #1: Type: text/plain, Size: 668 bytes --]
On 7/20/26 07:38, Andrew Lunn wrote:
> On Mon, Jul 20, 2026 at 11:24:51AM +0200, Bartosz Golaszewski wrote:
>> Prefer the higher-level platform_device_set_fwnode() over the
>> OF-specific platform_device_set_of_node() for dynamically allocated
>> platform devices.
>
> Why?
>
> This driver is OF only. It does not support ACPI, and probably never
> will. In general, networking and ACPI don't go together, ACPI is not
> sufficiently advanced.
>
> What is you use case here?
The driver has been, or was used on ACPI-based platforms:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=99c6b06a37d4cab118c45448fef9d28df62d35d8
--
Florian
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5485 bytes --]
^ permalink raw reply
* Re: [PATCH net 2/2] selftests/net: packetdrill: cover RST validation in SYN-RECEIVED
From: Eric Dumazet @ 2026-07-20 16:48 UTC (permalink / raw)
To: Yuxiang Yang
Cc: netdev, linux-kernel, linux-kselftest, Neal Cardwell,
Kuniyuki Iwashima, David S . Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, Yizhou Zhao, Ao Wang, Xuewei Feng,
Qi Li, Ke Xu, yyxroy22
In-Reply-To: <20260717081443.809393-3-yangyx22@mails.tsinghua.edu.cn>
On Fri, Jul 17, 2026 at 10:15 AM Yuxiang Yang
<yangyx22@mails.tsinghua.edu.cn> wrote:
>
> Add packetdrill coverage for the RFC 9293 reset checks on request
> sockets in SYN-RECEIVED. Verify that an exact RST removes the request,
> a non-exact in-window RST sends a challenge ACK without removing it,
> and an out-of-window RST is silently discarded.
>
> Also cover an RST|ACK with an unacceptable ACK number to ensure RST
> sequence validation runs before ACK-field validation.
>
> Signed-off-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Thanks!
^ permalink raw reply
* Re: [PATCH net 1/2] tcp: challenge ACK for non-exact RST in SYN-RECEIVED
From: Eric Dumazet @ 2026-07-20 16:45 UTC (permalink / raw)
To: Yuxiang Yang
Cc: netdev, linux-kernel, linux-kselftest, Neal Cardwell,
Kuniyuki Iwashima, David S . Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, Yizhou Zhao, Ao Wang, Xuewei Feng,
Qi Li, Ke Xu, stable, yyxroy22
In-Reply-To: <20260717081443.809393-2-yangyx22@mails.tsinghua.edu.cn>
On Fri, Jul 17, 2026 at 10:15 AM Yuxiang Yang
<yangyx22@mails.tsinghua.edu.cn> wrote:
>
> The SYN-RECEIVED request-socket path in tcp_check_req() accepts an
> in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A
> non-exact RST therefore removes the request instead of eliciting a
> challenge ACK.
>
> RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in
> SYN-RECEIVED: an exact RST resets the connection, while a non-exact
> in-window RST must trigger a challenge ACK and be dropped.
>
> Apply that check before the ACK-field validation, following the RFC
> sequence-number, RST, then ACK processing order. Factor the per-netns
> challenge ACK quota out of tcp_send_challenge_ack() so request sockets
> can share it. Use the request socket's send_ack() callback and its own
> out-of-window ACK timestamp to send and rate-limit the response.
>
> Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
> Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
> Reported-by: Ao Wang <wangao@seu.edu.cn>
> Reported-by: Xuewei Feng <fengxw06@126.com>
> Reported-by: Qi Li <qli01@tsinghua.edu.cn>
> Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
> Fixes: 282f23c6ee34 ("tcp: implement RFC 5961 3.2")
> Cc: stable@vger.kernel.org
> Signed-off-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Note : Please do not add a Reported-by: Yuxiang Yang
<yangyx22@mails.tsinghua.edu.cn> if you are the patch author.
The amount of noise in this patch footer is quite annoying.
Reviewed-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* Re: [PATCH net v3] vmxnet3: fix BUG_ON in vmxnet3_get_hdr_len() for Geneve packets
From: Simon Horman @ 2026-07-20 16:41 UTC (permalink / raw)
To: Harshaka Narayana
Cc: davem, kuba, pabeni, netdev, ronak.doshi,
bcm-kernel-feedback-list, andrew+netdev, edumazet, linux-kernel,
guolin.yang, sankararaman.jayaraman
In-Reply-To: <20260713140915.3381715-1-harshaka.narayana@broadcom.com>
On Mon, Jul 13, 2026 at 07:09:15AM -0700, Harshaka Narayana wrote:
> vmxnet3_get_hdr_len() assumes gdesc->rcd.v4/v6/tcp always describe the
> outer header, but for a Geneve-encapsulated packet the device can set
> them based on the inner header instead, signalled by the
> VMXNET3_RCD_HDR_INNER_SHIFT bit in the completion descriptor. Since the
> function never skips the outer encapsulation, this mismatch triggers:
>
> - BUG_ON(hdr.ipv4->protocol != IPPROTO_TCP), because the outer
> protocol is UDP (Geneve), not TCP.
> - BUG_ON(hdr.eth->h_proto != ...), when the tunnel's outer and inner
> IP versions differ (e.g. outer IPv6/inner IPv4 or vice versa).
>
> Check VMXNET3_RCD_HDR_INNER_SHIFT up front and bail out, since the
> function cannot locate the inner header it would need to parse. Also
> convert the remaining BUG_ON()s in this function to return 0
> defensively.
>
> Fixes: 45dac1d6ea04 ("vmxnet3: Changes for vmxnet3 adapter version 2 (fwd)")
> Signed-off-by: Harshaka Narayana <harshaka.narayana@broadcom.com>
> Reviewed-by: Ronak Doshi <ronak.doshi@broadcom.com>
> Reviewed-by: Sankararaman Jayaraman <sankararaman.jayaraman@broadcom.com>
> ---
> v3:
> - Combined the two early return-0 checks into one condition
> - Replaced stacked Signed-off-by tags with Reviewed-by for Ronak
> Doshi and Sankararaman Jayaraman
> v2: https://lore.kernel.org/netdev/20260709201654.4108084-1-harshaka.narayana@broadcom.com/
> - Check VMXNET3_RCD_HDR_INNER_SHIFT up front to catch the Geneve
> inner-header case directly, and convert the remaining
> BUG_ON(hdr.eth->h_proto != ...) checks to return 0
> - Reworded commit message to describe the root cause via
> VMXNET3_RCD_HDR_INNER_SHIFT
> v1: https://lore.kernel.org/netdev/20260707165248.1859188-1-harshaka.narayana@broadcom.com/
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* Re: [PATCH net-next v5 00/15][pull request] Introduce iXD driver
From: Larysa Zaremba @ 2026-07-20 16:24 UTC (permalink / raw)
To: Tony Nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
przemyslaw.kitszel, aleksander.lobakin, sridhar.samudrala,
michal.swiatkowski, maciej.fijalkowski, emil.s.tantilov,
madhu.chittim, joshua.a.hay, jacob.e.keller,
jayaprakash.shanmugam, jiri, horms, corbet, richardcochran, skhan,
linux-doc
In-Reply-To: <20260715180042.1972010-1-anthony.l.nguyen@intel.com>
I have looked though Sashiko feedback for this version. A lot medium+ comments
were things that I have addressed as false-positives in v4, so those are left
out, same as many of low-severity subjective issues. Unfortunately, patch 4 does
need a fixup (see Re: for the patch itself), but hopefully this does not warrant
another PR.
^ permalink raw reply
* [PATCH net-next v2 7/7] selftests: net: getsockopt_iter: cover rawv6, ieee802154, phonet and tls
From: Breno Leitao @ 2026-07-20 16:17 UTC (permalink / raw)
To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
Sabrina Dubroca, Shuah Khan
Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
kernel-team, Rémi Denis-Courmont
In-Reply-To: <20260720-getsockopt_phase4-v2-0-8a08fcfa0d72@debian.org>
Add fixtures for the newly converted getsockopt leaves:
- rawv6: IPV6_HDRINCL / IPV6_CHECKSUM int paths + a SOL_RAW
unknown-optname case that reaches do_rawv6_getsockopt().
- ieee802154: WPAN_WANTACK dgram int path + non-SOL_IEEE802154 level
rejection.
- phonet: PNPIPE_ENCAP pep int path + non-SOL_PNPIPE level
rejection.
- tls: TLS_TX_ZEROCOPY_RO, the TLS_TX crypto_info round-trip at
the base and full cipher sizes, the NULL-optval and short
buffer EINVAL paths, and an unknown optname. It skips when
the kernel lacks TLS or AES-GCM.
Each fixture pins the returned-length / errno semantics across exact,
oversized and short buffers, an unknown optname and a bogus level. The
semantics are unchanged by the sockopt_t conversion, so the tests pass
both before and after the leaf conversions.
Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Rémi Denis-Courmont <remi@remlab.net>
---
tools/testing/selftests/net/getsockopt_iter.c | 424 ++++++++++++++++++++++++++
1 file changed, 424 insertions(+)
diff --git a/tools/testing/selftests/net/getsockopt_iter.c b/tools/testing/selftests/net/getsockopt_iter.c
index fe5a5268bc34e..974065a23fa82 100644
--- a/tools/testing/selftests/net/getsockopt_iter.c
+++ b/tools/testing/selftests/net/getsockopt_iter.c
@@ -28,7 +28,10 @@
#include <linux/vm_sockets.h>
#include <linux/icmp.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
#include <sys/socket.h>
+#include <linux/tls.h>
#include "kselftest_harness.h"
#ifndef AF_VSOCK
@@ -40,6 +43,45 @@
#ifndef ICMP_FILTER
#define ICMP_FILTER 1
#endif
+#ifndef IPV6_HDRINCL
+#define IPV6_HDRINCL 36
+#endif
+#ifndef IPV6_CHECKSUM
+#define IPV6_CHECKSUM 7
+#endif
+#ifndef AF_IEEE802154
+#define AF_IEEE802154 36
+#endif
+#ifndef SOL_IEEE802154
+#define SOL_IEEE802154 0
+#endif
+#ifndef WPAN_WANTACK
+#define WPAN_WANTACK 0
+#endif
+#ifndef AF_PHONET
+#define AF_PHONET 35
+#endif
+#ifndef SOL_PNPIPE
+#define SOL_PNPIPE 275
+#endif
+#ifndef PN_PROTO_PIPE
+#define PN_PROTO_PIPE 2
+#endif
+#ifndef PNPIPE_ENCAP
+#define PNPIPE_ENCAP 1
+#endif
+#ifndef PNPIPE_ENCAP_NONE
+#define PNPIPE_ENCAP_NONE 0
+#endif
+#ifndef PNPIPE_ENCAP_IP
+#define PNPIPE_ENCAP_IP 1
+#endif
+#ifndef SOL_TLS
+#define SOL_TLS 282
+#endif
+#ifndef TCP_ULP
+#define TCP_ULP 31
+#endif
/* ---------- netlink ---------- */
@@ -394,4 +436,386 @@ TEST_F(raw, bad_optname)
ASSERT_EQ(sizeof(val), optlen);
}
+/* ---------- raw (ipv6) ---------- */
+
+FIXTURE(rawv6)
+{
+ int fd;
+};
+
+FIXTURE_SETUP(rawv6)
+{
+ self->fd = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
+ if (self->fd < 0)
+ SKIP(return, "SOCK_RAW/IPv6 socket: %s", strerror(errno));
+}
+
+FIXTURE_TEARDOWN(rawv6)
+{
+ if (self->fd >= 0)
+ close(self->fd);
+}
+
+TEST_F(rawv6, hdrincl_exact)
+{
+ socklen_t optlen;
+ int val = -1;
+
+ optlen = sizeof(val);
+
+ ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
+ &val, &optlen));
+ ASSERT_EQ(sizeof(int), optlen);
+ ASSERT_TRUE(val == 0 || val == 1);
+}
+
+TEST_F(rawv6, hdrincl_oversize_clamped)
+{
+ char buf[16] = {};
+ socklen_t optlen = sizeof(buf);
+
+ ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
+ buf, &optlen));
+ ASSERT_EQ(sizeof(int), optlen);
+}
+
+/* Raw int options clamp the reported length down to the user buffer
+ * instead of returning EINVAL on a short buffer.
+ */
+TEST_F(rawv6, hdrincl_undersize_clamped)
+{
+ socklen_t optlen = 2;
+ int val = 0;
+
+ ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
+ &val, &optlen));
+ ASSERT_EQ(2, optlen);
+}
+
+TEST_F(rawv6, checksum_default)
+{
+ socklen_t optlen;
+ int val = 0;
+
+ optlen = sizeof(val);
+
+ /* A non-ICMPv6 raw socket has the checksum disabled, reported as -1. */
+ ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_CHECKSUM,
+ &val, &optlen));
+ ASSERT_EQ(sizeof(int), optlen);
+ ASSERT_EQ(-1, val);
+}
+
+TEST_F(rawv6, bad_optname)
+{
+ socklen_t optlen;
+ int val;
+
+ optlen = sizeof(val);
+
+ /* SOL_RAW reaches do_rawv6_getsockopt() directly. */
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_RAW, 0x7fff, &val, &optlen));
+ ASSERT_EQ(ENOPROTOOPT, errno);
+ ASSERT_EQ(sizeof(val), optlen);
+}
+
+/* ---------- ieee802154 (dgram) ---------- */
+
+FIXTURE(ieee802154)
+{
+ int fd;
+};
+
+FIXTURE_SETUP(ieee802154)
+{
+ self->fd = socket(AF_IEEE802154, SOCK_DGRAM, 0);
+ if (self->fd < 0)
+ SKIP(return, "AF_IEEE802154 dgram socket: %s", strerror(errno));
+}
+
+FIXTURE_TEARDOWN(ieee802154)
+{
+ if (self->fd >= 0)
+ close(self->fd);
+}
+
+TEST_F(ieee802154, wantack_exact)
+{
+ socklen_t optlen;
+ int val = -1;
+
+ optlen = sizeof(val);
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_IEEE802154, WPAN_WANTACK,
+ &val, &optlen));
+ ASSERT_EQ(sizeof(int), optlen);
+ ASSERT_TRUE(val == 0 || val == 1);
+}
+
+TEST_F(ieee802154, wantack_oversize_clamped)
+{
+ char buf[16] = {};
+ socklen_t optlen = sizeof(buf);
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_IEEE802154, WPAN_WANTACK,
+ buf, &optlen));
+ ASSERT_EQ(sizeof(int), optlen);
+}
+
+TEST_F(ieee802154, wantack_undersize_clamped)
+{
+ socklen_t optlen = 2;
+ int val = 0;
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_IEEE802154, WPAN_WANTACK,
+ &val, &optlen));
+ ASSERT_EQ(2, optlen);
+}
+
+TEST_F(ieee802154, bad_optname)
+{
+ socklen_t optlen;
+ int val;
+
+ optlen = sizeof(val);
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_IEEE802154, 0x7fff,
+ &val, &optlen));
+ ASSERT_EQ(ENOPROTOOPT, errno);
+ ASSERT_EQ(sizeof(val), optlen);
+}
+
+/* dgram_getsockopt() rejects any level other than SOL_IEEE802154. */
+TEST_F(ieee802154, bad_level)
+{
+ socklen_t optlen;
+ int val;
+
+ optlen = sizeof(val);
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_RAW, WPAN_WANTACK,
+ &val, &optlen));
+ ASSERT_EQ(EOPNOTSUPP, errno);
+ ASSERT_EQ(sizeof(val), optlen);
+}
+
+/* ---------- phonet (pep) ---------- */
+
+FIXTURE(phonet)
+{
+ int fd;
+};
+
+FIXTURE_SETUP(phonet)
+{
+ self->fd = socket(AF_PHONET, SOCK_SEQPACKET, PN_PROTO_PIPE);
+ if (self->fd < 0)
+ SKIP(return, "AF_PHONET pipe socket: %s", strerror(errno));
+}
+
+FIXTURE_TEARDOWN(phonet)
+{
+ if (self->fd >= 0)
+ close(self->fd);
+}
+
+TEST_F(phonet, encap_exact)
+{
+ socklen_t optlen;
+ int val = -1;
+
+ optlen = sizeof(val);
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_PNPIPE, PNPIPE_ENCAP,
+ &val, &optlen));
+ ASSERT_EQ(sizeof(int), optlen);
+ ASSERT_TRUE(val == PNPIPE_ENCAP_NONE || val == PNPIPE_ENCAP_IP);
+}
+
+TEST_F(phonet, encap_oversize_clamped)
+{
+ char buf[16] = {};
+ socklen_t optlen = sizeof(buf);
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_PNPIPE, PNPIPE_ENCAP,
+ buf, &optlen));
+ ASSERT_EQ(sizeof(int), optlen);
+}
+
+/* pep clamps the reported length down to the user buffer. Use an
+ * int-sized backing buffer with a short optlen so the baseline kernel,
+ * which writes a full int via put_user(), does not scribble past it.
+ */
+TEST_F(phonet, encap_undersize_clamped)
+{
+ socklen_t optlen = 2;
+ int val = 0;
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_PNPIPE, PNPIPE_ENCAP,
+ &val, &optlen));
+ ASSERT_EQ(2, optlen);
+}
+
+TEST_F(phonet, bad_optname)
+{
+ socklen_t optlen;
+ int val;
+
+ optlen = sizeof(val);
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_PNPIPE, 0x7fff, &val, &optlen));
+ ASSERT_EQ(ENOPROTOOPT, errno);
+ ASSERT_EQ(sizeof(val), optlen);
+}
+
+/* pep_getsockopt() rejects any level other than SOL_PNPIPE. */
+TEST_F(phonet, bad_level)
+{
+ socklen_t optlen;
+ int val;
+
+ optlen = sizeof(val);
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_RAW, PNPIPE_ENCAP, &val, &optlen));
+ ASSERT_EQ(ENOPROTOOPT, errno);
+ ASSERT_EQ(sizeof(val), optlen);
+}
+
+/* ---------- tls ---------- */
+
+FIXTURE(tls)
+{
+ int fd;
+ int sfd;
+};
+
+FIXTURE_SETUP(tls)
+{
+ struct sockaddr_in a = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+ socklen_t alen = sizeof(a);
+ int lfd;
+
+ self->fd = -1;
+ self->sfd = -1;
+
+ lfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (lfd < 0)
+ SKIP(return, "TCP socket: %s", strerror(errno));
+ if (bind(lfd, (struct sockaddr *)&a, sizeof(a)) || listen(lfd, 1) ||
+ getsockname(lfd, (struct sockaddr *)&a, &alen)) {
+ close(lfd);
+ SKIP(return, "listener setup: %s", strerror(errno));
+ }
+ self->fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(self->fd, (struct sockaddr *)&a, sizeof(a))) {
+ close(lfd);
+ SKIP(return, "connect: %s", strerror(errno));
+ }
+ self->sfd = accept(lfd, NULL, NULL);
+ close(lfd);
+ if (setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")))
+ SKIP(return, "TCP_ULP=tls: %s (built without TLS?)",
+ strerror(errno));
+}
+
+FIXTURE_TEARDOWN(tls)
+{
+ if (self->fd >= 0)
+ close(self->fd);
+ if (self->sfd >= 0)
+ close(self->sfd);
+}
+
+/* do_tls_getsockopt_tx_zc(): fixed-size int, exact length required. */
+TEST_F(tls, tx_zerocopy_exact)
+{
+ socklen_t optlen = sizeof(int);
+ int val = -1;
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX_ZEROCOPY_RO,
+ &val, &optlen));
+ ASSERT_EQ(sizeof(int), optlen);
+ ASSERT_TRUE(val == 0 || val == 1);
+}
+
+TEST_F(tls, tx_zerocopy_wrong_len)
+{
+ socklen_t optlen = 2;
+ int val;
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX_ZEROCOPY_RO,
+ &val, &optlen));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+/* do_tls_getsockopt_conf(): NULL optval still yields EINVAL -- the
+ * converted code tests opt->iter_out.ubuf in place of optval.
+ */
+TEST_F(tls, conf_null_optval)
+{
+ socklen_t optlen = 64;
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, NULL, &optlen));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST_F(tls, conf_short)
+{
+ socklen_t optlen = 2;
+ char buf[2];
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, buf, &optlen));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+/* TLS_TX before crypto is set reports not-ready. */
+TEST_F(tls, conf_not_ready)
+{
+ struct tls_crypto_info info;
+ socklen_t optlen = sizeof(info);
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, &info, &optlen));
+ ASSERT_EQ(EBUSY, errno);
+}
+
+/* Set TX crypto, then read it back at the base and full sizes, exercising
+ * both copy_to_iter() branches. SKIP if AES-GCM is unavailable.
+ */
+TEST_F(tls, conf_crypto_roundtrip)
+{
+ struct tls12_crypto_info_aes_gcm_128 tx = {
+ .info.version = TLS_1_2_VERSION,
+ .info.cipher_type = TLS_CIPHER_AES_GCM_128,
+ };
+ struct tls12_crypto_info_aes_gcm_128 full;
+ struct tls_crypto_info base;
+ socklen_t optlen;
+
+ if (setsockopt(self->fd, SOL_TLS, TLS_TX, &tx, sizeof(tx)))
+ SKIP(return, "set TLS_TX aes_gcm_128: %s", strerror(errno));
+
+ optlen = sizeof(base);
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX, &base, &optlen));
+ ASSERT_EQ(sizeof(base), optlen);
+ ASSERT_EQ(TLS_1_2_VERSION, base.version);
+ ASSERT_EQ(TLS_CIPHER_AES_GCM_128, base.cipher_type);
+
+ optlen = sizeof(full);
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX, &full, &optlen));
+ ASSERT_EQ(sizeof(full), optlen);
+ ASSERT_EQ(TLS_CIPHER_AES_GCM_128, full.info.cipher_type);
+}
+
+TEST_F(tls, bad_optname)
+{
+ socklen_t optlen = sizeof(int);
+ int val;
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, 0x7fff, &val, &optlen));
+ ASSERT_EQ(ENOPROTOOPT, errno);
+}
+
TEST_HARNESS_MAIN
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 6/7] tls: convert getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-20 16:17 UTC (permalink / raw)
To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
Sabrina Dubroca, Shuah Khan
Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
kernel-team
In-Reply-To: <20260720-getsockopt_phase4-v2-0-8a08fcfa0d72@debian.org>
Continue converting the proto-layer getsockopt callbacks to the sockopt_t
interface, converting do_tls_getsockopt() and its per-option helpers to
take a sockopt_t.
The thin tls_getsockopt() wrapper keeps its __user signature for now: it
builds a user-backed sockopt_t with sockopt_init_user(), calls the helper,
and writes the returned length back to optlen. The helpers use
copy_to_iter() instead of copy_to_user(); the NULL optval check in the
TLS_TX/TLS_RX path is preserved by testing the iterator user buffer.
No functional change.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
net/tls/tls_main.c | 80 ++++++++++++++++++++++++++----------------------------
1 file changed, 38 insertions(+), 42 deletions(-)
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 8c588cdab733d..fbb274287aa5f 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -424,20 +424,16 @@ static __poll_t tls_sk_poll(struct file *file, struct socket *sock,
return mask;
}
-static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
- int __user *optlen, int tx)
+static int do_tls_getsockopt_conf(struct sock *sk, sockopt_t *opt, int tx)
{
int rc = 0;
const struct tls_cipher_desc *cipher_desc;
struct tls_context *ctx = tls_get_ctx(sk);
struct tls_crypto_info *crypto_info;
struct cipher_context *cctx;
- int len;
+ int len = opt->optlen;
- if (get_user(len, optlen))
- return -EFAULT;
-
- if (!optval || (len < sizeof(*crypto_info))) {
+ if (!opt->iter_out.ubuf || len < sizeof(*crypto_info)) {
rc = -EINVAL;
goto out;
}
@@ -462,7 +458,8 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
}
if (len == sizeof(*crypto_info)) {
- if (copy_to_user(optval, crypto_info, sizeof(*crypto_info)))
+ if (copy_to_iter(crypto_info, sizeof(*crypto_info),
+ &opt->iter_out) != sizeof(*crypto_info))
rc = -EFAULT;
goto out;
}
@@ -478,44 +475,38 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
memcpy(crypto_info_rec_seq(crypto_info, cipher_desc),
cctx->rec_seq, cipher_desc->rec_seq);
- if (copy_to_user(optval, crypto_info, cipher_desc->crypto_info))
+ if (copy_to_iter(crypto_info, cipher_desc->crypto_info,
+ &opt->iter_out) != cipher_desc->crypto_info)
rc = -EFAULT;
out:
return rc;
}
-static int do_tls_getsockopt_tx_zc(struct sock *sk, char __user *optval,
- int __user *optlen)
+static int do_tls_getsockopt_tx_zc(struct sock *sk, sockopt_t *opt)
{
struct tls_context *ctx = tls_get_ctx(sk);
unsigned int value;
- int len;
-
- if (get_user(len, optlen))
- return -EFAULT;
+ int len = opt->optlen;
if (len != sizeof(value))
return -EINVAL;
value = ctx->zerocopy_sendfile;
- if (copy_to_user(optval, &value, sizeof(value)))
+ if (copy_to_iter(&value, sizeof(value), &opt->iter_out) != sizeof(value))
return -EFAULT;
return 0;
}
-static int do_tls_getsockopt_no_pad(struct sock *sk, char __user *optval,
- int __user *optlen)
+static int do_tls_getsockopt_no_pad(struct sock *sk, sockopt_t *opt)
{
struct tls_context *ctx = tls_get_ctx(sk);
- int value, len;
+ int value, len = opt->optlen;
if (ctx->prot_info.version != TLS_1_3_VERSION)
return -EINVAL;
- if (get_user(len, optlen))
- return -EFAULT;
if (len < sizeof(value))
return -EINVAL;
@@ -525,38 +516,31 @@ static int do_tls_getsockopt_no_pad(struct sock *sk, char __user *optval,
if (value < 0)
return value;
- if (put_user(sizeof(value), optlen))
- return -EFAULT;
- if (copy_to_user(optval, &value, sizeof(value)))
+ opt->optlen = sizeof(value);
+ if (copy_to_iter(&value, sizeof(value), &opt->iter_out) != sizeof(value))
return -EFAULT;
return 0;
}
-static int do_tls_getsockopt_tx_payload_len(struct sock *sk, char __user *optval,
- int __user *optlen)
+static int do_tls_getsockopt_tx_payload_len(struct sock *sk, sockopt_t *opt)
{
struct tls_context *ctx = tls_get_ctx(sk);
u16 payload_len = ctx->tx_max_payload_len;
- int len;
-
- if (get_user(len, optlen))
- return -EFAULT;
+ int len = opt->optlen;
if (len < sizeof(payload_len))
return -EINVAL;
- if (put_user(sizeof(payload_len), optlen))
- return -EFAULT;
-
- if (copy_to_user(optval, &payload_len, sizeof(payload_len)))
+ opt->optlen = sizeof(payload_len);
+ if (copy_to_iter(&payload_len, sizeof(payload_len),
+ &opt->iter_out) != sizeof(payload_len))
return -EFAULT;
return 0;
}
-static int do_tls_getsockopt(struct sock *sk, int optname,
- char __user *optval, int __user *optlen)
+static int do_tls_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
{
int rc = 0;
@@ -565,17 +549,16 @@ static int do_tls_getsockopt(struct sock *sk, int optname,
switch (optname) {
case TLS_TX:
case TLS_RX:
- rc = do_tls_getsockopt_conf(sk, optval, optlen,
- optname == TLS_TX);
+ rc = do_tls_getsockopt_conf(sk, opt, optname == TLS_TX);
break;
case TLS_TX_ZEROCOPY_RO:
- rc = do_tls_getsockopt_tx_zc(sk, optval, optlen);
+ rc = do_tls_getsockopt_tx_zc(sk, opt);
break;
case TLS_RX_EXPECT_NO_PAD:
- rc = do_tls_getsockopt_no_pad(sk, optval, optlen);
+ rc = do_tls_getsockopt_no_pad(sk, opt);
break;
case TLS_TX_MAX_PAYLOAD_LEN:
- rc = do_tls_getsockopt_tx_payload_len(sk, optval, optlen);
+ rc = do_tls_getsockopt_tx_payload_len(sk, opt);
break;
default:
rc = -ENOPROTOOPT;
@@ -591,12 +574,25 @@ static int tls_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
struct tls_context *ctx = tls_get_ctx(sk);
+ sockopt_t opt;
+ int err;
if (level != SOL_TLS)
return ctx->sk_proto->getsockopt(sk, level,
optname, optval, optlen);
- return do_tls_getsockopt(sk, optname, optval, optlen);
+ err = sockopt_init_user(&opt, optval, optlen);
+ if (err)
+ return err;
+
+ err = do_tls_getsockopt(sk, optname, &opt);
+ if (err)
+ return err;
+
+ if (put_user(opt.optlen, optlen))
+ return -EFAULT;
+
+ return 0;
}
static int validate_crypto_info(const struct tls_crypto_info *crypto_info,
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 5/7] phonet: pep: convert getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-20 16:17 UTC (permalink / raw)
To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
Sabrina Dubroca, Shuah Khan
Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
kernel-team, Rémi Denis-Courmont
In-Reply-To: <20260720-getsockopt_phase4-v2-0-8a08fcfa0d72@debian.org>
Continue converting the proto-layer getsockopt callbacks to the
sockopt_t interface, splitting pep_getsockopt() into a
do_pep_getsockopt() helper that takes a sockopt_t.
The thin pep_getsockopt() wrapper keeps its __user signature for now:
it builds a user-backed sockopt_t with sockopt_init_user(), calls the
helper, and writes the returned length back to optlen. The helper uses
copy_to_iter() instead of copy_to_user(). No functional change.
Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Rémi Denis-Courmont <remi@remlab.net>
---
net/phonet/pep.c | 36 ++++++++++++++++++++++++++----------
1 file changed, 26 insertions(+), 10 deletions(-)
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 60d1a5375725b..7ef4a9a240ef8 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -1078,17 +1078,11 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
return err;
}
-static int pep_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+static int do_pep_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
{
struct pep_sock *pn = pep_sk(sk);
int len, val;
- if (level != SOL_PNPIPE)
- return -ENOPROTOOPT;
- if (get_user(len, optlen))
- return -EFAULT;
-
switch (optname) {
case PNPIPE_ENCAP:
val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
@@ -1112,11 +1106,33 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
return -ENOPROTOOPT;
}
- len = min_t(unsigned int, sizeof(int), len);
- if (put_user(len, optlen))
+ len = umin(sizeof(int), opt->optlen);
+ opt->optlen = len;
+ if (copy_to_iter(&val, len, &opt->iter_out) != len)
return -EFAULT;
- if (copy_to_user(optval, &val, len))
+ return 0;
+}
+
+static int pep_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ sockopt_t opt;
+ int err;
+
+ if (level != SOL_PNPIPE)
+ return -ENOPROTOOPT;
+
+ err = sockopt_init_user(&opt, optval, optlen);
+ if (err)
+ return err;
+
+ err = do_pep_getsockopt(sk, optname, &opt);
+ if (err)
+ return err;
+
+ if (put_user(opt.optlen, optlen))
return -EFAULT;
+
return 0;
}
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 4/7] phonet: pep: do not write beyond optlen in getsockopt
From: Breno Leitao @ 2026-07-20 16:17 UTC (permalink / raw)
To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
Sabrina Dubroca, Shuah Khan
Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
kernel-team, Rémi Denis-Courmont
In-Reply-To: <20260720-getsockopt_phase4-v2-0-8a08fcfa0d72@debian.org>
pep_getsockopt() clamps the reported length to the caller's buffer with
min_t(), but then stores the value with put_user(val, (int __user *)
optval), which always writes sizeof(int) bytes. A getsockopt() call with
an optlen smaller than sizeof(int) thus reports the clamped length yet
writes a full int, one to three bytes past the user buffer.
Write the value with copy_to_user() bounded by len, so at most optlen
bytes are copied, matching the length reported back to userspace.
Fixes: 02a47617cdce ("Phonet: implement GPRS virtual interface over PEP socket")
Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Rémi Denis-Courmont <remi@remlab.net>
---
net/phonet/pep.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 7069271393933..60d1a5375725b 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -1115,7 +1115,7 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
len = min_t(unsigned int, sizeof(int), len);
if (put_user(len, optlen))
return -EFAULT;
- if (put_user(val, (int __user *) optval))
+ if (copy_to_user(optval, &val, len))
return -EFAULT;
return 0;
}
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 3/7] ieee802154: convert dgram getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-20 16:17 UTC (permalink / raw)
To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
Sabrina Dubroca, Shuah Khan
Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
kernel-team
In-Reply-To: <20260720-getsockopt_phase4-v2-0-8a08fcfa0d72@debian.org>
Continue converting the proto-layer getsockopt callbacks to the sockopt_t
interface, splitting dgram_getsockopt() into a do_dgram_getsockopt() helper
that takes a sockopt_t.
No functional change.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
net/ieee802154/socket.c | 38 ++++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
index 85dce296d7513..763f63e48afe4 100644
--- a/net/ieee802154/socket.c
+++ b/net/ieee802154/socket.c
@@ -831,20 +831,12 @@ static int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
return ret;
}
-static int dgram_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+static int do_dgram_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
{
struct dgram_sock *ro = dgram_sk(sk);
-
int val, len;
- if (level != SOL_IEEE802154)
- return -EOPNOTSUPP;
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- len = min_t(unsigned int, len, sizeof(int));
+ len = min_t(unsigned int, opt->optlen, sizeof(int));
switch (optname) {
case WPAN_WANTACK:
@@ -871,10 +863,32 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname,
return -ENOPROTOOPT;
}
- if (put_user(len, optlen))
+ opt->optlen = len;
+ if (copy_to_iter(&val, len, &opt->iter_out) != len)
return -EFAULT;
- if (copy_to_user(optval, &val, len))
+ return 0;
+}
+
+static int dgram_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ sockopt_t opt;
+ int err;
+
+ if (level != SOL_IEEE802154)
+ return -EOPNOTSUPP;
+
+ err = sockopt_init_user(&opt, optval, optlen);
+ if (err)
+ return err;
+
+ err = do_dgram_getsockopt(sk, optname, &opt);
+ if (err)
+ return err;
+
+ if (put_user(opt.optlen, optlen))
return -EFAULT;
+
return 0;
}
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 2/7] ipv6: raw: convert do_rawv6_getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-20 16:17 UTC (permalink / raw)
To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
Sabrina Dubroca, Shuah Khan
Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
kernel-team
In-Reply-To: <20260720-getsockopt_phase4-v2-0-8a08fcfa0d72@debian.org>
Convert do_rawv6_getsockopt to the new sockopt_t model, mirroring what
we have in ipv4. The overall goal is to move these callbacks gradually
from __user points to use sockopt_t, and this part touches
do_rawv6_getsockopt.
No functional change.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
net/ipv6/raw.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 99eec36796fb9..1f15942d14163 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1051,14 +1051,12 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
}
-static int do_rawv6_getsockopt(struct sock *sk, int optname,
- char __user *optval, int __user *optlen)
+static int do_rawv6_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
{
struct raw6_sock *rp = raw6_sk(sk);
int val, len;
- if (get_user(len, optlen))
- return -EFAULT;
+ len = opt->optlen;
switch (optname) {
case IPV6_HDRINCL:
@@ -1082,9 +1080,8 @@ static int do_rawv6_getsockopt(struct sock *sk, int optname,
len = min_t(unsigned int, sizeof(int), len);
- if (put_user(len, optlen))
- return -EFAULT;
- if (copy_to_user(optval, &val, len))
+ opt->optlen = len;
+ if (copy_to_iter(&val, len, &opt->iter_out) != len)
return -EFAULT;
return 0;
}
@@ -1092,6 +1089,9 @@ static int do_rawv6_getsockopt(struct sock *sk, int optname,
static int rawv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
+ sockopt_t opt;
+ int err;
+
switch (level) {
case SOL_RAW:
break;
@@ -1109,7 +1109,18 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
return ipv6_getsockopt(sk, level, optname, optval, optlen);
}
- return do_rawv6_getsockopt(sk, optname, optval, optlen);
+ err = sockopt_init_user(&opt, optval, optlen);
+ if (err)
+ return err;
+
+ err = do_rawv6_getsockopt(sk, optname, &opt);
+ if (err)
+ return err;
+
+ if (put_user(opt.optlen, optlen))
+ return -EFAULT;
+
+ return 0;
}
static int rawv6_ioctl(struct sock *sk, int cmd, int *karg)
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 1/7] ipv6: raw: drop unused level argument from do_rawv6_getsockopt
From: Breno Leitao @ 2026-07-20 16:17 UTC (permalink / raw)
To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
Sabrina Dubroca, Shuah Khan
Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
kernel-team
In-Reply-To: <20260720-getsockopt_phase4-v2-0-8a08fcfa0d72@debian.org>
do_rawv6_getsockopt() takes a level argument but never uses it; the
level dispatch is handled by the caller, rawv6_getsockopt(). Drop it,
matching ipv4's do_raw_getsockopt().
No functional change.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
net/ipv6/raw.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 3cc58698cbbd3..99eec36796fb9 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1051,8 +1051,8 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
}
-static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+static int do_rawv6_getsockopt(struct sock *sk, int optname,
+ char __user *optval, int __user *optlen)
{
struct raw6_sock *rp = raw6_sk(sk);
int val, len;
@@ -1109,7 +1109,7 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
return ipv6_getsockopt(sk, level, optname, optval, optlen);
}
- return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
+ return do_rawv6_getsockopt(sk, optname, optval, optlen);
}
static int rawv6_ioctl(struct sock *sk, int cmd, int *karg)
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 0/7] net: convert rawv6, ieee802154, phonet and tls getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-20 16:17 UTC (permalink / raw)
To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
Sabrina Dubroca, Shuah Khan
Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
kernel-team, Rémi Denis-Courmont
Now that sockopt_init_user() was already merged, builds a user-backed
sockopt_t from the __user pair. A getsockopt leaf can then take
a sockopt_t behind a thin __user wrapper: the wrapper builds it, calls
the leaf, and writes the length back to optlen. The leaf copies with
copy_to_iter() instead of copy_to_user().
Convert four more leaves the way udp and raw already were: ipv6 raw
(do_rawv6_getsockopt), ieee802154 dgram, phonet pep, and tls
(do_tls_getsockopt and its per-option helpers).
Converting phonet surfaced a pre-existing bug: pep_getsockopt() clamps the
length it reports but writes a full int with put_user(), overrunning an
optval buffer shorter than sizeof(int). It is fixed in its own patch, with
a Fixes: tag, before the phonet conversion, so it can be backported alone.
The last patch adds getsockopt_iter selftest fixtures for rawv6,
ieee802154, phonet and tls, checking the returned length and errno across
exact, oversized and short buffers, an unknown optname and a bad level.
For full motivation about these changes, please check the initial thread
at link
https://lore.kernel.org/all/20260401-getsockopt-v2-0-611df6771aff@debian.org/#t
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Changes in v2:
- Replace min_t() by umin() (David)
- Link to v1: https://patch.msgid.link/20260716-getsockopt_phase4-v1-0-4f45cb12dce7@debian.org
---
Breno Leitao (7):
ipv6: raw: drop unused level argument from do_rawv6_getsockopt
ipv6: raw: convert do_rawv6_getsockopt to sockopt_t
ieee802154: convert dgram getsockopt to sockopt_t
phonet: pep: do not write beyond optlen in getsockopt
phonet: pep: convert getsockopt to sockopt_t
tls: convert getsockopt to sockopt_t
selftests: net: getsockopt_iter: cover rawv6, ieee802154, phonet and tls
net/ieee802154/socket.c | 38 ++-
net/ipv6/raw.c | 27 +-
net/phonet/pep.c | 36 ++-
net/tls/tls_main.c | 80 +++--
tools/testing/selftests/net/getsockopt_iter.c | 424 ++++++++++++++++++++++++++
5 files changed, 533 insertions(+), 72 deletions(-)
---
base-commit: f6f3b36c15ed44de1fbb44e645e4fae8c4a4453e
change-id: 20260715-getsockopt_phase4-180209cfc60a
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply
* Re: [PATCH net-next v5 04/15] libie: add control queue support
From: Larysa Zaremba @ 2026-07-20 16:17 UTC (permalink / raw)
To: Tony Nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
Phani R Burra, przemyslaw.kitszel, aleksander.lobakin,
sridhar.samudrala, michal.swiatkowski, maciej.fijalkowski,
emil.s.tantilov, madhu.chittim, joshua.a.hay, jacob.e.keller,
jayaprakash.shanmugam, jiri, horms, corbet, richardcochran, skhan,
linux-doc, Samuel Salin, Bharath R
In-Reply-To: <20260715180042.1972010-5-anthony.l.nguyen@intel.com>
Sashiko has found one pretty valid issue and one low-hanging-fruit in this
patch. Just in case, here is diff that addresses those:
Author: Larysa Zaremba <larysa.zaremba@intel.com>
Date: Mon Jul 20 18:00:25 2026 +0200
fixup! libie: add control queue support
diff --git a/drivers/net/ethernet/intel/libie/controlq.c b/drivers/net/ethernet/intel/libie/controlq.c
index 0a179957bfef..1eee507dd484 100644
--- a/drivers/net/ethernet/intel/libie/controlq.c
+++ b/drivers/net/ethernet/intel/libie/controlq.c
@@ -127,6 +127,7 @@ int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq)
if (likely(ctlq->next_to_post != ntp)) {
ctlq->next_to_post = ntp;
+ dma_wmb();
writel(ntp, ctlq->reg.tail);
}
@@ -331,11 +332,6 @@ libie_ctlq_add(struct libie_ctlq_ctx *ctx,
qinfo->len > FIELD_MAX(LIBIE_CTLQ_MBX_ATQ_LEN))
return ERR_PTR(-EOPNOTSUPP);
- /* libie_ctlq_init was not called */
- scoped_guard(spinlock, &ctx->ctlqs_lock)
- if (!ctx->ctlqs.next)
- return ERR_PTR(-EINVAL);
-
ctlq = kvzalloc_obj(*ctlq);
if (!ctlq)
return ERR_PTR(-ENOMEM);
^ permalink raw reply related
* Re: [PATCH net-next v5 14/15] ixd: add the core initialization
From: Larysa Zaremba @ 2026-07-20 16:14 UTC (permalink / raw)
To: Tony Nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
przemyslaw.kitszel, aleksander.lobakin, sridhar.samudrala,
michal.swiatkowski, maciej.fijalkowski, emil.s.tantilov,
madhu.chittim, joshua.a.hay, jacob.e.keller,
jayaprakash.shanmugam, jiri, horms, corbet, richardcochran, skhan,
linux-doc, Bharath R
In-Reply-To: <20260715180042.1972010-15-anthony.l.nguyen@intel.com>
Sashiko says:
> --- Patch [14]: [PATCH net-next v5 14/15] ixd: add the core initialization ---
> commit 43763d63c75ee5bcdd9189c20cf8b272997bdfec
> Author: Larysa Zaremba <larysa.zaremba@intel.com>
>
> ixd: add the core initialization
>
> This patch initializes the core when the mailbox is set up. The driver
> confirms the virtchnl version, requests necessary capabilities, and sets up
> the message handling framework.
>
> > diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
> > index 0000000000000..6d658be0695d4
> > --- /dev/null
> > +++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
>
> [ ... ]
>
> > @@ -0,0 +1,146 @@
>
> [ ... ]
>
> > +void ixd_ctlq_rx_task(struct work_struct *work)
> > +{
> > + struct ixd_adapter *adapter;
> > +
> > + adapter = container_of(work, struct ixd_adapter, mbx_task.work);
> > +
> > + queue_delayed_work(system_unbound_wq, &adapter->mbx_task,
> > + msecs_to_jiffies(300));
> > +
> > + ixd_ctlq_recv_mb_msg(adapter);
> > +}
>
> Does queueing the delayed work before executing the main logic create a race
> condition? If cancel_delayed_work_sync() is called (for example, during
> teardown in ixd_deinit_dflt_mbx()), try_to_grab_pending() could successfully
> delete the newly queued timer and return immediately, assuming the work is
> fully cancelled.
>
> This would bypass flush_work() and allow the teardown path to free
> adapter->xnm and set adapter->arq to NULL while ixd_ctlq_recv_mb_msg() is
> still running, potentially causing a use-after-free or NULL pointer
> dereference. Should the re-arming be moved to the end of the task?
>
I assume the process of cancelling delayed work is more robust.
> > diff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c
> > index afc413d3650fb..ce870aba143d4 100644
> > --- a/drivers/net/ethernet/intel/ixd/ixd_lib.c
> > +++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
>
> [ ... ]
>
> > @@ -136,8 +145,27 @@ void ixd_init_task(struct work_struct *work)
>
> [ ... ]
>
> > + libie_ctlq_xn_shutdown(adapter->xnm);/
> > + ixd_trigger_reset(adapter);
> > + ixd_deinit_dflt_mbx(adapter);
>
> Is it safe to trigger a hardware reset before cancelling the mailbox polling
> task? ixd_deinit_dflt_mbx() is responsible for cancelling the mbx_task, but
> calling ixd_trigger_reset() first means the polling task could run while the
> hardware is resetting.
>
> During reset, MMIO reads or DMA ring memory might temporarily contain invalid
> states, and the still-running mbx_task might process corrupted descriptors.
> Should the polling task be cancelled before asserting the hardware reset here,
> as well as in ixd_remove() in ixd_main.c?
>
Yes, this is safe, we just won't receive anything at this point.
^ permalink raw reply
* Re: [PATCH net-next v5 09/15] idpf: refactor idpf to use libie control queues
From: Larysa Zaremba @ 2026-07-20 16:11 UTC (permalink / raw)
To: Tony Nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
Pavan Kumar Linga, przemyslaw.kitszel, aleksander.lobakin,
sridhar.samudrala, michal.swiatkowski, maciej.fijalkowski,
emil.s.tantilov, joshua.a.hay, jacob.e.keller,
jayaprakash.shanmugam, jiri, horms, corbet, richardcochran, skhan,
linux-doc, Aleksandr Loktionov, Samuel Salin
In-Reply-To: <20260715180042.1972010-10-anthony.l.nguyen@intel.com>
Sashiko says:
> > +void idpf_send_vf_reset_msg(struct idpf_adapter *adapter)
> > +{
> > + struct libie_ctlq_info *ctlq = adapter->asq;
> > +
> > + /* Forcefully claim send queue slot */
> > + idpf_mb_clean(adapter, ctlq, true);
> > +
> > + scoped_guard(spinlock, &ctlq->lock) {
> > + *ctlq->tx_msg[ctlq->next_to_use] = (struct libie_ctlq_msg) {
> > + .opcode = LIBIE_CTLQ_SEND_MSG_TO_CP,
> > + .chnl_opcode = VIRTCHNL2_OP_RESET_VF,
> > + };
> > +
> > + libie_ctlq_send(adapter->asq, 1);
> > + }
> > +}
> Compared to the old call, which routed through idpf_send_mb_msg() and
> first ran idpf_is_reset_detected() (via the arq registers) to bail out
> early if the mailbox was gone, this new helper unconditionally
> dereferences adapter->asq and immediately calls idpf_mb_clean() which
> takes &ctlq->lock.
> Can adapter->asq be NULL here?
> idpf_deinit_dflt_mbx() sets asq = NULL after libie_ctlq_xn_deinit(),
> and idpf_init_dflt_mbx() can fail with asq/arq still NULL if
> libie_find_ctlq() returns NULL. If a hard reset flow is entered on
> such an error path, ctlq->lock would fault.
> Also, is bypassing the xn manager and reaching directly into libie
> internals (ctlq->tx_msg[ctlq->next_to_use], ctlq->lock, and
> libie_ctlq_send()) intentional? This is the only send path in the
> refactored driver that pokes libie state directly, and it is fragile
> against future changes to how tx_msg[] slots are allocated or
> lifecycled after a forced idpf_mb_clean().
> Finally, is it safe to writel() to the mailbox tail via
> libie_ctlq_send() when hardware is already in reset? The old
> idpf_is_reset_detected() gate specifically avoided that.
VF reset is done only in one flow, where it is performed only
if no other reset is going on.
[...]
>
> > +int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,
> > + struct libie_ctlq_xn_send_params *xn_params,
> > + void *send_buf, size_t send_buf_size)
> > +{
> > + int err = idpf_send_mb_msg(adapter, xn_params, send_buf, send_buf_size);
> > +
> > + if (libie_cp_can_send_onstack(send_buf_size))
> > + kfree(send_buf);
> > +
> > + return err;
> > +}
> Is the stack-vs-heap discrimination here safe as a long-term invariant?
> The reset-detected branch decides to kfree(send_buf) based purely on
> libie_cp_can_send_onstack(send_buf_size), and rel_tx_buf is set to
> kfree unconditionally so libie_ctlq_xn_send() will also invoke kfree
> on the send buffer when the send fails and the size crosses
> LIBIE_CP_TX_COPYBREAK (128 bytes).
> Many call sites pass the address of a stack-allocated struct:
> struct virtchnl2_get_capabilities caps = {};
> ... idpf_send_mb_msg(adapter, &xn_params, &caps, sizeof(caps));
> struct virtchnl2_vport_stats stats_msg = {};
> ... idpf_send_mb_msg(np->adapter, &xn_params, &stats_msg,
> sizeof(stats_msg));
> virtchnl2_vport_stats is exactly 128 bytes today, so it sits right at
> the LIBIE_CP_TX_COPYBREAK boundary. Adding one field to it, or any
> similar stack-passed structure growing past 128 bytes, would silently
> cause kfree() to be called on a stack address in the reset-detected
> or send-failure path, corrupting the slab allocator.
> Would a BUILD_BUG_ON at each stack-based call site, or a typed helper
> that only accepts on-stack buffers up to LIBIE_CP_TX_COPYBREAK, be
> worth adding so this constraint is enforced at compile time rather
> than by convention?
I would very much prefer to go the callback route right away, like in ixd,
but the diff would be even more unmanageable then.
[...]
>
> > @@ -1586,33 +1168,29 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
> > }
> >
> > if (!adapter->vport_params_recvd[idx]) {
> > - adapter->vport_params_recvd[idx] = kzalloc(IDPF_CTLQ_MAX_BUF_LEN,
> > - GFP_KERNEL);
> > + adapter->vport_params_recvd[idx] =
> > + kzalloc(LIBIE_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
> > if (!adapter->vport_params_recvd[idx]) {
> > err = -ENOMEM;
> > goto rel_buf;
> > }
> > }
> >
> > - xn_params.vc_op = VIRTCHNL2_OP_CREATE_VPORT;
> > - xn_params.send_buf.iov_base = vport_msg;
> > - xn_params.send_buf.iov_len = buf_size;
> > - xn_params.recv_buf.iov_base = adapter->vport_params_recvd[idx];
> > - xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
> > - xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> > - reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> > - if (reply_sz < 0) {
> > - err = reply_sz;
> > - goto free_vport_params;
> > + err = idpf_send_mb_msg_kfree(adapter, &xn_params, vport_msg,
> > + sizeof(*vport_msg));
> > + if (err) {
> > + kfree(adapter->vport_params_recvd[idx]);
> > + adapter->vport_params_recvd[idx] = NULL;
> > + return err;
> > }
> >
> > - kfree(vport_msg);
> > + memcpy(adapter->vport_params_recvd[idx], xn_params.recv_mem.iov_base,
> > + xn_params.recv_mem.iov_len);
> Is the memcpy() length here guaranteed to be bounded?
> adapter->vport_params_recvd[idx] is a fixed LIBIE_CTLQ_MAX_BUF_LEN
> allocation, but the copy length is taken directly from
> xn_params.recv_mem.iov_len without a defensive cap. This function
libie_cp does cap the iov_len at LIBIE_CTLQ_MAX_BUF_LEN in
libie_ctlq_fill_rx_msg(), so this is fine.
> relies on libie's Rx path always delivering iov_len <=
> LIBIE_CTLQ_MAX_BUF_LEN. If that invariant ever changes (larger RX
> buffers, multi-descriptor delivery, or a missing bounds check against
> the descriptor's data_len in libie), this becomes an unchecked heap
> overflow driven by CP firmware.
> Other call sites in the same patch use bounded copies, for example
> idpf_send_get_caps_msg():
> memcpy(&adapter->caps, xn_params.recv_mem.iov_base,
> sizeof(adapter->caps));
> Would using min_t(size_t, LIBIE_CTLQ_MAX_BUF_LEN,
> xn_params.recv_mem.iov_len) match the pattern used elsewhere in this
> file?
>
^ permalink raw reply
* Re: [PATCH v3 net] octeontx2-af: Block VFs from clobbering special CGX PKIND state
From: Simon Horman @ 2026-07-20 16:09 UTC (permalink / raw)
To: rkannoth
Cc: Simon Horman, davem, gakula, linux-kernel, netdev, sgoutham,
andrew+netdev, edumazet, kuba, pabeni, hkelam
In-Reply-To: <20260713121902.3938875-1-rkannoth@marvell.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260713121902.3938875-1-rkannoth@marvell.com?part=1
---
octeontx2-af: Block VFs from clobbering special CGX PKIND state
This commit prevents CGX-mapped VFs from resetting the shared LMAC RX
PKIND and default TX parse configuration when the LMAC is running with
HiGig2 or EDSA parsing enabled. It adds cgx_get_pkind() and
rvu_cgx_is_pkind_config_permitted() to gate the affected register
writes.
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
> index 4ff3935ed3fe..2be1da3476ac 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
> @@ -1355,3 +1355,35 @@ void rvu_mac_reset(struct rvu *rvu, u16 pcifunc)
> if (mac_ops->mac_reset(cgxd, lmac, !is_vf(pcifunc)))
> dev_err(rvu->dev, "Failed to reset MAC\n");
> }
> +
> +/* Do not allow CGX-mapped VFs to overwrite PKIND when special parse kinds
> + * (HiGig, EDSA, etc.) are in use on the shared LMAC.
> + */
> +bool rvu_cgx_is_pkind_config_permitted(struct rvu *rvu, u16 pcifunc)
> +{
> + int pf, err, rxpkind;
> + u8 cgx_id, lmac_id;
> + void *cgxd;
> +
> + pf = rvu_get_pf(rvu->pdev, pcifunc);
> +
> + if (!(pcifunc & RVU_PFVF_FUNC_MASK))
> + return true;
> +
> + if (!is_pf_cgxmapped(rvu, pf))
> + return true;
> +
> + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
> + cgxd = rvu_cgx_pdata(cgx_id, rvu);
> + err = cgx_get_pkind(cgxd, lmac_id, &rxpkind);
> + if (err)
> + return false;
> +
> + switch (rxpkind) {
> + case NPC_RX_HIGIG_PKIND:
> + case NPC_RX_EDSA_PKIND:
> + return false;
> + default:
> + return true;
> + }
> +}
[Medium]
The three call sites of rvu_cgx_is_pkind_config_permitted() interpret a
false return in two different ways. In nix_interface_init() and
rvu_mbox_handler_nix_lf_alloc() a false result silently skips the write,
but the TX branch of rvu_npc_set_parse_mode() converts it into an
-EINVAL to the caller.
Pre-patch, rvu_mbox_handler_npc_set_pkind() (via rvu_npc_set_parse_mode)
always wrote NIX_AF_LFX_TX_PARSE_CFG. Post-patch, a VF whose parent
PF's LMAC is programmed with NPC_RX_HIGIG_PKIND or NPC_RX_EDSA_PKIND
now receives a hard error where the call previously succeeded.
The same path is also reached from rvu_nix_lf_teardown() ->
rvu_npc_set_parse_mode(), where the -EINVAL is ignored but the intended
reset write to NIX_AF_LFX_TX_PARSE_CFG is skipped.
Is this mbox-level behavior change intended? The commit message uses
the word "skip", which reads like a silent no-op, but this call site
aborts with -EINVAL rather than skipping.
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
> index 6a0ce2665031..040eb4c9b8d1 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
[ ... ]
> @@ -1685,8 +1693,10 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
> rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf), req->rx_cfg);
>
> /* Configure pkind for TX parse config */
> - cfg = NPC_TX_DEF_PKIND;
> - rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
> + if (rvu_cgx_is_pkind_config_permitted(rvu, pcifunc)) {
> + cfg = NPC_TX_DEF_PKIND;
> + rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
> + }
[Medium]
This check-then-write pair reads the CGX RX pkind register (via
cgx_get_pkind() inside rvu_cgx_is_pkind_config_permitted()) without
holding cgxd->lock, but the corresponding cgx_set_pkind() writers were
just wrapped in cgxd->lock in this same patch.
Consider the following interleaving:
CPU0 (VF nix_lf_alloc) CPU1 (PF set_parse_mode)
----------------------------------- ---------------------------
rvu_cgx_is_pkind_config_permitted()
cgx_get_pkind() -> normal pkind
returns true
mutex_lock(&cgxd->lock);
cgx_set_pkind(..., HIGIG);
mutex_unlock(&cgxd->lock);
rvu_write64(NIX_AF_LFX_TX_PARSE_CFG,
NPC_TX_DEF_PKIND);
Can a concurrent PF that transitions the LMAC to NPC_RX_HIGIG_PKIND or
NPC_RX_EDSA_PKIND between the check and the write flip the state the
check depends on?
The nix_interface_init() call site holds cgxd->lock across both the
check and the writes; should the same pattern be applied here (and in
the TX branch of rvu_npc_set_parse_mode()) for consistency?
[Medium]
NIX_AF_LFX_TX_PARSE_CFG(nixlf) is indexed by NIX LF, not by LMAC.
Skipping the write when the LMAC is in HiGig/EDSA mode means the
register is left at whatever value it currently holds — either the
hardware reset value on a fresh LF, or stale contents from a previous
owner when an LF is reused across configurations.
If a HiGig VF needs NIX_AF_LFX_TX_PARSE_CFG programmed (for example to
NPC_TX_HIGIG_PKIND) to emit correctly formatted frames, where is that
value installed? This hunk unconditionally elides the write when the
LMAC is HiGig/EDSA, and the teardown path via rvu_nix_lf_teardown() ->
rvu_npc_set_parse_mode() is likewise blocked from restoring the
default, so a subsequent non-HiGig owner reusing the same LF would
observe the previous owner's TX parse configuration.
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> index c7bc0b3a29b9..1297c6681a01 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> @@ -4241,6 +4245,9 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
> if (rc)
> return rc;
>
> + if (!rvu_cgx_is_pkind_config_permitted(rvu, pcifunc))
> + return -EINVAL;
> +
> rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
> txpkind);
> }
^ permalink raw reply
* Re: [PATCH net-next v5 08/15] idpf: refactor idpf to use libie_pci APIs
From: Larysa Zaremba @ 2026-07-20 16:09 UTC (permalink / raw)
To: Tony Nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
Pavan Kumar Linga, przemyslaw.kitszel, aleksander.lobakin,
sridhar.samudrala, michal.swiatkowski, maciej.fijalkowski,
emil.s.tantilov, joshua.a.hay, jacob.e.keller,
jayaprakash.shanmugam, jiri, horms, corbet, richardcochran, skhan,
linux-doc, Samuel Salin
In-Reply-To: <20260715180042.1972010-9-anthony.l.nguyen@intel.com>
Sashiko says:
> > + wait_for_completion_timeout(&xn->cmd_completion_event,
> > + msecs_to_jiffies(params->timeout_ms));
> > +
> > + spin_lock(&xn->xn_lock);
> > + switch (xn->state) {
> > + case LIBIE_CTLQ_XN_WAITING:
> > + ret = -ETIMEDOUT;
> > + break;
> > + case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
> > + params->recv_mem = xn->recv_mem;
> > + break;
> > + default:
> > + ret = -EBADMSG;
> > + break;
> > + }
> > +
> > + /* Free the receive buffer in case of failure. On timeout, receive
> > + * buffer is not allocated.
> > + */
> > + if (ret && ret != -ETIMEDOUT)
> > + libie_ctlq_release_rx_buf(&xn->recv_mem);
> Can this cause a double free on a stale receive buffer if the transaction was
> aborted? When a transaction is returned to the free pool, xn->recv_mem is not
> cleared. If it is reallocated and enters the WAITING state, it still contains
> the recv_mem pointer from its last successful use. If libie_ctlq_xn_shutdown()
> aborts this transaction, its state changes to SHUTDOWN. This switch falls through
> to the default case setting ret = -EBADMSG, and this cleanup logic will call
> libie_ctlq_release_rx_buf() on the stale recv_mem pointer.
LIBIE_CTLQ_XN_WAITING can only occur in the previous critical sections,
since it's only applicable to idle transactions.
>
> > + wait_for_completion_timeout(&xn->cmd_completion_event,
> > + msecs_to_jiffies(params->timeout_ms));
> params->timeout_ms is declared u64 in struct libie_ctlq_xn_send_params
> (and stored to xn->timeout_ms which is also u64), but msecs_to_jiffies()
> takes const unsigned int. On 64-bit builds, values above UINT_MAX get
> silently truncated to 32 bits before conversion, and the MAX_JIFFY_OFFSET
> clamp inside _msecs_to_jiffies() only fires against a value that already
> fits in int, so it can't rescue the truncation.
> The async path uses ktime_ms_delta against a u64 correctly, so the sync
> and async paths would disagree for the same input.
> Should timeout_ms be u32 in both structures (matching msecs_to_jiffies()),
> or should the value be clamped before conversion here?
>
> > + if (!libie_cp_can_send_onstack(msg->data_len)) {
> > + libie_cp_unmap_dma_mem(dev, &msg->send_mem);
> > + params->rel_tx_buf(msg->send_mem.va);
> [Medium, Medium]
> Two questions about locking context here.
> First, params->rel_tx_buf() is being called while ctlq->lock (a plain
> spin_lock) is held. In libie_ctlq_xn_send() the same callback is invoked
> at the free_buf label with no locks held, so the two libie call sites
> impose different atomic-context constraints on the same driver-supplied
> callback. Should rel_tx_buf either be moved outside the critical section
> or explicitly documented as required to be non-sleeping?
I see no reason to do this currently
> Second, xnm->free_xns_bm_lock, xn->xn_lock, and ctlq->lock are all
> acquired with plain spin_lock() throughout the new code. If a future
> consumer drives libie_ctlq_xn_recv() from softirq (NAPI-like, which the
> budget parameter and page_pool usage suggest) while libie_ctlq_xn_send()
> runs from process context on the same CPU, wouldn't the softirq deadlock
> against the process-context lock holder? Would spin_lock_bh() variants,
> or an explicit documented callable-context contract, be preferable?
No softirqs
>
> > +/**
> > + * libie_ctlq_xn_deinit - deallocate and free the transaction manager resources
> > + * @xnm: pointer to the transaction manager
> > + * @ctx: controlq context structure
> > + *
> > + * All Rx processing must be stopped beforehand.
> > + */
> > +void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
> > + struct libie_ctlq_ctx *ctx)
> > +{
> > + libie_ctlq_xn_shutdown(xnm);
> > + libie_ctlq_xn_deinit_dma(&ctx->mmio_info.pdev->dev, xnm,
> > + LIBIE_CTLQ_MAX_XN_ENTRIES);
> > + kfree(xnm);
> > + libie_ctlq_deinit(ctx);
> > +}
> > +EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_deinit, "LIBIE_CP");
> [High, Medium]
> Two concerns about this deinit path.
> First, do large in-flight sends leak DMA mappings and TX buffers?
> libie_ctlq_xn_shutdown() only manages xn slot state and does not touch
> the TX descriptor ring. libie_ctlq_xn_deinit_dma() only walks
> xn->dma_mem (the copybreak buffers), not ctlq_msg->send_mem for larger
> sends. libie_ctlq_deinit() eventually reaches libie_ctlq_free_tx_msgs()
> which does only kfree(ctlq->tx_msg[i]).
> Nothing on this path calls libie_cp_unmap_dma_mem() on msg->send_mem or
> invokes rel_tx_buf() for a msg->send_mem.va that a caller supplied via
> kmalloc. Wouldn't every posted-but-not-yet-completion-cleaned large send
> leak its DMA mapping and buffer? The kerneldoc only requires "All Rx
> processing must be stopped beforehand" and doesn't warn that
> libie_ctlq_xn_send_clean(force=true) must be called first.
Could be phrased better, but idpf and ixd use the API correctly.
^ permalink raw reply
* Re: [PATCH net-next v5 05/15] libie: add bookkeeping support for control queue messages
From: Larysa Zaremba @ 2026-07-20 16:07 UTC (permalink / raw)
To: Tony Nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
Phani R Burra, przemyslaw.kitszel, aleksander.lobakin,
sridhar.samudrala, michal.swiatkowski, maciej.fijalkowski,
emil.s.tantilov, madhu.chittim, joshua.a.hay, jacob.e.keller,
jayaprakash.shanmugam, jiri, horms, corbet, richardcochran, skhan,
linux-doc, Bharath R, Samuel Salin
In-Reply-To: <20260715180042.1972010-6-anthony.l.nguyen@intel.com>
Sashiko says:
> > + wait_for_completion_timeout(&xn->cmd_completion_event,
> > + msecs_to_jiffies(params->timeout_ms));
> > +
> > + spin_lock(&xn->xn_lock);
> > + switch (xn->state) {
> > + case LIBIE_CTLQ_XN_WAITING:
> > + ret = -ETIMEDOUT;
> > + break;
> > + case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
> > + params->recv_mem = xn->recv_mem;
> > + break;
> > + default:
> > + ret = -EBADMSG;
> > + break;
> > + }
> > +
> > + /* Free the receive buffer in case of failure. On timeout, receive
> > + * buffer is not allocated.
> > + */
> > + if (ret && ret != -ETIMEDOUT)
> > + libie_ctlq_release_rx_buf(&xn->recv_mem);
> Can this cause a double free on a stale receive buffer if the transaction was
> aborted? When a transaction is returned to the free pool, xn->recv_mem is not
> cleared. If it is reallocated and enters the WAITING state, it still contains
> the recv_mem pointer from its last successful use. If libie_ctlq_xn_shutdown()
> aborts this transaction, its state changes to SHUTDOWN. This switch falls through
> to the default case setting ret = -EBADMSG, and this cleanup logic will call
> libie_ctlq_release_rx_buf() on the stale recv_mem pointer.
LIBIE_CTLQ_XN_WAITING can only occur in the previous critical sections,
since it's only applicable to idle transactions.
[...]
>
> > + wait_for_completion_timeout(&xn->cmd_completion_event,
> > + msecs_to_jiffies(params->timeout_ms));
> params->timeout_ms is declared u64 in struct libie_ctlq_xn_send_params
> (and stored to xn->timeout_ms which is also u64), but msecs_to_jiffies()
> takes const unsigned int. On 64-bit builds, values above UINT_MAX get
> silently truncated to 32 bits before conversion, and the MAX_JIFFY_OFFSET
> clamp inside _msecs_to_jiffies() only fires against a value that already
> fits in int, so it can't rescue the truncation.
> The async path uses ktime_ms_delta against a u64 correctly, so the sync
> and async paths would disagree for the same input.
> Should timeout_ms be u32 in both structures (matching msecs_to_jiffies()),
> or should the value be clamped before conversion here?
>
> > + if (!libie_cp_can_send_onstack(msg->data_len)) {
> > + libie_cp_unmap_dma_mem(dev, &msg->send_mem);
> > + params->rel_tx_buf(msg->send_mem.va);
> [Medium, Medium]
> Two questions about locking context here.
> First, params->rel_tx_buf() is being called while ctlq->lock (a plain
> spin_lock) is held. In libie_ctlq_xn_send() the same callback is invoked
> at the free_buf label with no locks held, so the two libie call sites
> impose different atomic-context constraints on the same driver-supplied
> callback. Should rel_tx_buf either be moved outside the critical section
> or explicitly documented as required to be non-sleeping?
I see no reason to do this currently
> Second, xnm->free_xns_bm_lock, xn->xn_lock, and ctlq->lock are all
> acquired with plain spin_lock() throughout the new code. If a future
> consumer drives libie_ctlq_xn_recv() from softirq (NAPI-like, which the
> budget parameter and page_pool usage suggest) while libie_ctlq_xn_send()
> runs from process context on the same CPU, wouldn't the softirq deadlock
> against the process-context lock holder? Would spin_lock_bh() variants,
> or an explicit documented callable-context contract, be preferable?
No softirqs
[...]
>
> > +/**
> > + * libie_ctlq_xn_deinit - deallocate and free the transaction manager resources
> > + * @xnm: pointer to the transaction manager
> > + * @ctx: controlq context structure
> > + *
> > + * All Rx processing must be stopped beforehand.
> > + */
> > +void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
> > + struct libie_ctlq_ctx *ctx)
> > +{
> > + libie_ctlq_xn_shutdown(xnm);
> > + libie_ctlq_xn_deinit_dma(&ctx->mmio_info.pdev->dev, xnm,
> > + LIBIE_CTLQ_MAX_XN_ENTRIES);
> > + kfree(xnm);
> > + libie_ctlq_deinit(ctx);
> > +}
> > +EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_deinit, "LIBIE_CP");
> [High, Medium]
> Two concerns about this deinit path.
> First, do large in-flight sends leak DMA mappings and TX buffers?
> libie_ctlq_xn_shutdown() only manages xn slot state and does not touch
> the TX descriptor ring. libie_ctlq_xn_deinit_dma() only walks
> xn->dma_mem (the copybreak buffers), not ctlq_msg->send_mem for larger
> sends. libie_ctlq_deinit() eventually reaches libie_ctlq_free_tx_msgs()
> which does only kfree(ctlq->tx_msg[i]).
> Nothing on this path calls libie_cp_unmap_dma_mem() on msg->send_mem or
> invokes rel_tx_buf() for a msg->send_mem.va that a caller supplied via
> kmalloc. Wouldn't every posted-but-not-yet-completion-cleaned large send
> leak its DMA mapping and buffer? The kerneldoc only requires "All Rx
> processing must be stopped beforehand" and doesn't warn that
> libie_ctlq_xn_send_clean(force=true) must be called first.
Could be phrased better, but idpf and ixd use the API correctly, so no
real consequences.
^ permalink raw reply
* [PATCH net] vxlan: mdb: Fix source list corruption on a failed replace
From: James Raphael Tiovalen @ 2026-07-20 16:04 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev
Cc: James Raphael Tiovalen, stable, Kees Cook, Nikolay Aleksandrov,
Ido Schimmel, linux-kernel
When replacing the source list of an MDB remote entry, all existing
sources are first marked for deletion and vxlan_mdb_remote_srcs_add()
is then called to add the new source list. Sources present in the new
list have their deletion mark cleared, and any sources left marked
afterwards are removed.
If vxlan_mdb_remote_srcs_add() fails partway through, its error path
deletes all entries on the remote's source list. That rollback is only
correct for its other caller, vxlan_mdb_remote_add(), where the remote
was just allocated and the list contains solely entries added during
the call. On the replace path the list also holds pre-existing sources,
so a failed replace tears them down together with their (S, G)
forwarding entries instead of leaving the entry unchanged.
This is reachable from an existing (*, G) remote. An EXCLUDE filter
that loses sources starts forwarding traffic that should be blocked,
while an INCLUDE filter that loses sources drops traffic that should be
forwarded.
Mark entries created during the current pass with a new
VXLAN_SGRP_F_NEW flag. On failure, delete only those entries and clear
the deletion mark on the pre-existing ones, so a failed replace leaves
the source list untouched. Retain the flag until the whole operation
succeeds and then clear it. Also stop vxlan_mdb_remote_src_add() from
deleting a pre-existing entry it only looked up when adding that
entry's forwarding entry fails.
Fixes: a3a48de5eade ("vxlan: mdb: Add MDB control path support")
Cc: stable@vger.kernel.org
Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
---
drivers/net/vxlan/vxlan_mdb.c | 30 ++++++++++++++++++------------
1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c
index 055a4969f593..af7a0d7f95a5 100644
--- a/drivers/net/vxlan/vxlan_mdb.c
+++ b/drivers/net/vxlan/vxlan_mdb.c
@@ -42,6 +42,7 @@ struct vxlan_mdb_remote {
};
#define VXLAN_SGRP_F_DELETE BIT(0)
+#define VXLAN_SGRP_F_NEW BIT(1)
struct vxlan_mdb_src_entry {
struct hlist_node node;
@@ -844,6 +845,7 @@ vxlan_mdb_remote_src_add(const struct vxlan_mdb_config *cfg,
ent = vxlan_mdb_remote_src_entry_add(remote, &src->addr);
if (!ent)
return -ENOMEM;
+ ent->flags |= VXLAN_SGRP_F_NEW;
} else if (!(cfg->nlflags & NLM_F_REPLACE)) {
NL_SET_ERR_MSG_MOD(extack, "Source entry already exists");
return -EEXIST;
@@ -853,15 +855,16 @@ vxlan_mdb_remote_src_add(const struct vxlan_mdb_config *cfg,
if (err)
goto err_src_del;
- /* Clear flags in case source entry was marked for deletion as part of
- * replace flow.
+ /* Clear the deletion mark so the entry survives the replace sweep.
+ * The new mark is retained until the whole operation succeeds.
*/
- ent->flags = 0;
+ ent->flags &= ~VXLAN_SGRP_F_DELETE;
return 0;
err_src_del:
- vxlan_mdb_remote_src_entry_del(ent);
+ if (ent->flags & VXLAN_SGRP_F_NEW)
+ vxlan_mdb_remote_src_entry_del(ent);
return err;
}
@@ -889,11 +892,19 @@ static int vxlan_mdb_remote_srcs_add(const struct vxlan_mdb_config *cfg,
goto err_src_del;
}
+ hlist_for_each_entry(ent, &remote->src_list, node)
+ ent->flags &= ~VXLAN_SGRP_F_NEW;
+
return 0;
err_src_del:
- hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node)
- vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote, ent);
+ hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) {
+ if (ent->flags & VXLAN_SGRP_F_NEW)
+ vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote,
+ ent);
+ else
+ ent->flags &= ~VXLAN_SGRP_F_DELETE;
+ }
return err;
}
@@ -1069,7 +1080,7 @@ vxlan_mdb_remote_srcs_replace(const struct vxlan_mdb_config *cfg,
err = vxlan_mdb_remote_srcs_add(cfg, remote, extack);
if (err)
- goto err_clear_delete;
+ return err;
hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) {
if (ent->flags & VXLAN_SGRP_F_DELETE)
@@ -1078,11 +1089,6 @@ vxlan_mdb_remote_srcs_replace(const struct vxlan_mdb_config *cfg,
}
return 0;
-
-err_clear_delete:
- hlist_for_each_entry(ent, &remote->src_list, node)
- ent->flags &= ~VXLAN_SGRP_F_DELETE;
- return err;
}
static int vxlan_mdb_remote_replace(const struct vxlan_mdb_config *cfg,
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 7/8] net: mv643xx: use platform_device_set_fwnode()
From: Bartosz Golaszewski @ 2026-07-20 16:01 UTC (permalink / raw)
To: Andrew Lunn
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Andi Shyti,
Joerg Roedel (AMD), Will Deacon, Robin Murphy, Andy Shevchenko,
Doug Berger, Florian Fainelli,
Broadcom internal kernel review list, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Ulf Hansson, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Lee Jones, Sebastian Hesselbarth,
Srinivas Kandagatla, brgl, driver-core, linuxppc-dev,
linux-kernel, linux-i2c, iommu, netdev, linux-pm, imx,
linux-arm-kernel, mfd, linux-arm-msm, linux-sound
In-Reply-To: <86b2aba7-b049-47e6-bc94-6cb499b30ce4@lunn.ch>
On Mon, 20 Jul 2026 16:43:40 +0200, Andrew Lunn <andrew@lunn.ch> said:
> On Mon, Jul 20, 2026 at 11:24:54AM +0200, Bartosz Golaszewski wrote:
>> Prefer the higher-level platform_device_set_fwnode() over the
>> OF-specific platform_device_set_of_node() for dynamically allocated
>> platform devices.
>>
>> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>> ---
>> drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
>> index 9caa1e47c174c9d7a161b7f2e2ee12a829b813d4..2f2d6cce8d852b9ec3ab42678a04a7915d1f00cc 100644
>> --- a/drivers/net/ethernet/marvell/mv643xx_eth.c
>> +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
>> @@ -2780,7 +2780,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
>> goto put_err;
>> }
>> ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
>> - platform_device_set_of_node(ppdev, pnp);
>> + platform_device_set_fwnode(ppdev, of_fwnode_handle(pnp));
>
> This is definitely an OF only driver. There are no other calls to
> fwnode functions in this driver, so this is the wrong thing to do.
>
> Sorry, NACK.
>
I'm not going to die on this hill but drivers are OF-only until they're not.
For example, Qualcomm is now working on a hybrid ACPI-OF approach for
laptops[1] and we may end up needing to start converting drivers to fwnode
after all.
There's no real benefit to sticking to OF-specific APIs unless you need to
iterate over all properties of a node or use some other functionality not
available in fwnode. The overhead is minimal and it's never a hot path.
Thanks,
Bartosz
[1] https://lore.kernel.org/all/20260623145225.143218-1-johannes.goede@oss.qualcomm.com/
^ permalink raw reply
* RE: [Intel-wired-lan] [PATCH iwl-next v3 1/2] idpf: remove conditional MBX deinit from idpf_vc_core_deinit()
From: Salin, Samuel @ 2026-07-20 15:59 UTC (permalink / raw)
To: Tantilov, Emil S, intel-wired-lan@lists.osuosl.org
Cc: netdev@vger.kernel.org, Kitszel, Przemyslaw, Bhat, Jay,
Barrera, Ivan D, Loktionov, Aleksandr, Zaremba, Larysa,
Nguyen, Anthony L, andrew+netdev@lunn.ch, davem@davemloft.net,
edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
Lobakin, Aleksander, linux-pci@vger.kernel.org, Chittim, Madhu,
decot@google.com, willemb@google.com, sheenamo@google.com,
lukas@wunner.de
In-Reply-To: <20260630231854.11536-2-emil.s.tantilov@intel.com>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of
> Emil Tantilov
> Sent: Tuesday, June 30, 2026 4:19 PM
> To: intel-wired-lan@lists.osuosl.org
> Cc: netdev@vger.kernel.org; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Bhat, Jay <jay.bhat@intel.com>; Barrera,
> Ivan D <ivan.d.barrera@intel.com>; Loktionov, Aleksandr
> <aleksandr.loktionov@intel.com>; Zaremba, Larysa
> <larysa.zaremba@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; andrew+netdev@lunn.ch;
> davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
> pabeni@redhat.com; Lobakin, Aleksander <aleksander.lobakin@intel.com>;
> linux-pci@vger.kernel.org; Chittim, Madhu <madhu.chittim@intel.com>;
> decot@google.com; willemb@google.com; sheenamo@google.com;
> lukas@wunner.de
> Subject: [Intel-wired-lan] [PATCH iwl-next v3 1/2] idpf: remove conditional
> MBX deinit from idpf_vc_core_deinit()
>
> Previously it was assumed that idpf_vc_core_deinit() is always being called
> during reset handling, where the MBX is disabled by the reset, with remove
> being the exception. Ideally the driver needs to communicate the changes to
> FW in all instances where the MBX is not already disabled.
> Remove the remove_in_prog check from idpf_vc_core_deinit() as the MBX
> was already disabled while handling the reset via libie_ctlq_xn_shutdown() in
> the service task. This is also needed by the following patch, introducing PCI
> callbacks support, specifically in the case where FLR is being triggered by a
> user, in which case, the driver still has the ability to notify FW before the reset
> happens.
>
> Add call to libie_ctlq_xn_shutdown() in idpf_shutdown() to avoid a possible
> regression where long timeouts can happen on shutdown when FW is down.
>
> Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
> Reviewed-by: Jay Bhat <jay.bhat@intel.com>
> Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> ---
> 2.37.3
Tested-by: Samuel Salin <Samuel.salin@intel.com>
^ permalink raw reply
* [PATCH net] xsk: reject tx_metadata_len smaller than struct xsk_tx_metadata
From: Cen Zhang (Microsoft) @ 2026-07-20 15:52 UTC (permalink / raw)
To: magnus.karlsson, maciej.fijalkowski, davem, edumazet, kuba,
pabeni
Cc: sdf, horms, netdev, bpf, linux-kernel, AutonomousCodeSecurity,
tgopinath, kys, blbllhy
xdp_umem_reg() validates tx_metadata_len for upper bound (<256) and
alignment (%8) but not a lower bound. xsk_skb_metadata() computes
meta = buffer - pool->tx_metadata_len then unconditionally accesses
the full 24-byte struct xsk_tx_metadata, so any value less than
sizeof(struct xsk_tx_metadata) allows an out-of-bounds read.
KASAN reports this as:
BUG: KASAN: vmalloc-out-of-bounds in xsk_skb_metadata+0x4b2/0x500
Read of size 8 at addr ffffc90000f11000 by task exploit/148
xsk_skb_metadata (net/xdp/xsk.c:837)
xsk_build_skb (net/xdp/xsk.c)
__xsk_generic_xmit (net/xdp/xsk.c)
xsk_sendmsg (net/xdp/xsk.c)
Add a lower-bound check in xdp_umem_reg() to reject tx_metadata_len
values that cannot cover the full metadata struct.
Fixes: 341ac980eab9 ("xsk: Support tx_metadata_len")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
---
net/xdp/xdp_umem.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c
index 58da2f4f4397..d16ad9d8f919 100644
--- a/net/xdp/xdp_umem.c
+++ b/net/xdp/xdp_umem.c
@@ -208,7 +208,8 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
return -EINVAL;
if (mr->flags & XDP_UMEM_TX_METADATA_LEN) {
- if (mr->tx_metadata_len >= 256 || mr->tx_metadata_len % 8)
+ if (mr->tx_metadata_len < sizeof(struct xsk_tx_metadata) ||
+ mr->tx_metadata_len >= 256 || mr->tx_metadata_len % 8)
return -EINVAL;
umem->tx_metadata_len = mr->tx_metadata_len;
}
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox