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