@ai-ecoverse/slicc-kernel 1.64.0 → 1.64.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.js CHANGED
@@ -410,6 +410,11 @@ var Created = class {
410
410
  function deny(g, op, path, errno = "EACCES") {
411
411
  g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno });
412
412
  }
413
+ var TTY_MODE = 400;
414
+ function ttyOpenable(g, tty) {
415
+ if (!g || !tty.owner || permits(g.cred, tty.owner, R_OK | W_OK, false)) return;
416
+ deny(g, "open", tty.name ?? "/dev/tty");
417
+ }
413
418
  async function need(g, op, path, want, options = {}, shown = path) {
414
419
  const walked = await access(g.fs, g.cred, path, want, options);
415
420
  if (walked.denied !== void 0) deny(g, op, shown);
@@ -2307,10 +2312,18 @@ var UserDb = class {
2307
2312
  };
2308
2313
  }
2309
2314
  async lookup(user) {
2315
+ return (await this.lookupTerminal(user))?.account;
2316
+ }
2317
+ async ttyGroup() {
2318
+ return parsed(parseGroup(await this.read(GROUP, DEFAULT_GROUP))).find((g) => g.name === "tty")?.gid;
2319
+ }
2320
+ async lookupTerminal(user) {
2310
2321
  const { passwd, group } = await this.tables();
2311
2322
  const key = typeof user === "number" ? "uid" : "name";
2312
2323
  const row = parsed(passwd).find((r) => r[key] === user);
2313
- return row && this.account(row, parsed(group));
2324
+ const groups = parsed(group);
2325
+ const tty = groups.find((g) => g.name === "tty")?.gid;
2326
+ return row && { account: this.account(row, groups), tty };
2314
2327
  }
2315
2328
  async list() {
2316
2329
  const { passwd, group } = await this.tables();
@@ -7292,8 +7305,10 @@ var EARLY_WHOLE_FILE = 64 * 1024;
7292
7305
 
7293
7306
  // src/process/process-fds.ts
7294
7307
  var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
7308
+ var pinnedRoot;
7309
+ var rootKind = () => globalThis.navigator?.storage ? "opfs" : "memory";
7295
7310
  function mountTable(mounts = []) {
7296
- const root = globalThis.navigator?.storage ? "opfs" : "memory";
7311
+ const root = pinnedRoot ?? rootKind();
7297
7312
  const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
7298
7313
  for (const m of mounts) {
7299
7314
  const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
@@ -9589,6 +9604,7 @@ var KernelTty = class {
9589
9604
  waiters = [];
9590
9605
  hungUp = false;
9591
9606
  name;
9607
+ owner;
9592
9608
  onRead;
9593
9609
  readers = 0;
9594
9610
  screen;
@@ -9932,10 +9948,11 @@ var PtyTable = class {
9932
9948
  this.signal = signal;
9933
9949
  this.onRead = onRead;
9934
9950
  }
9935
- open() {
9951
+ open(owner) {
9936
9952
  let index = 0;
9937
9953
  while (this.pairs.has(index)) index += 1;
9938
9954
  const pair = new PtyPair(index, this.signal, (p) => this.pairs.delete(p.index), this.onRead);
9955
+ if (owner) pair.slave.owner = { uid: owner.uid, gid: owner.gid, mode: TTY_MODE };
9939
9956
  this.pairs.set(index, pair);
9940
9957
  return { pair, master: pair.master() };
9941
9958
  }
@@ -9948,6 +9965,10 @@ var PtyTable = class {
9948
9965
  return [...this.pairs.keys()].sort((a, b) => a - b);
9949
9966
  }
9950
9967
  };
9968
+ function ptsNumber(path) {
9969
+ const m = /^\/dev\/pts\/(\d+)$/.exec(path);
9970
+ return m ? Number(m[1]) : void 0;
9971
+ }
9951
9972
  var PTY_OPS = [
9952
9973
  "pty-open",
9953
9974
  "pty-slave-open",
@@ -9975,11 +9996,12 @@ function ptySyscall(req, ctx) {
9975
9996
  switch (req.op) {
9976
9997
  case "pty-open": {
9977
9998
  if (!ctx.ptys) throw new KernelError("ENOENT");
9978
- return json4(ctx.fds.install(ctx.ptys.open().master, 3));
9999
+ return json4(ctx.fds.install(ctx.ptys.open(ctx.owner).master, 3));
9979
10000
  }
9980
10001
  case "pty-slave-open": {
9981
10002
  if (!ctx.ptys) throw new KernelError("ENOENT");
9982
10003
  const pair = ctx.ptys.get(req.n);
10004
+ ttyOpenable(ctx.guard, pair.slave);
9983
10005
  const fd = ctx.fds.install(pair.openSlave(), 3);
9984
10006
  if (!req.noctty) ctx.jobs?.acquireTerminal(ctx.pid, pair.slave);
9985
10007
  return json4(fd);
@@ -10795,6 +10817,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
10795
10817
  "fd-promote",
10796
10818
  "fd-open-tty",
10797
10819
  "fd-tty-names",
10820
+ "fd-tty-owner",
10798
10821
  "tty-get",
10799
10822
  "tty-set",
10800
10823
  "tty-winsz",
@@ -10996,7 +11019,9 @@ var WasmProcess = class {
10996
11019
  }
10997
11020
  if (isPtySyscall(req)) {
10998
11021
  const { ptys, jobs } = this.options;
10999
- return ptySyscall(req, { pid: this.pid, fds: this.fds, ptys, jobs });
11022
+ const owner = this.options.owners ? this.ttyOwner() : void 0;
11023
+ const guard2 = this.guarded();
11024
+ return ptySyscall(req, { pid: this.pid, fds: this.fds, ptys, jobs, guard: guard2, owner });
11000
11025
  }
11001
11026
  return await this.procSyscall(req, cancelled);
11002
11027
  } catch (e) {
@@ -11128,6 +11153,25 @@ var WasmProcess = class {
11128
11153
  const want = (access2 === 1 ? 0 : R_OK) | (access2 !== 0 || req.truncate ? W_OK : 0);
11129
11154
  await openable(g, "open", req.path, want, req.create === true);
11130
11155
  }
11156
+ openTty(name2) {
11157
+ const tty = name2 === void 0 ? this.controllingTerminal() : this.options.jobs?.terminalNamed(name2);
11158
+ if (!tty) throw new KernelError("ENXIO");
11159
+ if (name2 !== void 0) ttyOpenable(this.guarded(), tty);
11160
+ return this.fds.install(tty.file(), 3);
11161
+ }
11162
+ guarded() {
11163
+ const { guard: guard2 } = this.options;
11164
+ return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
11165
+ }
11166
+ ttyOwner() {
11167
+ return { uid: this.cred.euid, gid: this.cred.egid, mode: TTY_MODE };
11168
+ }
11169
+ terminalByName(name2) {
11170
+ const n = ptsNumber(name2);
11171
+ const tty = n === void 0 ? this.options.jobs?.terminalNamed(name2) : this.options.ptys?.get(n).slave;
11172
+ if (!tty) throw new KernelError("ENOENT");
11173
+ return tty;
11174
+ }
11131
11175
  newOwner() {
11132
11176
  if (!this.options.owners) return void 0;
11133
11177
  return { uid: this.cred.euid, gid: this.cred.egid, mode: 438 & ~this.umask };
@@ -11231,13 +11275,12 @@ var WasmProcess = class {
11231
11275
  if (!req.keep) await Promise.resolve(this.fds.close(req.from));
11232
11276
  }
11233
11277
  return { ok: true, kind: "void" };
11234
- case "fd-open-tty": {
11235
- const tty = req.name === void 0 ? this.controllingTerminal() : this.options.jobs?.terminalNamed(req.name);
11236
- if (!tty) throw new KernelError("ENXIO");
11237
- return { ok: true, kind: "json", json: this.fds.install(tty.file(), 3) };
11238
- }
11278
+ case "fd-open-tty":
11279
+ return { ok: true, kind: "json", json: this.openTty(req.name) };
11239
11280
  case "fd-tty-names":
11240
11281
  return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
11282
+ case "fd-tty-owner":
11283
+ return { ok: true, kind: "json", json: this.terminalByName(req.name).owner ?? null };
11241
11284
  case "fd-select": {
11242
11285
  const { read, write, timeoutMs } = req;
11243
11286
  if (this.owed && timeoutMs !== 0) {
@@ -11918,7 +11961,7 @@ function spawnWasmProcess(opts) {
11918
11961
  finish(...dying.status(data.code));
11919
11962
  } else if (data?.type === WASM_PROCESS_ERROR) {
11920
11963
  if (!dying.ending) opts.onError?.(String(data.message));
11921
- finish(...dying.status(CRASHED));
11964
+ finish(...dying.status(data.code));
11922
11965
  } else if (data?.type === WASM_THREAD_SPAWN && data.thread) {
11923
11966
  spawnThread(data.thread);
11924
11967
  }
@@ -14962,7 +15005,12 @@ var Launcher = class {
14962
15005
  }
14963
15006
  async account(user) {
14964
15007
  if (typeof user === "object") return user;
14965
- const found = await this.users.lookup(user ?? 0);
15008
+ return (await this.terminalAccount(user)).account;
15009
+ }
15010
+ async terminalAccount(user) {
15011
+ if (typeof user === "object")
15012
+ return { account: user, tty: this.owners ? await this.users.ttyGroup() : void 0 };
15013
+ const found = await this.users.lookupTerminal(user ?? 0);
14966
15014
  if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
14967
15015
  return found;
14968
15016
  }
@@ -14984,7 +15032,7 @@ var Launcher = class {
14984
15032
  return { cwd, file, planned };
14985
15033
  }
14986
15034
  async openTerminal(argv, options) {
14987
- const account = await this.account(options.user);
15035
+ const { account, tty: ttyGroup } = await this.terminalAccount(options.user);
14988
15036
  const { cwd, file, planned } = await this.starting(argv, options.cwd, account);
14989
15037
  if (!planned) throw new Error(`${file}: command not found`);
14990
15038
  let leader = 0;
@@ -14994,6 +15042,7 @@ var Launcher = class {
14994
15042
  );
14995
15043
  tty.onRead = () => this.settling.reading(this.jobs.tcgetpgrp(tty, leader));
14996
15044
  tty.name = `/dev/tty${++this.terminals}`;
15045
+ if (this.owners) tty.owner = { uid: account.uid, gid: ttyGroup ?? account.gid, mode: TTY_MODE };
14997
15046
  tty.setSize(options.cols ?? 80, options.rows ?? 24);
14998
15047
  const fds = new FdTable();
14999
15048
  const stdio = tty.file();