aboutsummaryrefslogtreecommitdiff
path: root/snag/src/sandboxing.c
diff options
context:
space:
mode:
Diffstat (limited to 'snag/src/sandboxing.c')
-rw-r--r--snag/src/sandboxing.c101
1 files changed, 101 insertions, 0 deletions
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);
+}