1 // SPDX-License-Identifier: BSD-3-Clause 2 /* 3 * Simple Landlock sandbox manager able to execute a process restricted by 4 * user-defined file system and network access control policies. 5 * 6 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net> 7 * Copyright © 2020 ANSSI 8 */ 9 10 #define _GNU_SOURCE 11 #define __SANE_USERSPACE_TYPES__ 12 #include <arpa/inet.h> 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <limits.h> 16 #include <linux/landlock.h> 17 #include <linux/sched.h> 18 #include <linux/socket.h> 19 #include <stdbool.h> 20 #include <stddef.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <sys/prctl.h> 25 #include <sys/stat.h> 26 #include <sys/syscall.h> 27 #include <unistd.h> 28 29 #ifdef USE_LIBCAP 30 #include <sys/capability.h> 31 #endif 32 33 #if defined(__GLIBC__) 34 #include <linux/prctl.h> 35 #endif 36 37 #ifndef landlock_create_ruleset 38 static inline int 39 landlock_create_ruleset(const struct landlock_ruleset_attr *const attr, 40 const size_t size, const __u32 flags) 41 { 42 return syscall(__NR_landlock_create_ruleset, attr, size, flags); 43 } 44 #endif 45 46 #ifndef landlock_add_rule 47 static inline int landlock_add_rule(const int ruleset_fd, 48 const enum landlock_rule_type rule_type, 49 const void *const rule_attr, 50 const __u32 flags) 51 { 52 return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, 53 flags); 54 } 55 #endif 56 57 #ifndef landlock_restrict_self 58 static inline int landlock_restrict_self(const int ruleset_fd, 59 const __u32 flags) 60 { 61 return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); 62 } 63 #endif 64 65 #define ENV_FS_RO_NAME "LL_FS_RO" 66 #define ENV_FS_RW_NAME "LL_FS_RW" 67 #define ENV_FS_QUIET_NAME "LL_FS_QUIET" 68 #define ENV_TCP_BIND_NAME "LL_TCP_BIND" 69 #define ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT" 70 #define ENV_NET_QUIET_NAME "LL_NET_QUIET" 71 #define ENV_NS_NAME "LL_NS" 72 #define ENV_NS_QUIET_NAME "LL_NS_QUIET" 73 #define ENV_CAP_NAME "LL_CAP" 74 #define ENV_CAP_QUIET_NAME "LL_CAP_QUIET" 75 #define ENV_SCOPED_NAME "LL_SCOPED" 76 #define ENV_QUIET_ACCESS_NAME "LL_QUIET_ACCESS" 77 #define ENV_FORCE_LOG_NAME "LL_FORCE_LOG" 78 #define ENV_UDP_BIND_NAME "LL_UDP_BIND" 79 #define ENV_UDP_CONNECT_SEND_NAME "LL_UDP_CONNECT_SEND" 80 #define ENV_DELIMITER ":" 81 82 #ifdef USE_LIBCAP 83 #define CAP_VALUE_DESCRIPTION "names or numbers" 84 #define CAP_VALUE_EXAMPLES "cap_net_bind_service, cap_sys_admin, 18" 85 #define CAP_VALUE_EXAMPLE "cap_sys_admin" 86 #else 87 #define CAP_VALUE_DESCRIPTION "numbers" 88 #define CAP_VALUE_EXAMPLES "10, 18, 21" 89 #define CAP_VALUE_EXAMPLE "21" 90 #endif 91 92 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) 93 94 static int str2num(const char *numstr, __u64 *num_dst) 95 { 96 char *endptr = NULL; 97 int err = 0; 98 __u64 num; 99 100 errno = 0; 101 num = strtoull(numstr, &endptr, 10); 102 if (errno != 0) 103 err = errno; 104 /* Was the string empty, or not entirely parsed successfully? */ 105 else if ((*numstr == '\0') || (*endptr != '\0')) 106 err = EINVAL; 107 else 108 *num_dst = num; 109 110 return err; 111 } 112 113 static int parse_path(char *env_path, const char ***const path_list) 114 { 115 int i, num_paths = 0; 116 117 if (env_path) { 118 num_paths++; 119 for (i = 0; env_path[i]; i++) { 120 if (env_path[i] == ENV_DELIMITER[0]) 121 num_paths++; 122 } 123 } 124 *path_list = malloc(num_paths * sizeof(**path_list)); 125 if (!*path_list) 126 return -1; 127 128 for (i = 0; i < num_paths; i++) 129 (*path_list)[i] = strsep(&env_path, ENV_DELIMITER); 130 131 return num_paths; 132 } 133 134 /* clang-format off */ 135 136 #define ACCESS_FILE ( \ 137 LANDLOCK_ACCESS_FS_EXECUTE | \ 138 LANDLOCK_ACCESS_FS_WRITE_FILE | \ 139 LANDLOCK_ACCESS_FS_READ_FILE | \ 140 LANDLOCK_ACCESS_FS_TRUNCATE | \ 141 LANDLOCK_ACCESS_FS_IOCTL_DEV | \ 142 LANDLOCK_ACCESS_FS_RESOLVE_UNIX) 143 144 /* clang-format on */ 145 146 static int populate_ruleset_fs(const char *const env_var, const int ruleset_fd, 147 const __u64 allowed_access, __u32 flags) 148 { 149 int num_paths, i, ret = 1; 150 char *env_path_name; 151 const char **path_list = NULL; 152 struct landlock_path_beneath_attr path_beneath = { 153 .parent_fd = -1, 154 }; 155 156 env_path_name = getenv(env_var); 157 if (!env_path_name) { 158 /* Prevents users to forget a setting. */ 159 fprintf(stderr, "Missing environment variable %s\n", env_var); 160 return 1; 161 } 162 env_path_name = strdup(env_path_name); 163 unsetenv(env_var); 164 num_paths = parse_path(env_path_name, &path_list); 165 if (num_paths < 0) { 166 fprintf(stderr, "Failed to allocate memory\n"); 167 goto out_free_name; 168 } 169 if (num_paths == 1 && path_list[0][0] == '\0') { 170 /* 171 * Allows to not use all possible restrictions (e.g. use 172 * LL_FS_RO without LL_FS_RW). 173 */ 174 ret = 0; 175 goto out_free_name; 176 } 177 178 for (i = 0; i < num_paths; i++) { 179 struct stat statbuf; 180 181 path_beneath.parent_fd = open(path_list[i], O_PATH | O_CLOEXEC); 182 if (path_beneath.parent_fd < 0) { 183 fprintf(stderr, "Failed to open \"%s\": %s\n", 184 path_list[i], strerror(errno)); 185 continue; 186 } 187 if (fstat(path_beneath.parent_fd, &statbuf)) { 188 fprintf(stderr, "Failed to stat \"%s\": %s\n", 189 path_list[i], strerror(errno)); 190 close(path_beneath.parent_fd); 191 goto out_free_name; 192 } 193 path_beneath.allowed_access = allowed_access; 194 if (!S_ISDIR(statbuf.st_mode)) 195 path_beneath.allowed_access &= ACCESS_FILE; 196 if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 197 &path_beneath, flags)) { 198 fprintf(stderr, 199 "Failed to update the ruleset with \"%s\": %s\n", 200 path_list[i], strerror(errno)); 201 close(path_beneath.parent_fd); 202 goto out_free_name; 203 } 204 close(path_beneath.parent_fd); 205 } 206 ret = 0; 207 208 out_free_name: 209 free(path_list); 210 free(env_path_name); 211 return ret; 212 } 213 214 static int populate_ruleset_net(const char *const env_var, const int ruleset_fd, 215 const __u64 allowed_access, __u32 flags) 216 { 217 int ret = 1; 218 char *env_port_name, *env_port_name_next, *strport; 219 struct landlock_net_port_attr net_port = { 220 .allowed_access = allowed_access, 221 }; 222 223 env_port_name = getenv(env_var); 224 if (!env_port_name) 225 return 0; 226 env_port_name = strdup(env_port_name); 227 unsetenv(env_var); 228 229 env_port_name_next = env_port_name; 230 while ((strport = strsep(&env_port_name_next, ENV_DELIMITER))) { 231 __u64 port; 232 233 if (strcmp(strport, "") == 0) 234 continue; 235 236 if (str2num(strport, &port)) { 237 fprintf(stderr, "Failed to parse port at \"%s\"\n", 238 strport); 239 goto out_free_name; 240 } 241 net_port.port = port; 242 if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 243 &net_port, flags)) { 244 fprintf(stderr, 245 "Failed to update the ruleset with port \"%llu\": %s\n", 246 net_port.port, strerror(errno)); 247 goto out_free_name; 248 } 249 } 250 ret = 0; 251 252 out_free_name: 253 free(env_port_name); 254 return ret; 255 } 256 257 static __u64 str2ns(const char *const name) 258 { 259 static const struct { 260 const char *name; 261 __u64 value; 262 } ns_map[] = { 263 /* clang-format off */ 264 { "cgroup", CLONE_NEWCGROUP }, 265 { "ipc", CLONE_NEWIPC }, 266 { "mnt", CLONE_NEWNS }, 267 { "net", CLONE_NEWNET }, 268 { "pid", CLONE_NEWPID }, 269 { "time", CLONE_NEWTIME }, 270 { "user", CLONE_NEWUSER }, 271 { "uts", CLONE_NEWUTS }, 272 /* clang-format on */ 273 }; 274 size_t i; 275 276 for (i = 0; i < ARRAY_SIZE(ns_map); i++) { 277 if (strcmp(name, ns_map[i].name) == 0) 278 return ns_map[i].value; 279 } 280 return 0; 281 } 282 283 /* 284 * Parses a colon-delimited list of namespace type names into a bitmask. 285 * Returns 0 on success (mask 0 when the variable is unset or empty), or 1 on a 286 * parse error. 287 */ 288 static int parse_ns_list(const char *const env_var, __u64 *const mask) 289 { 290 int ret = 1; 291 char *env_ns_name, *env_ns_name_next, *strns; 292 293 *mask = 0; 294 env_ns_name = getenv(env_var); 295 if (!env_ns_name) 296 return 0; 297 env_ns_name = strdup(env_ns_name); 298 unsetenv(env_var); 299 300 env_ns_name_next = env_ns_name; 301 while ((strns = strsep(&env_ns_name_next, ENV_DELIMITER))) { 302 __u64 ns_type; 303 304 if (strcmp(strns, "") == 0) 305 continue; 306 307 ns_type = str2ns(strns); 308 if (!ns_type) { 309 fprintf(stderr, "Unknown namespace type \"%s\"\n", 310 strns); 311 goto out_free_name; 312 } 313 *mask |= ns_type; 314 } 315 ret = 0; 316 317 out_free_name: 318 free(env_ns_name); 319 return ret; 320 } 321 322 static int populate_ruleset_ns(const char *const allowed_env, 323 const char *const quiet_env, 324 const int ruleset_fd) 325 { 326 struct landlock_namespace_attr ns_attr = { 327 .permissions = LANDLOCK_PERMISSION_NAMESPACE_USE, 328 }; 329 330 if (parse_ns_list(allowed_env, &ns_attr.allowed_namespace_types)) 331 return 1; 332 if (parse_ns_list(quiet_env, &ns_attr.quiet_namespace_types)) 333 return 1; 334 335 if (!ns_attr.allowed_namespace_types && !ns_attr.quiet_namespace_types) 336 return 0; 337 338 if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NAMESPACE, &ns_attr, 339 0)) { 340 fprintf(stderr, 341 "Failed to update the ruleset with namespace types: %s\n", 342 strerror(errno)); 343 return 1; 344 } 345 return 0; 346 } 347 348 static int str2cap(const char *const strcap, __u64 *const cap) 349 { 350 #ifdef USE_LIBCAP 351 cap_value_t value; 352 #endif 353 354 if (!str2num(strcap, cap)) 355 return 0; 356 357 #ifdef USE_LIBCAP 358 if (cap_from_name(strcap, &value)) 359 return 1; 360 *cap = value; 361 return 0; 362 #else 363 return 1; 364 #endif 365 } 366 367 /* 368 * Parses a colon-delimited list of capability values into a bitmask. Returns 0 369 * on success (mask 0 when the variable is unset or empty), or 1 on a parse 370 * error. 371 */ 372 static int parse_cap_list(const char *const env_var, __u64 *const mask) 373 { 374 int ret = 1; 375 char *env_cap_name, *env_cap_name_next, *strcap; 376 377 *mask = 0; 378 env_cap_name = getenv(env_var); 379 if (!env_cap_name) 380 return 0; 381 env_cap_name = strdup(env_cap_name); 382 unsetenv(env_var); 383 384 env_cap_name_next = env_cap_name; 385 while ((strcap = strsep(&env_cap_name_next, ENV_DELIMITER))) { 386 __u64 cap; 387 388 if (strcmp(strcap, "") == 0) 389 continue; 390 391 if (str2cap(strcap, &cap)) { 392 fprintf(stderr, "Failed to parse capability \"%s\"\n", 393 strcap); 394 goto out_free_name; 395 } 396 if (cap >= sizeof(*mask) * CHAR_BIT) { 397 fprintf(stderr, "Capability \"%s\" is out of range\n", 398 strcap); 399 goto out_free_name; 400 } 401 *mask |= 1ULL << cap; 402 } 403 ret = 0; 404 405 out_free_name: 406 free(env_cap_name); 407 return ret; 408 } 409 410 static int populate_ruleset_cap(const char *const allowed_env, 411 const char *const quiet_env, 412 const int ruleset_fd) 413 { 414 struct landlock_capability_attr cap_attr = { 415 .permissions = LANDLOCK_PERMISSION_CAPABILITY_USE, 416 }; 417 418 if (parse_cap_list(allowed_env, &cap_attr.allowed_capabilities)) 419 return 1; 420 if (parse_cap_list(quiet_env, &cap_attr.quiet_capabilities)) 421 return 1; 422 423 if (!cap_attr.allowed_capabilities && !cap_attr.quiet_capabilities) 424 return 0; 425 426 if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_CAPABILITY, &cap_attr, 427 0)) { 428 fprintf(stderr, 429 "Failed to update the ruleset with capabilities: %s\n", 430 strerror(errno)); 431 return 1; 432 } 433 return 0; 434 } 435 436 /* Returns true on error, false otherwise. */ 437 static bool check_ruleset_scope(const char *const env_var, 438 struct landlock_ruleset_attr *ruleset_attr) 439 { 440 char *env_type_scope, *env_type_scope_next, *ipc_scoping_name; 441 bool error = false; 442 bool abstract_scoping = false; 443 bool signal_scoping = false; 444 445 /* Scoping is not supported by Landlock ABI */ 446 if (!(ruleset_attr->scoped & 447 (LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | LANDLOCK_SCOPE_SIGNAL))) 448 goto out_unset; 449 450 env_type_scope = getenv(env_var); 451 /* Scoping is not supported by the user */ 452 if (!env_type_scope || strcmp("", env_type_scope) == 0) 453 goto out_unset; 454 455 env_type_scope = strdup(env_type_scope); 456 env_type_scope_next = env_type_scope; 457 while ((ipc_scoping_name = 458 strsep(&env_type_scope_next, ENV_DELIMITER))) { 459 if (strcmp("a", ipc_scoping_name) == 0 && !abstract_scoping) { 460 abstract_scoping = true; 461 } else if (strcmp("s", ipc_scoping_name) == 0 && 462 !signal_scoping) { 463 signal_scoping = true; 464 } else { 465 fprintf(stderr, "Unknown or duplicate scope \"%s\"\n", 466 ipc_scoping_name); 467 error = true; 468 goto out_free_name; 469 } 470 } 471 472 out_free_name: 473 free(env_type_scope); 474 475 out_unset: 476 if (!abstract_scoping) 477 ruleset_attr->scoped &= ~LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET; 478 if (!signal_scoping) 479 ruleset_attr->scoped &= ~LANDLOCK_SCOPE_SIGNAL; 480 481 unsetenv(env_var); 482 return error; 483 } 484 485 /* clang-format off */ 486 487 #define ACCESS_FS_ROUGHLY_READ ( \ 488 LANDLOCK_ACCESS_FS_EXECUTE | \ 489 LANDLOCK_ACCESS_FS_READ_FILE | \ 490 LANDLOCK_ACCESS_FS_READ_DIR) 491 492 #define ACCESS_FS_ROUGHLY_WRITE ( \ 493 LANDLOCK_ACCESS_FS_WRITE_FILE | \ 494 LANDLOCK_ACCESS_FS_REMOVE_DIR | \ 495 LANDLOCK_ACCESS_FS_REMOVE_FILE | \ 496 LANDLOCK_ACCESS_FS_MAKE_CHAR | \ 497 LANDLOCK_ACCESS_FS_MAKE_DIR | \ 498 LANDLOCK_ACCESS_FS_MAKE_REG | \ 499 LANDLOCK_ACCESS_FS_MAKE_SOCK | \ 500 LANDLOCK_ACCESS_FS_MAKE_FIFO | \ 501 LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ 502 LANDLOCK_ACCESS_FS_MAKE_SYM | \ 503 LANDLOCK_ACCESS_FS_REFER | \ 504 LANDLOCK_ACCESS_FS_TRUNCATE | \ 505 LANDLOCK_ACCESS_FS_IOCTL_DEV | \ 506 LANDLOCK_ACCESS_FS_RESOLVE_UNIX) 507 508 /* clang-format on */ 509 510 /* 511 * Parses ENV_QUIET_ACCESS_NAME and sets the quiet_access_fs, quiet_access_net 512 * and quiet_scoped masks of @ruleset_attr accordingly. 513 */ 514 static int add_quiet_access(const char *const env_var, 515 struct landlock_ruleset_attr *const ruleset_attr) 516 { 517 char *env_quiet_access, *env_quiet_access_next, *str_access; 518 519 env_quiet_access = getenv(env_var); 520 if (!env_quiet_access) 521 return 0; 522 523 env_quiet_access = strdup(env_quiet_access); 524 env_quiet_access_next = env_quiet_access; 525 unsetenv(env_var); 526 527 while ((str_access = strsep(&env_quiet_access_next, ENV_DELIMITER))) { 528 if (strcmp(str_access, "") == 0) 529 continue; 530 else if (strcmp(str_access, "all") == 0) { 531 ruleset_attr->quiet_access_fs = 532 ruleset_attr->handled_access_fs; 533 ruleset_attr->quiet_access_net = 534 ruleset_attr->handled_access_net; 535 ruleset_attr->quiet_scoped = ruleset_attr->scoped; 536 } else if (strcmp(str_access, "read") == 0) 537 ruleset_attr->quiet_access_fs |= ACCESS_FS_ROUGHLY_READ; 538 else if (strcmp(str_access, "write") == 0) 539 ruleset_attr->quiet_access_fs |= 540 ACCESS_FS_ROUGHLY_WRITE; 541 else if (strcmp(str_access, "tcp_bind") == 0) 542 ruleset_attr->quiet_access_net |= 543 LANDLOCK_ACCESS_NET_BIND_TCP; 544 else if (strcmp(str_access, "tcp_connect") == 0) 545 ruleset_attr->quiet_access_net |= 546 LANDLOCK_ACCESS_NET_CONNECT_TCP; 547 else if (strcmp(str_access, "udp_bind") == 0) 548 ruleset_attr->quiet_access_net |= 549 LANDLOCK_ACCESS_NET_BIND_UDP; 550 else if (strcmp(str_access, "udp_connect") == 0) 551 ruleset_attr->quiet_access_net |= 552 LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP; 553 else if (strcmp(str_access, "abstract_unix_socket") == 0) 554 ruleset_attr->quiet_scoped |= 555 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET; 556 else if (strcmp(str_access, "signal") == 0) 557 ruleset_attr->quiet_scoped |= LANDLOCK_SCOPE_SIGNAL; 558 else { 559 fprintf(stderr, "Unknown quiet access \"%s\"\n", 560 str_access); 561 free(env_quiet_access); 562 return -1; 563 } 564 } 565 566 free(env_quiet_access); 567 ruleset_attr->quiet_access_fs &= ruleset_attr->handled_access_fs; 568 ruleset_attr->quiet_access_net &= ruleset_attr->handled_access_net; 569 ruleset_attr->quiet_scoped &= ruleset_attr->scoped; 570 return 0; 571 } 572 573 #define LANDLOCK_ABI_LAST 12 574 575 #define XSTR(s) #s 576 #define STR(s) XSTR(s) 577 578 /* clang-format off */ 579 580 static const char help[] = 581 "usage: " ENV_FS_RO_NAME "=\"...\" " ENV_FS_RW_NAME "=\"...\" " 582 "[other environment variables] %1$s <cmd> [args]...\n" 583 "\n" 584 "Execute the given command in a restricted environment.\n" 585 "Multi-valued settings (lists of ports, paths, scopes) are colon-delimited.\n" 586 "\n" 587 "Mandatory settings:\n" 588 "* " ENV_FS_RO_NAME ": paths allowed to be used in a read-only way\n" 589 "* " ENV_FS_RW_NAME ": paths allowed to be used in a read-write way\n" 590 "\n" 591 "Optional settings (when not set, their associated access check " 592 "is always allowed, which is different from an empty string which " 593 "means an empty list):\n" 594 "* " ENV_TCP_BIND_NAME ": ports allowed to bind (server)\n" 595 "* " ENV_TCP_CONNECT_NAME ": ports allowed to connect (client)\n" 596 "* " ENV_UDP_BIND_NAME ": local UDP ports allowed to bind (server: " 597 "prepare to receive on port / client: set as source port)\n" 598 "* " ENV_UDP_CONNECT_SEND_NAME ": remote UDP ports allowed to connect " 599 "or send to (client: use as destination port / server: receive only from it)\n" 600 "(caution: sending requires being able to bind to a local source port)\n" 601 "* " ENV_NS_NAME ": namespace types allowed to use\n" 602 " (cgroup, ipc, mnt, net, pid, time, user, uts)\n" 603 "* " ENV_NS_QUIET_NAME 604 ": namespace types whose denial should not be audit logged\n" 605 " (same value format as " ENV_NS_NAME 606 "; quieting an allowed member is inert,\n" 607 " as an allowed member is never denied; setting it alone still\n" 608 " restricts namespace use, denying every type)\n" 609 "* " ENV_CAP_NAME ": capabilities allowed to use, as " 610 CAP_VALUE_DESCRIPTION "\n" 611 " (e.g. " CAP_VALUE_EXAMPLES ")\n" 612 "* " ENV_CAP_QUIET_NAME 613 ": capabilities whose denial should not be audit logged\n" 614 " (same value format as " ENV_CAP_NAME 615 "; quieting an allowed member is inert,\n" 616 " as an allowed member is never denied; setting it alone still\n" 617 " restricts capability use, denying every capability)\n" 618 "* " ENV_SCOPED_NAME ": actions denied on the outside of the landlock domain\n" 619 " - \"a\" to restrict opening abstract unix sockets\n" 620 " - \"s\" to restrict sending signals\n" 621 "\n" 622 "A sandboxer should not log denied access requests to avoid spamming logs, " 623 "but to test audit we can set " ENV_FORCE_LOG_NAME "=1\n" 624 ENV_FS_QUIET_NAME " and " ENV_NET_QUIET_NAME ", both optional, can then be used " 625 "to make access to some denied paths or network ports not trigger audit logging.\n" 626 ENV_QUIET_ACCESS_NAME " can be used to specify which accesses should be quieted " 627 "(required when " ENV_FS_QUIET_NAME " or " ENV_NET_QUIET_NAME " is set):\n" 628 " - \"all\" to quiet all of the accesses below\n" 629 " - \"read\" to quiet all file/dir read accesses\n" 630 " - \"write\" to quiet all file/dir write accesses\n" 631 " - \"tcp_bind\" to quiet tcp bind denials\n" 632 " - \"tcp_connect\" to quiet tcp connect denials\n" 633 " - \"udp_bind\" to quiet udp bind denials\n" 634 " - \"udp_connect\" to quiet udp connect / send denials\n" 635 " - \"abstract_unix_socket\" to quiet abstract unix socket denials\n" 636 " - \"signal\" to quiet signal denials\n" 637 "\n" 638 "Example:\n" 639 ENV_FS_RO_NAME "=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" " 640 ENV_FS_RW_NAME "=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" " 641 ENV_TCP_BIND_NAME "=\"9418\" " 642 ENV_TCP_CONNECT_NAME "=\"80:443\" " 643 ENV_UDP_CONNECT_SEND_NAME "=\"53\" " 644 ENV_NS_NAME "=\"user:uts:net\" " 645 ENV_CAP_NAME "=\"" CAP_VALUE_EXAMPLE "\" " 646 ENV_SCOPED_NAME "=\"a:s\" " 647 "%1$s bash -i\n" 648 "\n" 649 "This sandboxer can use Landlock features up to ABI version " 650 STR(LANDLOCK_ABI_LAST) ".\n"; 651 652 /* clang-format on */ 653 654 int main(const int argc, char *const argv[], char *const *const envp) 655 { 656 const char *cmd_path; 657 char *const *cmd_argv; 658 int ruleset_fd, abi; 659 char *env_port_name, *env_force_log; 660 __u64 access_fs_ro = ACCESS_FS_ROUGHLY_READ, 661 access_fs_rw = ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_WRITE; 662 663 struct landlock_ruleset_attr ruleset_attr = { 664 .handled_access_fs = access_fs_rw, 665 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 666 LANDLOCK_ACCESS_NET_CONNECT_TCP | 667 LANDLOCK_ACCESS_NET_BIND_UDP | 668 LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP, 669 .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | 670 LANDLOCK_SCOPE_SIGNAL, 671 .quiet_access_fs = 0, 672 .quiet_access_net = 0, 673 .quiet_scoped = 0, 674 .handled_permissions = LANDLOCK_PERMISSION_NAMESPACE_USE | 675 LANDLOCK_PERMISSION_CAPABILITY_USE, 676 }; 677 bool quiet_supported = true; 678 int supported_restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON | 679 LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS; 680 int set_restrict_flags = LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS; 681 682 if (argc < 2) { 683 fprintf(stderr, help, argv[0]); 684 return 1; 685 } 686 687 abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); 688 if (abi < 0) { 689 const int err = errno; 690 691 perror("Failed to check Landlock compatibility"); 692 switch (err) { 693 case ENOSYS: 694 fprintf(stderr, 695 "Hint: Landlock is not supported by the current kernel. " 696 "To support it, build the kernel with " 697 "CONFIG_SECURITY_LANDLOCK=y and prepend " 698 "\"landlock,\" to the content of CONFIG_LSM.\n"); 699 break; 700 case EOPNOTSUPP: 701 fprintf(stderr, 702 "Hint: Landlock is currently disabled. " 703 "It can be enabled in the kernel configuration by " 704 "prepending \"landlock,\" to the content of CONFIG_LSM, " 705 "or at boot time by setting the same content to the " 706 "\"lsm\" kernel parameter.\n"); 707 break; 708 } 709 return 1; 710 } 711 712 /* Best-effort security. */ 713 switch (abi) { 714 case 1: 715 /* 716 * Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 717 * 718 * Note: The "refer" operations (file renaming and linking 719 * across different directories) are always forbidden when using 720 * Landlock with ABI 1. 721 * 722 * If only ABI 1 is available, this sandboxer knowingly forbids 723 * refer operations. 724 * 725 * If a program *needs* to do refer operations after enabling 726 * Landlock, it can not use Landlock at ABI level 1. To be 727 * compatible with different kernel versions, such programs 728 * should then fall back to not restrict themselves at all if 729 * the running kernel only supports ABI 1. 730 */ 731 ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; 732 __attribute__((fallthrough)); 733 case 2: 734 /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */ 735 ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; 736 __attribute__((fallthrough)); 737 case 3: 738 /* Removes network support for ABI < 4 */ 739 ruleset_attr.handled_access_net &= 740 ~(LANDLOCK_ACCESS_NET_BIND_TCP | 741 LANDLOCK_ACCESS_NET_CONNECT_TCP); 742 __attribute__((fallthrough)); 743 case 4: 744 /* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */ 745 ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV; 746 747 __attribute__((fallthrough)); 748 case 5: 749 /* Removes LANDLOCK_SCOPE_* for ABI < 6 */ 750 ruleset_attr.scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | 751 LANDLOCK_SCOPE_SIGNAL); 752 __attribute__((fallthrough)); 753 case 6: 754 /* Removes LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON for ABI < 7 */ 755 supported_restrict_flags &= 756 ~LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON; 757 __attribute__((fallthrough)); 758 case 7: 759 case 8: 760 /* Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX for ABI < 9 */ 761 ruleset_attr.handled_access_fs &= 762 ~LANDLOCK_ACCESS_FS_RESOLVE_UNIX; 763 __attribute__((fallthrough)); 764 case 9: 765 /* Removes UDP support for ABI < 10 */ 766 ruleset_attr.handled_access_net &= 767 ~(LANDLOCK_ACCESS_NET_BIND_UDP | 768 LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP); 769 /* Removes quiet flags for ABI < 10 later on. */ 770 quiet_supported = false; 771 __attribute__((fallthrough)); 772 case 10: 773 /* Removes LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS for ABI < 11 */ 774 supported_restrict_flags &= 775 ~LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS; 776 set_restrict_flags &= ~LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS; 777 __attribute__((fallthrough)); 778 case 11: 779 /* Removes LANDLOCK_PERMISSION_* for ABI < 12 */ 780 ruleset_attr.handled_permissions &= 781 ~(LANDLOCK_PERMISSION_NAMESPACE_USE | 782 LANDLOCK_PERMISSION_CAPABILITY_USE); 783 /* Must be printed for any ABI < LANDLOCK_ABI_LAST. */ 784 fprintf(stderr, 785 "Hint: You should update the running kernel " 786 "to leverage Landlock features " 787 "provided by ABI version %d (instead of %d).\n", 788 LANDLOCK_ABI_LAST, abi); 789 __attribute__((fallthrough)); 790 case LANDLOCK_ABI_LAST: 791 break; 792 default: 793 fprintf(stderr, 794 "Hint: You should update this sandboxer " 795 "to leverage Landlock features " 796 "provided by ABI version %d (instead of %d).\n", 797 abi, LANDLOCK_ABI_LAST); 798 } 799 access_fs_ro &= ruleset_attr.handled_access_fs; 800 access_fs_rw &= ruleset_attr.handled_access_fs; 801 802 /* Removes bind access attribute if not supported by a user. */ 803 env_port_name = getenv(ENV_TCP_BIND_NAME); 804 if (!env_port_name) { 805 ruleset_attr.handled_access_net &= 806 ~LANDLOCK_ACCESS_NET_BIND_TCP; 807 } 808 /* Removes connect access attribute if not supported by a user. */ 809 env_port_name = getenv(ENV_TCP_CONNECT_NAME); 810 if (!env_port_name) { 811 ruleset_attr.handled_access_net &= 812 ~LANDLOCK_ACCESS_NET_CONNECT_TCP; 813 } 814 /* Removes UDP bind access control if not supported by a user. */ 815 env_port_name = getenv(ENV_UDP_BIND_NAME); 816 if (!env_port_name) { 817 ruleset_attr.handled_access_net &= 818 ~LANDLOCK_ACCESS_NET_BIND_UDP; 819 } 820 /* Removes UDP connect/send access control if not supported by a user. */ 821 env_port_name = getenv(ENV_UDP_CONNECT_SEND_NAME); 822 if (!env_port_name) { 823 ruleset_attr.handled_access_net &= 824 ~LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP; 825 } 826 827 /* Removes namespace handling if not set by a user. */ 828 if (!getenv(ENV_NS_NAME) && !getenv(ENV_NS_QUIET_NAME)) 829 ruleset_attr.handled_permissions &= 830 ~LANDLOCK_PERMISSION_NAMESPACE_USE; 831 if (!(ruleset_attr.handled_permissions & 832 LANDLOCK_PERMISSION_NAMESPACE_USE)) { 833 unsetenv(ENV_NS_NAME); 834 unsetenv(ENV_NS_QUIET_NAME); 835 } 836 837 #ifndef USE_LIBCAP 838 if (getenv(ENV_CAP_NAME) || getenv(ENV_CAP_QUIET_NAME)) 839 fprintf(stderr, 840 "Warning: Built without libcap; use capability numbers, not names.\n"); 841 #endif 842 843 /* Removes capability handling if not set by a user. */ 844 if (!getenv(ENV_CAP_NAME) && !getenv(ENV_CAP_QUIET_NAME)) 845 ruleset_attr.handled_permissions &= 846 ~LANDLOCK_PERMISSION_CAPABILITY_USE; 847 if (!(ruleset_attr.handled_permissions & 848 LANDLOCK_PERMISSION_CAPABILITY_USE)) { 849 unsetenv(ENV_CAP_NAME); 850 unsetenv(ENV_CAP_QUIET_NAME); 851 } 852 853 if (check_ruleset_scope(ENV_SCOPED_NAME, &ruleset_attr)) 854 return 1; 855 856 /* Enables optional logs. */ 857 env_force_log = getenv(ENV_FORCE_LOG_NAME); 858 if (env_force_log) { 859 if (strcmp(env_force_log, "1") != 0) { 860 fprintf(stderr, "Unknown value for " ENV_FORCE_LOG_NAME 861 " (only \"1\" is handled)\n"); 862 return 1; 863 } 864 if (!(supported_restrict_flags & 865 LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON)) { 866 fprintf(stderr, 867 "Audit logs not supported by current kernel\n"); 868 return 1; 869 } 870 set_restrict_flags |= LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON; 871 unsetenv(ENV_FORCE_LOG_NAME); 872 } 873 874 /* Set the quiet access masks. */ 875 if (quiet_supported) { 876 if ((getenv(ENV_FS_QUIET_NAME) || getenv(ENV_NET_QUIET_NAME)) && 877 !getenv(ENV_QUIET_ACCESS_NAME)) { 878 fprintf(stderr, 879 "%s must be set (e.g. to \"all\") when %s or %s is used\n", 880 ENV_QUIET_ACCESS_NAME, ENV_FS_QUIET_NAME, 881 ENV_NET_QUIET_NAME); 882 return 1; 883 } 884 if (add_quiet_access(ENV_QUIET_ACCESS_NAME, &ruleset_attr)) 885 return 1; 886 } else if (getenv(ENV_FS_QUIET_NAME) || getenv(ENV_NET_QUIET_NAME) || 887 getenv(ENV_QUIET_ACCESS_NAME)) { 888 fprintf(stderr, 889 "Quiet flags not supported by current kernel\n"); 890 return 1; 891 } 892 893 ruleset_fd = 894 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 895 if (ruleset_fd < 0) { 896 perror("Failed to create a ruleset"); 897 return 1; 898 } 899 900 if (populate_ruleset_fs(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro, 0)) 901 goto err_close_ruleset; 902 if (populate_ruleset_fs(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw, 0)) 903 goto err_close_ruleset; 904 905 /* Don't require this env to be present. */ 906 if (quiet_supported && getenv(ENV_FS_QUIET_NAME)) { 907 if (populate_ruleset_fs(ENV_FS_QUIET_NAME, ruleset_fd, 0, 908 LANDLOCK_ADD_RULE_QUIET)) 909 goto err_close_ruleset; 910 } 911 912 if (populate_ruleset_net(ENV_TCP_BIND_NAME, ruleset_fd, 913 LANDLOCK_ACCESS_NET_BIND_TCP, 0)) { 914 goto err_close_ruleset; 915 } 916 if (populate_ruleset_net(ENV_TCP_CONNECT_NAME, ruleset_fd, 917 LANDLOCK_ACCESS_NET_CONNECT_TCP, 0)) { 918 goto err_close_ruleset; 919 } 920 if (populate_ruleset_net(ENV_UDP_BIND_NAME, ruleset_fd, 921 LANDLOCK_ACCESS_NET_BIND_UDP, 0)) { 922 goto err_close_ruleset; 923 } 924 if (populate_ruleset_net(ENV_UDP_CONNECT_SEND_NAME, ruleset_fd, 925 LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP, 0)) { 926 goto err_close_ruleset; 927 } 928 929 if (quiet_supported) { 930 if (populate_ruleset_net(ENV_NET_QUIET_NAME, ruleset_fd, 0, 931 LANDLOCK_ADD_RULE_QUIET)) { 932 goto err_close_ruleset; 933 } 934 } 935 936 if ((ruleset_attr.handled_permissions & 937 LANDLOCK_PERMISSION_NAMESPACE_USE) && 938 populate_ruleset_ns(ENV_NS_NAME, ENV_NS_QUIET_NAME, ruleset_fd)) 939 goto err_close_ruleset; 940 941 if ((ruleset_attr.handled_permissions & 942 LANDLOCK_PERMISSION_CAPABILITY_USE) && 943 populate_ruleset_cap(ENV_CAP_NAME, ENV_CAP_QUIET_NAME, ruleset_fd)) 944 goto err_close_ruleset; 945 946 if (!(set_restrict_flags & LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS) && 947 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 948 perror("Failed to restrict privileges"); 949 goto err_close_ruleset; 950 } 951 if (landlock_restrict_self(ruleset_fd, set_restrict_flags)) { 952 perror("Failed to enforce ruleset"); 953 goto err_close_ruleset; 954 } 955 close(ruleset_fd); 956 957 cmd_path = argv[1]; 958 cmd_argv = argv + 1; 959 fprintf(stderr, "Executing the sandboxed command...\n"); 960 execvpe(cmd_path, cmd_argv, envp); 961 fprintf(stderr, "Failed to execute \"%s\": %s\n", cmd_path, 962 strerror(errno)); 963 fprintf(stderr, "Hint: access to the binary, the interpreter or " 964 "shared libraries may be denied.\n"); 965 return 1; 966 967 err_close_ruleset: 968 close(ruleset_fd); 969 return 1; 970 } 971