@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/node.js
CHANGED
|
@@ -3702,7 +3702,7 @@ function satisfies(version, range2) {
|
|
|
3702
3702
|
}
|
|
3703
3703
|
|
|
3704
3704
|
// src/version.ts
|
|
3705
|
-
var KERNEL_VERSION = true ? "1.
|
|
3705
|
+
var KERNEL_VERSION = true ? "1.174.0" : "0.0.0-dev";
|
|
3706
3706
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3707
3707
|
function procVersion() {
|
|
3708
3708
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -23011,9 +23011,10 @@ var WasmProcess = class {
|
|
|
23011
23011
|
cwd: typeof req.cwd === "string" && req.cwd.startsWith("/") ? req.cwd : "/",
|
|
23012
23012
|
...typeof req.term === "string" ? { term: req.term } : {}
|
|
23013
23013
|
};
|
|
23014
|
-
const answer2 = await sudo(call, this.blockingSignal(cancelled));
|
|
23014
|
+
const answer2 = await sudo(call, this.blockingSignal(cancelled), this.stdinKind());
|
|
23015
23015
|
if (!("grant" in answer2)) return answer2;
|
|
23016
23016
|
if (this.dying) throw new KernelError("EINTR");
|
|
23017
|
+
if (answer2.notice !== void 0) await this.complainLine(answer2.notice);
|
|
23017
23018
|
const { file, argv, env, cwd, cred, caller } = answer2.grant;
|
|
23018
23019
|
const stdio = [{ fd: 0 }, { fd: 1 }, { fd: 2 }];
|
|
23019
23020
|
return {
|
|
@@ -23023,6 +23024,14 @@ var WasmProcess = class {
|
|
|
23023
23024
|
})
|
|
23024
23025
|
};
|
|
23025
23026
|
}
|
|
23027
|
+
stdinKind() {
|
|
23028
|
+
if (!this.fds.has(0)) return "none";
|
|
23029
|
+
const { file } = this.fds.get(0);
|
|
23030
|
+
if (file.tty) return "tty";
|
|
23031
|
+
const meta = file.heldMeta;
|
|
23032
|
+
if (meta && "device" in meta) return meta.device === "null" ? "none" : "file";
|
|
23033
|
+
return file.seek || file.held ? "file" : "pipe";
|
|
23034
|
+
}
|
|
23026
23035
|
async mountSyscall(req, cancelled) {
|
|
23027
23036
|
const { mount, umount } = this.options;
|
|
23028
23037
|
if (!mount || !umount) throw new KernelError("ENOSYS");
|
|
@@ -30645,24 +30654,36 @@ var SUDO_TIMEOUT_MS = 3e5;
|
|
|
30645
30654
|
var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
|
|
30646
30655
|
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
30647
30656
|
var RULE = new RegExp(
|
|
30648
|
-
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
30657
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(none)\s+)?Cmnd(?:\s+(.*))?$`
|
|
30649
30658
|
);
|
|
30650
30659
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
30651
30660
|
var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
30652
|
-
var CONTROL = /[\
|
|
30661
|
+
var CONTROL = /[\p{Cc}\u2028\u2029]/u;
|
|
30662
|
+
var CONTROLS = /[\p{Cc}\u2028\u2029]/gu;
|
|
30653
30663
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
30654
30664
|
var DENIED2 = "sudo: approval denied";
|
|
30655
30665
|
var DENIAL_MAX = 500;
|
|
30656
30666
|
var ABORTED = /* @__PURE__ */ Symbol("aborted");
|
|
30667
|
+
var RAN_ONCE = "sudo: ran once; this command line can't be recorded as always";
|
|
30668
|
+
var ROOT_ONLY_MAX = 64;
|
|
30669
|
+
var OPERANDS_MAX = 256;
|
|
30670
|
+
var PATH_MAX = 4096;
|
|
30657
30671
|
function hasControl(text) {
|
|
30658
30672
|
return CONTROL.test(text);
|
|
30659
30673
|
}
|
|
30674
|
+
function stdinMatches(rule, stdin) {
|
|
30675
|
+
return rule.stdin === void 0 || stdin === "tty" || stdin === "none";
|
|
30676
|
+
}
|
|
30677
|
+
function recordable(cwd, argv) {
|
|
30678
|
+
return !hasControl(cwd) && !argv.some(hasControl);
|
|
30679
|
+
}
|
|
30660
30680
|
function withoutControl(text) {
|
|
30661
|
-
return text.replace(
|
|
30681
|
+
return text.replace(CONTROLS, (ch) => {
|
|
30662
30682
|
const n = ch.charCodeAt(0);
|
|
30663
30683
|
if (n === 9) return "\\t";
|
|
30664
30684
|
if (n === 10) return "\\n";
|
|
30665
30685
|
if (n === 13) return "\\r";
|
|
30686
|
+
if (n > 255) return `\\u${n.toString(16)}`;
|
|
30666
30687
|
return `\\x${n.toString(16).padStart(2, "0")}`;
|
|
30667
30688
|
});
|
|
30668
30689
|
}
|
|
@@ -30846,11 +30867,17 @@ function parseRule(line) {
|
|
|
30846
30867
|
if (text === "" || text.startsWith("#")) return null;
|
|
30847
30868
|
const m = RULE.exec(text);
|
|
30848
30869
|
if (!m) return void 0;
|
|
30849
|
-
const [, nopasswd, who = "", target = "root", dir, rest2 = ""] = m;
|
|
30870
|
+
const [, nopasswd, who = "", target = "root", dir, stdin, rest2 = ""] = m;
|
|
30850
30871
|
if (!validWho(who) || target !== "ALL" && !NAME3.test(target)) return void 0;
|
|
30851
30872
|
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
30852
30873
|
if (cwd === "") return void 0;
|
|
30853
|
-
const rule = {
|
|
30874
|
+
const rule = {
|
|
30875
|
+
nopasswd: !!nopasswd,
|
|
30876
|
+
who,
|
|
30877
|
+
target,
|
|
30878
|
+
...cwd !== void 0 ? { cwd } : {},
|
|
30879
|
+
...stdin === "none" ? { stdin: "none" } : {}
|
|
30880
|
+
};
|
|
30854
30881
|
if (rest2.trim() === "*") return { ...rule, cmnd: "*" };
|
|
30855
30882
|
const words2 = splitPatterns(rest2);
|
|
30856
30883
|
const [first, ...args] = words2 ?? [];
|
|
@@ -30868,7 +30895,8 @@ function recordedBare(line, file, rule) {
|
|
|
30868
30895
|
const head = `NOPASSWD ${rule.who} (${rule.target}) `;
|
|
30869
30896
|
const cmnd = `Cmnd ${quoteWord(rule.cmnd.path)}`;
|
|
30870
30897
|
const cwd = rule.cwd === void 0 ? "" : `Cwd ${quoteWord(rule.cwd)} `;
|
|
30871
|
-
|
|
30898
|
+
const stdin = rule.stdin === void 0 ? "" : "Stdin none ";
|
|
30899
|
+
return line.trimEnd() === `${head}${cwd}${stdin}${cmnd}`;
|
|
30872
30900
|
}
|
|
30873
30901
|
function flags(parsed2, arg, next3) {
|
|
30874
30902
|
for (let j = 1; j < arg.length; j++) {
|
|
@@ -30908,7 +30936,8 @@ function parseArgs(args) {
|
|
|
30908
30936
|
function described(rule) {
|
|
30909
30937
|
const cmnd = rule.cmnd === "*" ? "ALL" : commandText(rule.cmnd);
|
|
30910
30938
|
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
30911
|
-
|
|
30939
|
+
const stdin = rule.stdin === void 0 ? "" : "STDIN=none ";
|
|
30940
|
+
return ` (${rule.target}) ${cwd}${stdin}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
|
|
30912
30941
|
}
|
|
30913
30942
|
var Sudo = class {
|
|
30914
30943
|
o;
|
|
@@ -30943,6 +30972,51 @@ var Sudo = class {
|
|
|
30943
30972
|
}
|
|
30944
30973
|
return true;
|
|
30945
30974
|
}
|
|
30975
|
+
async rootOnly(cwd, args) {
|
|
30976
|
+
const { fs } = this.o;
|
|
30977
|
+
const found = {};
|
|
30978
|
+
const paths = [cwd];
|
|
30979
|
+
for (const arg of args.slice(0, OPERANDS_MAX)) {
|
|
30980
|
+
const value2 = /^--[^=]+=(.+)$/s.exec(arg)?.[1];
|
|
30981
|
+
for (const word of value2 === void 0 ? [arg] : [arg, value2]) {
|
|
30982
|
+
if (word === "" || word.length > PATH_MAX) continue;
|
|
30983
|
+
const raw2 = word.startsWith("/") ? word : `${cwd}/${word}`;
|
|
30984
|
+
if (word.startsWith("/") || await fs.lstat(normalizePath(raw2)).catch(() => void 0)) {
|
|
30985
|
+
paths.push(raw2);
|
|
30986
|
+
}
|
|
30987
|
+
}
|
|
30988
|
+
}
|
|
30989
|
+
for (const raw2 of paths) {
|
|
30990
|
+
const key = normalizePath(raw2);
|
|
30991
|
+
const known = Object.hasOwn(found, key);
|
|
30992
|
+
if (!known && Object.keys(found).length >= ROOT_ONLY_MAX) break;
|
|
30993
|
+
if (known && !found[key]) continue;
|
|
30994
|
+
found[key] = !await this.crossesLink(raw2) && await this.trusted(await this.existing(key));
|
|
30995
|
+
}
|
|
30996
|
+
return found;
|
|
30997
|
+
}
|
|
30998
|
+
async crossesLink(path) {
|
|
30999
|
+
const parts2 = [];
|
|
31000
|
+
for (const part of path.split("/")) {
|
|
31001
|
+
if (part === "" || part === ".") continue;
|
|
31002
|
+
if (part !== "..") {
|
|
31003
|
+
parts2.push(part);
|
|
31004
|
+
continue;
|
|
31005
|
+
}
|
|
31006
|
+
const at = `/${parts2.join("/")}`;
|
|
31007
|
+
const st = parts2.length > 0 ? await this.o.fs.lstat(at).catch(() => void 0) : void 0;
|
|
31008
|
+
if (st?.isSymbolicLink) return true;
|
|
31009
|
+
parts2.pop();
|
|
31010
|
+
}
|
|
31011
|
+
return false;
|
|
31012
|
+
}
|
|
31013
|
+
async existing(path) {
|
|
31014
|
+
let at = normalizePath(path);
|
|
31015
|
+
while (at !== "/" && !await this.o.fs.lstat(at).catch(() => void 0)) {
|
|
31016
|
+
at = at.slice(0, at.lastIndexOf("/")) || "/";
|
|
31017
|
+
}
|
|
31018
|
+
return at;
|
|
31019
|
+
}
|
|
30946
31020
|
async policyFile(path) {
|
|
30947
31021
|
if (!await this.trusted(path)) {
|
|
30948
31022
|
this.warn(`sudo: ${path} skipped: it must be root's, no symlink, and writable by root only`);
|
|
@@ -31050,7 +31124,7 @@ var Sudo = class {
|
|
|
31050
31124
|
if (untrusted2) return untrusted2;
|
|
31051
31125
|
const argv = [path, ...args];
|
|
31052
31126
|
const matching = rules.filter(
|
|
31053
|
-
(rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && commandMatches(rule.cmnd, argv)
|
|
31127
|
+
(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)
|
|
31054
31128
|
);
|
|
31055
31129
|
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
31056
31130
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
@@ -31072,14 +31146,19 @@ var Sudo = class {
|
|
|
31072
31146
|
}
|
|
31073
31147
|
const changed = await this.untrusted(path, cwd, word);
|
|
31074
31148
|
if (changed) return changed;
|
|
31075
|
-
if (answer2 === "
|
|
31076
|
-
|
|
31077
|
-
}
|
|
31078
|
-
return grant();
|
|
31149
|
+
if (answer2 === "once") return grant();
|
|
31150
|
+
return await this.always(self, target, cwd, argv, recordable(cwd, parsed2.command), grant);
|
|
31079
31151
|
} finally {
|
|
31080
31152
|
this.pending.delete(cred.ruid);
|
|
31081
31153
|
}
|
|
31082
31154
|
}
|
|
31155
|
+
async always(self, target, cwd, argv, shown, grant) {
|
|
31156
|
+
if (!shown || !recordable(cwd, argv)) return { ...grant(), notice: RAN_ONCE };
|
|
31157
|
+
if (!await this.remember(self, target, cwd, argv)) {
|
|
31158
|
+
return failed3("EIO", "sudo: the rule could not be recorded");
|
|
31159
|
+
}
|
|
31160
|
+
return grant();
|
|
31161
|
+
}
|
|
31083
31162
|
listed(self, root, rules) {
|
|
31084
31163
|
const host = this.o.hostname;
|
|
31085
31164
|
if (root) {
|
|
@@ -31116,7 +31195,9 @@ ${lines2}
|
|
|
31116
31195
|
...caller.tty ? { tty: caller.tty } : {},
|
|
31117
31196
|
createdAt,
|
|
31118
31197
|
expiresAt: createdAt + timeout,
|
|
31119
|
-
always:
|
|
31198
|
+
always: recordable(cwd, [path, ...argv]),
|
|
31199
|
+
stdin: caller.stdin,
|
|
31200
|
+
rootOnly: await this.rootOnly(cwd, argv.slice(1))
|
|
31120
31201
|
};
|
|
31121
31202
|
const control = new AbortController();
|
|
31122
31203
|
const timer = setTimeout(() => control.abort("expired"), timeout);
|
|
@@ -31139,7 +31220,6 @@ ${lines2}
|
|
|
31139
31220
|
const { fs } = this.o;
|
|
31140
31221
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
31141
31222
|
if (!NAME3.test(self.name)) return false;
|
|
31142
|
-
if (hasControl(cwd) || argv.some(hasControl)) return false;
|
|
31143
31223
|
try {
|
|
31144
31224
|
await this.provision();
|
|
31145
31225
|
if (!await this.trusted(SUDOERS_D)) return false;
|
|
@@ -31147,7 +31227,7 @@ ${lines2}
|
|
|
31147
31227
|
if (st && !await this.trusted(path)) return false;
|
|
31148
31228
|
const old = st ? await fs.readFile(path) : "";
|
|
31149
31229
|
const words2 = recordedCommand(argv);
|
|
31150
|
-
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Cmnd ${words2}
|
|
31230
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none Cmnd ${words2}
|
|
31151
31231
|
`;
|
|
31152
31232
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
31153
31233
|
${line}`;
|
|
@@ -32913,7 +32993,7 @@ var Launcher = class {
|
|
|
32913
32993
|
fileIds: this.rootFs.fileIdWrites?.() ?? 0,
|
|
32914
32994
|
holds: this.rootFs.holdCounts?.()
|
|
32915
32995
|
}),
|
|
32916
|
-
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
32996
|
+
sudo: (call, signal, stdin) => this.sudo(pid, call, signal, stdin),
|
|
32917
32997
|
crontab: (call) => this.crontab(pid, call),
|
|
32918
32998
|
openFiles: this.openFiles,
|
|
32919
32999
|
nodes: stack.nodes,
|
|
@@ -33153,12 +33233,13 @@ var Launcher = class {
|
|
|
33153
33233
|
base: this.tagBases.get(pid)
|
|
33154
33234
|
});
|
|
33155
33235
|
}
|
|
33156
|
-
sudo(pid, call, signal) {
|
|
33236
|
+
sudo(pid, call, signal, stdin) {
|
|
33157
33237
|
const caller = {
|
|
33158
33238
|
cred: this.credOf(pid),
|
|
33159
33239
|
pid: this.jobs.shown(pid),
|
|
33160
33240
|
tags: this.tagsOf(pid),
|
|
33161
|
-
tty: this.described.get(pid)?.tty
|
|
33241
|
+
tty: this.described.get(pid)?.tty,
|
|
33242
|
+
stdin
|
|
33162
33243
|
};
|
|
33163
33244
|
return this.sudoer.request(caller, call, signal);
|
|
33164
33245
|
}
|