* Re: [PATCH net 0/7] pull request: sfc 2026-07-01
From: Paolo Abeni @ 2026-07-07 10:59 UTC (permalink / raw)
To: alejandro.lucero-palau, netdev, kuba, davem, edumazet, horms,
dave.jiang
Cc: Alejandro Lucero
In-Reply-To: <20260701113805.14072-1-alejandro.lucero-palau@amd.com>
On 7/1/26 1:37 PM, alejandro.lucero-palau@amd.com wrote:
> From: Alejandro Lucero <alucerop@amd.com>
>
> Dear net maintainers,
>
> here are the last CXL core changes for enabling CXL Type2 drivers to
> initialize a CXL-capable device plus the netdev sfc driver changes using
> this new CXL core Type2 support.
>
> Please pull or let me know of any problem!
Process note: this is 'net-next' material (as opposed to 'net'); the
target tree should be reported in each patch subj prefix.
/P
^ permalink raw reply
* Re: [PATCH net 1/7] cxl: Support Type2 cxl regs mapping
From: patchwork-bot+netdevbpf @ 2026-07-07 11:00 UTC (permalink / raw)
To: Lucero, Palau, Alejandro
Cc: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang,
alucerop, dan.j.williams, Jonathan.Cameron, benjamin.cheatham,
ecree.xilinx
In-Reply-To: <20260701113805.14072-2-alejandro.lucero-palau@amd.com>
Hello:
This series was applied to netdev/net-next.git (main)
by Dave Jiang <dave.jiang@intel.com>:
On Wed, 1 Jul 2026 12:37:59 +0100 you wrote:
> From: Alejandro Lucero <alucerop@amd.com>
>
> Export cxl core functions for a Type2 driver being able to discover and
> map the device registers.
>
> Signed-off-by: Alejandro Lucero <alucerop@amd.com>
> Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
> Acked-by: Edward Cree <ecree.xilinx@gmail.com>
> Link: https://patch.msgid.link/20260629183727.51502-2-alejandro.lucero-palau@amd.com
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>
> [...]
Here is the summary with links:
- [net,1/7] cxl: Support Type2 cxl regs mapping
https://git.kernel.org/netdev/net-next/c/2c599da8231f
- [net,2/7] cxl: Support dpa without a mailbox
https://git.kernel.org/netdev/net-next/c/96ddf1af34f5
- [net,3/7] sfc: add cxl support
https://git.kernel.org/netdev/net-next/c/a3fc56b12e3a
- [net,4/7] sfc: Map cxl regs
https://git.kernel.org/netdev/net-next/c/08699796dabf
- [net,5/7] sfc: Initialize cxl dpa
https://git.kernel.org/netdev/net-next/c/230284c1b165
- [net,6/7] sfc: obtain and map cxl range using devm_cxl_probe_mem
https://git.kernel.org/netdev/net-next/c/0418860ef2ca
- [net,7/7] sfc: support pio mapping based on cxl
https://git.kernel.org/netdev/net-next/c/bd6550bcdb0c
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH nf] netfilter: ecache: fix inverted time_after() check
From: Yizhou Zhao @ 2026-07-07 11:00 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, netfilter-devel,
coreteam
Cc: Yizhou Zhao, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, netdev, linux-kernel, stable,
Yuxiang Yang, Ao Wang, Xuewei Feng, Qi Li, Ke Xu
ecache_work_evict_list() redelivers DESTROY events for conntracks that
were moved to the per-netns dying_list after event delivery failed. It
sets a 10ms deadline:
stop = jiffies + ECACHE_MAX_JIFFIES
but then tests:
time_after(stop, jiffies)
This condition is true while the deadline is still in the future, so the
worker returns STATE_RESTART after the first successful redelivery in the
usual case. ecache_work() maps STATE_RESTART to delay 0, which turns the
redelivery path into one dying conntrack per workqueue dispatch and makes
the sent > 16 batching/cond_resched() path effectively unreachable.
A conntrack netlink listener whose receive queue is congested can make
DESTROY event delivery fail with -ENOBUFS. With sustained conntrack
churn, entries then accumulate on the dying_list and are only drained at
the degraded one-entry-per-dispatch rate once delivery succeeds again,
wasting CPU on back-to-back workqueue reschedules and prolonging
conntrack memory/resource pressure.
In a KASAN QEMU test with CONFIG_NF_CONNTRACK_EVENTS=y and
nf_conntrack.enable_hooks=1, a congested DESTROY listener caused 8192
nf_ct_delete() calls to return false and move entries to the dying_list.
After closing the listener, the unfixed kernel needed 7670 ecache_work()
entries to destroy 7669 conntracks. With this change, the same 8192
entries were destroyed by 2 ecache_work() entries.
Swap the comparison so the worker restarts only after the deadline has
expired.
Fixes: 2ed3bf188b33 ("netfilter: ecache: use dedicated list for event redelivery")
Cc: stable@vger.kernel.org
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Yuxiang Yang <yangyx22@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>
Assisted-by: Claude-Code:GLM-5.2
Signed-off-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
---
net/netfilter/nf_conntrack_ecache.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index 9df159448b89..cc8d8e85169f 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -77,7 +77,7 @@ static enum retry_state ecache_work_evict_list(struct nf_conntrack_net *cnet)
hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode, &evicted_list);
- if (time_after(stop, jiffies)) {
+ if (time_after(jiffies, stop)) {
ret = STATE_RESTART;
break;
}
--
2.47.3
^ permalink raw reply related
* Re: [PATCH net-next v4 2/3] net: af_unix: useful handling of LSM denials on SCM_RIGHTS
From: Christian Brauner @ 2026-07-07 11:02 UTC (permalink / raw)
To: Jori Koolstra
Cc: Christian Brauner, Aleksa Sarai, Kuniyuki Iwashima,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, netdev, linux-fsdevel, linux-kernel
In-Reply-To: <20260705123826.3818443-3-jkoolstra@xs4all.nl>
> Right now if some LSM such as Smack denies an AF_UNIX socket peer to
> receive an SCM_RIGHTS fd, the SCM_RIGHTS fd array will be cut short at
> that point, and MSG_CTRUNC is set on return of recvmsg(). This is
> highly problematic behaviour, because it leaves the receiver
> wondering what happened. As per man page MSG_CTRUNC is supposed to
> indicate that the control buffer was sized too short, but suddenly
> a permission error might result in the exact same flag being set.
> Moreover, the receiver has no chance to determine how many fds got
> originally sent and how many were suppressed.[1]
>
> Add a SO_RIGHTS_NOTRUNC option to UNIX sockets to enable more useful
> handling of LSM denials when receiving SCM_RIGHTS messages: instead of
> truncating the message at the first blocked fd, keep every fd slot
> and store the LSM errno in the blocked slot.
>
> [1]: https://github.com/uapi-group/kernel-features#useful-handling-of-lsm-denials-on-scm_rights
>
> Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
Reviewed-by: Christian Brauner (Amutable) <brauner@kernel.org>
> -void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
> +int scm_recv_one_fd(struct file *f, int __user *ufd, unsigned int flags,
> + bool notrunc)
> +{
> + int error;
> +
> + if (!ufd)
> + return -EFAULT;
> +
> + error = security_file_receive(f);
> + if (error)
> + return notrunc ? put_user(error, ufd) : error;
> +
> + FD_PREPARE(fdf, flags, get_file(f));
> + if (fdf.err)
> + return fdf.err;
> +
> + error = put_user(fd_prepare_fd(fdf), ufd);
> + if (error)
> + return error;
> +
> + __receive_sock(fd_prepare_file(fdf));
> + return fd_publish(fdf);
> +}
Seems good.
> +
> +void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm, bool notrunc)
> {
> struct cmsghdr __user *cm =
> (__force struct cmsghdr __user *)msg->msg_control_user;
> @@ -365,12 +389,12 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
> return;
>
> if (msg->msg_flags & MSG_CMSG_COMPAT) {
> - scm_detach_fds_compat(msg, scm);
> + scm_detach_fds_compat(msg, scm, notrunc);
> return;
> }
>
> for (i = 0; i < fdmax; i++) {
> - err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
> + err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags, notrunc);
> if (err < 0)
> break;
> }
> @@ -542,8 +566,14 @@ void scm_recv_unix(struct socket *sock, struct msghdr *msg,
> if (!__scm_recv_common(sock->sk, msg, scm, flags))
> return;
>
> - if (scm->fp)
> - scm_detach_fds(msg, scm);
> + if (scm->fp) {
> + struct unix_sock *u;
> + bool notrunc;
> +
> + u = unix_sk(sock->sk);
> + notrunc = READ_ONCE(u->scm_rights_notrunc);
> + scm_detach_fds(msg, scm, notrunc);
Minor nit: Really no need for the boolean. Would be enough to do:
scm_detach_fds(msg, scm, READ_ONCE(u->scm_rights_notrunc));
--
Christian Brauner <brauner@kernel.org>
^ permalink raw reply
* Re: [PATCH net-next v4 3/3] selftest: Add tests for useful handling of LSM denials on SCM_RIGHTS
From: Christian Brauner @ 2026-07-07 11:02 UTC (permalink / raw)
To: Jori Koolstra
Cc: Christian Brauner, Aleksa Sarai, Kuniyuki Iwashima,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, netdev, linux-fsdevel, linux-kernel
In-Reply-To: <20260705123826.3818443-4-jkoolstra@xs4all.nl>
> Tests SCM_RIGHTS fd passing on a socket with the new socket option
> SO_RIGHTS_NOTRUNC turned on. To hook into the security_file_receive()
> call, BPF is used. The BPF program shares a hashmap with userspace that
> lists the inos to be blocked (of the receiver tgid).
>
> Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
>
> diff --git a/tools/testing/selftests/net/af_unix/.gitignore b/tools/testing/selftests/net/af_unix/.gitignore
> index 240b26740c9e..5034482f8864 100644
> --- a/tools/testing/selftests/net/af_unix/.gitignore
> +++ b/tools/testing/selftests/net/af_unix/.gitignore
> @@ -3,6 +3,8 @@ msg_oob
> scm_inq
> scm_pidfd
> scm_rights
> +scm_rights_denial_lsm
> +scm_rights_denial_lsm.bpf.o
> so_peek_off
> unix_connect
> unix_connreset
> diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/selftests/net/af_unix/Makefile
> index 4c0375e28bbe..594cd26ec398 100644
> --- a/tools/testing/selftests/net/af_unix/Makefile
> +++ b/tools/testing/selftests/net/af_unix/Makefile
> @@ -11,9 +11,17 @@ TEST_GEN_PROGS := \
> scm_inq \
> scm_pidfd \
> scm_rights \
> + scm_rights_denial_lsm \
> so_peek_off \
> unix_connect \
> unix_connreset \
> # end of TEST_GEN_PROGS
>
> +TEST_GEN_FILES := scm_rights_denial_lsm.bpf.o
> +
> include ../../lib.mk
> +include ../bpf.mk
> +
> +$(OUTPUT)/scm_rights_denial_lsm: $(BPFOBJ)
> +$(OUTPUT)/scm_rights_denial_lsm: CFLAGS += -I$(SCRATCH_DIR)/include
> +$(OUTPUT)/scm_rights_denial_lsm: LDLIBS += -lelf -lz
> diff --git a/tools/testing/selftests/net/af_unix/scm_rights_denial_lsm.bpf.c b/tools/testing/selftests/net/af_unix/scm_rights_denial_lsm.bpf.c
> new file mode 100644
> index 000000000000..4f2414465bfd
> --- /dev/null
> +++ b/tools/testing/selftests/net/af_unix/scm_rights_denial_lsm.bpf.c
> @@ -0,0 +1,36 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <linux/bpf.h>
> +#include <linux/errno.h>
> +#include <bpf/bpf_helpers.h>
> +#include <bpf/bpf_tracing.h>
> +
> +char _license[] SEC("license") = "GPL";
> +
> +struct inode {
> + unsigned long i_ino;
> +} __attribute__((preserve_access_index));
> +
> +struct file {
> + struct inode *f_inode;
> +} __attribute__((preserve_access_index));
> +
> +struct {
> + __uint(type, BPF_MAP_TYPE_HASH);
> + __uint(max_entries, 16);
> + __type(key, __u64); /* inode number */
> + __type(value, __u32); /* tgid of the receiver being tested */
> +} denied_inodes SEC(".maps");
> +
> +SEC("lsm/file_receive")
> +int BPF_PROG(scm_rights_deny, struct file *file)
> +{
> + __u32 tgid = bpf_get_current_pid_tgid() >> 32;
> + __u64 ino = file->f_inode->i_ino;
> + __u32 *owner;
> +
> + owner = bpf_map_lookup_elem(&denied_inodes, &ino);
> + if (owner && *owner == tgid)
> + return -EPERM;
> +
> + return 0;
> +}
> diff --git a/tools/testing/selftests/net/af_unix/scm_rights_denial_lsm.c b/tools/testing/selftests/net/af_unix/scm_rights_denial_lsm.c
> new file mode 100644
> index 000000000000..b8656de86efe
> --- /dev/null
> +++ b/tools/testing/selftests/net/af_unix/scm_rights_denial_lsm.c
> @@ -0,0 +1,263 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#define _GNU_SOURCE
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/socket.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +
> +#include <bpf/bpf.h>
> +#include <bpf/libbpf.h>
> +
> +#include "kselftest_harness.h"
> +
> +#ifndef SO_RIGHTS_NOTRUNC
> +#define SO_RIGHTS_NOTRUNC 85
> +#endif
> +
> +#define NR_FILES 2
> +
> +/* Per-file content, so a received fd can be matched to the file sent */
> +#define SECRET(n) "secret %d", (n)
> +
> +/* Indices into the socketpair */
> +#define SK_SENDER 0
> +#define SK_RECEIVER 1
> +
> +FIXTURE(scm_rights_denial_bpf)
> +{
> + struct bpf_object *obj;
> + struct bpf_link *link;
> + int map_fd;
> + int sk[2];
> + int files[NR_FILES];
> + __u64 inos[NR_FILES];
> + char paths[NR_FILES][64];
> +};
> +
> +FIXTURE_SETUP(scm_rights_denial_bpf)
> +{
> + struct bpf_program *prog;
> + char lsms[256] = {};
> + int i, fd;
> +
> + if (geteuid() != 0)
> + SKIP(return, "requires root");
> +
> + fd = open("/sys/kernel/security/lsm", O_RDONLY);
> + ASSERT_LE(0, fd);
> + ASSERT_LT(0, read(fd, lsms, sizeof(lsms) - 1));
> + close(fd);
> +
> + if (!strstr(lsms, "bpf"))
> + SKIP(return, "BPF LSM not active (boot with lsm=...,bpf)");
> +
> + self->obj = bpf_object__open_file("scm_rights_denial_lsm.bpf.o", NULL);
> + ASSERT_NE(NULL, self->obj);
> + ASSERT_EQ(0, bpf_object__load(self->obj));
> +
> + prog = bpf_object__find_program_by_name(self->obj, "scm_rights_deny");
> + ASSERT_NE(NULL, prog);
> +
> + self->link = bpf_program__attach_lsm(prog);
> + ASSERT_NE(NULL, self->link);
> +
> + self->map_fd = bpf_object__find_map_fd_by_name(self->obj,
> + "denied_inodes");
> + ASSERT_LE(0, self->map_fd);
> +
> + ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, self->sk));
> +
> + for (i = 0; i < NR_FILES; i++) {
> + struct stat st;
> +
> + snprintf(self->paths[i], sizeof(self->paths[i]),
> + "/tmp/scm_rights_denial_bpf.%d.XXXXXX", i);
> + self->files[i] = mkstemp(self->paths[i]);
> + ASSERT_LE(0, self->files[i]);
> +
> + ASSERT_LT(0, dprintf(self->files[i], SECRET(i)));
> +
> + ASSERT_EQ(0, fstat(self->files[i], &st));
> + self->inos[i] = st.st_ino;
> + }
> +}
> +
> +FIXTURE_TEARDOWN(scm_rights_denial_bpf)
> +{
> + bpf_link__destroy(self->link);
> + bpf_object__close(self->obj);
> +
> + for (int i = 0; i < NR_FILES; i++) {
> + if (self->files[i] >= 0) {
> + close(self->files[i]);
> + unlink(self->paths[i]);
> + }
> + }
> +
> + close(self->sk[SK_SENDER]);
> + close(self->sk[SK_RECEIVER]);
> +}
> +
> +static int deny_inode(int map_fd, __u64 ino)
> +{
> + __u32 tgid = getpid();
> + return bpf_map_update_elem(map_fd, &ino, &tgid, BPF_ANY);
> +}
> +
> +static int set_notrunc(int sk)
> +{
> + int one = 1;
> + return setsockopt(sk, SOL_SOCKET, SO_RIGHTS_NOTRUNC,
> + &one, sizeof(one));
> +}
> +
> +static int send_fds(int sk, int *fds, int n)
> +{
> + char ctrl[CMSG_SPACE(NR_FILES * sizeof(int))] = {};
> + char data = 'x';
> + struct iovec iov = {
> + .iov_base = &data,
> + .iov_len = sizeof(data),
> + };
> + struct msghdr msg = {
> + .msg_iov = &iov,
> + .msg_iovlen = 1,
> + .msg_control = ctrl,
> + .msg_controllen = CMSG_SPACE(n * sizeof(int)),
> + };
> + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
> +
> + cmsg->cmsg_level = SOL_SOCKET;
> + cmsg->cmsg_type = SCM_RIGHTS;
> + cmsg->cmsg_len = CMSG_LEN(n * sizeof(int));
> + memcpy(CMSG_DATA(cmsg), fds, n * sizeof(int));
> +
> + return sendmsg(sk, &msg, 0);
> +}
> +
> +static int recv_fd_slots(int sk, int *slots, int *msg_flags)
> +{
> + int nr_slots;
> + char ctrl[CMSG_SPACE(NR_FILES * sizeof(int))];
> + char data;
> + struct iovec iov = {
> + .iov_base = &data,
> + .iov_len = sizeof(data),
> + };
> + struct msghdr msg = {
> + .msg_iov = &iov,
> + .msg_iovlen = 1,
> + .msg_control = ctrl,
> + .msg_controllen = sizeof(ctrl),
> + };
> + struct cmsghdr *cmsg;
> +
> + if (recvmsg(sk, &msg, 0) < 0)
> + return -1;
> +
> + *msg_flags = msg.msg_flags;
> +
> + cmsg = CMSG_FIRSTHDR(&msg);
> + if (!cmsg)
> + return 0;
> +
> + nr_slots = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
> + memcpy(slots, CMSG_DATA(cmsg), nr_slots * sizeof(int));
> +
> + return nr_slots;
> +}
> +
> +/* Prove a received fd works by reading back the file's content. */
> +static int check_secret(int fd, int idx)
> +{
> + char want[32], got[32] = {};
> +
> + snprintf(want, sizeof(want), SECRET(idx));
> + if (pread(fd, got, sizeof(got) - 1, 0) < 0)
> + return -1;
> +
> + return strcmp(want, got);
> +}
> +
> +TEST_F(scm_rights_denial_bpf, all_allowed)
> +{
> + int slots[NR_FILES], nr_slots, flags, i;
> +
> + ASSERT_EQ(0, set_notrunc(self->sk[SK_RECEIVER]));
> + ASSERT_NE(-1, send_fds(self->sk[SK_SENDER], self->files, NR_FILES));
> + nr_slots = recv_fd_slots(self->sk[SK_RECEIVER], slots, &flags);
> +
> + ASSERT_EQ(NR_FILES, nr_slots);
> + EXPECT_EQ(0, flags & MSG_CTRUNC);
> +
> + for (i = 0; i < NR_FILES; i++) {
> + ASSERT_LE(0, slots[i]);
Why do you assert less-or-equal? You want a valid fd so you should
expect >= 0?
> + EXPECT_EQ(0, check_secret(slots[i], i));
> + close(slots[i]);
> + }
> +}
> +
> +TEST_F(scm_rights_denial_bpf, first_denied)
> +{
> + int slots[NR_FILES], nr_slots, flags;
> +
> + ASSERT_EQ(0, deny_inode(self->map_fd, self->inos[0]));
> +
> + ASSERT_EQ(0, set_notrunc(self->sk[SK_RECEIVER]));
> + ASSERT_NE(-1, send_fds(self->sk[SK_SENDER], self->files, NR_FILES));
> + nr_slots = recv_fd_slots(self->sk[SK_RECEIVER], slots, &flags);
> +
> + ASSERT_EQ(NR_FILES, nr_slots);
> + EXPECT_EQ(0, flags & MSG_CTRUNC);
> + EXPECT_EQ(-EPERM, slots[0]);
> +
> + ASSERT_LE(0, slots[1]);
> + EXPECT_EQ(0, check_secret(slots[1], 1));
> + close(slots[1]);
> +}
> +
> +TEST_F(scm_rights_denial_bpf, all_denied)
> +{
> + int slots[NR_FILES], nr_slots, flags, i;
> +
> + for (i = 0; i < NR_FILES; i++)
> + ASSERT_EQ(0, deny_inode(self->map_fd, self->inos[i]));
> +
> + ASSERT_EQ(0, set_notrunc(self->sk[SK_RECEIVER]));
> + ASSERT_NE(-1, send_fds(self->sk[SK_SENDER], self->files, NR_FILES));
> + nr_slots = recv_fd_slots(self->sk[SK_RECEIVER], slots, &flags);
> +
> + ASSERT_EQ(NR_FILES, nr_slots);
> + EXPECT_EQ(0, flags & MSG_CTRUNC);
> +
> + for (i = 0; i < NR_FILES; i++)
> + EXPECT_EQ(-EPERM, slots[i]);
> +}
> +
> +TEST_F(scm_rights_denial_bpf, denied_without_notrunc)
> +{
> + int slots[NR_FILES], nr_slots, flags;
> +
> + /*
> + * Baseline behaviour without SO_RIGHTS_NOTRUNC: the fd array is
> + * truncated at the first denied fd and MSG_CTRUNC is set.
> + */
> + ASSERT_EQ(0, deny_inode(self->map_fd, self->inos[1]));
> +
> + ASSERT_NE(-1, send_fds(self->sk[SK_SENDER], self->files, NR_FILES));
> + nr_slots = recv_fd_slots(self->sk[SK_RECEIVER], slots, &flags);
> +
> + ASSERT_EQ(1, nr_slots);
> + EXPECT_NE(0, flags & MSG_CTRUNC);
> +
> + ASSERT_LE(0, slots[0]);
Why do you expect less-equal than zero? Don't you need ASSERT_GE()
because you want slots[0] to be a valid file desscriptor?
And even the other way around... Zero is a valid file descriptor so on
failure you must expect ASSERT_LT()?
--
Christian Brauner <brauner@kernel.org>
^ permalink raw reply
* Re: [PATCH net-next v5 2/8] net: phy: phylink: add helper to modify pause
From: Maxime Chevallier @ 2026-07-07 11:10 UTC (permalink / raw)
To: javen, hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, daniel, linux, enelsonmoore, daniel
In-Reply-To: <20260707091637.371-3-javen_xu@realsil.com.cn>
Hi,
On 7/7/26 11:16, javen wrote:
> From: Javen Xu <javen_xu@realsil.com.cn>
>
> For Realtek nics, when we enable jumbo, pause are not supported. So we
> must check the pause capabilities from ourself and lp.
>
> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
> ---
> Changes in v5:
> - no changes, new file
> ---
> drivers/net/phy/phylink.c | 66 +++++++++++++++++++++++++++++++++++++++
> include/linux/phylink.h | 2 ++
> 2 files changed, 68 insertions(+)
>
> diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
> index 59dfe35afa54..c450ee33b75c 100644
> --- a/drivers/net/phy/phylink.c
> +++ b/drivers/net/phy/phylink.c
> @@ -1828,6 +1828,72 @@ int phylink_set_fixed_link(struct phylink *pl,
> }
> EXPORT_SYMBOL_GPL(phylink_set_fixed_link);
>
> +/**
> + * phylink_set_mac_capabilities() - Dynamically update MAC capabilities
> + * @pl: a pointer to a &struct phylink returned from phylink_create()
> + * @mac_capabilities: the new MAC capabilities mask
> + *
> + * This function allows a MAC driver to dynamically change its capabilities,
> + * such as losing/gaining Pause frame support based on MTU size.
> + * It recalculates supported link modes and triggers renegotiation if needed.
> + */
> +void phylink_set_mac_capabilities(struct phylink *pl, unsigned long mac_capabilities)
This is a step in the right direction, but this is maybe too generic, as
mac_capabilities represent both the MAC's Pause support as well as Speed/Duplex
support.
The speed/duplex parts shouldn't be changed dynamically, I think the helper
needs to be specific in its naming that this is strictly about changing the MAC's
Pause / Asym capabilities dynamically, and be either passed some booleans, one for
rx one for tx, or fail if we try to change anything other than MAC_SYM_PAUSE and
MAC_ASYM_PAUSE.
Maybe something like "phylink_update_mac_pause_capabilities" ?
The 'update' part makes it clear this may trigger re-negotiation.
Maxime
^ permalink raw reply
* Re: [PATCH net v3] net: usb: lan78xx: disable VLAN filter in promiscuous mode
From: patchwork-bot+netdevbpf @ 2026-07-07 11:20 UTC (permalink / raw)
To: Enrico Pozzobon
Cc: Thangaraj.S, Rengarajan.S, UNGLinuxDriver, andrew+netdev, davem,
edumazet, kuba, pabeni, Woojung.Huh, netdev, linux-usb,
linux-kernel
In-Reply-To: <20260701-lan78xx-vlan-promisc-v3-1-232266d32743@dissecto.com>
Hello:
This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Wed, 01 Jul 2026 16:47:23 +0200 you wrote:
> From: Enrico Pozzobon <enrico.pozzobon@dissecto.com>
>
> The hardware VLAN filter (RFE_CTL_VLAN_FILTER_) drops VLAN-tagged frames
> whose VID has not been registered via lan78xx_vlan_rx_add_vid(). It is
> left enabled in promiscuous mode, so packet capture (e.g. tcpdump or
> Wireshark) does not see tagged frames for unregistered VIDs.
>
> [...]
Here is the summary with links:
- [net,v3] net: usb: lan78xx: disable VLAN filter in promiscuous mode
https://git.kernel.org/netdev/net/c/60444706aa17
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next v5 3/8] r8169: add support for phylink
From: Maxime Chevallier @ 2026-07-07 11:37 UTC (permalink / raw)
To: javen, hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, daniel, linux, enelsonmoore, daniel
In-Reply-To: <20260707091637.371-4-javen_xu@realsil.com.cn>
On 7/7/26 11:16, javen wrote:
> From: Javen Xu <javen_xu@realsil.com.cn>
>
> Transfer old framework to phylink. Phylink can support fiber mode card
> which can not get link status or link speed from standard phy registers.
>
> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
> ---
> Changes in v2:
> - merge patch v1 3/6 and v1 4/6.
> - add helper rtl_mac_enable_tx_lpi(), rtl_mac_disable_tx_lpi()
> and rtl8169_get_lpi_caps()
>
> Changes in v3:
> - use phylink_ethtool_set_pauseparam to set pause status when change
> mtu
> - replace phy_do_ioctl_running with rtl8169_ioctl
> - recover phy_mode according to tp->supports_gmii for 1G nics
>
> Changes in v4:
> - set lpi_interface if support eee
> - Only if jumbo changes, set pause
>
> Changes in v5:
> - no changes
> ---
> drivers/net/ethernet/realtek/Kconfig | 1 +
> drivers/net/ethernet/realtek/r8169_main.c | 279 ++++++++++++++++------
> 2 files changed, 206 insertions(+), 74 deletions(-)
>
> diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
> index 9b0f4f9631db..49ac72734225 100644
> --- a/drivers/net/ethernet/realtek/Kconfig
> +++ b/drivers/net/ethernet/realtek/Kconfig
> @@ -88,6 +88,7 @@ config R8169
> select CRC32
> select PHYLIB
PHYLINK selects PHYLIB, you can therefore drop this.
Besides this and potential reworks for the pause, this patch looks
pretty good :)
Maxime
^ permalink raw reply
* Re: [PATCH net] net: hsr: fix memory leak on slave unregistration by removing synced VLANs
From: Felix Maurer @ 2026-07-07 11:38 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
Andrew Lunn, netdev, eric.dumazet, syzbot+456957213f32970c0762
In-Reply-To: <20260707082327.3238690-1-edumazet@google.com>
On Tue, Jul 07, 2026 at 08:23:27AM +0000, Eric Dumazet wrote:
> When an HSR master device is brought UP, it auto-adds VLAN 0 via
> vlan_vid0_add(), which propagates VID 0 to its slave devices.
>
> If a slave device is later unregistered while HSR is active (e.g., during
> netns cleanup or interface destruction), hsr_del_port() is called to
> detach the slave port from the HSR master. However, hsr_del_port() currently
> does not delete the VLAN IDs that were synced to the slave device by HSR.
>
> As a result, the slave device retains a refcount on VID 0 (and any other
> synced VLANs). When the slave device is destroyed, its vlan_info /
> vlan_vid_info structure remains allocated, leading to a memory leak.
>
> Fix this by calling vlan_vids_del_by_dev(port->dev, master->dev) in
> hsr_del_port() before unlinking the slave device, matching the cleanup
> behavior in bonding and team drivers.
>
> Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
> Reported-by: syzbot+456957213f32970c0762@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/netdev/6a4cb6ca.57639fcc.86d58.000b.GAE@google.com/T/#u
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Looks good to me, thank you!
Reviewed-by: Felix Maurer <fmaurer@redhat.com>
> ---
> net/hsr/hsr_slave.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
> index d9af9e65f72f07b1997b80c85db16d812fbda488..2d1e3ea72088e35d5d870b4cc86dd2f789670394 100644
> --- a/net/hsr/hsr_slave.c
> +++ b/net/hsr/hsr_slave.c
> @@ -242,6 +242,7 @@ void hsr_del_port(struct hsr_port *port)
> netdev_rx_handler_unregister(port->dev);
> if (!port->hsr->fwd_offloaded)
> dev_set_promiscuity(port->dev, -1);
> + vlan_vids_del_by_dev(port->dev, master->dev);
> netdev_upper_dev_unlink(port->dev, master->dev);
> if (hsr->prot_version == PRP_V1 &&
> port->type == HSR_PT_SLAVE_B) {
> --
> 2.55.0.795.g602f6c329a-goog
>
^ permalink raw reply
* Re: [PATCH net] bonding: fix devconf_all NULL dereference when IPv6 is disabled
From: Hangbin Liu @ 2026-07-07 11:40 UTC (permalink / raw)
To: Vadim Fedorenko
Cc: zhangzl2013, Jay Vosburgh, Andrew Lunn, Jakub Kicinski,
David S . Miller, Eric Dumazet, Paolo Abeni, netdev, linux-kernel,
Qianheng Peng, Zhaolong Zhang
In-Reply-To: <9e8f5dfe-d66b-47c9-b7d9-e57ed2aa6fef@linux.dev>
On Tue, Jul 7, 2026 at 6:35 PM Vadim Fedorenko
<vadim.fedorenko@linux.dev> wrote:
>
> On 07/07/2026 02:06, zhangzl2013@126.com wrote:
> > From: Zhaolong Zhang <zhangzl68@chinatelecom.cn>
> >
> > When booting with the 'ipv6.disable=1' parameter, the devconf_all is
> > never initialized because inet6_init() exits before addrconf_init() is
> > called which initializes it. bond_send_validate(), however, will still
> > call bond_ns_send_all() even ipv6 is indeed disabled. It will lead to
> > NULL derefence of net->ipv6.devconf_all in ip6_pol_route().
> >
> > BUG: kernel NULL pointer dereference, address: 000000000000000c
> > [...]
> > Workqueue: bond0 bond_arp_monitor [bonding]
> > RIP: 0010:ip6_pol_route+0x69/0x480
> > [...]
> > Call Trace:
> > <TASK>
> > ? srso_return_thunk+0x5/0x5f
> > ? __pfx_ip6_pol_route_output+0x10/0x10
> > fib6_rule_lookup+0xfe/0x260
> > ? wakeup_preempt+0x8a/0x90
> > ? srso_return_thunk+0x5/0x5f
> > ? srso_return_thunk+0x5/0x5f
> > ? sched_balance_rq+0x369/0x810
> > ip6_route_output_flags+0xd7/0x170
> > bond_ns_send_all+0xde/0x280 [bonding]
> > bond_ab_arp_probe+0x296/0x320 [bonding]
> > ? srso_return_thunk+0x5/0x5f
> > bond_activebackup_arp_mon+0xb4/0x2c0 [bonding]
> > process_one_work+0x196/0x370
> > worker_thread+0x1af/0x320
> > ? srso_return_thunk+0x5/0x5f
> > ? __pfx_worker_thread+0x10/0x10
> > kthread+0xe3/0x120
> > ? __pfx_kthread+0x10/0x10
> > ret_from_fork+0x199/0x260
> > ? __pfx_kthread+0x10/0x10
> > ret_from_fork_asm+0x1a/0x30
> > </TASK>
> >
> > Fix this by adding ipv6_mod_enabled() condition check in the caller.
> >
> > Fixes: 4e24be018eb9 ("bonding: add new parameter ns_targets")
> > Signed-off-by: Qianheng Peng <pengqh1@chinatelecom.cn>
> > Signed-off-by: Zhaolong Zhang <zhangzl68@chinatelecom.cn>
> > ---
> > drivers/net/bonding/bond_main.c | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> > index e044fc733b8c..522eab060f9e 100644
> > --- a/drivers/net/bonding/bond_main.c
> > +++ b/drivers/net/bonding/bond_main.c
> > @@ -3455,7 +3455,8 @@ static void bond_send_validate(struct bonding *bond, struct slave *slave)
> > {
> > bond_arp_send_all(bond, slave);
> > #if IS_ENABLED(CONFIG_IPV6)
> > - bond_ns_send_all(bond, slave);
> > + if (likely(ipv6_mod_enabled()))
> > + bond_ns_send_all(bond, slave);
> > #endif
> > }
> >
>
> ipv6_mod_enabled() doesn't depend on CONFIG_IPV6, please, remove
> #if IS_ENABLED as well
No, bond_ns_send_all() is static and protected by IS_ENABLED(CONFIG_IPV6).
Remove this IS_ENABLED will cause build error.
Thanks
Hangbin
^ permalink raw reply
* Re: [PATCH net] bonding: fix devconf_all NULL dereference when IPv6 is disabled
From: Hangbin Liu @ 2026-07-07 11:41 UTC (permalink / raw)
To: zhangzl2013
Cc: Jay Vosburgh, Andrew Lunn, Jakub Kicinski, David S . Miller,
Eric Dumazet, Paolo Abeni, netdev, linux-kernel, Qianheng Peng,
Zhaolong Zhang
In-Reply-To: <20260707010622.487333-1-zhangzl2013@126.com>
On Tue, Jul 7, 2026 at 9:07 AM <zhangzl2013@126.com> wrote:
>
> From: Zhaolong Zhang <zhangzl68@chinatelecom.cn>
>
> When booting with the 'ipv6.disable=1' parameter, the devconf_all is
> never initialized because inet6_init() exits before addrconf_init() is
> called which initializes it. bond_send_validate(), however, will still
> call bond_ns_send_all() even ipv6 is indeed disabled. It will lead to
> NULL derefence of net->ipv6.devconf_all in ip6_pol_route().
>
> BUG: kernel NULL pointer dereference, address: 000000000000000c
> [...]
> Workqueue: bond0 bond_arp_monitor [bonding]
> RIP: 0010:ip6_pol_route+0x69/0x480
> [...]
> Call Trace:
> <TASK>
> ? srso_return_thunk+0x5/0x5f
> ? __pfx_ip6_pol_route_output+0x10/0x10
> fib6_rule_lookup+0xfe/0x260
> ? wakeup_preempt+0x8a/0x90
> ? srso_return_thunk+0x5/0x5f
> ? srso_return_thunk+0x5/0x5f
> ? sched_balance_rq+0x369/0x810
> ip6_route_output_flags+0xd7/0x170
> bond_ns_send_all+0xde/0x280 [bonding]
> bond_ab_arp_probe+0x296/0x320 [bonding]
> ? srso_return_thunk+0x5/0x5f
> bond_activebackup_arp_mon+0xb4/0x2c0 [bonding]
> process_one_work+0x196/0x370
> worker_thread+0x1af/0x320
> ? srso_return_thunk+0x5/0x5f
> ? __pfx_worker_thread+0x10/0x10
> kthread+0xe3/0x120
> ? __pfx_kthread+0x10/0x10
> ret_from_fork+0x199/0x260
> ? __pfx_kthread+0x10/0x10
> ret_from_fork_asm+0x1a/0x30
> </TASK>
>
> Fix this by adding ipv6_mod_enabled() condition check in the caller.
>
> Fixes: 4e24be018eb9 ("bonding: add new parameter ns_targets")
> Signed-off-by: Qianheng Peng <pengqh1@chinatelecom.cn>
> Signed-off-by: Zhaolong Zhang <zhangzl68@chinatelecom.cn>
> ---
> drivers/net/bonding/bond_main.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index e044fc733b8c..522eab060f9e 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -3455,7 +3455,8 @@ static void bond_send_validate(struct bonding *bond, struct slave *slave)
> {
> bond_arp_send_all(bond, slave);
> #if IS_ENABLED(CONFIG_IPV6)
> - bond_ns_send_all(bond, slave);
> + if (likely(ipv6_mod_enabled()))
> + bond_ns_send_all(bond, slave);
> #endif
> }
>
Thanks for your fix. Next time please use PATCHv2 with a change log.
Reviewed-by: Hangbin Liu <liuhangbin@gmail.com>
^ permalink raw reply
* Re: [PATCH 1/2] af_unix: Do not wait for garbage collector in sendmsg()
From: Sebastian Andrzej Siewior @ 2026-07-07 11:42 UTC (permalink / raw)
To: Nam Cao
Cc: Kuniyuki Iwashima, sashiko-reviews, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, netdev,
linux-kernel, linux-rt-devel
In-Reply-To: <87wlvbmgtv.fsf@yellow.woof>
On 2026-07-04 08:03:56 [+0200], Nam Cao wrote:
> Kuniyuki Iwashima <kuniyu@google.com> writes:
> > your patch makes it much easier to abuse.
> > UNIX_INFLIGHT_SANE_USER is usually much smaller than
> > RLIMIT_NOFILE.
> >
> > unix_schedule_gc() in sendmsg() is to self-regulate malicious users,
> > otherwise GC relies on unrelated AF_UNIX socket's close() and could
> > be triggered too late since GC is system-wide.
>
> About the abuse, the scenario where inflight sockets bypass
> UNIX_INFLIGHT_SANE_USER and delay GC until an unrelated AF_UNIX socket
> closes actually exists today.
We don't bypass the limit for an ordinary user. That one gets blocked in
too_many_unix_fds(). But for the CAP_SYS_RESOURCE + CAP_SYS_ADMIN it is
a different story.
In that case we cross the UNIX_INFLIGHT_SANE_USER and schedule the GC,
it is not delayed. The worker is triggered regularity and the thread
waits for its completion it is just the GC worker does not clean up
anything so it continues to increase. The only thing that actually
limits the sender is if it runs out of socket memory and needs to wait.
So it kind of works for a single thread.
…
> To address this properly, we can schedule the GC at task exit. I can
> include that patch in my series, if that sounds good to you.
task exit or closing the socket?
Either way, in your PoC it hardly makes any sense to schedule the worker
over and over and wait for it since it does not do anything. Sure it is
the system as a whole so triggering might make sense but I'm not sure
about waiting for its completion.
Side note: gc_in_progress is redundant since you can't schedule a worker
twice and work_pending(&unix_gc_work) would provide the same
information. The only difference is that you avoid scheduling the worker
while it is running but I don't think this is a problem.
> Nam
Sebastian
^ permalink raw reply
* Re: [PATCH net-next v5 2/4] net: pse-pd: add Realtek/Broadcom PSE MCU core
From: Jonas Jelonek @ 2026-07-07 12:00 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Oleksij Rempel, Kory Maincent, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
linux-kernel, Daniel Golle, Bjørn Mork
In-Reply-To: <akvhq1YcUFP6eizf@monoceros>
Hi Uwe,
On 06.07.26 19:12, Uwe Kleine-König wrote:
> Hello,
>
> On Mon, Jul 06, 2026 at 11:24:22AM +0000, Jonas Jelonek wrote:
>> +#include <linux/mod_devicetable.h>
> Please only include those <linux/device-id/*.h> that you actively need.
> I'm working on getting rid of <linux/mod_devicetable.h>, so please don't
> introduce new users.
I'll fix this in the next version. Thanks for the hint.
> Best regards
> Uwe
Best regards,
Jonas
^ permalink raw reply
* [PATCH v2 1/7] wifi: ath9k_htc: don't store usb_device_id
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Toke Høiland-Jørgensen, Johan Hovold,
Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Chas Williams, Alan Stern
Cc: linux-usb, driver-core, linux-wireless, linux-media,
linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>
usb_device_id is not guaranteed to live longer than probe due to presence
of dynamic ID. All information apart from driver_data can be easily
retrieved from usb_device, so just store driver_data.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/net/wireless/ath/ath9k/hif_usb.c | 12 ++++++------
drivers/net/wireless/ath/ath9k/hif_usb.h | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 47f904e7e652..d3491ff08e6e 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -1087,7 +1087,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
}
kfree(buf);
- if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+ if (IS_AR7010_DEVICE(hif_dev->id_info))
firm_offset = AR7010_FIRMWARE_TEXT;
else
firm_offset = AR9271_FIRMWARE_TEXT;
@@ -1182,7 +1182,7 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
if (MAJOR_VERSION_REQ == 1 && hif_dev->fw_minor_index == 3) {
const char *filename;
- if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+ if (IS_AR7010_DEVICE(hif_dev->id_info))
filename = FIRMWARE_AR7010_1_1;
else
filename = FIRMWARE_AR9271;
@@ -1198,7 +1198,7 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
return -ENOENT;
} else {
- if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+ if (IS_AR7010_DEVICE(hif_dev->id_info))
chip = "7010";
else
chip = "9271";
@@ -1255,9 +1255,9 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
ret = ath9k_htc_hw_init(hif_dev->htc_handle,
&hif_dev->interface->dev,
- hif_dev->usb_device_id->idProduct,
+ le16_to_cpu(hif_dev->udev->descriptor.idProduct),
hif_dev->udev->product,
- hif_dev->usb_device_id->driver_info);
+ hif_dev->id_info);
if (ret) {
ret = -EINVAL;
goto err_htc_hw_init;
@@ -1369,7 +1369,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
hif_dev->udev = udev;
hif_dev->interface = interface;
- hif_dev->usb_device_id = id;
+ hif_dev->id_info = id->driver_info;
#ifdef CONFIG_PM
udev->reset_resume = 1;
#endif
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index dc0b0fa5c325..b3e7b0fb54b8 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -115,7 +115,7 @@ struct cmd_buf {
struct hif_device_usb {
struct usb_device *udev;
struct usb_interface *interface;
- const struct usb_device_id *usb_device_id;
+ int id_info;
const void *fw_data;
size_t fw_size;
struct completion fw_done;
--
2.54.0
^ permalink raw reply related
* [PATCH v2 4/7] media: as102: do not rely on id table address comparison
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Toke Høiland-Jørgensen, Johan Hovold,
Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Chas Williams, Alan Stern
Cc: linux-usb, driver-core, linux-wireless, linux-media,
linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>
The driver info should be retrieved using the driver_info field, not by
address comparison.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/media/usb/as102/as102_usb_drv.c | 73 ++++++++++++++-------------------
1 file changed, 30 insertions(+), 43 deletions(-)
diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c
index a11024451ceb..be2f8be560fa 100644
--- a/drivers/media/usb/as102/as102_usb_drv.c
+++ b/drivers/media/usb/as102/as102_usb_drv.c
@@ -24,35 +24,33 @@ static void as102_usb_stop_stream(struct as102_dev_t *dev);
static int as102_open(struct inode *inode, struct file *file);
static int as102_release(struct inode *inode, struct file *file);
-static const struct usb_device_id as102_usb_id_table[] = {
- { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) },
- { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) },
- { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) },
- { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) },
- { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) },
- { } /* Terminating entry */
+struct as102_dev_info {
+ const char *name;
+ /*
+ * eLNA configuration: devices built on the reference design work best
+ * with 0xA0, while custom designs seem to require 0xC0
+ */
+ uint8_t elna_cfg;
};
-/* Note that this table must always have the same number of entries as the
- as102_usb_id_table struct */
-static const char * const as102_device_names[] = {
- AS102_REFERENCE_DESIGN,
- AS102_PCTV_74E,
- AS102_ELGATO_EYETV_DTT_NAME,
- AS102_NBOX_DVBT_DONGLE_NAME,
- AS102_SKY_IT_DIGITAL_KEY_NAME,
- NULL /* Terminating entry */
-};
+#define DRIVER_INFO(dev_name, dev_elna_cfg) \
+ .driver_info = (kernel_ulong_t)&(const struct as102_dev_info){ \
+ .name = (dev_name), \
+ .elna_cfg = (dev_elna_cfg), \
+ }
-/* eLNA configuration: devices built on the reference design work best
- with 0xA0, while custom designs seem to require 0xC0 */
-static uint8_t const as102_elna_cfg[] = {
- 0xA0,
- 0xC0,
- 0xC0,
- 0xA0,
- 0xA0,
- 0x00 /* Terminating entry */
+static const struct usb_device_id as102_usb_id_table[] = {
+ { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001),
+ DRIVER_INFO(AS102_REFERENCE_DESIGN, 0xA0) },
+ { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID),
+ DRIVER_INFO(AS102_PCTV_74E, 0xC0) },
+ { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID),
+ DRIVER_INFO(AS102_ELGATO_EYETV_DTT_NAME, 0xC0) },
+ { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID),
+ DRIVER_INFO(AS102_NBOX_DVBT_DONGLE_NAME, 0xA0) },
+ { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID),
+ DRIVER_INFO(AS102_SKY_IT_DIGITAL_KEY_NAME, 0xA0) },
+ { } /* Terminating entry */
};
struct usb_driver as102_usb_driver = {
@@ -336,29 +334,18 @@ static int as102_usb_probe(struct usb_interface *intf,
{
int ret;
struct as102_dev_t *as102_dev;
- int i;
-
- /* This should never actually happen */
- if (ARRAY_SIZE(as102_usb_id_table) !=
- (sizeof(as102_device_names) / sizeof(const char *))) {
- pr_err("Device names table invalid size");
- return -EINVAL;
- }
+ const struct as102_dev_info *info = (const struct as102_dev_info *)id->driver_info;
as102_dev = kzalloc_obj(struct as102_dev_t);
if (as102_dev == NULL)
return -ENOMEM;
- /* Assign the user-friendly device name */
- for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
- if (id == &as102_usb_id_table[i]) {
- as102_dev->name = as102_device_names[i];
- as102_dev->elna_cfg = as102_elna_cfg[i];
- }
- }
-
- if (as102_dev->name == NULL)
+ if (info) {
+ as102_dev->name = info->name;
+ as102_dev->elna_cfg = info->elna_cfg;
+ } else {
as102_dev->name = "Unknown AS102 device";
+ }
/* set private callback functions */
as102_dev->bus_adap.ops = &as102_priv_ops;
--
2.54.0
^ permalink raw reply related
* [PATCH v2 0/7] usb: fix UAF related to dynamic ID
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Toke Høiland-Jørgensen, Johan Hovold,
Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Chas Williams, Alan Stern
Cc: linux-usb, driver-core, linux-wireless, linux-media,
linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo,
Manuel Ebner
This is the USB version of the dynamic ID UAF fix similar to that of PCI
[1]. usb_match_dynamic_id returns a pointer to field of usb_dynid, which
can be freed when dynamic ID is removed via sysfs. It can be triggered with
the following sequence:
echo <vid> <pid> > /sys/bus/usb/drivers/<name>/new_id
<probe start>
echo <vid> <pid> > /sys/bus/usb/drivers/<name>/remove_id
<probe use ID>
Fix it by making a stack copy of the ID. This does mean that the lifetime
of ID is scoped to probe (which is already the case but never spelled out
explicitly). Drivers use these device IDs creatively, so this series also
fix these drivers.
The following coccinelle script is used to find all cases that are deemed
suspicious. Only useful case for IDs should be access its fields, or
forwarding (without type cast) to functions that do so.
@usage@
identifier fn, id;
position p;
@@
fn(..., struct usb_device_id *id, ...)
{
...
id@p
...
}
// Due to cocci isomorphism this needs to be explicit
@bad@
identifier fn, id;
type T;
position usage.p;
@@
fn(..., struct usb_device_id *id, ...)
{
...
(T*)id@p
...
}
// Good use cases
@good@
identifier fn, id, fld;
expression E;
position usage.p;
@@
fn(..., struct usb_device_id *id, ...)
{
...
(
id@p->fld
|
E(..., id@p, ...)
|
// Redundant checks, but ignore
!id@p
|
// Redundant checks, but ignore
id ? ... : ...
)
...
}
@script:python depends on usage && (bad || !good)@
p << usage.p;
@@
coccilib.report.print_report(p[0], "suspicious use of device ID")
There're 3 drivers that store usb_device_id, and they're converted to just
use driver_info instead. The other fields of usb_device_id can be easily
retrieved from usb_device via descriptor.id{Vendor,Product}.
There're also a few users that rely on pointer arithmetics. Pegaus and
xusbatm are converted to use driver_info. All unusal USB mass storage
drivers rely on pointer arithemtic to index into a side table, because USB
storage subsystem is using the driver_data for flags. Luckily all these
drivers set no_dynamic_id. Ideally these could be fixed too but their
maintainers probably have a better idea of how.
Link: https://lore.kernel.org/driver-core/20260706-pci_id_fix-v3-0-2d48fc025acc@garyguo.net [1]
Signed-off-by: Gary Guo <gary@garyguo.net>
---
Changes in v2:
- Add le16_to_cpu in ath9k patch.
- Fix AS102 which relies on address comparison. (Sashiko)
- Fix pegasus, xusbatm which relies on pointer arithmetic.
- usb_device_id from static ID table is now not copied. This ensures that
USB mass storage subsystem can still perform pointer arithmetic. This
also addresses Danilo's review feedback.
- Link to v1: https://patch.msgid.link/20260630-usb_dyn_id_uaf-v1-0-160a02be5ac2@garyguo.net
---
Gary Guo (7):
wifi: ath9k_htc: don't store usb_device_id
usb: usbtmc: don't store usb_device_id
usb: serial: spcp8x5: don't store usb_device_id
media: as102: do not rely on id table address comparison
net: usb: pegasus: don't rely on id table pointer arithmetic
usb: xusbatm: don't rely on id table pointer arithmetic
usb: fix UAF when probe runs concurrent to dyn ID removal
drivers/media/usb/as102/as102_usb_drv.c | 73 +++++++++++++-------------------
drivers/net/usb/pegasus.c | 54 ++++++++++-------------
drivers/net/usb/pegasus.h | 3 --
drivers/net/wireless/ath/ath9k/hif_usb.c | 12 +++---
drivers/net/wireless/ath/ath9k/hif_usb.h | 2 +-
drivers/usb/atm/xusbatm.c | 6 ++-
drivers/usb/class/usbtmc.c | 2 -
drivers/usb/core/driver.c | 12 ++++--
drivers/usb/serial/spcp8x5.c | 6 +--
include/linux/usb.h | 3 +-
10 files changed, 76 insertions(+), 97 deletions(-)
---
base-commit: 2b763db0c2763d6bf73d7d3e69665222d1f377cf
change-id: 20260629-usb_dyn_id_uaf-9d5f415387d4
Best regards,
--
Gary Guo <gary@garyguo.net>
^ permalink raw reply
* [PATCH v2 5/7] net: usb: pegasus: don't rely on id table pointer arithmetic
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Toke Høiland-Jørgensen, Johan Hovold,
Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Chas Williams, Alan Stern
Cc: linux-usb, driver-core, linux-wireless, linux-media,
linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>
The current code is broken when dynamic ID is involved; in such cases
usb_device_id parameter of probe lives on the heap and the pointer
arithmetic will get an index that is wildly out of bound. Instead of
keeping a side table for additional information, use driver_info field of
the usb_device_id.
The dynamic ID parsing code needs to be updated for this; convert it to
just write to the reserved entry for dynamic ID and remove the weird loop.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/net/usb/pegasus.c | 54 +++++++++++++++++++----------------------------
drivers/net/usb/pegasus.h | 3 ---
2 files changed, 22 insertions(+), 35 deletions(-)
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 8700eeb8e22d..aba1a640fc26 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -43,21 +43,12 @@ static bool loopback;
static bool mii_mode;
static char *devid;
-static struct usb_eth_dev usb_dev_id[] = {
-#define PEGASUS_DEV(pn, vid, pid, flags) \
- {.name = pn, .vendor = vid, .device = pid, .private = flags},
-#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
- PEGASUS_DEV(pn, vid, pid, flags)
-#include "pegasus.h"
-#undef PEGASUS_DEV
-#undef PEGASUS_DEV_CLASS
- {NULL, 0, 0, 0},
- {NULL, 0, 0, 0}
-};
+static struct usb_eth_dev dynamic_id_info = {};
static struct usb_device_id pegasus_ids[] = {
#define PEGASUS_DEV(pn, vid, pid, flags) \
- {.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid},
+ {.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid, \
+ .driver_info = (kernel_ulong_t)&(const struct usb_eth_dev) {.name = pn, .private = flags}},
/*
* The Belkin F8T012xx1 bluetooth adaptor has the same vendor and product
* IDs as the Belkin F5D5050, so we need to teach the pegasus driver to
@@ -66,7 +57,8 @@ static struct usb_device_id pegasus_ids[] = {
*/
#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
{.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS), \
- .idVendor = vid, .idProduct = pid, .bDeviceClass = dclass},
+ .idVendor = vid, .idProduct = pid, .bDeviceClass = dclass, \
+ .driver_info = (kernel_ulong_t)&(const struct usb_eth_dev) {.name = pn, .private = flags}},
#include "pegasus.h"
#undef PEGASUS_DEV
#undef PEGASUS_DEV_CLASS
@@ -402,12 +394,12 @@ static inline int reset_mac(pegasus_t *pegasus)
if (i == REG_TIMEOUT)
return -ETIMEDOUT;
- if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
- usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
+ if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS ||
+ le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_DLINK) {
set_register(pegasus, Gpio0, 0x24);
set_register(pegasus, Gpio0, 0x26);
}
- if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
+ if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_ELCON) {
__u16 auxmode;
ret = read_mii_word(pegasus, 3, 0x1b, &auxmode);
if (ret < 0)
@@ -445,9 +437,9 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
memcpy(pegasus->eth_regs, data, sizeof(data));
ret = set_registers(pegasus, EthCtrl0, 3, data);
- if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
- usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 ||
- usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
+ if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS ||
+ le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS2 ||
+ le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_DLINK) {
u16 auxmode;
ret = read_mii_word(pegasus, 0, 0x1b, &auxmode);
if (ret < 0)
@@ -1153,7 +1145,7 @@ static int pegasus_probe(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
struct net_device *net;
pegasus_t *pegasus;
- int dev_index = id - pegasus_ids;
+ const struct usb_eth_dev *info = (const struct usb_eth_dev *)id->driver_info;
int res = -ENOMEM;
static const u8 bulk_ep_addr[] = {
PEGASUS_USB_EP_BULK_IN | USB_DIR_IN,
@@ -1178,7 +1170,6 @@ static int pegasus_probe(struct usb_interface *intf,
goto out;
pegasus = netdev_priv(net);
- pegasus->dev_index = dev_index;
pegasus->intf = intf;
res = alloc_urbs(pegasus);
@@ -1206,7 +1197,7 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
- pegasus->features = usb_dev_id[dev_index].private;
+ pegasus->features = info ? info->private : DEFAULT_GPIO_RESET;
res = get_interrupt_interval(pegasus);
if (res)
goto out2;
@@ -1235,7 +1226,7 @@ static int pegasus_probe(struct usb_interface *intf,
queue_delayed_work(system_long_wq, &pegasus->carrier_check,
CARRIER_CHECK_DELAY);
dev_info(&intf->dev, "%s, %s, %pM\n", net->name,
- usb_dev_id[dev_index].name, net->dev_addr);
+ info ? info->name : "(unknown)", net->dev_addr);
return 0;
out3:
@@ -1325,8 +1316,9 @@ static struct usb_driver pegasus_driver = {
static void __init parse_id(char *id)
{
- unsigned int vendor_id = 0, device_id = 0, flags = 0, i = 0;
+ unsigned int vendor_id = 0, device_id = 0, flags = 0;
char *token, *name = NULL;
+ int dyn_id_index = ARRAY_SIZE(pegasus_ids) - 2;
token = strsep(&id, ":");
if (token)
@@ -1348,14 +1340,12 @@ static void __init parse_id(char *id)
if (device_id > 0x10000 || device_id == 0)
return;
- for (i = 0; usb_dev_id[i].name; i++);
- usb_dev_id[i].name = name;
- usb_dev_id[i].vendor = vendor_id;
- usb_dev_id[i].device = device_id;
- usb_dev_id[i].private = flags;
- pegasus_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- pegasus_ids[i].idVendor = vendor_id;
- pegasus_ids[i].idProduct = device_id;
+ dynamic_id_info.name = name;
+ dynamic_id_info.private = flags;
+ pegasus_ids[dyn_id_index].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+ pegasus_ids[dyn_id_index].idVendor = vendor_id;
+ pegasus_ids[dyn_id_index].idProduct = device_id;
+ pegasus_ids[dyn_id_index].driver_info = (kernel_ulong_t)&dynamic_id_info;
}
static int __init pegasus_init(void)
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h
index a05b143155ba..ccdedcef52e7 100644
--- a/drivers/net/usb/pegasus.h
+++ b/drivers/net/usb/pegasus.h
@@ -85,7 +85,6 @@ typedef struct pegasus {
unsigned features;
u32 msg_enable;
u32 wolopts;
- int dev_index;
int intr_interval;
struct tasklet_struct rx_tl;
struct delayed_work carrier_check;
@@ -102,8 +101,6 @@ typedef struct pegasus {
struct usb_eth_dev {
char *name;
- __u16 vendor;
- __u16 device;
__u32 private; /* LSB is gpio reset value */
};
--
2.54.0
^ permalink raw reply related
* [PATCH v2 6/7] usb: xusbatm: don't rely on id table pointer arithmetic
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Toke Høiland-Jørgensen, Johan Hovold,
Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Chas Williams, Alan Stern
Cc: linux-usb, driver-core, linux-wireless, linux-media,
linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>
The current code is broken when dynamic ID is involved; in such cases
usb_device_id parameter of probe lives on the heap and the pointer
arithmetic will get an index that is wildly out of bound. xusbatm
initialize the USB device IDs dynamically so it can just use driver_info
too.
Even with conversion, xusbatm still cannot support dynamic IDs, so also set
no_dynamic_id.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/usb/atm/xusbatm.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index 0befbf63d1cc..5c1e1f521555 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -79,7 +79,7 @@ static int xusbatm_bind(struct usbatm_data *usbatm,
struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
- int drv_ix = id - xusbatm_usb_ids;
+ int drv_ix = id->driver_info;
int rx_alt = rx_altsetting[drv_ix];
int tx_alt = tx_altsetting[drv_ix];
struct usb_interface *rx_intf = xusbatm_find_intf(usb_dev, rx_alt, rx_endpoint[drv_ix]);
@@ -168,7 +168,8 @@ static struct usb_driver xusbatm_usb_driver = {
.name = xusbatm_driver_name,
.probe = xusbatm_usb_probe,
.disconnect = usbatm_usb_disconnect,
- .id_table = xusbatm_usb_ids
+ .id_table = xusbatm_usb_ids,
+ .no_dynamic_id = 1,
};
static int __init xusbatm_init(void)
@@ -190,6 +191,7 @@ static int __init xusbatm_init(void)
xusbatm_usb_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
xusbatm_usb_ids[i].idVendor = vendor[i];
xusbatm_usb_ids[i].idProduct = product[i];
+ xusbatm_usb_ids[i].driver_info = i;
xusbatm_drivers[i].driver_name = xusbatm_driver_name;
xusbatm_drivers[i].bind = xusbatm_bind;
--
2.54.0
^ permalink raw reply related
* [PATCH v2 2/7] usb: usbtmc: don't store usb_device_id
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Toke Høiland-Jørgensen, Johan Hovold,
Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Chas Williams, Alan Stern
Cc: linux-usb, driver-core, linux-wireless, linux-media,
linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo,
Manuel Ebner
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>
usb_device_id is not guaranteed to live longer than probe due to presence
of dynamic ID. This stored ID is unused so remove it.
Reviewed-by: Manuel Ebner <manuelebner@mailbox.org>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/usb/class/usbtmc.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index af9ae55dae14..51cd9320a736 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -71,7 +71,6 @@ struct usbtmc_dev_capabilities {
* allocated for each USBTMC device in the driver's probe function.
*/
struct usbtmc_device_data {
- const struct usb_device_id *id;
struct usb_device *usb_dev;
struct usb_interface *intf;
struct list_head file_list;
@@ -2394,7 +2393,6 @@ static int usbtmc_probe(struct usb_interface *intf,
return -ENOMEM;
data->intf = intf;
- data->id = id;
data->usb_dev = usb_get_dev(interface_to_usbdev(intf));
usb_set_intfdata(intf, data);
kref_init(&data->kref);
--
2.54.0
^ permalink raw reply related
* [PATCH v2 7/7] usb: fix UAF when probe runs concurrent to dyn ID removal
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Toke Høiland-Jørgensen, Johan Hovold,
Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Chas Williams, Alan Stern
Cc: linux-usb, driver-core, linux-wireless, linux-media,
linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>
Dynamic IDs are only guaranteed to be valid when usb_dynids_lock is held,
as remove_id_store can free the node. Thus, make a copy in
usb_probe_interface. Clarify the documentation that the id parameter is
only valid during the probe.
USB serial has the same pattern, but it does not need fixing as the IDs
cannot be removed via sysfs.
Fixes: 0c7a2b72746a ("USB: add remove_id sysfs attr for usb drivers")
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/usb/core/driver.c | 12 ++++++++----
include/linux/usb.h | 3 ++-
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index f63004417058..7f33fe5ba03b 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -228,14 +228,16 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
}
static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
- const struct usb_driver *drv)
+ const struct usb_driver *drv,
+ struct usb_device_id *id_copy)
{
struct usb_dynid *dynid;
guard(mutex)(&usb_dynids_lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (usb_match_one_id(intf, &dynid->id)) {
- return &dynid->id;
+ *id_copy = dynid->id;
+ return id_copy;
}
}
return NULL;
@@ -321,6 +323,7 @@ static int usb_probe_interface(struct device *dev)
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
+ struct usb_device_id id_copy;
int error = -ENODEV;
int lpm_disable_error = -ENODEV;
@@ -340,7 +343,7 @@ static int usb_probe_interface(struct device *dev)
return error;
}
- id = usb_match_dynamic_id(intf, driver);
+ id = usb_match_dynamic_id(intf, driver, &id_copy);
if (!id)
id = usb_match_id(intf, driver->id_table);
if (!id)
@@ -892,6 +895,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
struct usb_interface *intf;
const struct usb_driver *usb_drv;
const struct usb_device_id *id;
+ struct usb_device_id id_copy;
/* device drivers never match interfaces */
if (is_usb_device_driver(drv))
@@ -904,7 +908,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
if (id)
return 1;
- id = usb_match_dynamic_id(intf, usb_drv);
+ id = usb_match_dynamic_id(intf, usb_drv, &id_copy);
if (id)
return 1;
}
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 1da4ad1610bc..49ab8dbb885f 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1185,7 +1185,8 @@ extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
* interface. It may also use usb_set_interface() to specify the
* appropriate altsetting. If unwilling to manage the interface,
* return -ENODEV, if genuine IO errors occurred, an appropriate
- * negative errno value.
+ * negative errno value. The usb_device_id parameter is only valid during
+ * probe.
* @disconnect: Called when the interface is no longer accessible, usually
* because its device has been (or is being) disconnected or the
* driver module is being unloaded.
--
2.54.0
^ permalink raw reply related
* [PATCH v2 3/7] usb: serial: spcp8x5: don't store usb_device_id
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Toke Høiland-Jørgensen, Johan Hovold,
Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Chas Williams, Alan Stern
Cc: linux-usb, driver-core, linux-wireless, linux-media,
linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo,
Manuel Ebner
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>
USB probe functions should not keep usb_device_id for longer than probe due
to presence of dynamic ID removal. USB serial does not support ID removal,
however in this case only driver_data is ever needed, there is no reason
keeping the usb_device_id in the first place, so convert it as well.
Reviewed-by: Manuel Ebner <manuelebner@mailbox.org>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/usb/serial/spcp8x5.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index c11d64bf08fb..0e7715a02df4 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -133,14 +133,14 @@ struct spcp8x5_private {
static int spcp8x5_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
- usb_set_serial_data(serial, (void *)id);
+ usb_set_serial_data(serial, (void *)id->driver_info);
return 0;
}
static int spcp8x5_port_probe(struct usb_serial_port *port)
{
- const struct usb_device_id *id = usb_get_serial_data(port->serial);
+ unsigned int quirks = (unsigned int)(unsigned long)usb_get_serial_data(port->serial);
struct spcp8x5_private *priv;
priv = kzalloc_obj(*priv);
@@ -148,7 +148,7 @@ static int spcp8x5_port_probe(struct usb_serial_port *port)
return -ENOMEM;
spin_lock_init(&priv->lock);
- priv->quirks = id->driver_info;
+ priv->quirks = quirks;
usb_set_serial_port_data(port, priv);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v1 net-next] net: phy: Drop #inclusion of <linux/mod_devicetable.h> from <linux/mdio.h>
From: Andrew Lunn @ 2026-07-07 12:10 UTC (permalink / raw)
To: Uwe Kleine-König (The Capable Hub)
Cc: Heiner Kallweit, Russell King, netdev, linux-kernel
In-Reply-To: <akynGw4TQimFiQST@monoceros>
On Tue, Jul 07, 2026 at 09:15:35AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> Hello Andrew,
>
> On Mon, Jul 06, 2026 at 11:28:33PM +0200, Andrew Lunn wrote:
> > > That's exactly my thought, and there is commit ad428f5811bd
> > > ("mod_devicetable.h: Split into per subsystem headers") that is part of
> > > v7.2-rc2 and that does exactly that (apart from the filename).
> >
> > Ah, O.K. net-next tends to great dragged along the -rcX versions. So
> > you can probably submit the networking changes in a weeks time. Just
> > make sure they apply to
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
>
> Note that while I created the patch under discussion on top of -rc2, the
> justification is also valid on -rc1 and the patch doesn't use the new
> headers, so it can be applied to the above repo already now.
Yes, our patchwork instance and its CI agree:
https://patchwork.kernel.org/project/netdevbpf/patch/ca270a534d0f230a939a3fb4a661808b35d6436d.1783329817.git.u.kleine-koenig@baylibre.com/
but i was actually meaning the patches which swaps to the broken out
header with only struct mdio_device_id. I assume that patch is the one
which really reduces the number of files which get recompiled on
unrelated changes. That patch can be submitted to netdev probably next
week.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* Re: [PATCH] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog
From: Andrew Lunn @ 2026-07-07 12:30 UTC (permalink / raw)
To: Daniel Thompson
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Alexandre Torgue,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev, Alex Elder, netdev,
linux-stm32, linux-arm-kernel, linux-kernel, bpf
In-Reply-To: <akzLgrzsw4xYmnLH@aspen.lan>
On Tue, Jul 07, 2026 at 10:48:50AM +0100, Daniel Thompson wrote:
> On Mon, Jul 06, 2026 at 05:17:58PM +0100, Daniel Thompson wrote:
> > Currently stmmac will run a full cycle of IRQ tear down and setup when
> > setting up a new XDP program. This makes tuning TSN systems difficult
> > because whenever a new XDP program is installed then the irq threads will
> > be stopped and restarted which will undo any thread tuning.
> >
> > The problem is avoided by removing stmmac_free_irq()/stmmac_request_irq()
> > from stmmac_xdp_release()/stmmac_xdp_open().
> >
> > stmmac_free_irq() implicitly synchronizes interrupts and, with that
> > removed, I was unable to prove that later actions in
> > stmmac_xdp_release() are safe when there are concurrent interrupts. To
> > avoid problems let's also move the code to disable DMA interrupts earlier
> > in the sequence and explicitly sync the interrupts handler(s).
> >
> > Signed-off-by: Daniel Thompson <daniel@riscstar.com>
> > <snip>
> > @@ -7156,10 +7201,8 @@ int stmmac_xdp_open(struct net_device *dev)
> > stmmac_reset_queues_param(priv);
> >
> > /* DMA CSR Channel configuration */
> > - for (chan = 0; chan < dma_csr_ch; chan++) {
> > + for (chan = 0; chan < dma_csr_ch; chan++)
> > stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan);
> > - stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
> > - }
>
> Sashiko picked up that stmmac_init_chan() has the effect of enabling DMA
> irqs, making this code unsafe.
>
> Given stmmac_xdp_open() can only be called on a running interface (and that
> stmmac_xdp_open() explicitly sets sph) then re-initializing with stmmac_init_chan()
> should have no effect and we can drop that as well.
Something i like to see is symmetry. In theory, stmmac_xdp_open() and
stmmac_xdp_release() should be mirrors of each other. But i don't see
anything like the opposite of stmmac_init_chan() in
stmmac_xdp_release(). So i can well understand that something is
wrong.
Maybe rather than just fixing this IRQ issue, you can look at both
functions and see about making them symmetric? I've no idea what that
actually entails, it could be a can of worms, which is not so uncommon
with stmmmac.
Andrew
^ permalink raw reply
* RE: [PATCH ethtool-next 1/2] sfpid: print all implemented options
From: Danielle Ratson @ 2026-07-07 12:33 UTC (permalink / raw)
To: Aleksander Jan Bajkowski, mkubecek@suse.cz, andrew@lunn.ch,
kuba@kernel.org, davem@davemloft.net, edumazet@google.com,
pabeni@redhat.com, netdev@vger.kernel.org
In-Reply-To: <20260705200637.2092534-1-olek2@wp.pl>
> -----Original Message-----
> From: Aleksander Jan Bajkowski <olek2@wp.pl>
> Sent: Sunday, 5 July 2026 23:06
> To: mkubecek@suse.cz; andrew@lunn.ch; Danielle Ratson
> <danieller@nvidia.com>; kuba@kernel.org; davem@davemloft.net;
> edumazet@google.com; pabeni@redhat.com; netdev@vger.kernel.org
> Cc: Aleksander Jan Bajkowski <olek2@wp.pl>
> Subject: [PATCH ethtool-next 1/2] sfpid: print all implemented options
>
> SFP modules implement multiple options. Before the “json” option was
> instroduced, all options were listed. Currently, only the last option is listed.
s/introduced/introduced
> This commit fixes this bug. Options are represented as array.
>
> Before:
> $ ethtool -m sfp-wan
> ...
> Option values : 0x00 0x32
> Option : RATE_SELECT implemented
> ...
> $ ethtool --json -m sfp-wan
> [ {
> ...
> "option_values": [ 0,50 ],
> "option": "RATE_SELECT implemented",
> ...
> } ]
>
> After:
> $ ethtool -m sfp-lan
> ...
> Option values : 0x00 0x32
> Option : RX_LOS implemented
> Option : TX_DISABLE implemented
> Option : RATE_SELECT implemented
> ...
> $ ethtool --json -m sfp-lan
> [ {
> ..
> "option_values": [ 0,50 ],
> "option": [ "RX_LOS implemented","TX_DISABLE
> implemented","RATE_SELECT implemented" ],
> } ]
> ..
>
> Fixes: 4071862f58d8 ("sfpid: Add JSON output handling to --module-info in
> SFF8079 modules")
> Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
> ---
> module-common.c | 8 ++++++++
> module-common.h | 1 +
> sfpid.c | 39 +++++++++++++++++++++++----------------
> 3 files changed, 32 insertions(+), 16 deletions(-)
>
> diff --git a/module-common.c b/module-common.c index 42fccf6..d736c7c
> 100644
> --- a/module-common.c
> +++ b/module-common.c
> @@ -258,6 +258,14 @@ void module_print_any_bool(const char *fn, char
> *given_json_fn, bool value,
> printf("\t%-41s : %s\n", fn, str_value); }
>
> +void module_print_array_string(const char *fn, const char *value) {
> + if (is_json_context())
> + print_string(PRINT_JSON, NULL, "%s", value);
> + else
> + printf("\t%-41s : %s\n", fn, value);
> +}
> +
The function name is a bit misleading, as no array is actually printed using this function only. Maybe "module_print_any_array_string_entry"?
It is a bit long but also align to the other functions and refers to the fact that the function is handling both json and fp contexts.
> void module_show_value_with_unit(const __u8 *id, unsigned int reg,
> const char *name, unsigned int mult,
> const char *unit)
> diff --git a/module-common.h b/module-common.h index 4063448..6f9da5f
> 100644
> --- a/module-common.h
> +++ b/module-common.h
> @@ -281,6 +281,7 @@ void module_print_any_string(const char *fn, const
> char *value); void module_print_any_float(const char *fn, float value, const
> char *unit); void module_print_any_bool(const char *fn, char
> *given_json_fn, bool value,
> const char *str_value);
> +void module_print_array_string(const char *fn, const char *value);
> void module_show_value_with_unit(const __u8 *id, unsigned int reg,
> const char *name, unsigned int mult,
> const char *unit);
> diff --git a/sfpid.c b/sfpid.c
> index 74a6f51..d6636ba 100644
> --- a/sfpid.c
> +++ b/sfpid.c
> @@ -396,7 +396,6 @@ static void
> sff8079_show_wavelength_or_copper_compliance(const __u8 *id) static
> void sff8079_show_options(const __u8 *id) {
> static const char *pfx = "Option";
> - char value[64] = "";
>
> if (is_json_context()) {
> open_json_array("option_values", ""); @@ -407,35 +406,43
> @@ static void sff8079_show_options(const __u8 *id)
> printf("\t%-41s : 0x%02x 0x%02x\n", "Option values", id[64],
> id[65]);
> }
> +
> + if (is_json_context())
> + open_json_array("option", "");
> +
> if (id[65] & (1 << 1))
> - sprintf(value, "%s", "RX_LOS implemented");
> + module_print_array_string(pfx, "RX_LOS implemented");
> if (id[65] & (1 << 2))
> - sprintf(value, "%s", "RX_LOS implemented, inverted");
> + module_print_array_string(pfx, "RX_LOS implemented,
> inverted");
> if (id[65] & (1 << 3))
> - sprintf(value, "%s", "TX_FAULT implemented");
> + module_print_array_string(pfx, "TX_FAULT implemented");
> if (id[65] & (1 << 4))
> - sprintf(value, "%s", "TX_DISABLE implemented");
> + module_print_array_string(pfx, "TX_DISABLE implemented");
> if (id[65] & (1 << 5))
> - sprintf(value, "%s", "RATE_SELECT implemented");
> + module_print_array_string(pfx, "RATE_SELECT
> implemented");
> if (id[65] & (1 << 6))
> - sprintf(value, "%s", "Tunable transmitter technology");
> + module_print_array_string(pfx,
> + "Tunable transmitter technology");
> if (id[65] & (1 << 7))
> - sprintf(value, "%s", "Receiver decision threshold
> implemented");
> + module_print_array_string(pfx,
> + "Receiver decision threshold implemented");
> if (id[64] & (1 << 0))
> - sprintf(value, "%s", "Linear receiver output implemented");
> + module_print_array_string(pfx,
> + "Linear receiver output implemented");
> if (id[64] & (1 << 1))
> - sprintf(value, "%s", "Power level 2 requirement");
> + module_print_array_string(pfx, "Power level 2 requirement");
> if (id[64] & (1 << 2))
> - sprintf(value, "%s", "Cooled transceiver implemented");
> + module_print_array_string(pfx,
> + "Cooled transceiver implemented");
> if (id[64] & (1 << 3))
> - sprintf(value, "%s", "Retimer or CDR implemented");
> + module_print_array_string(pfx, "Retimer or CDR
> implemented");
> if (id[64] & (1 << 4))
> - sprintf(value, "%s", "Paging implemented");
> + module_print_array_string(pfx, "Paging implemented");
> if (id[64] & (1 << 5))
> - sprintf(value, "%s", "Power level 3 requirement");
> + module_print_array_string(pfx, "Power level 3 requirement");
>
> - if (value[0] != '\0')
> - module_print_any_string(pfx, value);
> + if (is_json_context())
> + close_json_array("");
> }
>
> static void sff8079_show_all_common(const __u8 *id)
> --
> 2.53.0
^ permalink raw reply
* RE: [PATCH ethtool-next 2/2] sfpid: print all compliance codes
From: Danielle Ratson @ 2026-07-07 12:37 UTC (permalink / raw)
To: Aleksander Jan Bajkowski, mkubecek@suse.cz, andrew@lunn.ch,
kuba@kernel.org, davem@davemloft.net, edumazet@google.com,
pabeni@redhat.com, netdev@vger.kernel.org
In-Reply-To: <20260705200637.2092534-2-olek2@wp.pl>
> -----Original Message-----
> From: Aleksander Jan Bajkowski <olek2@wp.pl>
> Sent: Sunday, 5 July 2026 23:06
> To: mkubecek@suse.cz; andrew@lunn.ch; Danielle Ratson
> <danieller@nvidia.com>; kuba@kernel.org; davem@davemloft.net;
> edumazet@google.com; pabeni@redhat.com; netdev@vger.kernel.org
> Cc: Aleksander Jan Bajkowski <olek2@wp.pl>
> Subject: [PATCH ethtool-next 2/2] sfpid: print all compliance codes
>
> SFP modules implement multiple compliance codes. This is common for dual-
> rate modules. Before the `json` option was introduced, all compliance codes
> were displayed. Currently, only the last code is displayed. This commit fixes
> that bug. Compliance codes are represented as array.
>
> Before:
> $ ethtool -m sfp-lan
> ...
> Transceiver codes : 0x00 0x00 0x00 0x01 0x20 0x40 0x0c
> 0x15 0x00
> Transceiver type : FC: 100 MBytes/sec</pre>
</pre>? I think it is a leftover or something?
> ...
> $ ethtool --json -m sfp-wan
> [ {
> ...
> "transceiver_codes": [ 0,0,0,1,32,64,12,21,0 ],
> "transceiver_type": "FC: 100 MBytes/sec", ...
> } ]
>
> After:
> $ ethtool -m sfp-wan
> ...
> Transceiver codes : 0x00 0x00 0x00 0x01 0x20 0x40 0x0c
> 0x15 0x00
> Transceiver type : Ethernet: 1000BASE-SX
> Transceiver type : FC: intermediate distance (I)
> Transceiver type : FC: Shortwave laser w/o OFC (SN)
> Transceiver type : FC: Multimode, 62.5um (M6)
> Transceiver type : FC: Multimode, 50um (M5)
> Transceiver type : FC: 400 MBytes/sec
> Transceiver type : FC: 200 MBytes/sec
> Transceiver type : FC: 100 MBytes/sec
> ...
> $ ethtool --json -m sfp-wan
> [ {
I am a bit confused by the sfp-lan/sfp-wan examples naming. In the last patch the "Before" used "sfp-wan" and the "After" used "sfp-lan". This patch doesn’t follow the same convention. Maybe it is better to use the same module for both before and after.
> ...
> "transceiver_codes": [ 0,0,0,1,32,64,12,21,0 ],
> "transceiver_type": [ "Ethernet: 1000BASE-SX","FC: intermediate distance
> (I)","FC: Shortwave laser w/o OFC (SN)","FC: Multimode, 62.5um (M6)","FC:
> Multimode, 50um (M5)","FC: 400 MBytes/sec","FC: 200 MBytes/sec","FC:
> 100 MBytes/sec" ], ...
> } ]
>
> Fixes: 4071862f58d8 ("sfpid: Add JSON output handling to --module-info in
> SFF8079 modules")
> Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
> ---
Thanks for sending this fix!
^ permalink raw reply
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