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