]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/bpf: Add test for bpf_sock_read_xattr() kfunc
authorChristian Brauner <brauner@kernel.org>
Wed, 17 Jun 2026 11:18:28 +0000 (13:18 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 29 Jun 2026 08:31:14 +0000 (10:31 +0200)
Add a selftest that loads the kfunc in sleepable and non-sleepable
lsm/socket_connect programs and checks that a value set via fsetxattr()
on a socket is read back.

Link: https://patch.msgid.link/20260617-work-bpf-sock-xattr-v1-2-a1276f7c9da3@kernel.org
Reviewed-by: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
tools/testing/selftests/bpf/bpf_experimental.h
tools/testing/selftests/bpf/prog_tests/sock_xattr.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/sock_read_xattr.c [new file with mode: 0644]

index 67ff7882299ec5cd16147dc0299aa9495646e789..63e4e472fe36eed4360b2dc1bf68a74fc810870d 100644 (file)
@@ -364,6 +364,9 @@ extern void bpf_iter_dmabuf_destroy(struct bpf_iter_dmabuf *it) __weak __ksym;
 extern int bpf_cgroup_read_xattr(struct cgroup *cgroup, const char *name__str,
                                 struct bpf_dynptr *value_p) __weak __ksym;
 
+extern int bpf_sock_read_xattr(struct socket *sock, const char *name__str,
+                              struct bpf_dynptr *value_p) __weak __ksym;
+
 #define PREEMPT_BITS   8
 #define SOFTIRQ_BITS   8
 #define HARDIRQ_BITS   4
diff --git a/tools/testing/selftests/bpf/prog_tests/sock_xattr.c b/tools/testing/selftests/bpf/prog_tests/sock_xattr.c
new file mode 100644 (file)
index 0000000..b5816e9
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2026 Christian Brauner */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/xattr.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <test_progs.h>
+
+#include "sock_read_xattr.skel.h"
+
+static const char xattr_value[] = "bpf_sock_value";
+static const char xattr_name[] = "user.bpf_test";
+
+static void test_read_sock_xattr(void)
+{
+       struct sockaddr_in addr = {};
+       struct sock_read_xattr *skel = NULL;
+       struct bpf_link *link = NULL;
+       int sock_fd = -1, err;
+
+       sock_fd = socket(AF_INET, SOCK_STREAM, 0);
+       if (!ASSERT_OK_FD(sock_fd, "socket"))
+               return;
+
+       err = fsetxattr(sock_fd, xattr_name, xattr_value, sizeof(xattr_value), 0);
+       if (!ASSERT_OK(err, "fsetxattr"))
+               goto out;
+
+       skel = sock_read_xattr__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "sock_read_xattr__open_and_load"))
+               goto out;
+
+       skel->bss->monitored_pid = sys_gettid();
+
+       /* Only attach the functional program; the verifier-only programs
+        * above are not pid-gated and would clobber the shared globals.
+        */
+       link = bpf_program__attach(skel->progs.read_sock_xattr);
+       if (!ASSERT_OK_PTR(link, "attach read_sock_xattr"))
+               goto out;
+
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(1234);
+       addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       /* Only the lsm/socket_connect hook matters; the connect may fail. */
+       connect(sock_fd, (struct sockaddr *)&addr, sizeof(addr));
+
+       ASSERT_EQ(skel->data->read_ret, sizeof(xattr_value), "read_ret");
+       ASSERT_STREQ(skel->bss->value, xattr_value, "value");
+
+out:
+       bpf_link__destroy(link);
+       if (sock_fd >= 0)
+               close(sock_fd);
+       sock_read_xattr__destroy(skel);
+}
+
+void test_sock_xattr(void)
+{
+       RUN_TESTS(sock_read_xattr);
+
+       if (test__start_subtest("read_sock_xattr"))
+               test_read_sock_xattr();
+}
diff --git a/tools/testing/selftests/bpf/progs/sock_read_xattr.c b/tools/testing/selftests/bpf/progs/sock_read_xattr.c
new file mode 100644 (file)
index 0000000..c4a8eae
--- /dev/null
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Christian Brauner */
+
+#include <vmlinux.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+#include "bpf_experimental.h"
+#include "bpf_misc.h"
+
+char _license[] SEC("license") = "GPL";
+
+char value[16];
+int read_ret = -1;
+__u32 monitored_pid = 0;
+
+static __always_inline void read_xattr(struct socket *sock)
+{
+       struct bpf_dynptr value_ptr;
+
+       bpf_dynptr_from_mem(value, sizeof(value), 0, &value_ptr);
+       bpf_sock_read_xattr(sock, "user.bpf_test", &value_ptr);
+}
+
+SEC("lsm.s/socket_connect")
+__success
+int BPF_PROG(trusted_sock_ptr_sleepable, struct socket *sock)
+{
+       read_xattr(sock);
+       return 0;
+}
+
+SEC("lsm/socket_connect")
+__success
+int BPF_PROG(trusted_sock_ptr_non_sleepable, struct socket *sock)
+{
+       read_xattr(sock);
+       return 0;
+}
+
+SEC("lsm.s/socket_connect")
+__success
+int BPF_PROG(read_sock_xattr, struct socket *sock)
+{
+       struct bpf_dynptr value_ptr;
+       __u32 pid = bpf_get_current_pid_tgid() >> 32;
+
+       if (pid != monitored_pid)
+               return 0;
+
+       bpf_dynptr_from_mem(value, sizeof(value), 0, &value_ptr);
+       read_ret = bpf_sock_read_xattr(sock, "user.bpf_test", &value_ptr);
+       return 0;
+}