Misc bugfixes and robustness improvements

This commit is contained in:
Radon Rosborough 2020-07-05 12:21:59 -06:00
parent 4425f31b88
commit 337658a8bf
8 changed files with 79 additions and 50 deletions

View File

@ -43,8 +43,8 @@ container first:
$ make docker $ make docker
Note that building the image takes 30 minutes and requires about 15 GB Note that building the image takes about 30 minutes on high-end
of disk space. hardware and ethernet, and it requires about 15 GB of disk space.
## Flag ## Flag

View File

@ -10,7 +10,12 @@ import { v4 as getUUID } from "uuid";
import { PRIVILEGED } from "./config"; import { PRIVILEGED } from "./config";
import { LangConfig, langs } from "./langs"; import { LangConfig, langs } from "./langs";
import { borrowUser } from "./users"; import { borrowUser } from "./users";
import { callPrivileged, getEnv, spawnPrivileged } from "./util"; import {
callPrivileged,
getEnv,
rijuSystemPrivileged,
spawnPrivileged,
} from "./util";
export class Session { export class Session {
uuid: string; uuid: string;
@ -193,17 +198,15 @@ export class Session {
); );
} }
} }
const args = PRIVILEGED const args = [
? [ rijuSystemPrivileged,
"/home/docker/src/system/out/riju-system-privileged", "spawn",
"spawn", `${this.uid}`,
`${this.uid}`, `${this.uuid}`,
`${this.uuid}`, "bash",
"bash", "-c",
"-c", cmdline,
cmdline, ];
]
: ["bash", "-c", cmdline];
const env = getEnv(this.uuid); const env = getEnv(this.uuid);
const term = { const term = {
pty: pty.spawn(args[0], args.slice(1), { pty: pty.spawn(args[0], args.slice(1), {
@ -227,17 +230,15 @@ export class Session {
} }
}); });
if (lsp && this.lsp === null) { if (lsp && this.lsp === null) {
const lspArgs = PRIVILEGED const lspArgs = [
? [ rijuSystemPrivileged,
"/home/docker/src/system/out/riju-system-privileged", "spawn",
"spawn", `${this.uid}`,
`${this.uid}`, `${this.uuid}`,
`${this.uuid}`, "bash",
"bash", "-c",
"-c", lsp,
lsp, ];
]
: ["bash", "-c", lsp];
const proc = spawn(lspArgs[0], lspArgs.slice(1), { const proc = spawn(lspArgs[0], lspArgs.slice(1), {
env: getEnv(this.uuid), env: getEnv(this.uuid),
}); });
@ -254,6 +255,22 @@ export class Session {
}; };
cleanup = async () => { cleanup = async () => {
this.log(`Cleaning up session`); 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) { if (this.homedir) {
await callPrivileged(["teardown", this.uuid], this.log); await callPrivileged(["teardown", this.uuid], this.log);
} }

View File

@ -1,5 +1,6 @@
import { spawn } from "child_process"; import { spawn } from "child_process";
import * as fs from "fs"; import * as fs from "fs";
import * as os from "os";
import * as AsyncLock from "async-lock"; import * as AsyncLock from "async-lock";
import * as _ from "lodash"; import * as _ from "lodash";
@ -12,7 +13,7 @@ import { callPrivileged } from "./util";
const MIN_UID = 2000; const MIN_UID = 2000;
const MAX_UID = 65000; const MAX_UID = 65000;
const CUR_UID = parseInt(process.env.UID || "") || null; const CUR_UID = os.userInfo().uid;
let availIds: number[] | null = null; let availIds: number[] | null = null;
let nextId: number | null = null; let nextId: number | null = null;
@ -50,11 +51,7 @@ async function createUser(log: (msg: string) => void): Promise<number> {
export async function borrowUser(log: (msg: string) => void) { export async function borrowUser(log: (msg: string) => void) {
if (!PRIVILEGED) { if (!PRIVILEGED) {
if (CUR_UID === null) { return { uid: CUR_UID, cleanup: async () => {} };
throw new Error("unable to determine current UID");
} else {
return { uid: CUR_UID, cleanup: async () => {} };
}
} else { } else {
return await lock.acquire("key", async () => { return await lock.acquire("key", async () => {
if (availIds === null || nextId === null) { if (availIds === null || nextId === null) {

View File

@ -1,17 +1,23 @@
import { spawn, SpawnOptions } from "child_process"; import { spawn, SpawnOptions } from "child_process";
import * as process from "process"; import * as process from "process";
import * as appRoot from "app-root-path";
interface Options extends SpawnOptions { interface Options extends SpawnOptions {
input?: string; input?: string;
} }
export const rijuSystemPrivileged = appRoot.resolve(
"system/out/riju-system-privileged"
);
export function getEnv(uuid: string) { export function getEnv(uuid: string) {
const cwd = `/tmp/riju/${uuid}`; const cwd = `/tmp/riju/${uuid}`;
return { return {
HOME: cwd, HOME: cwd,
HOSTNAME: "riju", HOSTNAME: "riju",
LANG: "C.UTF-8", LANG: process.env.LANG || "",
LC_ALL: "C.UTF-8", LC_ALL: process.env.LC_ALL || "",
PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin", PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin",
PWD: cwd, PWD: cwd,
SHELL: "/usr/bin/bash", SHELL: "/usr/bin/bash",
@ -59,11 +65,7 @@ export async function callPrivileged(
log: (msg: string) => void, log: (msg: string) => void,
options?: Options options?: Options
) { ) {
await call( await call([rijuSystemPrivileged].concat(args), log, options);
["/home/docker/src/system/out/riju-system-privileged"].concat(args),
log,
options
);
} }
export async function spawnPrivileged( export async function spawnPrivileged(

View File

@ -49,9 +49,9 @@
"frontend": "webpack --production", "frontend": "webpack --production",
"frontend-dev": "webpack --development --watch", "frontend-dev": "webpack --development --watch",
"server": "scripts/setup.bash && node backend/out/server.js", "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": "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", "build": "run-s backend frontend system",
"dev": "run-p backend-dev frontend-dev system-dev server-dev" "dev": "run-p backend-dev frontend-dev system-dev server-dev"
} }

View File

@ -70,7 +70,7 @@ chmod +x /opt/mspyls/Microsoft.Python.LanguageServer
ln -s /opt/mspyls/Microsoft.Python.LanguageServer /usr/bin/Microsoft.Python.LanguageServer ln -s /opt/mspyls/Microsoft.Python.LanguageServer /usr/bin/Microsoft.Python.LanguageServer
# SNOBOL # 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 tar -xf snobol4-*.tar.gz
rm snobol4-*.tar.gz rm snobol4-*.tar.gz
pushd snobol4-* >/dev/null pushd snobol4-* >/dev/null

View File

@ -5,6 +5,6 @@ set -o pipefail
mkdir -p /tmp/riju mkdir -p /tmp/riju
if [[ -x system/out/riju-system-privileged ]]; then if [[ -x system/out/riju-system-privileged ]]; then
system/out/riju-system-privileged teardown "*" system/out/riju-system-privileged teardown "*" || true
fi fi
chmod a=x,u=rwx /tmp/riju chmod a=x,u=rwx /tmp/riju

View File

@ -12,6 +12,8 @@
const int MIN_UID = 2000; const int MIN_UID = 2000;
const int MAX_UID = 65000; const int MAX_UID = 65000;
int privileged;
void die(char *msg) void die(char *msg)
{ {
fprintf(stderr, "%s\n", msg); fprintf(stderr, "%s\n", msg);
@ -29,6 +31,8 @@ void die_with_usage()
int parseUID(char *str) int parseUID(char *str)
{ {
if (!privileged)
return -1;
char *endptr; char *endptr;
long uid = strtol(str, &endptr, 10); long uid = strtol(str, &endptr, 10);
if (!*str || *endptr) if (!*str || *endptr)
@ -50,6 +54,8 @@ char *parseUUID(char *uuid)
void useradd(int uid) void useradd(int uid)
{ {
if (!privileged)
die("useradd not allowed without root privileges");
char *cmdline; char *cmdline;
if (asprintf(&cmdline, "groupadd -g %1$d riju%1$d", uid) < 0) if (asprintf(&cmdline, "groupadd -g %1$d riju%1$d", uid) < 0)
die("asprintf failed"); die("asprintf failed");
@ -70,12 +76,14 @@ void spawn(int uid, char *uuid, char **cmdline)
die("asprintf failed"); die("asprintf failed");
if (chdir(cwd) < 0) if (chdir(cwd) < 0)
die("chdir failed"); die("chdir failed");
if (setgid(uid) < 0) if (privileged) {
die("setgid failed"); if (setgid(uid) < 0)
if (setgroups(0, NULL) < 0) die("setgid failed");
die("setgroups failed"); if (setgroups(0, NULL) < 0)
if (setuid(uid) < 0) die("setgroups failed");
die("setuid failed"); if (setuid(uid) < 0)
die("setuid failed");
}
umask(077); umask(077);
execvp(cmdline[0], cmdline); execvp(cmdline[0], cmdline);
die("execvp failed"); die("execvp failed");
@ -84,7 +92,9 @@ void spawn(int uid, char *uuid, char **cmdline)
void setup(int uid, char *uuid) void setup(int uid, char *uuid)
{ {
char *cmdline; 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"); die("asprintf failed");
int status = system(cmdline); int status = system(cmdline);
if (status) if (status)
@ -103,7 +113,10 @@ void teardown(char *uuid)
int main(int argc, char **argv) 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) if (argc < 2)
die_with_usage(); die_with_usage();
if (!strcmp(argv[1], "useradd")) { if (!strcmp(argv[1], "useradd")) {