geminid

A Sandboxed Gemini server
git clone git@git.mpah.dev/geminid.git
Log | Files | Refs | README

landlock_stubs.c (3416B)


      1 #define _GNU_SOURCE
      2 #include <fcntl.h>
      3 #include <linux/landlock.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <sys/prctl.h>
      7 #include <sys/syscall.h>
      8 #include <unistd.h>
      9 #include <caml/mlvalues.h>
     10 
     11 #ifndef landlock_create_ruleset
     12 static inline int
     13 landlock_create_ruleset(const struct landlock_ruleset_attr *const attr,
     14 			const size_t size, const __u32 flags)
     15 {
     16 	return syscall(__NR_landlock_create_ruleset, attr, size, flags);
     17 }
     18 #endif
     19 
     20 #ifndef landlock_add_rule
     21 static inline int landlock_add_rule(const int ruleset_fd,
     22 				    const enum landlock_rule_type rule_type,
     23 				    const void *const rule_attr,
     24 				    const __u32 flags)
     25 {
     26 	return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr,
     27 		       flags);
     28 }
     29 #endif
     30 
     31 #ifndef landlock_restrict_self
     32 static inline int landlock_restrict_self(const int ruleset_fd,
     33 					 const __u32 flags)
     34 {
     35 	return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
     36 }
     37 #endif
     38 
     39 static const int permissions_table[] = {
     40 	LANDLOCK_ACCESS_FS_EXECUTE,
     41 	LANDLOCK_ACCESS_FS_WRITE_FILE,
     42 	LANDLOCK_ACCESS_FS_READ_FILE,
     43 	LANDLOCK_ACCESS_FS_READ_DIR,
     44 	LANDLOCK_ACCESS_FS_REMOVE_DIR,
     45 	LANDLOCK_ACCESS_FS_REMOVE_FILE,
     46 	LANDLOCK_ACCESS_FS_MAKE_CHAR,
     47 	LANDLOCK_ACCESS_FS_MAKE_DIR,
     48 	LANDLOCK_ACCESS_FS_MAKE_REG,
     49 	LANDLOCK_ACCESS_FS_MAKE_SOCK,
     50 	LANDLOCK_ACCESS_FS_MAKE_FIFO,
     51 	LANDLOCK_ACCESS_FS_MAKE_BLOCK,
     52 	LANDLOCK_ACCESS_FS_MAKE_SYM
     53 };
     54 
     55 static inline int
     56 permissions_mask_val(value mask_list)
     57 {
     58 	int c_mask = 0; 
     59 	while (mask_list != Val_emptylist) {
     60 		value head = Field(mask_list, 0);
     61 		c_mask |= permissions_table[Long_val(head)];
     62 		mask_list = Field(mask_list, 1);
     63 	}
     64 	return c_mask;
     65 }
     66 
     67 CAMLprim value
     68 caml_landlock_init(value unit)
     69 {
     70 	int ruleset_fd;
     71 	struct landlock_ruleset_attr ruleset_attr = {
     72 		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE |
     73 				     LANDLOCK_ACCESS_FS_WRITE_FILE |
     74 				     LANDLOCK_ACCESS_FS_READ_FILE |
     75 				     LANDLOCK_ACCESS_FS_READ_DIR |
     76 				     LANDLOCK_ACCESS_FS_REMOVE_DIR |
     77 				     LANDLOCK_ACCESS_FS_REMOVE_FILE |
     78 				     LANDLOCK_ACCESS_FS_MAKE_CHAR |
     79 				     LANDLOCK_ACCESS_FS_MAKE_DIR |
     80 				     LANDLOCK_ACCESS_FS_MAKE_REG |
     81 				     LANDLOCK_ACCESS_FS_MAKE_SOCK |
     82 				     LANDLOCK_ACCESS_FS_MAKE_FIFO |
     83 				     LANDLOCK_ACCESS_FS_MAKE_BLOCK |
     84 				     LANDLOCK_ACCESS_FS_MAKE_SYM,
     85 	};
     86 
     87 	ruleset_fd =
     88 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
     89 	if (ruleset_fd < 0) {
     90 		perror("Failed to create a ruleset");
     91 		return -1;
     92 	}
     93 	return ruleset_fd;
     94 }
     95 
     96 CAMLprim value
     97 caml_landlock(value ruleset_fd, value *path, value perms)
     98 {
     99 	int err;
    100 	struct landlock_path_beneath_attr path_beneath = {
    101 		.allowed_access = permissions_mask_val(perms)
    102 	};
    103 
    104 	path_beneath.parent_fd = open(String_val(path), O_PATH | O_CLOEXEC);
    105 	if (path_beneath.parent_fd < 0) {
    106 		perror("Failed to open file");
    107 		close(ruleset_fd);
    108 		return -1;
    109 	}
    110 
    111 	err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
    112 				&path_beneath, 0);
    113 
    114 	close(path_beneath.parent_fd);
    115 	if (err) {
    116 		perror("Failed to update ruleset");
    117 		close(ruleset_fd);
    118 		return -1;
    119 	}
    120 
    121 	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
    122 		perror("Failed to restrict privileges");
    123 		close(ruleset_fd);
    124 		return -1;
    125 	}
    126 	return Val_int(ruleset_fd);
    127 }
    128 
    129 CAMLprim value
    130 caml_landlock_finish(value ruleset_fd)
    131 {
    132 	if (landlock_restrict_self(ruleset_fd, 0)) {
    133 		perror("Failed to enforce ruleset");
    134 		close(ruleset_fd);
    135 		return -1;
    136 	}
    137 	close(ruleset_fd);
    138 	return 0;
    139 }