1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include "bind_perm.skel.h"
4 
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/capability.h>
8 
9 static int duration;
10 
11 void try_bind(int family, int port, int expected_errno)
12 {
13 	struct sockaddr_storage addr = {};
14 	struct sockaddr_in6 *sin6;
15 	struct sockaddr_in *sin;
16 	int fd = -1;
17 
18 	fd = socket(family, SOCK_STREAM, 0);
19 	if (CHECK(fd < 0, "fd", "errno %d", errno))
20 		goto close_socket;
21 
22 	if (family == AF_INET) {
23 		sin = (struct sockaddr_in *)&addr;
24 		sin->sin_family = family;
25 		sin->sin_port = htons(port);
26 	} else {
27 		sin6 = (struct sockaddr_in6 *)&addr;
28 		sin6->sin6_family = family;
29 		sin6->sin6_port = htons(port);
30 	}
31 
32 	errno = 0;
33 	bind(fd, (struct sockaddr *)&addr, sizeof(addr));
34 	ASSERT_EQ(errno, expected_errno, "bind");
35 
36 close_socket:
37 	if (fd >= 0)
38 		close(fd);
39 }
40 
41 bool cap_net_bind_service(cap_flag_value_t flag)
42 {
43 	const cap_value_t cap_net_bind_service = CAP_NET_BIND_SERVICE;
44 	cap_flag_value_t original_value;
45 	bool was_effective = false;
46 	cap_t caps;
47 
48 	caps = cap_get_proc();
49 	if (CHECK(!caps, "cap_get_proc", "errno %d", errno))
50 		goto free_caps;
51 
52 	if (CHECK(cap_get_flag(caps, CAP_NET_BIND_SERVICE, CAP_EFFECTIVE,
53 			       &original_value),
54 		  "cap_get_flag", "errno %d", errno))
55 		goto free_caps;
56 
57 	was_effective = (original_value == CAP_SET);
58 
59 	if (CHECK(cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_bind_service,
60 			       flag),
61 		  "cap_set_flag", "errno %d", errno))
62 		goto free_caps;
63 
64 	if (CHECK(cap_set_proc(caps), "cap_set_proc", "errno %d", errno))
65 		goto free_caps;
66 
67 free_caps:
68 	CHECK(cap_free(caps), "cap_free", "errno %d", errno);
69 	return was_effective;
70 }
71 
72 void test_bind_perm(void)
73 {
74 	bool cap_was_effective;
75 	struct bind_perm *skel;
76 	int cgroup_fd;
77 
78 	cgroup_fd = test__join_cgroup("/bind_perm");
79 	if (CHECK(cgroup_fd < 0, "cg-join", "errno %d", errno))
80 		return;
81 
82 	skel = bind_perm__open_and_load();
83 	if (!ASSERT_OK_PTR(skel, "skel"))
84 		goto close_cgroup_fd;
85 
86 	skel->links.bind_v4_prog = bpf_program__attach_cgroup(skel->progs.bind_v4_prog, cgroup_fd);
87 	if (!ASSERT_OK_PTR(skel, "bind_v4_prog"))
88 		goto close_skeleton;
89 
90 	skel->links.bind_v6_prog = bpf_program__attach_cgroup(skel->progs.bind_v6_prog, cgroup_fd);
91 	if (!ASSERT_OK_PTR(skel, "bind_v6_prog"))
92 		goto close_skeleton;
93 
94 	cap_was_effective = cap_net_bind_service(CAP_CLEAR);
95 
96 	try_bind(AF_INET, 110, EACCES);
97 	try_bind(AF_INET6, 110, EACCES);
98 
99 	try_bind(AF_INET, 111, 0);
100 	try_bind(AF_INET6, 111, 0);
101 
102 	if (cap_was_effective)
103 		cap_net_bind_service(CAP_SET);
104 
105 close_skeleton:
106 	bind_perm__destroy(skel);
107 close_cgroup_fd:
108 	close(cgroup_fd);
109 }
110