89 lines
3.7 KiB
C
89 lines
3.7 KiB
C
#define _GNU_SOURCE
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <grp.h>
|
|
#include <pwd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
/* Installed only as a narrowly executable NixOS wrapper. This trusted helper
|
|
* accepts no executable, environment, filesystem root or arbitrary UID. The
|
|
* caller is platform authority, never a workspace guest or authored Worker. */
|
|
static void fail(const char *message) {
|
|
fprintf(stderr, "RESTRICTED_IDENTITY: %s\n", message);
|
|
exit(125);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
const char *root = "/run/quixos-restricted-engines/";
|
|
uid_t caller = getuid();
|
|
gid_t group = getgid();
|
|
struct passwd *owner = getpwnam("quixos-graph");
|
|
if (geteuid() != 0) fail("privileged wrapper unavailable");
|
|
if (!owner) fail("authority identity unavailable");
|
|
if (caller != owner->pw_uid) fail("caller identity mismatch");
|
|
if (argc != 3) fail("invalid arguments");
|
|
char *end;
|
|
unsigned long number = strtoul(argv[2], &end, 10);
|
|
if (!*argv[2] || *end || number < 610000 || number >= 610064)
|
|
fail("invalid engine identity");
|
|
uid_t identity = (uid_t)number;
|
|
if (strlen(argv[1]) != strlen(root) + 16 || strncmp(argv[1], root, strlen(root)))
|
|
fail("invalid engine directory");
|
|
const char *name = argv[1] + strlen(root);
|
|
if (strncmp(name, "qx-engine-", 10) ||
|
|
strlen(name) != 16 || strspn(name + 10, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") != 6)
|
|
fail("invalid engine directory");
|
|
int parent = open("/run/quixos-restricted-engines", O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
|
|
struct stat info;
|
|
if (parent < 0 || fstat(parent, &info) || info.st_uid != caller || (info.st_mode & 066))
|
|
fail("invalid engine root");
|
|
int directory = openat(parent, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
|
|
if (directory < 0 || fstat(directory, &info) || info.st_uid != caller || (info.st_mode & 077))
|
|
fail("invalid engine owner");
|
|
DIR *entries = fdopendir(dup(directory));
|
|
if (!entries) fail("engine entries");
|
|
struct dirent *entry;
|
|
unsigned int files = 0;
|
|
while ((entry = readdir(entries))) {
|
|
const char *file = entry->d_name;
|
|
if (!strcmp(file, ".") || !strcmp(file, "..")) continue;
|
|
int socket = !strcmp(file, "broker.sock");
|
|
if ((!socket && strcmp(file, "config.capnp") && strcmp(file, "parent.mjs")) ||
|
|
fstatat(directory, file, &info, AT_SYMLINK_NOFOLLOW) || info.st_uid != caller ||
|
|
info.st_nlink != 1 || (socket ? !S_ISSOCK(info.st_mode) : !S_ISREG(info.st_mode)) ||
|
|
info.st_size > 4 * 1024 * 1024)
|
|
fail("unexpected engine file");
|
|
files++;
|
|
}
|
|
closedir(entries);
|
|
if (files != 3) fail("incomplete engine configuration");
|
|
const char *files_to_transfer[] = {"config.capnp", "parent.mjs", "broker.sock"};
|
|
for (size_t i = 0; i < 3; i++) {
|
|
if (fchownat(directory, files_to_transfer[i], identity, group, AT_SYMLINK_NOFOLLOW) ||
|
|
fchmodat(directory, files_to_transfer[i], 0660, 0))
|
|
fail("engine file ownership");
|
|
}
|
|
if (fchown(directory, identity, group) || fchmod(directory, 0770))
|
|
fail("engine directory ownership");
|
|
close(directory);
|
|
close(parent);
|
|
struct rlimit core = {0, 0};
|
|
if (setrlimit(RLIMIT_CORE, &core) || setgroups(0, NULL) ||
|
|
setresgid(identity, identity, identity) || setresuid(identity, identity, identity) ||
|
|
prctl(PR_SET_DUMPABLE, 0) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
|
|
fail("identity confinement");
|
|
/* The containing directory grants only its owner and authority access. A
|
|
* socket created by workerd must also admit authority's different UID/GID. */
|
|
umask(0000);
|
|
char *args[] = {SANDBOX_EXECUTABLE, argv[1], NULL};
|
|
clearenv();
|
|
execv(SANDBOX_EXECUTABLE, args);
|
|
fail("sandbox launch");
|
|
}
|