|
1 | 1 | #include "ptbox.h" |
2 | 2 | #include "helper.h" |
| 3 | +#include "landlock_helpers.h" |
3 | 4 |
|
4 | 5 | #include <dirent.h> |
5 | 6 | #include <errno.h> |
|
31 | 32 | # define FD_DIR "/proc/self/fd" |
32 | 33 | #endif |
33 | 34 |
|
| 35 | + |
34 | 36 | inline void setrlimit2(int resource, rlim_t cur, rlim_t max) { |
35 | 37 | rlimit limit; |
36 | 38 | limit.rlim_cur = cur; |
@@ -72,14 +74,70 @@ int cptbox_child_run(const struct child_config *config) { |
72 | 74 |
|
73 | 75 | kill(getpid(), SIGSTOP); |
74 | 76 |
|
75 | | -#if !PTBOX_FREEBSD |
| 77 | +#ifndef __FreeBSD__ |
| 78 | + // landlock setup |
| 79 | + // if at any point landlock fails, we log and resume normal seccomp-trapping |
| 80 | + int ruleset_fd, rc; |
| 81 | + struct landlock_ruleset_attr ruleset_attr = { |
| 82 | + .handled_access_fs = |
| 83 | + LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_WRITE_FILE | |
| 84 | + LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR | |
| 85 | + LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_REMOVE_FILE | |
| 86 | + LANDLOCK_ACCESS_FS_MAKE_CHAR | LANDLOCK_ACCESS_FS_MAKE_DIR | |
| 87 | + LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_MAKE_SOCK | |
| 88 | + LANDLOCK_ACCESS_FS_MAKE_FIFO | LANDLOCK_ACCESS_FS_MAKE_BLOCK | |
| 89 | + LANDLOCK_ACCESS_FS_MAKE_SYM, |
| 90 | + }; |
| 91 | + |
| 92 | + ruleset_fd = |
| 93 | + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); |
| 94 | + if (ruleset_fd < 0) { |
| 95 | + if (errno != ENOSYS && errno != EOPNOTSUPP) { |
| 96 | + perror("Failed to create a ruleset"); |
| 97 | + return PTBOX_SPAWN_FAIL_LANDLOCK; |
| 98 | + } else |
| 99 | + goto seccomp_setup; |
| 100 | + } |
| 101 | + |
| 102 | +#define READ_EXACT_FILE_RULE \ |
| 103 | + LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_FILE |
| 104 | +#define READ_EXACT_DIR_RULE LANDLOCK_ACCESS_FS_READ_DIR |
| 105 | +#define READ_RECURSIVE_DIR_RULE READ_EXACT_FILE_RULE | READ_EXACT_DIR_RULE |
| 106 | +#define WRITE_EXACT_FILE_RULE LANDLOCK_ACCESS_FS_WRITE_FILE |
| 107 | +#define WRITE_EXACT_DIR_RULE LANDLOCK_ACCESS_FS_READ_DIR |
| 108 | +#define WRITE_RECURSIVE_DIR_RULE WRITE_EXACT_FILE_RULE | WRITE_EXACT_DIR_RULE |
| 109 | + |
| 110 | + if (landlock_add_rules(ruleset_fd, config->read_exact_files, |
| 111 | + READ_EXACT_FILE_RULE) || |
| 112 | + landlock_add_rules(ruleset_fd, config->read_exact_dirs, |
| 113 | + READ_EXACT_DIR_RULE) || |
| 114 | + landlock_add_rules(ruleset_fd, config->read_recursive_dirs, |
| 115 | + READ_RECURSIVE_DIR_RULE) || |
| 116 | + landlock_add_rules(ruleset_fd, config->write_exact_files, |
| 117 | + WRITE_EXACT_FILE_RULE) || |
| 118 | + landlock_add_rules(ruleset_fd, config->write_exact_dirs, |
| 119 | + WRITE_EXACT_DIR_RULE) || |
| 120 | + landlock_add_rules(ruleset_fd, config->write_recursive_dirs, |
| 121 | + WRITE_RECURSIVE_DIR_RULE)) { |
| 122 | + // landlock_add_rules logs errors |
| 123 | + close(ruleset_fd); |
| 124 | + return PTBOX_SPAWN_FAIL_LANDLOCK; |
| 125 | + } |
| 126 | + |
| 127 | + rc = landlock_restrict_self(ruleset_fd, 0); |
| 128 | + close(ruleset_fd); |
| 129 | + if (rc) { |
| 130 | + perror("Failed to enforce ruleset"); |
| 131 | + return PTBOX_SPAWN_FAIL_LANDLOCK; |
| 132 | + } |
| 133 | + |
| 134 | +seccomp_setup: |
76 | 135 | scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRACE(0)); |
77 | 136 | if (!ctx) { |
78 | 137 | fprintf(stderr, "Failed to initialize seccomp context!"); |
79 | | - goto seccomp_fail; |
| 138 | + return PTBOX_SPAWN_FAIL_SECCOMP; |
80 | 139 | } |
81 | 140 |
|
82 | | - int rc; |
83 | 141 | // By default, the native architecture is added to the filter already, so we add all the non-native ones. |
84 | 142 | // This will bloat the filter due to additional architectures, but a few extra compares in the BPF matters |
85 | 143 | // very little when syscalls are rare and other overhead is expensive. |
@@ -108,7 +166,7 @@ int cptbox_child_run(const struct child_config *config) { |
108 | 166 |
|
109 | 167 | if ((rc = seccomp_load(ctx))) { |
110 | 168 | fprintf(stderr, "seccomp_load: %s\n", strerror(-rc)); |
111 | | - goto seccomp_fail; |
| 169 | + return PTBOX_SPAWN_FAIL_SECCOMP; |
112 | 170 | } |
113 | 171 |
|
114 | 172 | seccomp_release(ctx); |
@@ -141,9 +199,21 @@ int cptbox_child_run(const struct child_config *config) { |
141 | 199 | execve(config->file, config->argv, config->envp); |
142 | 200 | perror("execve"); |
143 | 201 | return PTBOX_SPAWN_FAIL_EXECVE; |
| 202 | +} |
144 | 203 |
|
145 | | -seccomp_fail: |
146 | | - return PTBOX_SPAWN_FAIL_SECCOMP; |
| 204 | +int has_landlock_check() { |
| 205 | + int landlock_version = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); |
| 206 | + if(landlock_version < 0) { |
| 207 | + if(errno == ENOSYS || errno == EOPNOTSUPP) { |
| 208 | + return 0; |
| 209 | + } |
| 210 | + else { |
| 211 | + return -1; |
| 212 | + } |
| 213 | + } |
| 214 | + else { |
| 215 | + return 1; |
| 216 | + } |
147 | 217 | } |
148 | 218 |
|
149 | 219 | // From python's _posixsubprocess |
|
0 commit comments