#define _GNU_SOURCE #include "landlock_signatures.h" #include "util.h" #include "sandboxing.h" #include #include #include #include #include int create_new_landlock_ruleset(struct landlock_ruleset_attr* ruleset_attr) { int abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); if (abi < 0) { /* Degrades gracefully if Landlock is not handled. */ print("landlock is not enabled, sandboxing will not work\n"); return -1; } switch (abi) { case 1: /* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */ ruleset_attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; case 2: /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */ ruleset_attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; case 3: /* Removes network support for ABI < 4 */ ruleset_attr->handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); case 4: /* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */ ruleset_attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV; case 5: /* Removes LANDLOCK_SCOPE_* for ABI < 6 */ ruleset_attr->scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | LANDLOCK_SCOPE_SIGNAL); case 6 ... 8: /* Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX for ABI < 9 */ ruleset_attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_RESOLVE_UNIX; } int ruleset_fd = landlock_create_ruleset(ruleset_attr, sizeof(*ruleset_attr), 0); if (ruleset_fd < 0) { print("Failed to create landlock ruleset: %s", strerror(errno)); return -1; } return ruleset_fd; } bool landlock_add_path_rule(int landlock_fd, const struct landlock_ruleset_attr* ruleset_attr, const char* path, struct landlock_path_beneath_attr* path_beneath) { path_beneath->allowed_access &= ruleset_attr->handled_access_fs; if (path_beneath->allowed_access) { path_beneath->parent_fd = open(path, O_PATH | O_CLOEXEC); if (path_beneath->parent_fd < 0) { print("Failed to open file %s: %s\n", path, strerror(errno)); return false; } int err = landlock_add_rule(landlock_fd, LANDLOCK_RULE_PATH_BENEATH, path_beneath, 0); close(path_beneath->parent_fd); if (err) { print("Failed to update ruleset: %s\n", strerror(errno)); return false; } } return true; } bool landlock_enforce(int landlock_fd) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { print("Failed to restrict privileges: %s\n", strerror(errno)); return false; } uint32_t restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON | LANDLOCK_RESTRICT_SELF_TSYNC; int abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); switch (abi) { case 1 ... 6: /* Removes logging flags for ABI < 7 */ restrict_flags &= ~(LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF | LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON | LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF); case 7: /* * Removes multithreaded enforcement flag for ABI < 8 * * WARNING: Without this flag, calling landlock_restrict_self(2) is * only equivalent if the calling process is single-threaded. Below * ABI v8 (and as of ABI v8, when not using this flag), a Landlock * policy would only be enforced for the calling thread and its * children (and not for all threads, including parents and siblings). */ restrict_flags &= ~LANDLOCK_RESTRICT_SELF_TSYNC; } if (landlock_restrict_self(landlock_fd, restrict_flags)) { print("Failed to enforce ruleset: %s\n", strerror(errno)); return false; } close(landlock_fd); return true; }