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 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 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 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 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