Re: [PATCH bpf-next v2 2/2] selftests/bpf: verify that rebinding to port < 1024 from BPF works
From: Stanislav Fomichev <hidden>
Date: 2021-01-25 23:39:18
Also in:
bpf
On Mon, Jan 25, 2021 at 3:30 PM Martin KaFai Lau [off-list ref] wrote:
On Mon, Jan 25, 2021 at 09:26:41AM -0800, Stanislav Fomichev wrote:quoted
BPF rewrites from 111 to 111, but it still should mark the port as "changed". We also verify that if port isn't touched by BPF, it's still prohibited.The description requires an update.
Good point, will update this one and the comment!
quoted
Cc: Andrey Ignatov <redacted> Cc: Martin KaFai Lau <redacted> Signed-off-by: Stanislav Fomichev <redacted> --- .../selftests/bpf/prog_tests/bind_perm.c | 85 +++++++++++++++++++ tools/testing/selftests/bpf/progs/bind_perm.c | 36 ++++++++ 2 files changed, 121 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/bind_perm.c create mode 100644 tools/testing/selftests/bpf/progs/bind_perm.cdiff --git a/tools/testing/selftests/bpf/prog_tests/bind_perm.c b/tools/testing/selftests/bpf/prog_tests/bind_perm.c new file mode 100644 index 000000000000..61307d4494bf --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/bind_perm.c@@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> +#include "bind_perm.skel.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/capability.h> + +static int duration; + +void try_bind(int port, int expected_errno) +{ + struct sockaddr_in sin = {}; + int fd = -1; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (CHECK(fd < 0, "fd", "errno %d", errno)) + goto close_socket; + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + + errno = 0; + bind(fd, (struct sockaddr *)&sin, sizeof(sin)); + ASSERT_EQ(errno, expected_errno, "bind"); + +close_socket: + if (fd >= 0) + close(fd); +} + +void cap_net_bind_service(cap_flag_value_t flag) +{ + const cap_value_t cap_net_bind_service = CAP_NET_BIND_SERVICE; + cap_t caps; + + caps = cap_get_proc(); + if (CHECK(!caps, "cap_get_proc", "errno %d", errno)) + goto free_caps; + + if (CHECK(cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_bind_service, + CAP_CLEAR), + "cap_set_flag", "errno %d", errno)) + goto free_caps; + + if (CHECK(cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_bind_service, + CAP_CLEAR), + "cap_set_flag", "errno %d", errno))These two back-to-back cap_set_flag() looks incorrect. Also, the "cap_flag_value_t flag" is unused.
Ah, true, I never reset back CAP_NET_BIND_SERVICE, will fix, thanks!
quoted
+ goto free_caps; + + if (CHECK(cap_set_proc(caps), "cap_set_proc", "errno %d", errno)) + goto free_caps; + +free_caps: + if (CHECK(cap_free(caps), "cap_free", "errno %d", errno)) + goto free_caps;There is a loop.quoted
+} + +void test_bind_perm(void) +{ + struct bind_perm *skel; + int cgroup_fd; + + cgroup_fd = test__join_cgroup("/bind_perm"); + if (CHECK(cgroup_fd < 0, "cg-join", "errno %d", errno)) + return; + + skel = bind_perm__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel")) + goto close_cgroup_fd; + + skel->links.bind_v4_prog = bpf_program__attach_cgroup(skel->progs.bind_v4_prog, cgroup_fd); + if (!ASSERT_OK_PTR(skel, "bind_v4_prog")) + goto close_skeleton; + + cap_net_bind_service(CAP_CLEAR); + try_bind(110, EACCES); + try_bind(111, 0); + cap_net_bind_service(CAP_SET); + +close_skeleton: + bind_perm__destroy(skel); +close_cgroup_fd: + close(cgroup_fd); +}diff --git a/tools/testing/selftests/bpf/progs/bind_perm.c b/tools/testing/selftests/bpf/progs/bind_perm.c new file mode 100644 index 000000000000..31ae8d599796 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/bind_perm.c@@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/stddef.h> +#include <linux/bpf.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_endian.h> + +SEC("cgroup/bind4") +int bind_v4_prog(struct bpf_sock_addr *ctx) +{ + struct bpf_sock *sk; + __u32 user_ip4; + __u16 user_port; + + sk = ctx->sk; + if (!sk) + return 0; + + if (sk->family != AF_INET) + return 0; + + if (ctx->type != SOCK_STREAM) + return 0; + + /* Rewriting to the same value should still cause + * permission check to be bypassed. + */This comment is out dated also.quoted
+ if (ctx->user_port == bpf_htons(111)) + return 3; + + return 1; +} + +char _license[] SEC("license") = "GPL"; -- 2.30.0.280.ga3ce27912f-goog