On 12/6/22 8:32 AM, Daan De Meyer wrote:
This hook allows intercepting connect() calls on unix sockets. After
running the hook, we recalculate the sockaddr length as it the hook
as the hook
might have replaced the sun_path with a longer/shorter one. This is
safe because all kernelspace sockaddrs are stored in instances of
sockaddr_storage which is guaranteed to larger than sockaddr_un.
This hook can be used when users want to multiplex connect()
calls to a single unix socket to multiple different processes
behind the scenes by redirecting the connect() calls to process
specific sockets.
Signed-off-by: Daan De Meyer <daan.j.demeyer@xxxxxxxxx>
---
Documentation/bpf/libbpf/program_types.rst | 2 +
include/linux/bpf-cgroup-defs.h | 1 +
include/linux/bpf-cgroup.h | 12 ++-
include/uapi/linux/bpf.h | 10 ++-
kernel/bpf/cgroup.c | 5 +-
kernel/bpf/syscall.c | 3 +
net/core/filter.c | 28 +++++++
net/unix/af_unix.c | 37 +++++++++
tools/bpf/bpftool/common.c | 1 +
tools/include/uapi/linux/bpf.h | 10 ++-
tools/lib/bpf/libbpf.c | 2 +
.../selftests/bpf/prog_tests/section_names.c | 5 ++
.../selftests/bpf/progs/connectun_prog.c | 27 ++++++
tools/testing/selftests/bpf/test_sock_addr.c | 83 +++++++++++++++++--
14 files changed, 206 insertions(+), 20 deletions(-)
create mode 100644 tools/testing/selftests/bpf/progs/connectun_prog.c
Please break this into multiple patches for easier review:
patch 1: core change
> include/linux/bpf-cgroup-defs.h | 1 +
> include/linux/bpf-cgroup.h | 12 ++-
> include/uapi/linux/bpf.h | 10 ++-
> kernel/bpf/cgroup.c | 5 +-
> kernel/bpf/syscall.c | 3 +
> net/core/filter.c | 28 +++++++
> net/unix/af_unix.c
> tools/include/uapi/linux/bpf.h | 10 ++-
patch 2: libbpf change
> tools/lib/bpf/libbpf.c | 2 +
patch 3: bpftool change
> tools/bpf/bpftool/common.c | 1 +
patch 4: selftest change:
> .../selftests/bpf/prog_tests/section_names.c | 5 ++
> .../selftests/bpf/progs/connectun_prog.c | 27 ++++++
> tools/testing/selftests/bpf/test_sock_addr.c | 83 +++++++++++++++++--
patch 5: doc change:
> Documentation/bpf/libbpf/program_types.rst | 2 +
diff --git a/Documentation/bpf/libbpf/program_types.rst b/Documentation/bpf/libbpf/program_types.rst
index ad4d4d5eecb0..7d0bcd883561 100644
--- a/Documentation/bpf/libbpf/program_types.rst
+++ b/Documentation/bpf/libbpf/program_types.rst
@@ -56,6 +56,8 @@ described in more detail in the footnotes.
| | ``BPF_CGROUP_UDP6_RECVMSG`` | ``cgroup/recvmsg6`` | |
+ +----------------------------------------+----------------------------------+-----------+
| | ``BPF_CGROUP_UDP6_SENDMSG`` | ``cgroup/sendmsg6`` | |
+| +----------------------------------------+----------------------------------+-----------+
+| | ``BPF_CGROUP_UNIX_CONNECT`` | ``cgroup/connectun`` | |
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
| ``BPF_PROG_TYPE_CGROUP_SOCK`` | ``BPF_CGROUP_INET4_POST_BIND`` | ``cgroup/post_bind4`` | |
+ +----------------------------------------+----------------------------------+-----------+
[...]
@@ -6353,6 +6354,7 @@ struct bpf_sock_addr {
__u32 user_ip6[4]; /* Allows 1,2,4,8-byte read and 4,8-byte write.
* Stored in network byte order.
*/
+ char user_path[108]; /* Allows 1 byte read and write. */
__u32 user_port; /* Allows 1,2,4-byte read and 4-byte write.
* Stored in network byte order
*/
Please put the new field at the end of struct. Otherwise, we have
uapi compatibility issue.
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index bf2fdb33fb31..f1d20f69b260 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -1454,7 +1454,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sk);
* @flags: Pointer to u32 which contains higher bits of BPF program
* return value (OR'ed together).
*
- * socket is expected to be of type INET or INET6.
+ * socket is expected to be of type INET, INET6 or UNIX.
*
* This function will return %-EPERM if an attached program is found and
* returned value != 1 during execution. In all other cases, 0 is returned.
@@ -1476,7 +1476,8 @@ int __cgroup_bpf_run_filter_sock_addr(struct sock *sk,
/* Check socket family since not all sockets represent network
* endpoint (e.g. AF_UNIX).
*/
- if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)
+ if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6 &&
+ sk->sk_family != AF_UNIX)
return 0;
if (!ctx.uaddr) {
[...]
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..91097bd8df3c
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/connectun_prog.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Facebook
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include <string.h>
+
+#include <linux/stddef.h>
+#include <linux/bpf.h>
+#include <linux/if.h>
+#include <errno.h>
+
+#include <bpf/bpf_helpers.h>
+
+#define DST_REWRITE_PATH "/tmp/bpf_cgroup_unix_test_rewrite"
+
+SEC("cgroup/connectun")
+int connect_un_prog(struct bpf_sock_addr *ctx)
+{
+ if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
+ return 0;
+
+ /* Rewrite destination. */
+ memcpy(ctx->user_path, DST_REWRITE_PATH, sizeof(DST_REWRITE_PATH));
+
+ return 1;
+}
+
[...]