1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Landlock tests - Common user space base 4 * 5 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net> 6 * Copyright © 2019-2020 ANSSI 7 */ 8 9 #define _GNU_SOURCE 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <linux/keyctl.h> 13 #include <linux/landlock.h> 14 #include <string.h> 15 #include <sys/prctl.h> 16 #include <sys/socket.h> 17 #include <sys/types.h> 18 19 #include "common.h" 20 21 #ifndef O_PATH 22 #define O_PATH 010000000 23 #endif 24 25 TEST(inconsistent_attr) 26 { 27 const long page_size = sysconf(_SC_PAGESIZE); 28 char *const buf = malloc(page_size + 1); 29 struct landlock_ruleset_attr *const ruleset_attr = (void *)buf; 30 31 ASSERT_NE(NULL, buf); 32 33 /* Checks copy_from_user(). */ 34 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 0, 0)); 35 /* The size if less than sizeof(struct landlock_attr_enforce). */ 36 ASSERT_EQ(EINVAL, errno); 37 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 1, 0)); 38 ASSERT_EQ(EINVAL, errno); 39 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 7, 0)); 40 ASSERT_EQ(EINVAL, errno); 41 42 ASSERT_EQ(-1, landlock_create_ruleset(NULL, 1, 0)); 43 /* The size if less than sizeof(struct landlock_attr_enforce). */ 44 ASSERT_EQ(EFAULT, errno); 45 46 ASSERT_EQ(-1, landlock_create_ruleset( 47 NULL, sizeof(struct landlock_ruleset_attr), 0)); 48 ASSERT_EQ(EFAULT, errno); 49 50 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0)); 51 ASSERT_EQ(E2BIG, errno); 52 53 /* Checks minimal valid attribute size. */ 54 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 8, 0)); 55 ASSERT_EQ(ENOMSG, errno); 56 ASSERT_EQ(-1, landlock_create_ruleset( 57 ruleset_attr, 58 sizeof(struct landlock_ruleset_attr), 0)); 59 ASSERT_EQ(ENOMSG, errno); 60 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0)); 61 ASSERT_EQ(ENOMSG, errno); 62 63 /* Checks non-zero value. */ 64 buf[page_size - 2] = '.'; 65 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0)); 66 ASSERT_EQ(E2BIG, errno); 67 68 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0)); 69 ASSERT_EQ(E2BIG, errno); 70 71 free(buf); 72 } 73 74 TEST(abi_version) 75 { 76 const struct landlock_ruleset_attr ruleset_attr = { 77 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 78 }; 79 ASSERT_EQ(3, landlock_create_ruleset(NULL, 0, 80 LANDLOCK_CREATE_RULESET_VERSION)); 81 82 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, 83 LANDLOCK_CREATE_RULESET_VERSION)); 84 ASSERT_EQ(EINVAL, errno); 85 86 ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr), 87 LANDLOCK_CREATE_RULESET_VERSION)); 88 ASSERT_EQ(EINVAL, errno); 89 90 ASSERT_EQ(-1, 91 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 92 LANDLOCK_CREATE_RULESET_VERSION)); 93 ASSERT_EQ(EINVAL, errno); 94 95 ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, 96 LANDLOCK_CREATE_RULESET_VERSION | 97 1 << 31)); 98 ASSERT_EQ(EINVAL, errno); 99 } 100 101 /* Tests ordering of syscall argument checks. */ 102 TEST(create_ruleset_checks_ordering) 103 { 104 const int last_flag = LANDLOCK_CREATE_RULESET_VERSION; 105 const int invalid_flag = last_flag << 1; 106 int ruleset_fd; 107 const struct landlock_ruleset_attr ruleset_attr = { 108 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 109 }; 110 111 /* Checks priority for invalid flags. */ 112 ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, invalid_flag)); 113 ASSERT_EQ(EINVAL, errno); 114 115 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, invalid_flag)); 116 ASSERT_EQ(EINVAL, errno); 117 118 ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr), 119 invalid_flag)); 120 ASSERT_EQ(EINVAL, errno); 121 122 ASSERT_EQ(-1, 123 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 124 invalid_flag)); 125 ASSERT_EQ(EINVAL, errno); 126 127 /* Checks too big ruleset_attr size. */ 128 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, -1, 0)); 129 ASSERT_EQ(E2BIG, errno); 130 131 /* Checks too small ruleset_attr size. */ 132 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, 0)); 133 ASSERT_EQ(EINVAL, errno); 134 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 1, 0)); 135 ASSERT_EQ(EINVAL, errno); 136 137 /* Checks valid call. */ 138 ruleset_fd = 139 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 140 ASSERT_LE(0, ruleset_fd); 141 ASSERT_EQ(0, close(ruleset_fd)); 142 } 143 144 /* Tests ordering of syscall argument checks. */ 145 TEST(add_rule_checks_ordering) 146 { 147 const struct landlock_ruleset_attr ruleset_attr = { 148 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE, 149 }; 150 struct landlock_path_beneath_attr path_beneath_attr = { 151 .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE, 152 .parent_fd = -1, 153 }; 154 const int ruleset_fd = 155 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 156 157 ASSERT_LE(0, ruleset_fd); 158 159 /* Checks invalid flags. */ 160 ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1)); 161 ASSERT_EQ(EINVAL, errno); 162 163 /* Checks invalid ruleset FD. */ 164 ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 0)); 165 ASSERT_EQ(EBADF, errno); 166 167 /* Checks invalid rule type. */ 168 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, 0, NULL, 0)); 169 ASSERT_EQ(EINVAL, errno); 170 171 /* Checks invalid rule attr. */ 172 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 173 NULL, 0)); 174 ASSERT_EQ(EFAULT, errno); 175 176 /* Checks invalid path_beneath.parent_fd. */ 177 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 178 &path_beneath_attr, 0)); 179 ASSERT_EQ(EBADF, errno); 180 181 /* Checks valid call. */ 182 path_beneath_attr.parent_fd = 183 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); 184 ASSERT_LE(0, path_beneath_attr.parent_fd); 185 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 186 &path_beneath_attr, 0)); 187 ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); 188 ASSERT_EQ(0, close(ruleset_fd)); 189 } 190 191 /* Tests ordering of syscall argument and permission checks. */ 192 TEST(restrict_self_checks_ordering) 193 { 194 const struct landlock_ruleset_attr ruleset_attr = { 195 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE, 196 }; 197 struct landlock_path_beneath_attr path_beneath_attr = { 198 .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE, 199 .parent_fd = -1, 200 }; 201 const int ruleset_fd = 202 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 203 204 ASSERT_LE(0, ruleset_fd); 205 path_beneath_attr.parent_fd = 206 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); 207 ASSERT_LE(0, path_beneath_attr.parent_fd); 208 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 209 &path_beneath_attr, 0)); 210 ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); 211 212 /* Checks unprivileged enforcement without no_new_privs. */ 213 drop_caps(_metadata); 214 ASSERT_EQ(-1, landlock_restrict_self(-1, -1)); 215 ASSERT_EQ(EPERM, errno); 216 ASSERT_EQ(-1, landlock_restrict_self(-1, 0)); 217 ASSERT_EQ(EPERM, errno); 218 ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0)); 219 ASSERT_EQ(EPERM, errno); 220 221 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 222 223 /* Checks invalid flags. */ 224 ASSERT_EQ(-1, landlock_restrict_self(-1, -1)); 225 ASSERT_EQ(EINVAL, errno); 226 227 /* Checks invalid ruleset FD. */ 228 ASSERT_EQ(-1, landlock_restrict_self(-1, 0)); 229 ASSERT_EQ(EBADF, errno); 230 231 /* Checks valid call. */ 232 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 233 ASSERT_EQ(0, close(ruleset_fd)); 234 } 235 236 TEST(ruleset_fd_io) 237 { 238 struct landlock_ruleset_attr ruleset_attr = { 239 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 240 }; 241 int ruleset_fd; 242 char buf; 243 244 drop_caps(_metadata); 245 ruleset_fd = 246 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 247 ASSERT_LE(0, ruleset_fd); 248 249 ASSERT_EQ(-1, write(ruleset_fd, ".", 1)); 250 ASSERT_EQ(EINVAL, errno); 251 ASSERT_EQ(-1, read(ruleset_fd, &buf, 1)); 252 ASSERT_EQ(EINVAL, errno); 253 254 ASSERT_EQ(0, close(ruleset_fd)); 255 } 256 257 /* Tests enforcement of a ruleset FD transferred through a UNIX socket. */ 258 TEST(ruleset_fd_transfer) 259 { 260 struct landlock_ruleset_attr ruleset_attr = { 261 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR, 262 }; 263 struct landlock_path_beneath_attr path_beneath_attr = { 264 .allowed_access = LANDLOCK_ACCESS_FS_READ_DIR, 265 }; 266 int ruleset_fd_tx, dir_fd; 267 int socket_fds[2]; 268 pid_t child; 269 int status; 270 271 drop_caps(_metadata); 272 273 /* Creates a test ruleset with a simple rule. */ 274 ruleset_fd_tx = 275 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 276 ASSERT_LE(0, ruleset_fd_tx); 277 path_beneath_attr.parent_fd = 278 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); 279 ASSERT_LE(0, path_beneath_attr.parent_fd); 280 ASSERT_EQ(0, 281 landlock_add_rule(ruleset_fd_tx, LANDLOCK_RULE_PATH_BENEATH, 282 &path_beneath_attr, 0)); 283 ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); 284 285 /* Sends the ruleset FD over a socketpair and then close it. */ 286 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, 287 socket_fds)); 288 ASSERT_EQ(0, send_fd(socket_fds[0], ruleset_fd_tx)); 289 ASSERT_EQ(0, close(socket_fds[0])); 290 ASSERT_EQ(0, close(ruleset_fd_tx)); 291 292 child = fork(); 293 ASSERT_LE(0, child); 294 if (child == 0) { 295 const int ruleset_fd_rx = recv_fd(socket_fds[1]); 296 297 ASSERT_LE(0, ruleset_fd_rx); 298 ASSERT_EQ(0, close(socket_fds[1])); 299 300 /* Enforces the received ruleset on the child. */ 301 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 302 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd_rx, 0)); 303 ASSERT_EQ(0, close(ruleset_fd_rx)); 304 305 /* Checks that the ruleset enforcement. */ 306 ASSERT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)); 307 ASSERT_EQ(EACCES, errno); 308 dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC); 309 ASSERT_LE(0, dir_fd); 310 ASSERT_EQ(0, close(dir_fd)); 311 _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); 312 return; 313 } 314 315 ASSERT_EQ(0, close(socket_fds[1])); 316 317 /* Checks that the parent is unrestricted. */ 318 dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); 319 ASSERT_LE(0, dir_fd); 320 ASSERT_EQ(0, close(dir_fd)); 321 dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC); 322 ASSERT_LE(0, dir_fd); 323 ASSERT_EQ(0, close(dir_fd)); 324 325 ASSERT_EQ(child, waitpid(child, &status, 0)); 326 ASSERT_EQ(1, WIFEXITED(status)); 327 ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 328 } 329 330 TEST(cred_transfer) 331 { 332 struct landlock_ruleset_attr ruleset_attr = { 333 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR, 334 }; 335 int ruleset_fd, dir_fd; 336 pid_t child; 337 int status; 338 339 drop_caps(_metadata); 340 341 dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); 342 EXPECT_LE(0, dir_fd); 343 EXPECT_EQ(0, close(dir_fd)); 344 345 /* Denies opening directories. */ 346 ruleset_fd = 347 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 348 ASSERT_LE(0, ruleset_fd); 349 EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 350 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 351 EXPECT_EQ(0, close(ruleset_fd)); 352 353 /* Checks ruleset enforcement. */ 354 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)); 355 EXPECT_EQ(EACCES, errno); 356 357 /* Needed for KEYCTL_SESSION_TO_PARENT permission checks */ 358 EXPECT_NE(-1, syscall(__NR_keyctl, KEYCTL_JOIN_SESSION_KEYRING, NULL, 0, 359 0, 0)) 360 { 361 TH_LOG("Failed to join session keyring: %s", strerror(errno)); 362 } 363 364 child = fork(); 365 ASSERT_LE(0, child); 366 if (child == 0) { 367 /* Checks ruleset enforcement. */ 368 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)); 369 EXPECT_EQ(EACCES, errno); 370 371 /* 372 * KEYCTL_SESSION_TO_PARENT is a no-op unless we have a 373 * different session keyring in the child, so make that happen. 374 */ 375 EXPECT_NE(-1, syscall(__NR_keyctl, KEYCTL_JOIN_SESSION_KEYRING, 376 NULL, 0, 0, 0)); 377 378 /* 379 * KEYCTL_SESSION_TO_PARENT installs credentials on the parent 380 * that never go through the cred_prepare hook, this path uses 381 * cred_transfer instead. 382 */ 383 EXPECT_EQ(0, syscall(__NR_keyctl, KEYCTL_SESSION_TO_PARENT, 0, 384 0, 0, 0)); 385 386 /* Re-checks ruleset enforcement. */ 387 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)); 388 EXPECT_EQ(EACCES, errno); 389 390 _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); 391 return; 392 } 393 394 EXPECT_EQ(child, waitpid(child, &status, 0)); 395 EXPECT_EQ(1, WIFEXITED(status)); 396 EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 397 398 /* Re-checks ruleset enforcement. */ 399 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)); 400 EXPECT_EQ(EACCES, errno); 401 } 402 403 TEST_HARNESS_MAIN 404