From 337658a8bf2c6e7803edebafc762a4a0009d35b9 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Sun, 5 Jul 2020 12:21:59 -0600 Subject: [PATCH] Misc bugfixes and robustness improvements --- README.md | 4 +- backend/src/api.ts | 63 ++++++++++++++++++----------- backend/src/users.ts | 9 ++--- backend/src/util.ts | 16 ++++---- package.json | 4 +- scripts/docker-install-phase5.bash | 2 +- scripts/setup.bash | 2 +- system/src/riju-system-privileged.c | 29 +++++++++---- 8 files changed, 79 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 7aee9be..c290c31 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,8 @@ container first: $ make docker -Note that building the image takes 30 minutes and requires about 15 GB -of disk space. +Note that building the image takes about 30 minutes on high-end +hardware and ethernet, and it requires about 15 GB of disk space. ## Flag diff --git a/backend/src/api.ts b/backend/src/api.ts index c2b617d..a92d501 100644 --- a/backend/src/api.ts +++ b/backend/src/api.ts @@ -10,7 +10,12 @@ import { v4 as getUUID } from "uuid"; import { PRIVILEGED } from "./config"; import { LangConfig, langs } from "./langs"; import { borrowUser } from "./users"; -import { callPrivileged, getEnv, spawnPrivileged } from "./util"; +import { + callPrivileged, + getEnv, + rijuSystemPrivileged, + spawnPrivileged, +} from "./util"; export class Session { uuid: string; @@ -193,17 +198,15 @@ export class Session { ); } } - const args = PRIVILEGED - ? [ - "/home/docker/src/system/out/riju-system-privileged", - "spawn", - `${this.uid}`, - `${this.uuid}`, - "bash", - "-c", - cmdline, - ] - : ["bash", "-c", cmdline]; + const args = [ + rijuSystemPrivileged, + "spawn", + `${this.uid}`, + `${this.uuid}`, + "bash", + "-c", + cmdline, + ]; const env = getEnv(this.uuid); const term = { pty: pty.spawn(args[0], args.slice(1), { @@ -227,17 +230,15 @@ export class Session { } }); if (lsp && this.lsp === null) { - const lspArgs = PRIVILEGED - ? [ - "/home/docker/src/system/out/riju-system-privileged", - "spawn", - `${this.uid}`, - `${this.uuid}`, - "bash", - "-c", - lsp, - ] - : ["bash", "-c", lsp]; + const lspArgs = [ + rijuSystemPrivileged, + "spawn", + `${this.uid}`, + `${this.uuid}`, + "bash", + "-c", + lsp, + ]; const proc = spawn(lspArgs[0], lspArgs.slice(1), { env: getEnv(this.uuid), }); @@ -254,6 +255,22 @@ export class Session { }; cleanup = async () => { this.log(`Cleaning up session`); + if (this.term.pty) { + await spawnPrivileged( + this.uid!, + this.uuid, + ["kill", "-9", `${this.term.pty.pid}`], + this.log + ); + } + if (this.lsp !== null) { + await spawnPrivileged( + this.uid!, + this.uuid, + ["kill", "-9", `${this.lsp.proc.pid}`], + this.log + ); + } if (this.homedir) { await callPrivileged(["teardown", this.uuid], this.log); } diff --git a/backend/src/users.ts b/backend/src/users.ts index 0742a6b..89862b5 100644 --- a/backend/src/users.ts +++ b/backend/src/users.ts @@ -1,5 +1,6 @@ import { spawn } from "child_process"; import * as fs from "fs"; +import * as os from "os"; import * as AsyncLock from "async-lock"; import * as _ from "lodash"; @@ -12,7 +13,7 @@ import { callPrivileged } from "./util"; const MIN_UID = 2000; const MAX_UID = 65000; -const CUR_UID = parseInt(process.env.UID || "") || null; +const CUR_UID = os.userInfo().uid; let availIds: number[] | null = null; let nextId: number | null = null; @@ -50,11 +51,7 @@ async function createUser(log: (msg: string) => void): Promise { export async function borrowUser(log: (msg: string) => void) { if (!PRIVILEGED) { - if (CUR_UID === null) { - throw new Error("unable to determine current UID"); - } else { - return { uid: CUR_UID, cleanup: async () => {} }; - } + return { uid: CUR_UID, cleanup: async () => {} }; } else { return await lock.acquire("key", async () => { if (availIds === null || nextId === null) { diff --git a/backend/src/util.ts b/backend/src/util.ts index 235252c..b1d7a64 100644 --- a/backend/src/util.ts +++ b/backend/src/util.ts @@ -1,17 +1,23 @@ import { spawn, SpawnOptions } from "child_process"; import * as process from "process"; +import * as appRoot from "app-root-path"; + interface Options extends SpawnOptions { input?: string; } +export const rijuSystemPrivileged = appRoot.resolve( + "system/out/riju-system-privileged" +); + export function getEnv(uuid: string) { const cwd = `/tmp/riju/${uuid}`; return { HOME: cwd, HOSTNAME: "riju", - LANG: "C.UTF-8", - LC_ALL: "C.UTF-8", + LANG: process.env.LANG || "", + LC_ALL: process.env.LC_ALL || "", PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin", PWD: cwd, SHELL: "/usr/bin/bash", @@ -59,11 +65,7 @@ export async function callPrivileged( log: (msg: string) => void, options?: Options ) { - await call( - ["/home/docker/src/system/out/riju-system-privileged"].concat(args), - log, - options - ); + await call([rijuSystemPrivileged].concat(args), log, options); } export async function spawnPrivileged( diff --git a/package.json b/package.json index c5a08b2..daf5eb5 100644 --- a/package.json +++ b/package.json @@ -49,9 +49,9 @@ "frontend": "webpack --production", "frontend-dev": "webpack --development --watch", "server": "scripts/setup.bash && node backend/out/server.js", - "server-dev": "watchexec -w backend/out -r 'scripts/setup.bash && node backend/out/server.js'", + "server-dev": "watchexec --no-vcs-ignore -w backend/out -r 'scripts/setup.bash && node backend/out/server.js'", "system": "scripts/compile-system.bash", - "system-dev": "watchexec -w system/src -n scripts/compile-system.bash", + "system-dev": "watchexec --no-vcs-ignore -w system/src -n scripts/compile-system.bash", "build": "run-s backend frontend system", "dev": "run-p backend-dev frontend-dev system-dev server-dev" } diff --git a/scripts/docker-install-phase5.bash b/scripts/docker-install-phase5.bash index 003017c..7359c57 100755 --- a/scripts/docker-install-phase5.bash +++ b/scripts/docker-install-phase5.bash @@ -70,7 +70,7 @@ chmod +x /opt/mspyls/Microsoft.Python.LanguageServer ln -s /opt/mspyls/Microsoft.Python.LanguageServer /usr/bin/Microsoft.Python.LanguageServer # SNOBOL -wget -nv ftp://ftp.snobol4.org/snobol/snobol4-2.0.tar.gz +wget -nv ftp://ftp.snobol4.org/snobol/old/snobol4-2.1.4.tar.gz tar -xf snobol4-*.tar.gz rm snobol4-*.tar.gz pushd snobol4-* >/dev/null diff --git a/scripts/setup.bash b/scripts/setup.bash index 08923fb..e9a597e 100755 --- a/scripts/setup.bash +++ b/scripts/setup.bash @@ -5,6 +5,6 @@ set -o pipefail mkdir -p /tmp/riju if [[ -x system/out/riju-system-privileged ]]; then - system/out/riju-system-privileged teardown "*" + system/out/riju-system-privileged teardown "*" || true fi chmod a=x,u=rwx /tmp/riju diff --git a/system/src/riju-system-privileged.c b/system/src/riju-system-privileged.c index 8ad72d1..20772d8 100644 --- a/system/src/riju-system-privileged.c +++ b/system/src/riju-system-privileged.c @@ -12,6 +12,8 @@ const int MIN_UID = 2000; const int MAX_UID = 65000; +int privileged; + void die(char *msg) { fprintf(stderr, "%s\n", msg); @@ -29,6 +31,8 @@ void die_with_usage() int parseUID(char *str) { + if (!privileged) + return -1; char *endptr; long uid = strtol(str, &endptr, 10); if (!*str || *endptr) @@ -50,6 +54,8 @@ char *parseUUID(char *uuid) void useradd(int uid) { + if (!privileged) + die("useradd not allowed without root privileges"); char *cmdline; if (asprintf(&cmdline, "groupadd -g %1$d riju%1$d", uid) < 0) die("asprintf failed"); @@ -70,12 +76,14 @@ void spawn(int uid, char *uuid, char **cmdline) die("asprintf failed"); if (chdir(cwd) < 0) die("chdir failed"); - if (setgid(uid) < 0) - die("setgid failed"); - if (setgroups(0, NULL) < 0) - die("setgroups failed"); - if (setuid(uid) < 0) - die("setuid failed"); + if (privileged) { + if (setgid(uid) < 0) + die("setgid failed"); + if (setgroups(0, NULL) < 0) + die("setgroups failed"); + if (setuid(uid) < 0) + die("setuid failed"); + } umask(077); execvp(cmdline[0], cmdline); die("execvp failed"); @@ -84,7 +92,9 @@ void spawn(int uid, char *uuid, char **cmdline) void setup(int uid, char *uuid) { char *cmdline; - if (asprintf(&cmdline, "install -d -o riju%1$d -g riju%1$d -m 700 /tmp/riju/%2$s", uid, uuid) < 0) + if (asprintf(&cmdline, privileged + ? "install -d -o riju%1$d -g riju%1$d -m 700 /tmp/riju/%2$s" + : "install -d -m 700 /tmp/riju/%2$s", uid, uuid) < 0) die("asprintf failed"); int status = system(cmdline); if (status) @@ -103,7 +113,10 @@ void teardown(char *uuid) int main(int argc, char **argv) { - setuid(0); + int code = setuid(0); + if (code != 0 && code != -EPERM) + die("setuid failed"); + privileged = code == 0; if (argc < 2) die_with_usage(); if (!strcmp(argv[1], "useradd")) {