@ai-ecoverse/slicc-kernel 1.173.3 → 1.174.0
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/README.md +3 -3
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +101 -20
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +4 -3
- package/dist/node-process-worker.cjs.map +2 -2
- package/dist/node-process-worker.js +4 -3
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +101 -20
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +4 -3
- package/dist/process-worker.js.map +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/kernel/process.d.ts +3 -2
- package/dist/types/node.d.ts +1 -1
- package/dist/types/sudo.d.ts +10 -0
- package/package.json +2 -2
package/dist/kernel-worker.js
CHANGED
|
@@ -8740,7 +8740,7 @@ function satisfies(version, range2) {
|
|
|
8740
8740
|
}
|
|
8741
8741
|
|
|
8742
8742
|
// src/version.ts
|
|
8743
|
-
var KERNEL_VERSION = true ? "1.
|
|
8743
|
+
var KERNEL_VERSION = true ? "1.174.0" : "0.0.0-dev";
|
|
8744
8744
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8745
8745
|
function procVersion() {
|
|
8746
8746
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -27458,9 +27458,10 @@ var WasmProcess = class {
|
|
|
27458
27458
|
cwd: typeof req.cwd === "string" && req.cwd.startsWith("/") ? req.cwd : "/",
|
|
27459
27459
|
...typeof req.term === "string" ? { term: req.term } : {}
|
|
27460
27460
|
};
|
|
27461
|
-
const answer2 = await sudo(call, this.blockingSignal(cancelled));
|
|
27461
|
+
const answer2 = await sudo(call, this.blockingSignal(cancelled), this.stdinKind());
|
|
27462
27462
|
if (!("grant" in answer2)) return answer2;
|
|
27463
27463
|
if (this.dying) throw new KernelError("EINTR");
|
|
27464
|
+
if (answer2.notice !== void 0) await this.complainLine(answer2.notice);
|
|
27464
27465
|
const { file, argv, env, cwd, cred, caller } = answer2.grant;
|
|
27465
27466
|
const stdio = [{ fd: 0 }, { fd: 1 }, { fd: 2 }];
|
|
27466
27467
|
return {
|
|
@@ -27470,6 +27471,14 @@ var WasmProcess = class {
|
|
|
27470
27471
|
})
|
|
27471
27472
|
};
|
|
27472
27473
|
}
|
|
27474
|
+
stdinKind() {
|
|
27475
|
+
if (!this.fds.has(0)) return "none";
|
|
27476
|
+
const { file } = this.fds.get(0);
|
|
27477
|
+
if (file.tty) return "tty";
|
|
27478
|
+
const meta = file.heldMeta;
|
|
27479
|
+
if (meta && "device" in meta) return meta.device === "null" ? "none" : "file";
|
|
27480
|
+
return file.seek || file.held ? "file" : "pipe";
|
|
27481
|
+
}
|
|
27473
27482
|
async mountSyscall(req, cancelled) {
|
|
27474
27483
|
const { mount, umount } = this.options;
|
|
27475
27484
|
if (!mount || !umount) throw new KernelError("ENOSYS");
|
|
@@ -31745,24 +31754,36 @@ var SUDO_TIMEOUT_MS = 3e5;
|
|
|
31745
31754
|
var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
|
|
31746
31755
|
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
31747
31756
|
var RULE = new RegExp(
|
|
31748
|
-
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
31757
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(none)\s+)?Cmnd(?:\s+(.*))?$`
|
|
31749
31758
|
);
|
|
31750
31759
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
31751
31760
|
var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
31752
|
-
var CONTROL = /[\
|
|
31761
|
+
var CONTROL = /[\p{Cc}\u2028\u2029]/u;
|
|
31762
|
+
var CONTROLS = /[\p{Cc}\u2028\u2029]/gu;
|
|
31753
31763
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
31754
31764
|
var DENIED2 = "sudo: approval denied";
|
|
31755
31765
|
var DENIAL_MAX = 500;
|
|
31756
31766
|
var ABORTED = /* @__PURE__ */ Symbol("aborted");
|
|
31767
|
+
var RAN_ONCE = "sudo: ran once; this command line can't be recorded as always";
|
|
31768
|
+
var ROOT_ONLY_MAX = 64;
|
|
31769
|
+
var OPERANDS_MAX = 256;
|
|
31770
|
+
var PATH_MAX = 4096;
|
|
31757
31771
|
function hasControl(text) {
|
|
31758
31772
|
return CONTROL.test(text);
|
|
31759
31773
|
}
|
|
31774
|
+
function stdinMatches(rule, stdin) {
|
|
31775
|
+
return rule.stdin === void 0 || stdin === "tty" || stdin === "none";
|
|
31776
|
+
}
|
|
31777
|
+
function recordable(cwd, argv) {
|
|
31778
|
+
return !hasControl(cwd) && !argv.some(hasControl);
|
|
31779
|
+
}
|
|
31760
31780
|
function withoutControl(text) {
|
|
31761
|
-
return text.replace(
|
|
31781
|
+
return text.replace(CONTROLS, (ch) => {
|
|
31762
31782
|
const n = ch.charCodeAt(0);
|
|
31763
31783
|
if (n === 9) return "\\t";
|
|
31764
31784
|
if (n === 10) return "\\n";
|
|
31765
31785
|
if (n === 13) return "\\r";
|
|
31786
|
+
if (n > 255) return `\\u${n.toString(16)}`;
|
|
31766
31787
|
return `\\x${n.toString(16).padStart(2, "0")}`;
|
|
31767
31788
|
});
|
|
31768
31789
|
}
|
|
@@ -31946,11 +31967,17 @@ function parseRule(line) {
|
|
|
31946
31967
|
if (text === "" || text.startsWith("#")) return null;
|
|
31947
31968
|
const m = RULE.exec(text);
|
|
31948
31969
|
if (!m) return void 0;
|
|
31949
|
-
const [, nopasswd, who = "", target = "root", dir, rest2 = ""] = m;
|
|
31970
|
+
const [, nopasswd, who = "", target = "root", dir, stdin, rest2 = ""] = m;
|
|
31950
31971
|
if (!validWho(who) || target !== "ALL" && !NAME3.test(target)) return void 0;
|
|
31951
31972
|
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
31952
31973
|
if (cwd === "") return void 0;
|
|
31953
|
-
const rule = {
|
|
31974
|
+
const rule = {
|
|
31975
|
+
nopasswd: !!nopasswd,
|
|
31976
|
+
who,
|
|
31977
|
+
target,
|
|
31978
|
+
...cwd !== void 0 ? { cwd } : {},
|
|
31979
|
+
...stdin === "none" ? { stdin: "none" } : {}
|
|
31980
|
+
};
|
|
31954
31981
|
if (rest2.trim() === "*") return { ...rule, cmnd: "*" };
|
|
31955
31982
|
const words2 = splitPatterns(rest2);
|
|
31956
31983
|
const [first, ...args] = words2 ?? [];
|
|
@@ -31968,7 +31995,8 @@ function recordedBare(line, file, rule) {
|
|
|
31968
31995
|
const head = `NOPASSWD ${rule.who} (${rule.target}) `;
|
|
31969
31996
|
const cmnd = `Cmnd ${quoteWord(rule.cmnd.path)}`;
|
|
31970
31997
|
const cwd = rule.cwd === void 0 ? "" : `Cwd ${quoteWord(rule.cwd)} `;
|
|
31971
|
-
|
|
31998
|
+
const stdin = rule.stdin === void 0 ? "" : "Stdin none ";
|
|
31999
|
+
return line.trimEnd() === `${head}${cwd}${stdin}${cmnd}`;
|
|
31972
32000
|
}
|
|
31973
32001
|
function flags(parsed2, arg, next3) {
|
|
31974
32002
|
for (let j = 1; j < arg.length; j++) {
|
|
@@ -32008,7 +32036,8 @@ function parseArgs(args) {
|
|
|
32008
32036
|
function described(rule) {
|
|
32009
32037
|
const cmnd = rule.cmnd === "*" ? "ALL" : commandText(rule.cmnd);
|
|
32010
32038
|
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
32011
|
-
|
|
32039
|
+
const stdin = rule.stdin === void 0 ? "" : "STDIN=none ";
|
|
32040
|
+
return ` (${rule.target}) ${cwd}${stdin}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
|
|
32012
32041
|
}
|
|
32013
32042
|
var Sudo = class {
|
|
32014
32043
|
o;
|
|
@@ -32043,6 +32072,51 @@ var Sudo = class {
|
|
|
32043
32072
|
}
|
|
32044
32073
|
return true;
|
|
32045
32074
|
}
|
|
32075
|
+
async rootOnly(cwd, args) {
|
|
32076
|
+
const { fs } = this.o;
|
|
32077
|
+
const found = {};
|
|
32078
|
+
const paths = [cwd];
|
|
32079
|
+
for (const arg of args.slice(0, OPERANDS_MAX)) {
|
|
32080
|
+
const value2 = /^--[^=]+=(.+)$/s.exec(arg)?.[1];
|
|
32081
|
+
for (const word of value2 === void 0 ? [arg] : [arg, value2]) {
|
|
32082
|
+
if (word === "" || word.length > PATH_MAX) continue;
|
|
32083
|
+
const raw2 = word.startsWith("/") ? word : `${cwd}/${word}`;
|
|
32084
|
+
if (word.startsWith("/") || await fs.lstat(normalizePath(raw2)).catch(() => void 0)) {
|
|
32085
|
+
paths.push(raw2);
|
|
32086
|
+
}
|
|
32087
|
+
}
|
|
32088
|
+
}
|
|
32089
|
+
for (const raw2 of paths) {
|
|
32090
|
+
const key = normalizePath(raw2);
|
|
32091
|
+
const known = Object.hasOwn(found, key);
|
|
32092
|
+
if (!known && Object.keys(found).length >= ROOT_ONLY_MAX) break;
|
|
32093
|
+
if (known && !found[key]) continue;
|
|
32094
|
+
found[key] = !await this.crossesLink(raw2) && await this.trusted(await this.existing(key));
|
|
32095
|
+
}
|
|
32096
|
+
return found;
|
|
32097
|
+
}
|
|
32098
|
+
async crossesLink(path) {
|
|
32099
|
+
const parts2 = [];
|
|
32100
|
+
for (const part of path.split("/")) {
|
|
32101
|
+
if (part === "" || part === ".") continue;
|
|
32102
|
+
if (part !== "..") {
|
|
32103
|
+
parts2.push(part);
|
|
32104
|
+
continue;
|
|
32105
|
+
}
|
|
32106
|
+
const at = `/${parts2.join("/")}`;
|
|
32107
|
+
const st = parts2.length > 0 ? await this.o.fs.lstat(at).catch(() => void 0) : void 0;
|
|
32108
|
+
if (st?.isSymbolicLink) return true;
|
|
32109
|
+
parts2.pop();
|
|
32110
|
+
}
|
|
32111
|
+
return false;
|
|
32112
|
+
}
|
|
32113
|
+
async existing(path) {
|
|
32114
|
+
let at = normalizePath(path);
|
|
32115
|
+
while (at !== "/" && !await this.o.fs.lstat(at).catch(() => void 0)) {
|
|
32116
|
+
at = at.slice(0, at.lastIndexOf("/")) || "/";
|
|
32117
|
+
}
|
|
32118
|
+
return at;
|
|
32119
|
+
}
|
|
32046
32120
|
async policyFile(path) {
|
|
32047
32121
|
if (!await this.trusted(path)) {
|
|
32048
32122
|
this.warn(`sudo: ${path} skipped: it must be root's, no symlink, and writable by root only`);
|
|
@@ -32150,7 +32224,7 @@ var Sudo = class {
|
|
|
32150
32224
|
if (untrusted2) return untrusted2;
|
|
32151
32225
|
const argv = [path, ...args];
|
|
32152
32226
|
const matching = rules.filter(
|
|
32153
|
-
(rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && commandMatches(rule.cmnd, argv)
|
|
32227
|
+
(rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv)
|
|
32154
32228
|
);
|
|
32155
32229
|
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
32156
32230
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
@@ -32172,14 +32246,19 @@ var Sudo = class {
|
|
|
32172
32246
|
}
|
|
32173
32247
|
const changed = await this.untrusted(path, cwd, word);
|
|
32174
32248
|
if (changed) return changed;
|
|
32175
|
-
if (answer2 === "
|
|
32176
|
-
|
|
32177
|
-
}
|
|
32178
|
-
return grant();
|
|
32249
|
+
if (answer2 === "once") return grant();
|
|
32250
|
+
return await this.always(self, target, cwd, argv, recordable(cwd, parsed2.command), grant);
|
|
32179
32251
|
} finally {
|
|
32180
32252
|
this.pending.delete(cred.ruid);
|
|
32181
32253
|
}
|
|
32182
32254
|
}
|
|
32255
|
+
async always(self, target, cwd, argv, shown, grant) {
|
|
32256
|
+
if (!shown || !recordable(cwd, argv)) return { ...grant(), notice: RAN_ONCE };
|
|
32257
|
+
if (!await this.remember(self, target, cwd, argv)) {
|
|
32258
|
+
return failed3("EIO", "sudo: the rule could not be recorded");
|
|
32259
|
+
}
|
|
32260
|
+
return grant();
|
|
32261
|
+
}
|
|
32183
32262
|
listed(self, root, rules) {
|
|
32184
32263
|
const host = this.o.hostname;
|
|
32185
32264
|
if (root) {
|
|
@@ -32216,7 +32295,9 @@ ${lines2}
|
|
|
32216
32295
|
...caller.tty ? { tty: caller.tty } : {},
|
|
32217
32296
|
createdAt,
|
|
32218
32297
|
expiresAt: createdAt + timeout,
|
|
32219
|
-
always:
|
|
32298
|
+
always: recordable(cwd, [path, ...argv]),
|
|
32299
|
+
stdin: caller.stdin,
|
|
32300
|
+
rootOnly: await this.rootOnly(cwd, argv.slice(1))
|
|
32220
32301
|
};
|
|
32221
32302
|
const control = new AbortController();
|
|
32222
32303
|
const timer = setTimeout(() => control.abort("expired"), timeout);
|
|
@@ -32239,7 +32320,6 @@ ${lines2}
|
|
|
32239
32320
|
const { fs } = this.o;
|
|
32240
32321
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
32241
32322
|
if (!NAME3.test(self.name)) return false;
|
|
32242
|
-
if (hasControl(cwd) || argv.some(hasControl)) return false;
|
|
32243
32323
|
try {
|
|
32244
32324
|
await this.provision();
|
|
32245
32325
|
if (!await this.trusted(SUDOERS_D)) return false;
|
|
@@ -32247,7 +32327,7 @@ ${lines2}
|
|
|
32247
32327
|
if (st && !await this.trusted(path)) return false;
|
|
32248
32328
|
const old = st ? await fs.readFile(path) : "";
|
|
32249
32329
|
const words2 = recordedCommand(argv);
|
|
32250
|
-
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Cmnd ${words2}
|
|
32330
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none Cmnd ${words2}
|
|
32251
32331
|
`;
|
|
32252
32332
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
32253
32333
|
${line}`;
|
|
@@ -34017,7 +34097,7 @@ var Launcher = class {
|
|
|
34017
34097
|
fileIds: this.rootFs.fileIdWrites?.() ?? 0,
|
|
34018
34098
|
holds: this.rootFs.holdCounts?.()
|
|
34019
34099
|
}),
|
|
34020
|
-
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
34100
|
+
sudo: (call, signal, stdin) => this.sudo(pid, call, signal, stdin),
|
|
34021
34101
|
crontab: (call) => this.crontab(pid, call),
|
|
34022
34102
|
openFiles: this.openFiles,
|
|
34023
34103
|
nodes: stack.nodes,
|
|
@@ -34257,12 +34337,13 @@ var Launcher = class {
|
|
|
34257
34337
|
base: this.tagBases.get(pid)
|
|
34258
34338
|
});
|
|
34259
34339
|
}
|
|
34260
|
-
sudo(pid, call, signal) {
|
|
34340
|
+
sudo(pid, call, signal, stdin) {
|
|
34261
34341
|
const caller = {
|
|
34262
34342
|
cred: this.credOf(pid),
|
|
34263
34343
|
pid: this.jobs.shown(pid),
|
|
34264
34344
|
tags: this.tagsOf(pid),
|
|
34265
|
-
tty: this.described.get(pid)?.tty
|
|
34345
|
+
tty: this.described.get(pid)?.tty,
|
|
34346
|
+
stdin
|
|
34266
34347
|
};
|
|
34267
34348
|
return this.sudoer.request(caller, call, signal);
|
|
34268
34349
|
}
|