78 lines
2.4 KiB
C
78 lines
2.4 KiB
C
#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");
|
|
}
|