Misc bugfixes and robustness improvements
This commit is contained in:
parent
4425f31b88
commit
337658a8bf
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")) {
|
||||||
|
|
Loading…
Reference in New Issue