#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include static void check(int condition, const char *label) { if (!condition) { fprintf(stderr, "ESCAPE: %s (%s)\n", label, strerror(errno)); exit(1); } } int main(void) { for (int fd = 3; fd < 256; fd++) check(fcntl(fd, F_GETFD) < 0 && errno == EBADF, "inherited descriptor"); check(!getenv("QUIXOS_VM_SECRET"), "parent environment"); check(open("/etc/test-secret", O_RDONLY) < 0, "authority filesystem"); check(open("/sys/fs/cgroup/cgroup.procs", O_WRONLY) < 0, "resource controls"); check(open("/proc/1/root/etc/test-secret", O_RDONLY) < 0, "proc root escape"); check(socket(AF_INET, SOCK_STREAM, 0) < 0 && errno == EPERM, "IPv4 socket"); check(socket(AF_INET6, SOCK_STREAM, 0) < 0 && errno == EPERM, "IPv6 socket"); check(socket(AF_NETLINK, SOCK_RAW, 0) < 0 && errno == EPERM, "netlink socket"); check(ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0 && errno == EPERM, "ptrace"); check(unshare(CLONE_NEWUSER) < 0, "nested user namespace"); pid_t child = fork(); if (child == 0) _exit(2); check(child < 0 && errno == EPERM, "subprocess"); check(access("/bin/sh", X_OK) < 0, "ambient executable"); check(getppid() <= 1, "host process visibility"); struct sockaddr_un address = {.sun_family = AF_UNIX}; int outside = socket(AF_UNIX, SOCK_STREAM, 0); check(outside >= 0, "Unix socket support"); strcpy(address.sun_path, "/run/quixos-native-authority/test.sock"); check(connect(outside, (struct sockaddr *)&address, sizeof(address)) < 0, "authority Unix socket"); close(outside); outside = socket(AF_UNIX, SOCK_STREAM, 0); memset(address.sun_path, 0, sizeof(address.sun_path)); strcpy(address.sun_path + 1, "quixos-native-authority"); check(connect(outside, (struct sockaddr *)&address, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(address.sun_path + 1)) < 0, "authority abstract socket"); close(outside); char directory[4096]; check(getcwd(directory, sizeof(directory)) != NULL, "engine directory"); check(snprintf(address.sun_path, sizeof(address.sun_path), "%s/broker.sock", directory) < (int)sizeof(address.sun_path), "broker path length"); int broker = socket(AF_UNIX, SOCK_STREAM, 0); check(broker >= 0 && connect(broker, (struct sockaddr *)&address, sizeof(address)) == 0, "authorized broker"); check(write(broker, "sandbox-probe", 13) == 13, "broker write"); close(broker); puts("RESTRICTED_NATIVE_SANDBOX_PASSED"); return 0; }