Confine restricted engines before launch and preserve the reader recovery baseline
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Trusted, single-process admission gate. The supervisor charges this PID to
|
||||
* its engine cgroup before releasing stdin. All subsequently created namespace
|
||||
* helpers and threads inherit that charge. No authored code runs here. */
|
||||
static void fail(const char *message) {
|
||||
fprintf(stderr, "RESTRICTED_SANDBOX: %s\n", message);
|
||||
exit(125);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct stat info;
|
||||
if (argc != 2 || argv[1][0] != '/' || strstr(argv[1], "/../") ||
|
||||
lstat(argv[1], &info) || !S_ISDIR(info.st_mode) ||
|
||||
info.st_uid != getuid() || (info.st_mode & 077))
|
||||
fail("invalid engine directory");
|
||||
char gate;
|
||||
if (read(STDIN_FILENO, &gate, 1) != 1 || gate != 1)
|
||||
fail("engine admission was not released");
|
||||
int input = open("/dev/null", O_RDONLY);
|
||||
if (input < 0 || dup2(input, STDIN_FILENO) < 0)
|
||||
fail("stdin");
|
||||
close(input);
|
||||
int filter = open(SANDBOX_FILTER, O_RDONLY);
|
||||
if (filter < 0)
|
||||
fail("seccomp filter");
|
||||
char filter_fd[32];
|
||||
snprintf(filter_fd, sizeof(filter_fd), "%d", filter);
|
||||
char *args[4096];
|
||||
size_t count = 0;
|
||||
#define ARG(value) args[count++] = (value)
|
||||
ARG(SANDBOX_BWRAP);
|
||||
ARG("--unshare-all");
|
||||
ARG("--unshare-user");
|
||||
ARG("--die-with-parent");
|
||||
ARG("--disable-userns");
|
||||
ARG("--assert-userns-disabled");
|
||||
ARG("--cap-drop"); ARG("ALL");
|
||||
ARG("--hostname"); ARG("quixos-restricted");
|
||||
ARG("--clearenv");
|
||||
ARG("--setenv"); ARG("TZ"); ARG("UTC");
|
||||
ARG("--setenv"); ARG("LANG"); ARG("C.UTF-8");
|
||||
FILE *closure = fopen(SANDBOX_CLOSURE, "r");
|
||||
if (!closure)
|
||||
fail("runtime closure");
|
||||
char *line = NULL;
|
||||
size_t capacity = 0;
|
||||
while (getline(&line, &capacity, closure) >= 0) {
|
||||
line[strcspn(line, "\n")] = 0;
|
||||
if (strncmp(line, "/nix/store/", 11) || strchr(line, ' ') || count > 4000)
|
||||
fail("runtime closure entry");
|
||||
char *path = strdup(line);
|
||||
if (!path)
|
||||
fail("runtime closure allocation");
|
||||
ARG("--ro-bind"); ARG(path); ARG(path);
|
||||
}
|
||||
fclose(closure);
|
||||
free(line);
|
||||
ARG("--proc"); ARG("/proc");
|
||||
ARG("--dev"); ARG("/dev");
|
||||
ARG("--tmpfs"); ARG("/tmp");
|
||||
ARG("--bind"); ARG(argv[1]); ARG(argv[1]);
|
||||
ARG("--chdir"); ARG(argv[1]);
|
||||
ARG("--seccomp"); ARG(filter_fd);
|
||||
ARG("--"); ARG(SANDBOX_EXECUTABLE);
|
||||
ARG("serve"); ARG("--experimental"); ARG("config.capnp");
|
||||
ARG(NULL);
|
||||
execv(SANDBOX_BWRAP, args);
|
||||
fail("bubblewrap failed");
|
||||
}
|
||||
Reference in New Issue
Block a user