1 /* 2 * Copyright (C) 2026 Daniel Golle <daniel@makrotopia.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2.1 6 * as published by the Free Software Foundation 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #define _GNU_SOURCE 15 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 #include <sys/syscall.h> 22 23 #include <linux/landlock.h> 24 25 #include "log.h" 26 #include "landlock.h" 27 28 static int landlock_abi_cached = -2; 29 30 static int sys_landlock_create_ruleset(const struct landlock_ruleset_attr *attr, 31 size_t size, uint32_t flags) 32 { 33 return syscall(SYS_landlock_create_ruleset, attr, size, flags); 34 } 35 36 static int sys_landlock_add_rule(int ruleset_fd, enum landlock_rule_type type, 37 const void *rule_attr, uint32_t flags) 38 { 39 return syscall(SYS_landlock_add_rule, ruleset_fd, type, rule_attr, flags); 40 } 41 42 static int sys_landlock_restrict_self(int ruleset_fd, uint32_t flags) 43 { 44 return syscall(SYS_landlock_restrict_self, ruleset_fd, flags); 45 } 46 47 static int landlock_abi(void) 48 { 49 if (landlock_abi_cached == -2) 50 landlock_abi_cached = sys_landlock_create_ruleset(NULL, 0, 51 LANDLOCK_CREATE_RULESET_VERSION); 52 return landlock_abi_cached; 53 } 54 55 bool landlock_available(void) 56 { 57 return landlock_abi() >= 1; 58 } 59 60 int landlock_config_add(struct landlock_config *cfg, const char *path, uint64_t access) 61 { 62 struct landlock_rule *r; 63 64 r = realloc(cfg->rules, sizeof(*r) * (cfg->n + 1)); 65 if (!r) 66 return -ENOMEM; 67 cfg->rules = r; 68 r[cfg->n].path = strdup(path); 69 if (!r[cfg->n].path) 70 return -ENOMEM; 71 r[cfg->n].access = access; 72 cfg->n++; 73 return 0; 74 } 75 76 int landlock_config_add_paths(struct landlock_config *cfg, const char *paths, 77 uint64_t access) 78 { 79 char *dup, *tok, *save; 80 int rc = 0; 81 82 if (!paths || !*paths) 83 return 0; 84 85 dup = strdup(paths); 86 if (!dup) 87 return -ENOMEM; 88 89 for (tok = strtok_r(dup, ":", &save); tok; tok = strtok_r(NULL, ":", &save)) { 90 rc = landlock_config_add(cfg, tok, access); 91 if (rc) 92 break; 93 } 94 free(dup); 95 return rc; 96 } 97 98 int landlock_apply(const struct landlock_config *cfg) 99 { 100 struct landlock_ruleset_attr ra = { 0 }; 101 int ruleset_fd, rc = 0; 102 size_t i; 103 104 if (cfg->n == 0) 105 return 0; 106 if (!landlock_available()) 107 return -ENOSYS; 108 109 for (i = 0; i < cfg->n; i++) 110 ra.handled_access_fs |= cfg->rules[i].access; 111 112 ruleset_fd = sys_landlock_create_ruleset(&ra, sizeof(ra), 0); 113 if (ruleset_fd < 0) { 114 int saved_errno = errno; 115 ERROR("landlock_create_ruleset: %s\n", strerror(saved_errno)); 116 return -saved_errno; 117 } 118 119 for (i = 0; i < cfg->n; i++) { 120 struct landlock_path_beneath_attr pa = { 121 .allowed_access = cfg->rules[i].access, 122 }; 123 int saved_errno; 124 125 pa.parent_fd = open(cfg->rules[i].path, O_PATH | O_CLOEXEC); 126 if (pa.parent_fd < 0) { 127 saved_errno = errno; 128 ERROR("landlock: open(%s): %s\n", cfg->rules[i].path, 129 strerror(saved_errno)); 130 rc = -saved_errno; 131 goto out; 132 } 133 if (sys_landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 134 &pa, 0)) { 135 saved_errno = errno; 136 ERROR("landlock_add_rule(%s): %s\n", cfg->rules[i].path, 137 strerror(saved_errno)); 138 rc = -saved_errno; 139 close(pa.parent_fd); 140 goto out; 141 } 142 close(pa.parent_fd); 143 } 144 145 if (sys_landlock_restrict_self(ruleset_fd, 0)) { 146 int saved_errno = errno; 147 ERROR("landlock_restrict_self: %s\n", strerror(saved_errno)); 148 rc = -saved_errno; 149 } 150 151 out: 152 close(ruleset_fd); 153 return rc; 154 } 155 156 void landlock_config_free(struct landlock_config *cfg) 157 { 158 size_t i; 159 160 for (i = 0; i < cfg->n; i++) 161 free(cfg->rules[i].path); 162 free(cfg->rules); 163 cfg->rules = NULL; 164 cfg->n = 0; 165 } 166
This page was automatically generated by LXR 0.3.1. • OpenWrt