--- /dev/null
+// 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();
+}
--- /dev/null
+// 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;
+}