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