Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v6.16-rc5 256 lines 6.5 kB view raw
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 32static const char bin_sandbox_and_launch[] = "./sandbox-and-launch"; 33static const char bin_wait_pipe[] = "./wait-pipe"; 34static const char bin_wait_pipe_sandbox[] = "./wait-pipe-sandbox"; 35 36static 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 . */ 77static void __maybe_unused disable_caps(struct __test_metadata *const _metadata) 78{ 79 _init_caps(_metadata, false); 80} 81 82static void __maybe_unused drop_caps(struct __test_metadata *const _metadata) 83{ 84 _init_caps(_metadata, true); 85} 86 87static 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 103static 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 109static 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 115static void __maybe_unused 116set_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 127static 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. */ 136static 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. */ 171static 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 201static void __maybe_unused 202enforce_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 211static void __maybe_unused 212drop_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 227struct protocol_variant { 228 int domain; 229 int type; 230 int protocol; 231}; 232 233struct 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 247static 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}