1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Landlock test helpers 4 * 5 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net> 6 * Copyright © 2019-2020 ANSSI 7 * Copyright © 2021 Microsoft Corporation 8 */ 9 10 #include <arpa/inet.h> 11 #include <errno.h> 12 #include <linux/securebits.h> 13 #include <sys/capability.h> 14 #include <sys/prctl.h> 15 #include <sys/socket.h> 16 #include <sys/un.h> 17 #include <sys/wait.h> 18 #include <unistd.h> 19 20 #include "kselftest_harness.h" 21 #include "wrappers.h" 22 23 #define TMP_DIR "tmp" 24 25 /* TEST_F_FORK() should not be used for new tests. */ 26 #define TEST_F_FORK(fixture_name, test_name) TEST_F(fixture_name, test_name) 27 28 #define LANDLOCK_MAX_NUM_LAYERS 16 29 30 static const char bin_sandbox_and_launch[] = "./sandbox-and-launch"; 31 static const char bin_wait_pipe[] = "./wait-pipe"; 32 static const char bin_wait_pipe_sandbox[] = "./wait-pipe-sandbox"; 33 34 static void _init_caps(struct __test_metadata *const _metadata, bool drop_all) 35 { 36 cap_t cap_p; 37 /* Only these three capabilities are useful for the tests. */ 38 const cap_value_t caps[] = { 39 /* clang-format off */ 40 CAP_AUDIT_CONTROL, 41 CAP_DAC_OVERRIDE, 42 CAP_MKNOD, 43 CAP_NET_ADMIN, 44 CAP_NET_BIND_SERVICE, 45 CAP_SETUID, 46 CAP_SYS_ADMIN, 47 CAP_SYS_CHROOT, 48 /* clang-format on */ 49 }; 50 const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED; 51 52 if ((cap_get_secbits() & noroot) != noroot) 53 EXPECT_EQ(0, cap_set_secbits(noroot)); 54 55 cap_p = cap_get_proc(); 56 EXPECT_NE(NULL, cap_p); 57 EXPECT_NE(-1, cap_clear(cap_p)); 58 if (!drop_all) { 59 EXPECT_NE(-1, cap_set_flag(cap_p, CAP_PERMITTED, 60 ARRAY_SIZE(caps), caps, CAP_SET)); 61 } 62 63 /* Automatically resets ambient capabilities. */ 64 EXPECT_NE(-1, cap_set_proc(cap_p)) 65 { 66 TH_LOG("Failed to set capabilities: %s", strerror(errno)); 67 } 68 EXPECT_NE(-1, cap_free(cap_p)); 69 70 /* Quickly checks that ambient capabilities are cleared. */ 71 EXPECT_NE(-1, cap_get_ambient(caps[0])); 72 } 73 74 /* We cannot put such helpers in a library because of kselftest_harness.h . */ 75 static void __maybe_unused disable_caps(struct __test_metadata *const _metadata) 76 { 77 _init_caps(_metadata, false); 78 } 79 80 static void __maybe_unused drop_caps(struct __test_metadata *const _metadata) 81 { 82 _init_caps(_metadata, true); 83 } 84 85 static void _change_cap(struct __test_metadata *const _metadata, 86 const cap_flag_t flag, const cap_value_t cap, 87 const cap_flag_value_t value) 88 { 89 cap_t cap_p; 90 91 cap_p = cap_get_proc(); 92 EXPECT_NE(NULL, cap_p); 93 EXPECT_NE(-1, cap_set_flag(cap_p, flag, 1, &cap, value)); 94 EXPECT_NE(-1, cap_set_proc(cap_p)) 95 { 96 TH_LOG("Failed to set capability %d: %s", cap, strerror(errno)); 97 } 98 EXPECT_NE(-1, cap_free(cap_p)); 99 } 100 101 static void __maybe_unused set_cap(struct __test_metadata *const _metadata, 102 const cap_value_t cap) 103 { 104 _change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_SET); 105 } 106 107 static void __maybe_unused clear_cap(struct __test_metadata *const _metadata, 108 const cap_value_t cap) 109 { 110 _change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_CLEAR); 111 } 112 113 static void __maybe_unused 114 set_ambient_cap(struct __test_metadata *const _metadata, const cap_value_t cap) 115 { 116 _change_cap(_metadata, CAP_INHERITABLE, cap, CAP_SET); 117 118 EXPECT_NE(-1, cap_set_ambient(cap, CAP_SET)) 119 { 120 TH_LOG("Failed to set ambient capability %d: %s", cap, 121 strerror(errno)); 122 } 123 } 124 125 static void __maybe_unused clear_ambient_cap( 126 struct __test_metadata *const _metadata, const cap_value_t cap) 127 { 128 EXPECT_EQ(1, cap_get_ambient(cap)); 129 _change_cap(_metadata, CAP_INHERITABLE, cap, CAP_CLEAR); 130 EXPECT_EQ(0, cap_get_ambient(cap)); 131 } 132 133 /* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */ 134 static int __maybe_unused recv_fd(int usock) 135 { 136 int fd_rx; 137 union { 138 /* Aligned ancillary data buffer. */ 139 char buf[CMSG_SPACE(sizeof(fd_rx))]; 140 struct cmsghdr _align; 141 } cmsg_rx = {}; 142 char data = '\0'; 143 struct iovec io = { 144 .iov_base = &data, 145 .iov_len = sizeof(data), 146 }; 147 struct msghdr msg = { 148 .msg_iov = &io, 149 .msg_iovlen = 1, 150 .msg_control = &cmsg_rx.buf, 151 .msg_controllen = sizeof(cmsg_rx.buf), 152 }; 153 struct cmsghdr *cmsg; 154 int res; 155 156 res = recvmsg(usock, &msg, MSG_CMSG_CLOEXEC); 157 if (res < 0) 158 return -errno; 159 160 cmsg = CMSG_FIRSTHDR(&msg); 161 if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd_rx))) 162 return -EIO; 163 164 memcpy(&fd_rx, CMSG_DATA(cmsg), sizeof(fd_rx)); 165 return fd_rx; 166 } 167 168 /* Sends an FD on a UNIX socket. Returns 0 on success or -errno. */ 169 static int __maybe_unused send_fd(int usock, int fd_tx) 170 { 171 union { 172 /* Aligned ancillary data buffer. */ 173 char buf[CMSG_SPACE(sizeof(fd_tx))]; 174 struct cmsghdr _align; 175 } cmsg_tx = {}; 176 char data_tx = '.'; 177 struct iovec io = { 178 .iov_base = &data_tx, 179 .iov_len = sizeof(data_tx), 180 }; 181 struct msghdr msg = { 182 .msg_iov = &io, 183 .msg_iovlen = 1, 184 .msg_control = &cmsg_tx.buf, 185 .msg_controllen = sizeof(cmsg_tx.buf), 186 }; 187 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 188 189 cmsg->cmsg_len = CMSG_LEN(sizeof(fd_tx)); 190 cmsg->cmsg_level = SOL_SOCKET; 191 cmsg->cmsg_type = SCM_RIGHTS; 192 memcpy(CMSG_DATA(cmsg), &fd_tx, sizeof(fd_tx)); 193 194 if (sendmsg(usock, &msg, 0) < 0) 195 return -errno; 196 return 0; 197 } 198 199 static void __maybe_unused 200 enforce_ruleset(struct __test_metadata *const _metadata, const int ruleset_fd) 201 { 202 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 203 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)) 204 { 205 TH_LOG("Failed to enforce ruleset: %s", strerror(errno)); 206 } 207 } 208 209 static void __maybe_unused 210 drop_access_rights(struct __test_metadata *const _metadata, 211 const struct landlock_ruleset_attr *const ruleset_attr) 212 { 213 int ruleset_fd; 214 215 ruleset_fd = 216 landlock_create_ruleset(ruleset_attr, sizeof(*ruleset_attr), 0); 217 EXPECT_LE(0, ruleset_fd) 218 { 219 TH_LOG("Failed to create a ruleset: %s", strerror(errno)); 220 } 221 enforce_ruleset(_metadata, ruleset_fd); 222 EXPECT_EQ(0, close(ruleset_fd)); 223 } 224 225 struct protocol_variant { 226 int domain; 227 int type; 228 int protocol; 229 }; 230 231 struct service_fixture { 232 struct protocol_variant protocol; 233 /* port is also stored in ipv4_addr.sin_port or ipv6_addr.sin6_port */ 234 unsigned short port; 235 union { 236 struct sockaddr_in ipv4_addr; 237 struct sockaddr_in6 ipv6_addr; 238 struct { 239 struct sockaddr_un unix_addr; 240 socklen_t unix_addr_len; 241 }; 242 struct sockaddr_storage _largest; 243 }; 244 }; 245 246 static void __maybe_unused set_unix_address(struct service_fixture *const srv, 247 const unsigned short index) 248 { 249 srv->unix_addr.sun_family = AF_UNIX; 250 sprintf(srv->unix_addr.sun_path, 251 "_selftests-landlock-abstract-unix-tid%d-index%d", sys_gettid(), 252 index); 253 srv->unix_addr_len = SUN_LEN(&srv->unix_addr); 254 srv->unix_addr.sun_path[0] = '\0'; 255 } 256