diff mbox series

[bpf-next,v3,9/9] selftests/bpf: Add tests for cgroup unix socket address hooks

Message ID 20230829101838.851350-10-daan.j.demeyer@gmail.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series Add cgroup sockaddr hooks for unix sockets | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-0 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-5 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-1 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 fail Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 fail Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 fail Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-6 fail Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-24 fail Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 fail Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 fail Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-28 fail Logs for veristat
bpf/vmtest-bpf-next-VM_Test-10 fail Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-12 fail Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 fail Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-14 fail Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-16 fail Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 fail Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-11 fail Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-7 fail Logs for test_maps on s390x with gcc
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 9 this patch: 9
netdev/cc_maintainers warning 13 maintainers not CCed: daniel@iogearbox.net kpsingh@kernel.org john.fastabend@gmail.com song@kernel.org sdf@google.com andrii@kernel.org yonghong.song@linux.dev shuah@kernel.org mykolal@fb.com linux-kselftest@vger.kernel.org jolsa@kernel.org haoluo@google.com ast@kernel.org
netdev/build_clang success Errors and warnings before: 9 this patch: 9
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 9 this patch: 9
netdev/checkpatch warning CHECK: Lines should not end with a '(' CHECK: No space is necessary after a cast CHECK: extern prototypes should be avoided in .h files CHECK: multiple assignments should be avoided WARNING: Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88 WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? WARNING: line length of 100 exceeds 80 columns WARNING: line length of 81 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns WARNING: line length of 91 exceeds 80 columns WARNING: line length of 93 exceeds 80 columns WARNING: line length of 96 exceeds 80 columns WARNING: line length of 99 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 1 this patch: 1
netdev/source_inline success Was 0 now: 0

Commit Message

Daan De Meyer Aug. 29, 2023, 10:18 a.m. UTC
These selftests are written in prog_tests style instead of adding
them to the existing test_sock_addr tests. Migrating the existing
sock addr tests to prog_tests style is left for future work.

Signed-off-by: Daan De Meyer <daan.j.demeyer@gmail.com>
---
 tools/testing/selftests/bpf/bpf_kfuncs.h      |  13 +
 tools/testing/selftests/bpf/network_helpers.c |  34 ++
 tools/testing/selftests/bpf/network_helpers.h |   1 +
 .../selftests/bpf/prog_tests/section_names.c  |  30 ++
 .../selftests/bpf/prog_tests/sock_addr.c      | 313 ++++++++++++++++++
 .../testing/selftests/bpf/progs/bindun_prog.c |  25 ++
 .../selftests/bpf/progs/connectun_prog.c      |  26 ++
 .../selftests/bpf/progs/recvmsgun_prog.c      |  25 ++
 .../selftests/bpf/progs/sendmsgun_prog.c      |  26 ++
 9 files changed, 493 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_addr.c
 create mode 100644 tools/testing/selftests/bpf/progs/bindun_prog.c
 create mode 100644 tools/testing/selftests/bpf/progs/connectun_prog.c
 create mode 100644 tools/testing/selftests/bpf/progs/recvmsgun_prog.c
 create mode 100644 tools/testing/selftests/bpf/progs/sendmsgun_prog.c

Comments

Martin KaFai Lau Aug. 30, 2023, 6:51 a.m. UTC | #1
On 8/29/23 3:18 AM, Daan De Meyer wrote:
> +void test_bind(int cgroup_fd)
static

> +{
> +	struct bindun_prog *skel;
> +	struct sockaddr_storage expected_addr;
> +	socklen_t expected_addr_len = sizeof(struct sockaddr_storage);
> +	int serv = -1, client = -1, err;
> +
> +	skel = bindun_prog__open_and_load();
> +	if (!ASSERT_OK_PTR(skel, "skel_open"))
> +		return;
> +
> +	skel->links.bindun_prog = bpf_program__attach_cgroup(
> +		skel->progs.bindun_prog, cgroup_fd);
> +	if (!ASSERT_OK_PTR(skel->links.bindun_prog, "prog_attach"))
> +		goto cleanup;
> +
> +	serv = start_server(AF_UNIX, SOCK_STREAM, SERVUN_ADDRESS, 0, 0);
> +	if (!ASSERT_GE(serv, 0, "start_server"))
> +		goto cleanup;
> +
> +	err = make_sockaddr(AF_UNIX, SERVUN_REWRITE_ADDRESS, 0, &expected_addr, &expected_addr_len);
> +	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
> +		goto cleanup;
> +
> +	err = cmp_local_addr(serv, &expected_addr, expected_addr_len);
> +	if (!ASSERT_EQ(err, 0, "cmp_local_addr"))
> +		goto cleanup;
> +
> +	/* Try to connect to server just in case */
> +	client = connect_to_addr(&expected_addr, expected_addr_len, SOCK_STREAM);
> +	if (!ASSERT_GE(client, 0, "connect_to_addr"))
> +		goto cleanup;
> +
> +cleanup:
> +	if (client != -1)
> +		close(client);
> +	if (serv != -1)
> +		close(serv);
> +	bindun_prog__destroy(skel);
> +}
> +
> +void test_connect(int cgroup_fd)
static.

> +{
> +	struct connectun_prog *skel;
> +	struct sockaddr_storage addr, expected_addr;
> +	socklen_t addr_len = sizeof(struct sockaddr_storage),
> +		  expected_addr_len = sizeof(struct sockaddr_storage);
> +	int serv = -1, client = -1, err;
> +
> +	skel = connectun_prog__open_and_load();
> +	if (!ASSERT_OK_PTR(skel, "skel_open"))
> +		return;
> +
> +	skel->links.connectun_prog = bpf_program__attach_cgroup(
> +		skel->progs.connectun_prog, cgroup_fd);
> +	if (!ASSERT_OK_PTR(skel->links.connectun_prog, "prog_attach"))
> +		goto cleanup;
> +
> +	serv = start_server(AF_UNIX, SOCK_STREAM, SERVUN_REWRITE_ADDRESS, 0, 0);
> +	if (!ASSERT_GE(serv, 0, "start_server"))
> +		goto cleanup;
> +
> +	err = make_sockaddr(AF_UNIX, SERVUN_ADDRESS, 0, &addr, &addr_len);
> +	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
> +		goto cleanup;
> +
> +	client = connect_to_addr(&addr, addr_len, SOCK_STREAM);
> +	if (!ASSERT_GE(client, 0, "connect_to_addr"))
> +		goto cleanup;
> +
> +	err = make_sockaddr(AF_UNIX, SERVUN_REWRITE_ADDRESS, 0, &expected_addr, &expected_addr_len);
> +	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
> +		goto cleanup;
> +
> +	err = cmp_peer_addr(client, &expected_addr, expected_addr_len);
> +	if (!ASSERT_EQ(err, 0, "cmp_peer_addr"))
> +		goto cleanup;
> +
> +cleanup:
> +	if (client != -1)
> +		close(client);
> +	if (serv != -1)
> +		close(serv);
> +	connectun_prog__destroy(skel);
> +}
> +
> +void test_sendmsg(int cgroup_fd)
static.

> +{
> +	struct sendmsgun_prog *skel;
> +	struct sockaddr_storage addr;
> +	socklen_t addr_len = sizeof(struct sockaddr_storage);
> +	char data = 'a';
> +	int serv = -1, client = -1, err;
> +
> +	skel = sendmsgun_prog__open_and_load();
> +	if (!ASSERT_OK_PTR(skel, "skel_open"))
> +		return;
> +
> +	skel->links.sendmsgun_prog = bpf_program__attach_cgroup(
> +		skel->progs.sendmsgun_prog, cgroup_fd);
> +	if (!ASSERT_OK_PTR(skel->links.sendmsgun_prog, "prog_attach"))
> +		goto cleanup;
> +
> +	serv = start_server(AF_UNIX, SOCK_DGRAM, SERVUN_REWRITE_ADDRESS, 0, 0);
> +	if (!ASSERT_GE(serv, 0, "start_server"))
> +		goto cleanup;
> +
> +	client = socket(AF_UNIX, SOCK_DGRAM, 0);
> +	if (!ASSERT_GE(client, 0, "socket"))
> +		goto cleanup;
> +
> +	err = make_sockaddr(AF_UNIX, SERVUN_ADDRESS, 0, &addr, &addr_len);
> +	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
> +		goto cleanup;
> +
> +	err = sendto(client, &data, sizeof(data), 0, (const struct sockaddr *) &addr, addr_len);
> +	if (!ASSERT_EQ(err, sizeof(data), "sendto"))
> +		goto cleanup;
> +
> +	if (!ASSERT_EQ(recv(serv, &data, sizeof(data), 0), sizeof(data), "recv"))
> +		goto cleanup;
> +
> +	ASSERT_EQ(data, 'a', "data mismatch");
> +
> +cleanup:
> +	if (client != -1)
> +		close(client);
> +	if (serv != -1)
> +		close(serv);
> +	sendmsgun_prog__destroy(skel);
> +}
> +
> +void test_recvmsg(int cgroup_fd)
static.

> +{
> +	struct recvmsgun_prog *skel;
> +	struct sockaddr_storage addr, src_addr;
> +	socklen_t addr_len = sizeof(struct sockaddr_storage),
> +		  src_addr_len = sizeof(struct sockaddr_storage);
> +	char data = 'a';
> +	int serv = -1, client = -1, err;
> +
> +	/* Unlike the other tests, here we test that we can rewrite the src addr
> +	 * with a recvmsg() hook.
> +	 */
> +
> +	skel = recvmsgun_prog__open_and_load();
> +	if (!ASSERT_OK_PTR(skel, "skel_open"))
> +		return;
> +
> +	skel->links.recvmsgun_prog = bpf_program__attach_cgroup(
> +		skel->progs.recvmsgun_prog, cgroup_fd);
> +	if (!ASSERT_OK_PTR(skel->links.recvmsgun_prog, "prog_attach"))
> +		goto cleanup;
> +
> +	serv = start_server(AF_UNIX, SOCK_DGRAM, SERVUN_ADDRESS, 0, 0);
> +	if (!ASSERT_GE(serv, 0, "start_server"))
> +		goto cleanup;
> +
> +	client = socket(AF_UNIX, SOCK_DGRAM, 0);
> +	if (!ASSERT_GE(client, 0, "socket"))
> +		goto cleanup;
> +
> +	err = make_sockaddr(AF_UNIX, SRCUN_ADDRESS, 0, &src_addr, &src_addr_len);
> +	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
> +		goto cleanup;
> +
> +	if (!ASSERT_EQ(bind(client, (const struct sockaddr *) &src_addr, src_addr_len), 0, "bind"))
> +		goto cleanup;
> +
> +	err = make_sockaddr(AF_UNIX, SERVUN_ADDRESS, 0, &addr, &addr_len);
> +	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
> +		goto cleanup;
> +
> +	err = sendto(client, &data, sizeof(data), 0, (const struct sockaddr *) &addr, addr_len);
> +	if (!ASSERT_EQ(err, sizeof(data), "sendto"))
> +		goto cleanup;
> +
> +	addr_len = src_addr_len = sizeof(struct sockaddr_storage);
> +
> +	err = recvfrom(serv, &data, sizeof(data), 0, (struct sockaddr *) &addr, &addr_len);
> +	if (!ASSERT_EQ(err, sizeof(data), "recvfrom"))
> +		goto cleanup;
> +
> +	ASSERT_EQ(data, 'a', "data mismatch");
> +
> +	err = make_sockaddr(AF_UNIX, SRCUN_REWRITE_ADDRESS, 0, &src_addr, &src_addr_len);
> +	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
> +		goto cleanup;
> +
> +	if (!ASSERT_EQ(cmp_addr(&addr, addr_len, &src_addr, src_addr_len, 0), 0, "cmp_addr"))
> +		goto cleanup;
> +
> +cleanup:
> +	if (client != -1)
> +		close(client);
> +	if (serv != -1)
> +		close(serv);
> +	recvmsgun_prog__destroy(skel);
> +}
> +
> +void test_sock_addr(void)
> +{
> +	int cgroup_fd = -1;
> +
> +	cgroup_fd = test__join_cgroup("/sock_addr");
> +	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
> +		goto cleanup;
> +
> +	if (test__start_subtest("bind"))
> +		test_bind(cgroup_fd);
> +	if (test__start_subtest("connect"))
> +		test_connect(cgroup_fd);
> +	if (test__start_subtest("sendmsg"))
> +		test_sendmsg(cgroup_fd);
> +	if (test__start_subtest("recvmsg"))
> +		test_recvmsg(cgroup_fd);
> +
> +cleanup:
> +	if (cgroup_fd >= 0)
> +		close(cgroup_fd);
> +}
> diff --git a/tools/testing/selftests/bpf/progs/bindun_prog.c b/tools/testing/selftests/bpf/progs/bindun_prog.c
> new file mode 100644
> index 000000000000..e5e19c41f02d
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/bindun_prog.c
> @@ -0,0 +1,25 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
> +
> +#include "vmlinux.h"
> +
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_kfuncs.h"
> +
> +__u8 SERVUN_REWRITE_ADDRESS[] = "\0bpf_cgroup_unix_test_rewrite";
> +
> +SEC("cgroup/bindun")
> +int bindun_prog(struct bpf_sock_addr *ctx)
> +{
> +	struct bpf_sock_addr_kern *sa_kern = bpf_cast_to_kern_ctx(ctx);
> +	int ret;

It will be useful as an example to show how the unix address can be read from 
sa_kern->uaddr.

> +
> +	ret = bpf_sock_addr_set_addr(sa_kern, SERVUN_REWRITE_ADDRESS,
> +				     sizeof(SERVUN_REWRITE_ADDRESS) - 1);

Other tests are needed on bpf_sock_addr_set_addr() with AF_INET and AF_INET6 sk.

Please also cc netdev in the next respin. Thanks!
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h
index 642dda0e758a..e974cd9cf634 100644
--- a/tools/testing/selftests/bpf/bpf_kfuncs.h
+++ b/tools/testing/selftests/bpf/bpf_kfuncs.h
@@ -1,6 +1,8 @@ 
 #ifndef __BPF_KFUNCS__
 #define __BPF_KFUNCS__
 
+struct bpf_sock_addr_kern;
+
 /* Description
  *  Initializes an skb-type dynptr
  * Returns
@@ -41,4 +43,15 @@  extern bool bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym;
 extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym;
 extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym;
 
+/* Description
+ *  Modify the address of a sockaddr.
+ * Returns__bpf_kfunc
+ *  -EINVAL if the address size is too big or too small or, 0 if the sockaddr
+ * was successfully modified.
+ */
+extern int bpf_sock_addr_set_addr(struct bpf_sock_addr_kern *sa_kern,
+				  const __u8 *addr, __u32 addrlen__sz) __ksym;
+
+void *bpf_cast_to_kern_ctx(void *) __ksym;
+
 #endif
diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c
index da72a3a66230..6db27a9088e9 100644
--- a/tools/testing/selftests/bpf/network_helpers.c
+++ b/tools/testing/selftests/bpf/network_helpers.c
@@ -11,6 +11,7 @@ 
 #include <arpa/inet.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
+#include <sys/un.h>
 
 #include <linux/err.h>
 #include <linux/in.h>
@@ -257,6 +258,26 @@  static int connect_fd_to_addr(int fd,
 	return 0;
 }
 
+int connect_to_addr(const struct sockaddr_storage *addr, socklen_t addrlen, int type)
+{
+	int fd;
+
+	fd = socket(addr->ss_family, type, 0);
+	if (fd < 0) {
+		log_err("Failed to create client socket");
+		return -1;
+	}
+
+	if (connect_fd_to_addr(fd, addr, addrlen, false))
+		goto error_close;
+
+	return fd;
+
+error_close:
+	save_errno_close(fd);
+	return -1;
+}
+
 static const struct network_helper_opts default_opts;
 
 int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts)
@@ -380,6 +401,19 @@  int make_sockaddr(int family, const char *addr_str, __u16 port,
 		if (len)
 			*len = sizeof(*sin6);
 		return 0;
+	} else if (family == AF_UNIX) {
+		/* Note that we always use abstract unix sockets to avoid having
+		 * to clean up leftover files.
+		 */
+		struct sockaddr_un *sun = (void *)addr;
+
+		memset(addr, 0, sizeof(*sun));
+		sun->sun_family = family;
+		sun->sun_path[0] = 0;
+		strcpy(sun->sun_path + 1, addr_str);
+		if (len)
+			*len = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(addr_str);
+		return 0;
 	}
 	return -1;
 }
diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h
index 5eccc67d1a99..34f1200a781b 100644
--- a/tools/testing/selftests/bpf/network_helpers.h
+++ b/tools/testing/selftests/bpf/network_helpers.h
@@ -51,6 +51,7 @@  int *start_reuseport_server(int family, int type, const char *addr_str,
 			    __u16 port, int timeout_ms,
 			    unsigned int nr_listens);
 void free_fds(int *fds, unsigned int nr_close_fds);
+int connect_to_addr(const struct sockaddr_storage *addr, socklen_t len, int type);
 int connect_to_fd(int server_fd, int timeout_ms);
 int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts);
 int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms);
diff --git a/tools/testing/selftests/bpf/prog_tests/section_names.c b/tools/testing/selftests/bpf/prog_tests/section_names.c
index fc5248e94a01..51ebc8e6065d 100644
--- a/tools/testing/selftests/bpf/prog_tests/section_names.c
+++ b/tools/testing/selftests/bpf/prog_tests/section_names.c
@@ -113,6 +113,11 @@  static struct sec_name_test tests[] = {
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND},
 		{0, BPF_CGROUP_INET6_BIND},
 	},
+	{
+		"cgroup/bindun",
+		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UNIX_BIND},
+		{0, BPF_CGROUP_UNIX_BIND},
+	},
 	{
 		"cgroup/connect4",
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_CONNECT},
@@ -123,6 +128,11 @@  static struct sec_name_test tests[] = {
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_CONNECT},
 		{0, BPF_CGROUP_INET6_CONNECT},
 	},
+	{
+		"cgroup/connectun",
+		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UNIX_CONNECT},
+		{0, BPF_CGROUP_UNIX_CONNECT},
+	},
 	{
 		"cgroup/sendmsg4",
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_SENDMSG},
@@ -133,6 +143,11 @@  static struct sec_name_test tests[] = {
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG},
 		{0, BPF_CGROUP_UDP6_SENDMSG},
 	},
+	{
+		"cgroup/sendmsgun",
+		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UNIX_SENDMSG},
+		{0, BPF_CGROUP_UNIX_SENDMSG},
+	},
 	{
 		"cgroup/recvmsg4",
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_RECVMSG},
@@ -143,6 +158,11 @@  static struct sec_name_test tests[] = {
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_RECVMSG},
 		{0, BPF_CGROUP_UDP6_RECVMSG},
 	},
+	{
+		"cgroup/recvmsgun",
+		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UNIX_RECVMSG},
+		{0, BPF_CGROUP_UNIX_RECVMSG},
+	},
 	{
 		"cgroup/sysctl",
 		{0, BPF_PROG_TYPE_CGROUP_SYSCTL, BPF_CGROUP_SYSCTL},
@@ -168,6 +188,11 @@  static struct sec_name_test tests[] = {
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_GETPEERNAME},
 		{0, BPF_CGROUP_INET6_GETPEERNAME},
 	},
+	{
+		"cgroup/getpeernameun",
+		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UNIX_GETPEERNAME},
+		{0, BPF_CGROUP_UNIX_GETPEERNAME},
+	},
 	{
 		"cgroup/getsockname4",
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_GETSOCKNAME},
@@ -178,6 +203,11 @@  static struct sec_name_test tests[] = {
 		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_GETSOCKNAME},
 		{0, BPF_CGROUP_INET6_GETSOCKNAME},
 	},
+	{
+		"cgroup/getsocknameun",
+		{0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UNIX_GETSOCKNAME},
+		{0, BPF_CGROUP_UNIX_GETSOCKNAME},
+	},
 };
 
 static void test_prog_type_by_name(const struct sec_name_test *test)
diff --git a/tools/testing/selftests/bpf/prog_tests/sock_addr.c b/tools/testing/selftests/bpf/prog_tests/sock_addr.c
new file mode 100644
index 000000000000..82976dd61344
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/sock_addr.c
@@ -0,0 +1,313 @@ 
+// SPDX-License-Identifier: GPL-2.0
+#include <sys/un.h>
+
+#include "test_progs.h"
+
+#include "bindun_prog.skel.h"
+#include "connectun_prog.skel.h"
+#include "sendmsgun_prog.skel.h"
+#include "recvmsgun_prog.skel.h"
+#include "network_helpers.h"
+
+#include <stdio.h>
+
+#define TEST_NS "sock_addr_netns"
+
+#define SERVUN_ADDRESS         "bpf_cgroup_unix_test"
+#define SERVUN_REWRITE_ADDRESS "bpf_cgroup_unix_test_rewrite"
+#define SRCUN_ADDRESS	       "bpf_cgroup_unix_test_src"
+#define SRCUN_REWRITE_ADDRESS  "bpf_cgroup_unix_test_src_rewrite"
+
+typedef int (*info_fn)(int, struct sockaddr *, socklen_t *);
+
+static int cmp_addr(const struct sockaddr_storage *addr1, socklen_t addr1_len,
+		    const struct sockaddr_storage *addr2, socklen_t addr2_len,
+		    int cmp_port)
+{
+	const struct sockaddr_in *four1, *four2;
+	const struct sockaddr_in6 *six1, *six2;
+	const struct sockaddr_un *un1, *un2;
+
+	fprintf(stderr, "un1: %i\n", addr1->ss_family);
+	fprintf(stderr, "un2: %i\n", addr2->ss_family);
+
+	if (addr1->ss_family != addr2->ss_family)
+		return -1;
+
+	fprintf(stderr, "un1: %i\n", addr1_len);
+	fprintf(stderr, "un2: %i\n", addr2_len);
+
+	if (addr1_len != addr2_len)
+		return -1;
+
+	if (addr1->ss_family == AF_INET) {
+		four1 = (const struct sockaddr_in *)addr1;
+		four2 = (const struct sockaddr_in *)addr2;
+		return !((four1->sin_port == four2->sin_port || !cmp_port) &&
+			 four1->sin_addr.s_addr == four2->sin_addr.s_addr);
+	} else if (addr1->ss_family == AF_INET6) {
+		six1 = (const struct sockaddr_in6 *)addr1;
+		six2 = (const struct sockaddr_in6 *)addr2;
+		return !((six1->sin6_port == six2->sin6_port || !cmp_port) &&
+			 !memcmp(&six1->sin6_addr, &six2->sin6_addr,
+				 sizeof(struct in6_addr)));
+	} else if (addr1->ss_family == AF_UNIX) {
+		un1 = (const struct sockaddr_un *)addr1;
+		un2 = (const struct sockaddr_un *)addr2;
+		fprintf(stderr, "un1: %s\n", un1->sun_path + 1);
+		fprintf(stderr, "un2: %s\n", un2->sun_path + 1);
+		return memcmp(un1, un2, addr1_len);
+	}
+
+	return -1;
+}
+
+static int cmp_sock_addr(info_fn fn, int sock1,
+			 const struct sockaddr_storage *addr2,
+			 socklen_t addr2_len, int cmp_port)
+{
+	struct sockaddr_storage addr1;
+	socklen_t len1 = sizeof(addr1);
+
+	memset(&addr1, 0, len1);
+	if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0)
+		return -1;
+
+	return cmp_addr(&addr1, len1, addr2, addr2_len, cmp_port);
+}
+
+static int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2,
+			  socklen_t addr2_len)
+{
+	return cmp_sock_addr(getsockname, sock1, addr2, addr2_len,
+			     /*cmp_port*/ 1);
+}
+
+static int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2,
+			 socklen_t addr2_len)
+{
+	return cmp_sock_addr(getpeername, sock1, addr2, addr2_len,
+			     /*cmp_port*/ 1);
+}
+
+void test_bind(int cgroup_fd)
+{
+	struct bindun_prog *skel;
+	struct sockaddr_storage expected_addr;
+	socklen_t expected_addr_len = sizeof(struct sockaddr_storage);
+	int serv = -1, client = -1, err;
+
+	skel = bindun_prog__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "skel_open"))
+		return;
+
+	skel->links.bindun_prog = bpf_program__attach_cgroup(
+		skel->progs.bindun_prog, cgroup_fd);
+	if (!ASSERT_OK_PTR(skel->links.bindun_prog, "prog_attach"))
+		goto cleanup;
+
+	serv = start_server(AF_UNIX, SOCK_STREAM, SERVUN_ADDRESS, 0, 0);
+	if (!ASSERT_GE(serv, 0, "start_server"))
+		goto cleanup;
+
+	err = make_sockaddr(AF_UNIX, SERVUN_REWRITE_ADDRESS, 0, &expected_addr, &expected_addr_len);
+	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
+		goto cleanup;
+
+	err = cmp_local_addr(serv, &expected_addr, expected_addr_len);
+	if (!ASSERT_EQ(err, 0, "cmp_local_addr"))
+		goto cleanup;
+
+	/* Try to connect to server just in case */
+	client = connect_to_addr(&expected_addr, expected_addr_len, SOCK_STREAM);
+	if (!ASSERT_GE(client, 0, "connect_to_addr"))
+		goto cleanup;
+
+cleanup:
+	if (client != -1)
+		close(client);
+	if (serv != -1)
+		close(serv);
+	bindun_prog__destroy(skel);
+}
+
+void test_connect(int cgroup_fd)
+{
+	struct connectun_prog *skel;
+	struct sockaddr_storage addr, expected_addr;
+	socklen_t addr_len = sizeof(struct sockaddr_storage),
+		  expected_addr_len = sizeof(struct sockaddr_storage);
+	int serv = -1, client = -1, err;
+
+	skel = connectun_prog__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "skel_open"))
+		return;
+
+	skel->links.connectun_prog = bpf_program__attach_cgroup(
+		skel->progs.connectun_prog, cgroup_fd);
+	if (!ASSERT_OK_PTR(skel->links.connectun_prog, "prog_attach"))
+		goto cleanup;
+
+	serv = start_server(AF_UNIX, SOCK_STREAM, SERVUN_REWRITE_ADDRESS, 0, 0);
+	if (!ASSERT_GE(serv, 0, "start_server"))
+		goto cleanup;
+
+	err = make_sockaddr(AF_UNIX, SERVUN_ADDRESS, 0, &addr, &addr_len);
+	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
+		goto cleanup;
+
+	client = connect_to_addr(&addr, addr_len, SOCK_STREAM);
+	if (!ASSERT_GE(client, 0, "connect_to_addr"))
+		goto cleanup;
+
+	err = make_sockaddr(AF_UNIX, SERVUN_REWRITE_ADDRESS, 0, &expected_addr, &expected_addr_len);
+	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
+		goto cleanup;
+
+	err = cmp_peer_addr(client, &expected_addr, expected_addr_len);
+	if (!ASSERT_EQ(err, 0, "cmp_peer_addr"))
+		goto cleanup;
+
+cleanup:
+	if (client != -1)
+		close(client);
+	if (serv != -1)
+		close(serv);
+	connectun_prog__destroy(skel);
+}
+
+void test_sendmsg(int cgroup_fd)
+{
+	struct sendmsgun_prog *skel;
+	struct sockaddr_storage addr;
+	socklen_t addr_len = sizeof(struct sockaddr_storage);
+	char data = 'a';
+	int serv = -1, client = -1, err;
+
+	skel = sendmsgun_prog__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "skel_open"))
+		return;
+
+	skel->links.sendmsgun_prog = bpf_program__attach_cgroup(
+		skel->progs.sendmsgun_prog, cgroup_fd);
+	if (!ASSERT_OK_PTR(skel->links.sendmsgun_prog, "prog_attach"))
+		goto cleanup;
+
+	serv = start_server(AF_UNIX, SOCK_DGRAM, SERVUN_REWRITE_ADDRESS, 0, 0);
+	if (!ASSERT_GE(serv, 0, "start_server"))
+		goto cleanup;
+
+	client = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (!ASSERT_GE(client, 0, "socket"))
+		goto cleanup;
+
+	err = make_sockaddr(AF_UNIX, SERVUN_ADDRESS, 0, &addr, &addr_len);
+	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
+		goto cleanup;
+
+	err = sendto(client, &data, sizeof(data), 0, (const struct sockaddr *) &addr, addr_len);
+	if (!ASSERT_EQ(err, sizeof(data), "sendto"))
+		goto cleanup;
+
+	if (!ASSERT_EQ(recv(serv, &data, sizeof(data), 0), sizeof(data), "recv"))
+		goto cleanup;
+
+	ASSERT_EQ(data, 'a', "data mismatch");
+
+cleanup:
+	if (client != -1)
+		close(client);
+	if (serv != -1)
+		close(serv);
+	sendmsgun_prog__destroy(skel);
+}
+
+void test_recvmsg(int cgroup_fd)
+{
+	struct recvmsgun_prog *skel;
+	struct sockaddr_storage addr, src_addr;
+	socklen_t addr_len = sizeof(struct sockaddr_storage),
+		  src_addr_len = sizeof(struct sockaddr_storage);
+	char data = 'a';
+	int serv = -1, client = -1, err;
+
+	/* Unlike the other tests, here we test that we can rewrite the src addr
+	 * with a recvmsg() hook.
+	 */
+
+	skel = recvmsgun_prog__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "skel_open"))
+		return;
+
+	skel->links.recvmsgun_prog = bpf_program__attach_cgroup(
+		skel->progs.recvmsgun_prog, cgroup_fd);
+	if (!ASSERT_OK_PTR(skel->links.recvmsgun_prog, "prog_attach"))
+		goto cleanup;
+
+	serv = start_server(AF_UNIX, SOCK_DGRAM, SERVUN_ADDRESS, 0, 0);
+	if (!ASSERT_GE(serv, 0, "start_server"))
+		goto cleanup;
+
+	client = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (!ASSERT_GE(client, 0, "socket"))
+		goto cleanup;
+
+	err = make_sockaddr(AF_UNIX, SRCUN_ADDRESS, 0, &src_addr, &src_addr_len);
+	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
+		goto cleanup;
+
+	if (!ASSERT_EQ(bind(client, (const struct sockaddr *) &src_addr, src_addr_len), 0, "bind"))
+		goto cleanup;
+
+	err = make_sockaddr(AF_UNIX, SERVUN_ADDRESS, 0, &addr, &addr_len);
+	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
+		goto cleanup;
+
+	err = sendto(client, &data, sizeof(data), 0, (const struct sockaddr *) &addr, addr_len);
+	if (!ASSERT_EQ(err, sizeof(data), "sendto"))
+		goto cleanup;
+
+	addr_len = src_addr_len = sizeof(struct sockaddr_storage);
+
+	err = recvfrom(serv, &data, sizeof(data), 0, (struct sockaddr *) &addr, &addr_len);
+	if (!ASSERT_EQ(err, sizeof(data), "recvfrom"))
+		goto cleanup;
+
+	ASSERT_EQ(data, 'a', "data mismatch");
+
+	err = make_sockaddr(AF_UNIX, SRCUN_REWRITE_ADDRESS, 0, &src_addr, &src_addr_len);
+	if (!ASSERT_EQ(err, 0, "make_sockaddr"))
+		goto cleanup;
+
+	if (!ASSERT_EQ(cmp_addr(&addr, addr_len, &src_addr, src_addr_len, 0), 0, "cmp_addr"))
+		goto cleanup;
+
+cleanup:
+	if (client != -1)
+		close(client);
+	if (serv != -1)
+		close(serv);
+	recvmsgun_prog__destroy(skel);
+}
+
+void test_sock_addr(void)
+{
+	int cgroup_fd = -1;
+
+	cgroup_fd = test__join_cgroup("/sock_addr");
+	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
+		goto cleanup;
+
+	if (test__start_subtest("bind"))
+		test_bind(cgroup_fd);
+	if (test__start_subtest("connect"))
+		test_connect(cgroup_fd);
+	if (test__start_subtest("sendmsg"))
+		test_sendmsg(cgroup_fd);
+	if (test__start_subtest("recvmsg"))
+		test_recvmsg(cgroup_fd);
+
+cleanup:
+	if (cgroup_fd >= 0)
+		close(cgroup_fd);
+}
diff --git a/tools/testing/selftests/bpf/progs/bindun_prog.c b/tools/testing/selftests/bpf/progs/bindun_prog.c
new file mode 100644
index 000000000000..e5e19c41f02d
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bindun_prog.c
@@ -0,0 +1,25 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include "vmlinux.h"
+
+#include <bpf/bpf_helpers.h>
+#include "bpf_kfuncs.h"
+
+__u8 SERVUN_REWRITE_ADDRESS[] = "\0bpf_cgroup_unix_test_rewrite";
+
+SEC("cgroup/bindun")
+int bindun_prog(struct bpf_sock_addr *ctx)
+{
+	struct bpf_sock_addr_kern *sa_kern = bpf_cast_to_kern_ctx(ctx);
+	int ret;
+
+	ret = bpf_sock_addr_set_addr(sa_kern, SERVUN_REWRITE_ADDRESS,
+				     sizeof(SERVUN_REWRITE_ADDRESS) - 1);
+	if (ret)
+		return 0;
+
+	return 1;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/connectun_prog.c b/tools/testing/selftests/bpf/progs/connectun_prog.c
new file mode 100644
index 000000000000..33cb6e4698e9
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/connectun_prog.c
@@ -0,0 +1,26 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include "vmlinux.h"
+
+#include <bpf/bpf_helpers.h>
+#include "bpf_kfuncs.h"
+
+__u8 SERVUN_REWRITE_ADDRESS[] = "\0bpf_cgroup_unix_test_rewrite";
+
+SEC("cgroup/connectun")
+int connectun_prog(struct bpf_sock_addr *ctx)
+{
+	struct bpf_sock_addr_kern *sa_kern = bpf_cast_to_kern_ctx(ctx);
+	int ret;
+
+	/* Rewrite destination. */
+	ret = bpf_sock_addr_set_addr(sa_kern, SERVUN_REWRITE_ADDRESS,
+				     sizeof(SERVUN_REWRITE_ADDRESS) - 1);
+	if (ret)
+		return 0;
+
+	return 1;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/recvmsgun_prog.c b/tools/testing/selftests/bpf/progs/recvmsgun_prog.c
new file mode 100644
index 000000000000..a53eb082c604
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/recvmsgun_prog.c
@@ -0,0 +1,25 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include "vmlinux.h"
+
+#include <bpf/bpf_helpers.h>
+#include "bpf_kfuncs.h"
+
+__u8 SRCUN_REWRITE_ADDRESS[] = "\0bpf_cgroup_unix_test_src_rewrite";
+
+SEC("cgroup/recvmsgun")
+int recvmsgun_prog(struct bpf_sock_addr *ctx)
+{
+	struct bpf_sock_addr_kern *sa_kern = bpf_cast_to_kern_ctx(ctx);
+	int ret;
+
+	ret = bpf_sock_addr_set_addr(sa_kern, SRCUN_REWRITE_ADDRESS,
+				     sizeof(SRCUN_REWRITE_ADDRESS) - 1);
+	if (ret)
+		return 1;
+
+	return 1;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/sendmsgun_prog.c b/tools/testing/selftests/bpf/progs/sendmsgun_prog.c
new file mode 100644
index 000000000000..b78932e3d57b
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/sendmsgun_prog.c
@@ -0,0 +1,26 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include "vmlinux.h"
+
+#include <bpf/bpf_helpers.h>
+#include "bpf_kfuncs.h"
+
+__u8 SERVUN_REWRITE_ADDRESS[] = "\0bpf_cgroup_unix_test_rewrite";
+
+SEC("cgroup/sendmsgun")
+int sendmsgun_prog(struct bpf_sock_addr *ctx)
+{
+	struct bpf_sock_addr_kern *sa_kern = bpf_cast_to_kern_ctx(ctx);
+	int ret;
+
+	/* Rewrite destination. */
+	ret = bpf_sock_addr_set_addr(sa_kern, SERVUN_REWRITE_ADDRESS,
+				     sizeof(SERVUN_REWRITE_ADDRESS) - 1);
+	if (ret)
+		return 0;
+
+	return 1;
+}
+
+char _license[] SEC("license") = "GPL";