aboutsummaryrefslogtreecommitdiff
path: root/snag/src
diff options
context:
space:
mode:
Diffstat (limited to 'snag/src')
-rw-r--r--snag/src/build_db.c112
-rw-r--r--snag/src/landlock_signatures.h37
-rw-r--r--snag/src/sandboxing.c101
-rw-r--r--snag/src/sandboxing.h15
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