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