Netdev List
 help / color / mirror / Atom feed
* BUG: bpf_iter_tcp can trigger inet_csk_listen_stop() WARN_ON(sock_owned_by_user(child))
@ 2026-08-07  9:57 Junseo Lim
  2026-08-07 21:43 ` Kuniyuki Iwashima
  0 siblings, 1 reply; 2+ messages in thread
From: Junseo Lim @ 2026-08-07  9:57 UTC (permalink / raw)
  To: Eric Dumazet, Neal Cardwell
  Cc: David S. Miller, Kuniyuki Iwashima, Alexei Starovoitov,
	Daniel Borkmann, netdev, bpf, Sechang Lim, Martin KaFai Lau

Hi,

inet_csk_listen_stop() removes a request from the accept queue, locks the
child socket with bh_lock_sock(), and then checks:

	while ((req = reqsk_queue_remove(queue, sk)) != NULL) {
		...
		WARN_ON(sock_owned_by_user(child));
    ...
  }

This assumes that no process context owns the child socket at this point.
However, once a connection is completed for the listener, the child
socket is also visible from the established hash table. 

In the normal connection-completion path, tcp_v4_syn_recv_sock() inserts
the child into ehash via inet_ehash_nolisten(), and
inet_csk_reqsk_queue_add() later stores the same child in req->sk on the
listener accept queue. bpf_iter_tcp can then take the child from ehash and
lock it in bpf_iter_tcp_seq_show().

This is different from the recent bpf_iter_tcp_established_batch
request_sock refcount issue
(https://lore.kernel.org/all/20260803112218.3361213-1-dingning04@gmail.com/).
In this case the socket is already a full child socket, so the iterator
can successfully take a reference and then acquire lock_sock() before the
listener teardown path reaches the child.

If acquiring lock_sock() in the BPF iterator is valid for this socket, 
then the WARN_ON() in inet_csk_listen_stop() may simply encode an invariant
that is no longer true. In that case, removing the WARN_ON() and 
documenting this case may be the right fix.
Otherwise, bpf_iter_tcp may need to skip full child sockets that are still
queued on the listener's accept queue.

I included a C reproducer, below.
  - tested in the bpf/master at 7a3c0289c3c8eb4607dff448ae9ff9f902c813af

This was found by a custom fuzzer developed 
by Sechang Lim <rhkrqnwk98@gmail.com>

Thanks,
Junseo Lim

---

[    5.970506] ------------[ cut here ]------------
[    5.970910] WARNING: net/ipv4/inet_connection_sock.c:1474 at inet_csk_listen_stop+0x85a/0xc10, CPU#0: bpf_iter_tcp_lo/90
[    5.971656] CPU: 0 UID: 0 PID: 90 Comm: bpf_iter_tcp_lo Not tainted 7.2.0-rc4-00484-g7a3c0289c3c8 #87 PREEMPT(full) 
[    5.972340] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014
[    5.972955] RIP: 0010:inet_csk_listen_stop+0x85a/0xc10
[    5.973309] Code: 00 00 00 e8 b8 d5 f1 fe e9 7a f9 ff ff e8 8e 70 15 fe 48 8b 3c 24 be 02 00 00 00 e8 a0 d5 f1 fe e9 62 f9 ff ff e8 76 70 15 fe <0f> 0b e9 04 f9 ff ff e8 6a 70 15 fe e8 d5 20 04 fe 84 c0 0f 85 f2
[    5.974547] RSP: 0018:ffffc900004dfc98 EFLAGS: 00010293
[    5.976344] RAX: 0000000000000000 RBX: ffff888107f21a00 RCX: ffffffff83724aca
[    5.976918] RDX: ffff88810613c400 RSI: ffffffff84c7aae2 RDI: ffff888107f21bc0
[    5.977416] RBP: ffff8881073fb3e0 R08: 0000000000000001 R09: 0000000000000001
[    5.977960] R10: 0000000000000000 R11: fffff5200009bf87 R12: 0000000000000000
[    5.978466] R13: 0000000000000001 R14: dffffc0000000000 R15: ffff8881073b0d00
[    5.979354] FS:  00000000005cd400(0000) GS:ffff888193fda000(0000) knlGS:0000000000000000
[    5.979921] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    5.980685] CR2: 00007ffd196dd820 CR3: 0000000105d33000 CR4: 0000000000750ef0
[    5.981356] PKRU: 55555554
[    5.981547] Call Trace:
[    5.981723]  <TASK>
[    5.981886]  ? __pfx_sock_close+0x10/0x10
[    5.982174]  __tcp_close+0xc04/0xfd0
[    5.982457]  ? __pfx_sock_close+0x10/0x10
[    5.982743]  ? srso_alias_return_thunk+0x5/0xfbef5
[    5.983079]  ? trace_hardirqs_on+0x18/0x1a0
[    5.983390]  ? __pfx_sock_close+0x10/0x10
[    5.983675]  tcp_close+0x31/0xf0
[    5.983915]  ? srso_alias_return_thunk+0x5/0xfbef5
[    5.984244]  inet_release+0x121/0x2b0
[    5.984510]  sock_close+0x96/0x250
[    5.984756]  ? srso_alias_return_thunk+0x5/0xfbef5
[    5.985090]  ? security_file_release+0x2b/0x70
[    5.985404]  ? srso_alias_return_thunk+0x5/0xfbef5
[    5.985735]  __fput+0x39f/0xa00
[    5.985973]  fput_close_sync+0xf6/0x210
[    5.986243]  ? __pfx_fput_close_sync+0x10/0x10
[    5.986587]  ? srso_alias_return_thunk+0x5/0xfbef5
[    5.986924]  __x64_sys_close+0x96/0x110
[    5.987214]  do_syscall_64+0xae/0x5e0
[    5.987475]  ? srso_alias_return_thunk+0x5/0xfbef5
[    5.987805]  ? exc_page_fault+0x85/0xa0
[    5.988086]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[    5.988433] RIP: 0033:0x4555ae
[    5.988652] Code: 4d 89 d8 e8 14 1f 00 00 4c 8b 5d f8 41 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 11 c9 c3 0f 1f 80 00 00 00 00 48 8b 45 10 0f 05 <c9> c3 83 e2 39 83 fa 08 75 e7 e8 03 ff ff ff 0f 1f 00 f3 0f 1e fa
[    5.989837] RSP: 002b:00007ffd196de830 EFLAGS: 00000202 ORIG_RAX: 0000000000000003
[    5.990585] RAX: ffffffffffffffda RBX: 0000000000000040 RCX: 00000000004555ae
[    5.991066] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000005
[    5.991552] RBP: 00007ffd196de840 R08: 0000000000000000 R09: 0000000000000000
[    5.992029] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000040
[    5.992496] R13: 0000000000000005 R14: 0000000000000004 R15: 0000000000000045
[    5.992981]  </TASK>
[    5.993145] Kernel panic - not syncing: kernel: panic_on_warn set ...
[    5.993593] CPU: 0 UID: 0 PID: 90 Comm: bpf_iter_tcp_lo Not tainted 7.2.0-rc4-00484-g7a3c0289c3c8 #87 PREEMPT(full) 
[    5.994318] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014
[    5.994976] Call Trace:
[    5.995158]  <TASK>
[    5.995315]  dump_stack_lvl+0xb0/0x110
[    5.995591]  vpanic+0x230/0x5b0
[    5.995824]  panic+0xd0/0xd0
[    5.996045]  ? __pfx_panic+0x10/0x10
[    5.996307]  ? check_panic_on_warn.cold+0x5/0x34
[    5.996630]  ? panic_on_this_cpu+0x1a/0x30
[    5.996920]  ? inet_csk_listen_stop+0x85a/0xc10
[    5.997236]  check_panic_on_warn.cold+0x19/0x34
[    5.997554]  __warn.cold+0x294/0x2d1
[    5.997814]  ? inet_csk_listen_stop+0x85a/0xc10
[    5.998135]  __report_bug+0x2bf/0x470
[    5.998417]  ? __pfx___report_bug+0x10/0x10
[    5.998716]  ? srso_alias_return_thunk+0x5/0xfbef5
[    5.999055]  ? mark_held_locks+0x40/0x70
[    5.999330]  ? srso_alias_return_thunk+0x5/0xfbef5
[    5.999660]  ? lockdep_hardirqs_on_prepare+0xdc/0x1d0
[    6.000016]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.000346]  ? trace_hardirqs_on+0x18/0x1a0
[    6.000639]  ? inet_csk_listen_stop+0x85a/0xc10
[    6.000958]  report_bug+0xab/0x220
[    6.001199]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.001526]  ? inet_csk_listen_stop+0x85c/0xc10
[    6.001843]  handle_bug+0x273/0x2d0
[    6.002097]  ? inet_csk_listen_stop+0x85a/0xc10
[    6.002444]  exc_invalid_op+0x1d/0x60
[    6.002703]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.003048]  asm_exc_invalid_op+0x1a/0x20
[    6.003327] RIP: 0010:inet_csk_listen_stop+0x85a/0xc10
[    6.003680] Code: 00 00 00 e8 b8 d5 f1 fe e9 7a f9 ff ff e8 8e 70 15 fe 48 8b 3c 24 be 02 00 00 00 e8 a0 d5 f1 fe e9 62 f9 ff ff e8 76 70 15 fe <0f> 0b e9 04 f9 ff ff e8 6a 70 15 fe e8 d5 20 04 fe 84 c0 0f 85 f2
[    6.004883] RSP: 0018:ffffc900004dfc98 EFLAGS: 00010293
[    6.005240] RAX: 0000000000000000 RBX: ffff888107f21a00 RCX: ffffffff83724aca
[    6.005710] RDX: ffff88810613c400 RSI: ffffffff84c7aae2 RDI: ffff888107f21bc0
[    6.006181] RBP: ffff8881073fb3e0 R08: 0000000000000001 R09: 0000000000000001
[    6.006733] R10: 0000000000000000 R11: fffff5200009bf87 R12: 0000000000000000
[    6.007784] R13: 0000000000000001 R14: dffffc0000000000 R15: ffff8881073b0d00
[    6.008799]  ? inet_csk_listen_stop+0x85a/0xc10
[    6.009123]  ? inet_csk_listen_stop+0x85a/0xc10
[    6.009443]  ? __pfx_sock_close+0x10/0x10
[    6.009726]  __tcp_close+0xc04/0xfd0
[    6.009985]  ? __pfx_sock_close+0x10/0x10
[    6.010283]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.010613]  ? trace_hardirqs_on+0x18/0x1a0
[    6.010907]  ? __pfx_sock_close+0x10/0x10
[    6.011192]  tcp_close+0x31/0xf0
[    6.011431]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.011769]  inet_release+0x121/0x2b0
[    6.012043]  sock_close+0x96/0x250
[    6.012292]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.012620]  ? security_file_release+0x2b/0x70
[    6.012934]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.013263]  __fput+0x39f/0xa00
[    6.013495]  fput_close_sync+0xf6/0x210
[    6.013767]  ? __pfx_fput_close_sync+0x10/0x10
[    6.014079]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.014424]  __x64_sys_close+0x96/0x110
[    6.014698]  do_syscall_64+0xae/0x5e0
[    6.014961]  ? srso_alias_return_thunk+0x5/0xfbef5
[    6.015291]  ? exc_page_fault+0x85/0xa0
[    6.015564]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[    6.015910] RIP: 0033:0x4555ae
[    6.016127] Code: 4d 89 d8 e8 14 1f 00 00 4c 8b 5d f8 41 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 11 c9 c3 0f 1f 80 00 00 00 00 48 8b 45 10 0f 05 <c9> c3 83 e2 39 83 fa 08 75 e7 e8 03 ff ff ff 0f 1f 00 f3 0f 1e fa
[    6.017315] RSP: 002b:00007ffd196de830 EFLAGS: 00000202 ORIG_RAX: 0000000000000003
[    6.017814] RAX: ffffffffffffffda RBX: 0000000000000040 RCX: 00000000004555ae
[    6.018294] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000005
[    6.018758] RBP: 00007ffd196de840 R08: 0000000000000000 R09: 0000000000000000
[    6.019227] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000040
[    6.019693] R13: 0000000000000005 R14: 0000000000000004 R15: 0000000000000045
[    6.020171]  </TASK>
[    6.020459] Kernel Offset: disabled
[    6.020715] ---[ end Kernel panic - not syncing: kernel: panic_on_warn set ... ]---

---

// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/bpf.h>
#include <linux/types.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#ifndef __NR_bpf
#define __NR_bpf 321
#endif

#ifndef BPF_LINK_CREATE
#define BPF_LINK_CREATE 28
#endif

#ifndef BPF_ITER_CREATE
#define BPF_ITER_CREATE 33
#endif

#ifndef BPF_PROG_TYPE_TRACING
#define BPF_PROG_TYPE_TRACING 26
#endif

#ifndef BPF_TRACE_ITER
#define BPF_TRACE_ITER 28
#endif

#ifndef BPF_OBJ_NAME_LEN
#define BPF_OBJ_NAME_LEN 16
#endif

#define DEFAULT_ROUNDS 20000
#define DEFAULT_CLIENTS 64
#define DEFAULT_WORKERS 1
#define DEFAULT_BURN_INSNS 65536
#define READ_BUF_SIZE 4096

#define BTF_MAGIC 0xeb9f
#define BTF_KIND_INT 1
#define BTF_KIND_PTR 2
#define BTF_KIND_ARRAY 3
#define BTF_KIND_STRUCT 4
#define BTF_KIND_UNION 5
#define BTF_KIND_ENUM 6
#define BTF_KIND_FWD 7
#define BTF_KIND_TYPEDEF 8
#define BTF_KIND_VOLATILE 9
#define BTF_KIND_CONST 10
#define BTF_KIND_RESTRICT 11
#define BTF_KIND_FUNC 12
#define BTF_KIND_FUNC_PROTO 13
#define BTF_KIND_VAR 14
#define BTF_KIND_DATASEC 15
#define BTF_KIND_FLOAT 16
#define BTF_KIND_DECL_TAG 17
#define BTF_KIND_TYPE_TAG 18
#define BTF_KIND_ENUM64 19

#define BPF_ALU64_IMM(OP, DST, IMM) \
	((struct bpf_insn){ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
			    .dst_reg = DST, .imm = IMM })
#define BPF_EXIT_INSN() \
	((struct bpf_insn){ .code = BPF_JMP | BPF_EXIT })

union bpf_attr_local {
	struct {
		uint32_t prog_type;
		uint32_t insn_cnt;
		uint64_t insns;
		uint64_t license;
		uint32_t log_level;
		uint32_t log_size;
		uint64_t log_buf;
		uint32_t kern_version;
		uint32_t prog_flags;
		char prog_name[BPF_OBJ_NAME_LEN];
		uint32_t prog_ifindex;
		uint32_t expected_attach_type;
		uint32_t prog_btf_fd;
		uint32_t func_info_rec_size;
		uint64_t func_info;
		uint32_t func_info_cnt;
		uint32_t line_info_rec_size;
		uint64_t line_info;
		uint32_t line_info_cnt;
		uint32_t attach_btf_id;
	} prog_load;
	struct {
		uint32_t prog_fd;
		uint32_t target_fd;
		uint32_t attach_type;
		uint32_t flags;
		uint64_t iter_info;
		uint32_t iter_info_len;
	} link_create;
	struct {
		uint32_t link_fd;
		uint32_t flags;
	} iter_create;
	uint8_t pad[256];
};

struct btf_header {
	uint16_t magic;
	uint8_t version;
	uint8_t flags;
	uint32_t hdr_len;
	uint32_t type_off;
	uint32_t type_len;
	uint32_t str_off;
	uint32_t str_len;
};

struct btf_type {
	uint32_t name_off;
	uint32_t info;
	union {
		uint32_t size;
		uint32_t type;
	};
};

static volatile int stop_workers;

static uint64_t ptr_to_u64(const void *ptr)
{
	return (uint64_t)(uintptr_t)ptr;
}

static long sys_bpf(int cmd, union bpf_attr_local *attr)
{
	return syscall(__NR_bpf, cmd, attr, sizeof(*attr));
}

static void *read_file(const char *path, size_t *size_out)
{
	size_t done = 0;
	off_t size;
	char *buf;
	int fd;

	fd = open(path, O_RDONLY);
	if (fd < 0) {
		perror(path);
		return NULL;
	}

	size = lseek(fd, 0, SEEK_END);
	if (size <= 0 || lseek(fd, 0, SEEK_SET) < 0) {
		perror("lseek");
		close(fd);
		return NULL;
	}

	buf = malloc((size_t)size);
	if (!buf) {
		perror("malloc");
		close(fd);
		return NULL;
	}

	while (done < (size_t)size) {
		ssize_t n = read(fd, buf + done, (size_t)size - done);

		if (n < 0) {
			if (errno == EINTR)
				continue;
			perror("read");
			free(buf);
			close(fd);
			return NULL;
		}
		if (n == 0)
			break;
		done += (size_t)n;
	}

	close(fd);
	*size_out = done;
	return buf;
}

static uint32_t btf_kind(uint32_t info)
{
	return (info >> 24) & 0x1f;
}

static uint32_t btf_vlen(uint32_t info)
{
	return info & 0xffff;
}

static size_t btf_extra_size(const struct btf_type *t)
{
	uint32_t kind = btf_kind(t->info);
	uint32_t vlen = btf_vlen(t->info);

	switch (kind) {
	case BTF_KIND_INT:
	case BTF_KIND_VAR:
	case BTF_KIND_DECL_TAG:
		return 4;
	case BTF_KIND_ARRAY:
		return 12;
	case BTF_KIND_STRUCT:
	case BTF_KIND_UNION:
		return (size_t)vlen * 12;
	case BTF_KIND_ENUM:
	case BTF_KIND_FUNC_PROTO:
		return (size_t)vlen * 8;
	case BTF_KIND_DATASEC:
	case BTF_KIND_ENUM64:
		return (size_t)vlen * 12;
	case BTF_KIND_PTR:
	case BTF_KIND_FWD:
	case BTF_KIND_TYPEDEF:
	case BTF_KIND_VOLATILE:
	case BTF_KIND_CONST:
	case BTF_KIND_RESTRICT:
	case BTF_KIND_FUNC:
	case BTF_KIND_FLOAT:
	case BTF_KIND_TYPE_TAG:
		return 0;
	default:
		fprintf(stderr, "unknown BTF kind %u\n", kind);
		exit(1);
	}
}

static int find_btf_func_id(const char *name)
{
	const struct btf_header *hdr;
	const uint8_t *types, *types_end;
	const char *strs;
	size_t btf_size;
	void *btf;
	uint32_t id = 1;

	btf = read_file("/sys/kernel/btf/vmlinux", &btf_size);
	if (!btf)
		return -1;
	if (btf_size < sizeof(*hdr)) {
		fprintf(stderr, "short BTF header\n");
		free(btf);
		return -1;
	}

	hdr = btf;
	if (hdr->magic != BTF_MAGIC) {
		fprintf(stderr, "unexpected BTF magic 0x%x\n", hdr->magic);
		free(btf);
		return -1;
	}
	if ((size_t)hdr->hdr_len + hdr->type_off + hdr->type_len > btf_size ||
	    (size_t)hdr->hdr_len + hdr->str_off + hdr->str_len > btf_size) {
		fprintf(stderr, "invalid BTF section bounds\n");
		free(btf);
		return -1;
	}

	types = (const uint8_t *)btf + hdr->hdr_len + hdr->type_off;
	types_end = types + hdr->type_len;
	strs = (const char *)btf + hdr->hdr_len + hdr->str_off;

	while (types + sizeof(struct btf_type) <= types_end) {
		const struct btf_type *t = (const struct btf_type *)types;
		size_t rec_size = sizeof(*t) + btf_extra_size(t);

		if (types + rec_size > types_end) {
			fprintf(stderr, "truncated BTF type section\n");
			free(btf);
			return -1;
		}

		if (btf_kind(t->info) == BTF_KIND_FUNC &&
		    t->name_off < hdr->str_len &&
		    strcmp(strs + t->name_off, name) == 0) {
			free(btf);
			return (int)id;
		}

		types += rec_size;
		id++;
	}

	fprintf(stderr, "BTF FUNC %s not found\n", name);
	free(btf);
	return -1;
}

static int load_tcp_iter_prog(uint32_t attach_btf_id, int burn_insns)
{
	static char log_buf[1 << 20];
	static char license[] = "GPL";
	union bpf_attr_local attr;
	struct bpf_insn *insns;
	int insn_cnt;
	int saved_errno;
	int fd;
	int i;

	if (burn_insns < 0)
		burn_insns = 0;

	insn_cnt = burn_insns + 3;
	insns = calloc((size_t)insn_cnt, sizeof(*insns));
	if (!insns) {
		perror("calloc(insns)");
		return -1;
	}

	insns[0] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0);
	for (i = 1; i <= burn_insns; i++)
		insns[i] = BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1);
	insns[insn_cnt - 2] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0);
	insns[insn_cnt - 1] = BPF_EXIT_INSN();

	memset(&attr, 0, sizeof(attr));
	attr.prog_load.prog_type = BPF_PROG_TYPE_TRACING;
	attr.prog_load.insn_cnt = (uint32_t)insn_cnt;
	attr.prog_load.insns = ptr_to_u64(insns);
	attr.prog_load.license = ptr_to_u64(license);
	attr.prog_load.expected_attach_type = BPF_TRACE_ITER;
	attr.prog_load.attach_btf_id = attach_btf_id;
	memcpy(attr.prog_load.prog_name, "tcpit_burn", sizeof("tcpit_burn"));

	fd = (int)sys_bpf(BPF_PROG_LOAD, &attr);
	if (fd >= 0) {
		free(insns);
		return fd;
	}

	saved_errno = errno;
	if (saved_errno == ENOSPC) {
		fprintf(stderr,
			"BPF_PROG_LOAD without verifier log failed with ENOSPC; "
			"try a smaller burn_insns value\n");
		free(insns);
		errno = saved_errno;
		return -1;
	}

	attr.prog_load.log_level = 1;
	attr.prog_load.log_size = sizeof(log_buf);
	attr.prog_load.log_buf = ptr_to_u64(log_buf);

	fd = (int)sys_bpf(BPF_PROG_LOAD, &attr);
	if (fd < 0) {
		perror("BPF_PROG_LOAD(iter/tcp)");
		if (log_buf[0])
			fprintf(stderr, "verifier log:\n%s\n", log_buf);
	}

	free(insns);
	return fd;
}

static int create_iter_link(int prog_fd)
{
	union bpf_attr_local attr;
	int link_fd;

	memset(&attr, 0, sizeof(attr));
	attr.link_create.prog_fd = (uint32_t)prog_fd;
	attr.link_create.target_fd = 0;
	attr.link_create.attach_type = BPF_TRACE_ITER;
	attr.link_create.flags = 0;
	attr.link_create.iter_info = 0;
	attr.link_create.iter_info_len = 0;

	link_fd = (int)sys_bpf(BPF_LINK_CREATE, &attr);
	if (link_fd < 0)
		perror("BPF_LINK_CREATE(iter/tcp)");
	return link_fd;
}

static int create_iter_fd(int link_fd)
{
	union bpf_attr_local attr;
	int iter_fd;

	memset(&attr, 0, sizeof(attr));
	attr.iter_create.link_fd = (uint32_t)link_fd;
	attr.iter_create.flags = 0;

	iter_fd = (int)sys_bpf(BPF_ITER_CREATE, &attr);
	return iter_fd;
}

static void iter_worker(int link_fd)
{
	char buf[READ_BUF_SIZE];

	while (!stop_workers) {
		int iter_fd = create_iter_fd(link_fd);

		if (iter_fd < 0)
			continue;

		for (;;) {
			ssize_t n = read(iter_fd, buf, sizeof(buf));

			if (n <= 0)
				break;
		}
		close(iter_fd);
	}
	_exit(0);
}

static int make_listener(uint16_t *port_out)
{
	struct sockaddr_in addr;
	socklen_t len = sizeof(addr);
	int one = 1;
	int fd;

	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fd < 0)
		return -1;

	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
	setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	addr.sin_port = 0;

	if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
		goto fail;
	if (listen(fd, 256) < 0)
		goto fail;
	if (getsockname(fd, (struct sockaddr *)&addr, &len) < 0)
		goto fail;

	*port_out = ntohs(addr.sin_port);
	return fd;

fail:
	close(fd);
	return -1;
}

static int connect_client(uint16_t port)
{
	struct sockaddr_in addr;
	int fd;

	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fd < 0)
		return -1;

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	addr.sin_port = htons(port);

	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		close(fd);
		return -1;
	}

	return fd;
}

static int fill_accept_queue(uint16_t port, int *clients, int max_clients)
{
	int i, n = 0;

	for (i = 0; i < max_clients; i++) {
		int fd = connect_client(port);

		if (fd < 0)
			break;
		clients[n++] = fd;
	}

	return n;
}

static void close_clients(int *clients, int n)
{
	int i;

	for (i = 0; i < n; i++)
		if (clients[i] >= 0)
			close(clients[i]);
}

static int run_round(int clients_per_round)
{
	int *clients;
	uint16_t port;
	int listener;
	int n;

	clients = calloc((size_t)clients_per_round, sizeof(*clients));
	if (!clients)
		return -1;

	listener = make_listener(&port);
	if (listener < 0) {
		free(clients);
		return -1;
	}

	n = fill_accept_queue(port, clients, clients_per_round);
	usleep(100);
	close(listener);
	close_clients(clients, n);
	free(clients);
	return n > 0 ? 0 : -1;
}

int main(int argc, char **argv)
{
	int rounds = DEFAULT_ROUNDS;
	int clients = DEFAULT_CLIENTS;
	int workers = DEFAULT_WORKERS;
	int burn_insns = DEFAULT_BURN_INSNS;
	pid_t *pids;
	int attach_btf_id;
	int prog_fd;
	int link_fd;
	int i;

	printf("[repro] rounds=%d clients=%d workers=%d burn_insns=%d\n",
	       rounds, clients, workers, burn_insns);
	
    attach_btf_id = find_btf_func_id("bpf_iter_tcp");
	if (attach_btf_id < 0)
		return 1;
	printf("[repro] bpf_iter_tcp attach_btf_id=%d\n", attach_btf_id);

	prog_fd = load_tcp_iter_prog((uint32_t)attach_btf_id, burn_insns);
	if (prog_fd < 0)
		return 1;

	link_fd = create_iter_link(prog_fd);
	if (link_fd < 0)
		return 1;

	pids = calloc((size_t)workers, sizeof(*pids));
	if (!pids)
		return 1;

	for (i = 0; i < workers; i++) {
		pids[i] = fork();
		if (pids[i] == 0)
			iter_worker(link_fd);
	}

	for (i = 0; i < rounds; i++) {
		run_round(clients);
		if ((i & 0xff) == 0)
			fprintf(stderr, "[repro] round %d/%d\n", i, rounds);
	}

	stop_workers = 1;
	for (i = 0; i < workers; i++) {
		if (pids[i] > 0) {
			kill(pids[i], SIGTERM);
			waitpid(pids[i], NULL, 0);
		}
	}

	free(pids);
	close(link_fd);
	close(prog_fd);
	return 0;
}

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

end of thread, other threads:[~2026-08-07 21:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-07  9:57 BUG: bpf_iter_tcp can trigger inet_csk_listen_stop() WARN_ON(sock_owned_by_user(child)) Junseo Lim
2026-08-07 21:43 ` Kuniyuki Iwashima

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