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 }