1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #define _GNU_SOURCE |
3 | #include <sched.h> |
4 | #include <stdlib.h> |
5 | #include <sys/types.h> |
6 | #include <sys/socket.h> |
7 | |
8 | #include "test_progs.h" |
9 | #include "cap_helpers.h" |
10 | #include "bind_perm.skel.h" |
11 | |
12 | static int create_netns(void) |
13 | { |
14 | if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns" )) |
15 | return -1; |
16 | |
17 | return 0; |
18 | } |
19 | |
20 | void try_bind(int family, int port, int expected_errno) |
21 | { |
22 | struct sockaddr_storage addr = {}; |
23 | struct sockaddr_in6 *sin6; |
24 | struct sockaddr_in *sin; |
25 | int fd = -1; |
26 | |
27 | fd = socket(family, SOCK_STREAM, 0); |
28 | if (!ASSERT_GE(fd, 0, "socket" )) |
29 | goto close_socket; |
30 | |
31 | if (family == AF_INET) { |
32 | sin = (struct sockaddr_in *)&addr; |
33 | sin->sin_family = family; |
34 | sin->sin_port = htons(port); |
35 | } else { |
36 | sin6 = (struct sockaddr_in6 *)&addr; |
37 | sin6->sin6_family = family; |
38 | sin6->sin6_port = htons(port); |
39 | } |
40 | |
41 | errno = 0; |
42 | bind(fd, (struct sockaddr *)&addr, sizeof(addr)); |
43 | ASSERT_EQ(errno, expected_errno, "bind" ); |
44 | |
45 | close_socket: |
46 | if (fd >= 0) |
47 | close(fd); |
48 | } |
49 | |
50 | void test_bind_perm(void) |
51 | { |
52 | const __u64 net_bind_svc_cap = 1ULL << CAP_NET_BIND_SERVICE; |
53 | struct bind_perm *skel; |
54 | __u64 old_caps = 0; |
55 | int cgroup_fd; |
56 | |
57 | if (create_netns()) |
58 | return; |
59 | |
60 | cgroup_fd = test__join_cgroup("/bind_perm" ); |
61 | if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup" )) |
62 | return; |
63 | |
64 | skel = bind_perm__open_and_load(); |
65 | if (!ASSERT_OK_PTR(skel, "skel" )) |
66 | goto close_cgroup_fd; |
67 | |
68 | skel->links.bind_v4_prog = bpf_program__attach_cgroup(skel->progs.bind_v4_prog, cgroup_fd); |
69 | if (!ASSERT_OK_PTR(skel, "bind_v4_prog" )) |
70 | goto close_skeleton; |
71 | |
72 | skel->links.bind_v6_prog = bpf_program__attach_cgroup(skel->progs.bind_v6_prog, cgroup_fd); |
73 | if (!ASSERT_OK_PTR(skel, "bind_v6_prog" )) |
74 | goto close_skeleton; |
75 | |
76 | ASSERT_OK(cap_disable_effective(net_bind_svc_cap, &old_caps), |
77 | "cap_disable_effective" ); |
78 | |
79 | try_bind(family: AF_INET, port: 110, expected_errno: EACCES); |
80 | try_bind(family: AF_INET6, port: 110, expected_errno: EACCES); |
81 | |
82 | try_bind(family: AF_INET, port: 111, expected_errno: 0); |
83 | try_bind(family: AF_INET6, port: 111, expected_errno: 0); |
84 | |
85 | if (old_caps & net_bind_svc_cap) |
86 | ASSERT_OK(cap_enable_effective(net_bind_svc_cap, NULL), |
87 | "cap_enable_effective" ); |
88 | |
89 | close_skeleton: |
90 | bind_perm__destroy(skel); |
91 | close_cgroup_fd: |
92 | close(cgroup_fd); |
93 | } |
94 | |