Netdev List
 help / color / mirror / Atom feed
From: Jakub Sitnicki <jakub@cloudflare.com>
To: Alexei Starovoitov <ast@kernel.org>,
	 Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	 Eduard Zingerman <eddyz87@gmail.com>,
	 Kumar Kartikeya Dwivedi <memxor@gmail.com>,
	 Martin KaFai Lau <martin.lau@linux.dev>,
	Song Liu <song@kernel.org>,
	 Yonghong Song <yonghong.song@linux.dev>,
	Jiri Olsa <jolsa@kernel.org>,
	 Emil Tsalapatis <emil@etsalapatis.com>,
	 Ihor Solodrai <ihor.solodrai@linux.dev>,
	Shuah Khan <shuah@kernel.org>,
	 Eric Dumazet <edumazet@kernel.org>,
	Kuniyuki Iwashima <kuniyu@google.com>,
	 Paolo Abeni <pabeni@redhat.com>,
	Willem de Bruijn <willemb@google.com>,
	 John Fastabend <john.fastabend@gmail.com>,
	 Jiayuan Chen <jiayuan.chen@linux.dev>,
	 "David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	 Simon Horman <horms@kernel.org>
Cc: bpf@vger.kernel.org, netdev@vger.kernel.org, kernel-team@cloudflare.com
Subject: [PATCH bpf-next 1/2] selftests/bpf: Cover concurrent sockmap update and delete
Date: Fri, 30 Oct 2026 13:01:53 +0100	[thread overview]
Message-ID: <20261030-bpf-next-v1-1-035eabf8eae7@cloudflare.com> (raw)
In-Reply-To: <20261030-bpf-next-v1-0-035eabf8eae7@cloudflare.com>

Add a sockmap_listen subtest where one thread keeps inserting a TCP
socket into a sockmap with an attached verdict program while another
thread deletes the same map entry.

Without any synchronization between the insert and delete paths, both
end up racing on psock teardown and the socket's proto callbacks,
which KCSAN reports as:

    ==================================================================
    BUG: KCSAN: data-race in sock_map_link / tcp_bpf_update_proto

    write (marked) to 0xffff88810b1f42a8 of 8 bytes by task 198 on cpu 0:
     tcp_bpf_update_proto+0x278/0x400
     sock_map_unref+0x1d3/0x240
     sock_map_delete_elem+0x7b/0xb0
     map_delete_elem+0x1e1/0x270
     __sys_bpf+0x71a/0x870
     __x64_sys_bpf+0x69/0x80
     x64_sys_call+0xf26/0x2550
     do_syscall_64+0xb8/0x2f0
     entry_SYSCALL_64_after_hwframe+0x76/0x7e

    read to 0xffff88810b1f42a8 of 8 bytes by task 194 on cpu 3:
     sock_map_link+0x146/0x5b0
     sock_map_update_common+0x74/0x2b0
     sock_map_update_elem_sys+0x246/0x2d0
     bpf_map_update_value+0x80/0x400
     map_update_elem+0x35c/0x3e0
     __sys_bpf+0x540/0x870
     __x64_sys_bpf+0x69/0x80
     x64_sys_call+0xf26/0x2550
     do_syscall_64+0xb8/0x2f0
     entry_SYSCALL_64_after_hwframe+0x76/0x7e

    value changed: 0xffffffff857540c0 -> 0xffffffff8468fde8

    Reported by Kernel Concurrency Sanitizer on:
    CPU: 3 UID: 0 PID: 194 Comm: test_progs Tainted: G           OE        7.3.0+ #12 PREEMPT(full)
    Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
    ==================================================================

Deleting an entry that is already gone is expected: sockmap reports
EINVAL and sockhash reports ENOENT. Re-inserting a socket whose psock
still holds the verdict program from a concurrent delete fails with
EBUSY. Tolerate these errnos; the test relies on KCSAN as the witness.

Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
---
 .../selftests/bpf/prog_tests/sockmap_listen.c      | 77 ++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
index 235e1d56f044..dca1f0de92e0 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
@@ -646,6 +646,82 @@ static void test_race_insert_listen(struct test_sockmap_listen *skel __always_un
 	xclose(s);
 }
 
+struct update_delete_ctx {
+	unsigned int nr_iter;
+	unsigned int done;
+	int mapfd;
+};
+
+static void *delete_elem_thread(void *arg)
+{
+	struct update_delete_ctx *ctx = arg;
+	unsigned int i;
+
+	for (i = 0; i < ctx->nr_iter; i++) {
+		/* Expecting EINVAL (sockmap) or ENOENT (sockhash) when the
+		 * entry is already gone.
+		 */
+		if (bpf_map_delete_elem(ctx->mapfd, &(u32){0}) &&
+		    errno != EINVAL && errno != ENOENT) {
+			FAIL_ERRNO("map_delete");
+			break;
+		}
+	}
+
+	WRITE_ONCE(ctx->done, 1);
+	return NULL;
+}
+
+/* One thread keeps inserting a socket into a sockmap with an attached
+ * verdict program while another thread deletes the same map entry.
+ */
+static void test_update_delete_with_prog(struct test_sockmap_listen *skel,
+					 int family, int sotype, int mapfd)
+{
+	struct update_delete_ctx ctx = { 0 };
+	int err, s, verdict;
+	pthread_t t;
+	u64 value;
+
+	verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
+	err = xbpf_prog_attach(verdict, mapfd, BPF_SK_SKB_VERDICT, 0);
+	if (err)
+		return;
+
+	s = xsocket(family, sotype, 0);
+	if (s < 0)
+		goto detach;
+
+	err = xlisten(s, 1);
+	if (err)
+		goto close;
+
+	ctx.mapfd = mapfd;
+	ctx.nr_iter = 10000;
+
+	err = xpthread_create(&t, NULL, delete_elem_thread, &ctx);
+	if (err)
+		goto close;
+
+	value = s;
+	while (!READ_ONCE(ctx.done)) {
+		/* Expecting EBUSY while a deleted socket's psock still
+		 * holds the verdict program.
+		 */
+		err = bpf_map_update_elem(mapfd, &(u32){0}, &value, BPF_ANY);
+		if (err && errno != EBUSY) {
+			FAIL_ERRNO("map_update");
+			break;
+		}
+	}
+
+	xpthread_join(t, NULL);
+close:
+	xclose(s);
+detach:
+	xbpf_prog_detach2(verdict, mapfd, BPF_SK_SKB_VERDICT);
+}
+
 static void zero_verdict_count(int mapfd)
 {
 	unsigned int zero = 0;
@@ -1289,6 +1365,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
 		TEST(test_destroy_orphan_child, SOCK_STREAM),
 		TEST(test_syn_recv_insert_delete, SOCK_STREAM),
 		TEST(test_race_insert_listen, SOCK_STREAM),
+		TEST(test_update_delete_with_prog, SOCK_STREAM),
 		/* child clone */
 		TEST(test_clone_after_delete, SOCK_STREAM),
 		TEST(test_accept_after_delete, SOCK_STREAM),

-- 
2.43.0


  reply	other threads:[~2026-10-30 12:02 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-30 12:01 [PATCH bpf-next 0/2] Fix psock update-side data races on sk->sk_prot and progs Jakub Sitnicki
2026-10-30 12:01 ` Jakub Sitnicki [this message]
2026-10-30 12:01 ` [PATCH bpf-next 2/2] bpf, sockmap: " Jakub Sitnicki
2026-10-30 12:45   ` bot+bpf-ci

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=20261030-bpf-next-v1-1-035eabf8eae7@cloudflare.com \
    --to=jakub@cloudflare.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=eddyz87@gmail.com \
    --cc=edumazet@kernel.org \
    --cc=emil@etsalapatis.com \
    --cc=horms@kernel.org \
    --cc=ihor.solodrai@linux.dev \
    --cc=jiayuan.chen@linux.dev \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kernel-team@cloudflare.com \
    --cc=kuba@kernel.org \
    --cc=kuniyu@google.com \
    --cc=martin.lau@linux.dev \
    --cc=memxor@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=shuah@kernel.org \
    --cc=song@kernel.org \
    --cc=willemb@google.com \
    --cc=yonghong.song@linux.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox