diff options
| author | Riley Beckett <rbeckettvt@gmail.com> | 2026-07-27 01:01:18 -0400 |
|---|---|---|
| committer | Riley Beckett <rbeckettvt@gmail.com> | 2026-07-27 01:01:18 -0400 |
| commit | 7eb17df0a722c251f0697821b20450e1478142f3 (patch) | |
| tree | 6da85851403f2b9f487e53f1d0db7926ab9c6196 /snag/src | |
| parent | 3f50d3c69750e059939c10b44755d329be65a47e (diff) | |
add some sandboxing code
Diffstat (limited to 'snag/src')
| -rw-r--r-- | snag/src/build_db.c | 112 | ||||
| -rw-r--r-- | snag/src/landlock_signatures.h | 37 | ||||
| -rw-r--r-- | snag/src/sandboxing.c | 101 | ||||
| -rw-r--r-- | snag/src/sandboxing.h | 15 |
4 files changed, 263 insertions, 2 deletions
diff --git a/snag/src/build_db.c b/snag/src/build_db.c index 83bf6d9..54a20cd 100644 --- a/snag/src/build_db.c +++ b/snag/src/build_db.c @@ -15,10 +15,115 @@ #include <sys/stat.h> #include <errno.h> +#include "sandboxing.h" + #define API_MESSAGE_NONE 0 #define API_MESSAGE_FINISHED 1 #define API_MESSAGE_TEST 2 +bool set_child_sandbox(const package_build_t* build) { + struct landlock_ruleset_attr ruleset_attr = { + .handled_access_fs = + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_READ_DIR | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_MAKE_CHAR | + LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_MAKE_SOCK | + LANDLOCK_ACCESS_FS_MAKE_FIFO | + LANDLOCK_ACCESS_FS_MAKE_BLOCK | + LANDLOCK_ACCESS_FS_MAKE_SYM | + LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_TRUNCATE | + LANDLOCK_ACCESS_FS_IOCTL_DEV | + LANDLOCK_ACCESS_FS_RESOLVE_UNIX, + .handled_access_net = + LANDLOCK_ACCESS_NET_BIND_TCP | + LANDLOCK_ACCESS_NET_CONNECT_TCP, + .scoped = + LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | + LANDLOCK_SCOPE_SIGNAL, + }; + + int landlock_fd = create_new_landlock_ruleset(&ruleset_attr); + if (landlock_fd < 0) { + return false; + } + + struct landlock_path_beneath_attr path_beneath = { + .allowed_access = + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_READ_DIR | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_MAKE_CHAR | + LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_MAKE_SOCK | + LANDLOCK_ACCESS_FS_MAKE_FIFO | + LANDLOCK_ACCESS_FS_MAKE_BLOCK | + LANDLOCK_ACCESS_FS_MAKE_SYM | + LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_TRUNCATE | + LANDLOCK_ACCESS_FS_IOCTL_DEV | + LANDLOCK_ACCESS_FS_RESOLVE_UNIX, + }; + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, build->source_directory, &path_beneath)) { + return false; + } + path_beneath.allowed_access = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_FILE; + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, cfg.build_package_script, &path_beneath)) { + return false; + } + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, build->package->script_path, &path_beneath)) { + return false; + } + path_beneath.allowed_access = + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_READ_DIR; + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, "/bin", &path_beneath)) { + return false; + } + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, "/usr/bin", &path_beneath)) { + return false; + } + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, "/lib64", &path_beneath)) { + return false; + } + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, "/lib", &path_beneath)) { + return false; + } + // this is just specific to my system - (rjb) + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, "/opt/gnome/lib64/libglib-2.0.so.0", &path_beneath)) { + return false; + } + path_beneath.allowed_access = + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_MAKE_FIFO | + LANDLOCK_ACCESS_FS_READ_DIR; + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, "/tmp", &path_beneath)) { + return false; + } + path_beneath.allowed_access = + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_READ_DIR; + if (!landlock_add_path_rule(landlock_fd, &ruleset_attr, "/usr", &path_beneath)) { + return false; + } + + landlock_enforce(landlock_fd); + + return true; +} + bool package_setup_build(const package_info_t* info, package_build_t* build) { // get timestamp string @@ -78,14 +183,17 @@ void build_run(const package_build_t* build) { // close unused api pipes close(api_from_sh[0]); close(api_to_sh[1]); - char buf1[1024]; + char buf1[12]; snprintf(buf1, sizeof(buf1), "%d", api_from_sh[1]); - char buf2[1024]; + char buf2[12]; snprintf(buf2, sizeof(buf2), "%d", api_to_sh[0]); // exec into install script chdir(build->source_directory); + set_child_sandbox(build); char* argv[] = { cfg.build_package_script, buf1, buf2, build->package->script_path, NULL }; execv(cfg.build_package_script, argv); + int finished = API_MESSAGE_FINISHED; + write(api_from_sh[1], &finished, sizeof(finished)); // what are you still doing here? die("CHILD - execve to %s failed: %s", cfg.build_package_script, strerror(errno)); } else { diff --git a/snag/src/landlock_signatures.h b/snag/src/landlock_signatures.h new file mode 100644 index 0000000..0d30608 --- /dev/null +++ b/snag/src/landlock_signatures.h @@ -0,0 +1,37 @@ +#ifndef LANDLOCK_SIGS_H +#define LANDLOCK_SIGS_H +#include <linux/landlock.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <stdint.h> +#include <stdlib.h> + +#ifndef landlock_create_ruleset +static inline int +landlock_create_ruleset(const struct landlock_ruleset_attr *const attr, + const size_t size, const uint32_t flags) +{ + return syscall(__NR_landlock_create_ruleset, attr, size, flags); +} +#endif + +#ifndef landlock_add_rule +static inline int landlock_add_rule(const int ruleset_fd, + const enum landlock_rule_type rule_type, + const void *const rule_attr, + const uint32_t flags) +{ + return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, + flags); +} +#endif + +#ifndef landlock_restrict_self +static inline int landlock_restrict_self(const int ruleset_fd, + const uint32_t flags) +{ + return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); +} +#endif + +#endif // LANDLOCK_SIGS_H diff --git a/snag/src/sandboxing.c b/snag/src/sandboxing.c new file mode 100644 index 0000000..5edc6ce --- /dev/null +++ b/snag/src/sandboxing.c @@ -0,0 +1,101 @@ +#define _GNU_SOURCE +#include "landlock_signatures.h" +#include "util.h" +#include "sandboxing.h" +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/prctl.h> +#include <linux/prctl.h> + +int create_new_landlock_ruleset(struct landlock_ruleset_attr* ruleset_attr) { + + int abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); + print("landlock abi version: %d\n", abi); + 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); +} diff --git a/snag/src/sandboxing.h b/snag/src/sandboxing.h new file mode 100644 index 0000000..4b7adfc --- /dev/null +++ b/snag/src/sandboxing.h @@ -0,0 +1,15 @@ +#ifndef SANDBOXING_H +#define SANDBOXING_H +#include <stdlib.h> +#include <linux/landlock.h> + +// returns -1 for error +int create_new_landlock_ruleset(struct landlock_ruleset_attr* ruleset_attr); + +// returns false for error +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); +// closes landlock_fd +// returns false for error +bool landlock_enforce(int landlock_fd); + +#endif // SANDBOXING_H |
