@ai-ecoverse/slicc-kernel 1.178.1 → 1.178.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/README.md +8 -7
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +172 -54
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +172 -54
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/kernel/children.d.ts +5 -0
- package/dist/types/launcher.d.ts +3 -0
- package/dist/types/node.d.ts +1 -1
- package/dist/types/sudo.d.ts +12 -1
- package/dist/types/sudoers.d.ts +3 -1
- package/package.json +3 -3
|
@@ -7518,7 +7518,7 @@ var init_version = __esm({
|
|
|
7518
7518
|
"src/version.ts"() {
|
|
7519
7519
|
"use strict";
|
|
7520
7520
|
init_captured_globals();
|
|
7521
|
-
KERNEL_VERSION = true ? "1.178.
|
|
7521
|
+
KERNEL_VERSION = true ? "1.178.2" : "0.0.0-dev";
|
|
7522
7522
|
OS_RELEASE = "6.0.0-slicc";
|
|
7523
7523
|
}
|
|
7524
7524
|
});
|
|
@@ -7517,7 +7517,7 @@ var init_version = __esm({
|
|
|
7517
7517
|
"src/version.ts"() {
|
|
7518
7518
|
"use strict";
|
|
7519
7519
|
init_captured_globals();
|
|
7520
|
-
KERNEL_VERSION = true ? "1.178.
|
|
7520
|
+
KERNEL_VERSION = true ? "1.178.2" : "0.0.0-dev";
|
|
7521
7521
|
OS_RELEASE = "6.0.0-slicc";
|
|
7522
7522
|
}
|
|
7523
7523
|
});
|
package/dist/node.js
CHANGED
|
@@ -3709,7 +3709,7 @@ function satisfies(version, range2) {
|
|
|
3709
3709
|
}
|
|
3710
3710
|
|
|
3711
3711
|
// src/version.ts
|
|
3712
|
-
var KERNEL_VERSION = true ? "1.178.
|
|
3712
|
+
var KERNEL_VERSION = true ? "1.178.2" : "0.0.0-dev";
|
|
3713
3713
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3714
3714
|
function procVersion() {
|
|
3715
3715
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -5004,9 +5004,9 @@ var UnlinkedKeeper = class {
|
|
|
5004
5004
|
if (kept.whole) return kept.undoing(async () => void 0);
|
|
5005
5005
|
await kept.undoing(
|
|
5006
5006
|
() => replace(target, async (gated, sealed) => {
|
|
5007
|
-
const
|
|
5008
|
-
if (
|
|
5009
|
-
else await keeper.settle(
|
|
5007
|
+
const pinned2 = await keeper.pin(target, gated, sealed);
|
|
5008
|
+
if (pinned2.moved.has(target)) pinned2.commit();
|
|
5009
|
+
else await keeper.settle(pinned2, () => fs.rm(path, options));
|
|
5010
5010
|
})
|
|
5011
5011
|
);
|
|
5012
5012
|
},
|
|
@@ -5019,8 +5019,8 @@ var UnlinkedKeeper = class {
|
|
|
5019
5019
|
() => keeper.marks.around(
|
|
5020
5020
|
[source],
|
|
5021
5021
|
() => replace(target, async (gated, sealed) => {
|
|
5022
|
-
const
|
|
5023
|
-
await keeper.settle(
|
|
5022
|
+
const pinned2 = await keeper.pin(target, gated, sealed);
|
|
5023
|
+
await keeper.settle(pinned2, () => fs.rename(from, to));
|
|
5024
5024
|
})
|
|
5025
5025
|
)
|
|
5026
5026
|
);
|
|
@@ -5055,14 +5055,14 @@ var UnlinkedKeeper = class {
|
|
|
5055
5055
|
}
|
|
5056
5056
|
return false;
|
|
5057
5057
|
}
|
|
5058
|
-
async settle(
|
|
5058
|
+
async settle(pinned2, op) {
|
|
5059
5059
|
try {
|
|
5060
5060
|
await op();
|
|
5061
5061
|
} catch (err) {
|
|
5062
|
-
await
|
|
5062
|
+
await pinned2.rollback();
|
|
5063
5063
|
throw err;
|
|
5064
5064
|
}
|
|
5065
|
-
|
|
5065
|
+
pinned2.commit();
|
|
5066
5066
|
}
|
|
5067
5067
|
heldWithin(target) {
|
|
5068
5068
|
const held = /* @__PURE__ */ new Map();
|
|
@@ -8294,6 +8294,13 @@ var SpawnError = class extends Error {
|
|
|
8294
8294
|
this.code = code;
|
|
8295
8295
|
}
|
|
8296
8296
|
};
|
|
8297
|
+
var ChangedError = class extends SpawnError {
|
|
8298
|
+
notice;
|
|
8299
|
+
constructor(notice) {
|
|
8300
|
+
super("EPERM");
|
|
8301
|
+
this.notice = notice;
|
|
8302
|
+
}
|
|
8303
|
+
};
|
|
8297
8304
|
function interrupted(signal) {
|
|
8298
8305
|
const { promise, reject } = Promise.withResolvers();
|
|
8299
8306
|
const fail3 = () => reject(new KernelError("EINTR"));
|
|
@@ -15304,8 +15311,10 @@ var SUDOERS_D = "/etc/sudoers.d";
|
|
|
15304
15311
|
var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
|
|
15305
15312
|
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
15306
15313
|
var KERNEL_FORM = new RegExp(
|
|
15307
|
-
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()]*)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(\S+)\s+)?Cmnd(?:\s+(.*))?$`
|
|
15314
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()]*)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(\S+)\s+)?((?:Sha256\s+${WORD}\s+)*)Cmnd(?:\s+(.*))?$`
|
|
15308
15315
|
);
|
|
15316
|
+
var SHA256_CLAUSE = new RegExp(String.raw`Sha256\s+(${WORD})`, "g");
|
|
15317
|
+
var HEX = /^[0-9a-f]{64}$/;
|
|
15309
15318
|
var SUDOERS_FORM = /^(\S+)\s+([^\s=]+)\s*=\s*(.*)$/;
|
|
15310
15319
|
var RUNAS = /^\(([^()]*)\)\s*/;
|
|
15311
15320
|
var TAG = /^([A-Z_]+)\s*:\s*/;
|
|
@@ -15314,7 +15323,7 @@ var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
|
15314
15323
|
var CONTROL2 = /[\p{Cc}\u2028\u2029]/u;
|
|
15315
15324
|
var CONTROLS = /[\p{Cc}\u2028\u2029]/gu;
|
|
15316
15325
|
var SHOWN_MAX = 60;
|
|
15317
|
-
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] Cmnd <command\u2026|*>";
|
|
15326
|
+
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] [Sha256 <file>=<sha256>\u2026] Cmnd <command\u2026|*>";
|
|
15318
15327
|
var SUDOERS_SYNTAX = "<user|%group|ALL> ALL=[(<target>[,<target>\u2026])] [NOPASSWD:] <command\u2026|ALL>";
|
|
15319
15328
|
var EXPECTED = `expected '${KERNEL_SYNTAX}' or '${SUDOERS_SYNTAX}'`;
|
|
15320
15329
|
var TIMESTAMP_TIMEOUT = 5;
|
|
@@ -15481,6 +15490,23 @@ function commandOf2(text, after) {
|
|
|
15481
15490
|
if (only && /\s""$/.test(text)) return { path, args: [] };
|
|
15482
15491
|
return args.length === 0 ? { path } : { path, args };
|
|
15483
15492
|
}
|
|
15493
|
+
function sha256Of(clauses) {
|
|
15494
|
+
const files = {};
|
|
15495
|
+
for (const [, word = ""] of clauses.matchAll(SHA256_CLAUSE)) {
|
|
15496
|
+
const [text = ""] = splitWords(word) ?? [];
|
|
15497
|
+
const at = text.lastIndexOf("=");
|
|
15498
|
+
const path = text.slice(0, at);
|
|
15499
|
+
const hex4 = text.slice(at + 1).toLowerCase();
|
|
15500
|
+
if (!path.startsWith("/") || !HEX.test(hex4)) {
|
|
15501
|
+
return `Sha256 expects <absolute file>=<sha256 in hex>, not ${shown(word)}`;
|
|
15502
|
+
}
|
|
15503
|
+
files[normalizePath(path)] = hex4;
|
|
15504
|
+
}
|
|
15505
|
+
return files;
|
|
15506
|
+
}
|
|
15507
|
+
function sha256Text(files) {
|
|
15508
|
+
return Object.entries(files).map(([path, hex4]) => `Sha256 ${quoteWord(`${path}=${hex4}`)} `).join("");
|
|
15509
|
+
}
|
|
15484
15510
|
function targetError(list) {
|
|
15485
15511
|
if (list.includes(",")) {
|
|
15486
15512
|
return `(${list}) names one user in this form: write one line per user, or use '${SUDOERS_SYNTAX}'`;
|
|
@@ -15488,19 +15514,22 @@ function targetError(list) {
|
|
|
15488
15514
|
return `expected one user name or ALL in (\u2026), not ${shown(`(${list})`)}`;
|
|
15489
15515
|
}
|
|
15490
15516
|
function kernelRules(m) {
|
|
15491
|
-
const [, nopasswd, who = "", target = "root", dir, stdin, rest2 = ""] = m;
|
|
15517
|
+
const [, nopasswd, who = "", target = "root", dir, stdin, sums = "", rest2 = ""] = m;
|
|
15492
15518
|
const bad = whoError(who);
|
|
15493
15519
|
if (bad !== void 0) return bad;
|
|
15494
15520
|
if (target !== "ALL" && !NAME3.test(target)) return targetError(target);
|
|
15495
15521
|
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
15496
15522
|
if (cwd === "") return `Cwd expects one absolute directory, not ${shown(dir)}`;
|
|
15497
15523
|
if (stdin !== void 0 && stdin !== "none") return `Stdin takes none, not ${shown(stdin)}`;
|
|
15524
|
+
const sha2564 = sha256Of(sums);
|
|
15525
|
+
if (typeof sha2564 === "string") return sha2564;
|
|
15498
15526
|
const rule = {
|
|
15499
15527
|
nopasswd: !!nopasswd,
|
|
15500
15528
|
who,
|
|
15501
15529
|
target,
|
|
15502
15530
|
...cwd !== void 0 ? { cwd } : {},
|
|
15503
|
-
...stdin === "none" ? { stdin: "none" } : {}
|
|
15531
|
+
...stdin === "none" ? { stdin: "none" } : {},
|
|
15532
|
+
...sums === "" ? {} : { sha256: sha2564 }
|
|
15504
15533
|
};
|
|
15505
15534
|
const text = rest2.trim();
|
|
15506
15535
|
if (text === "*") return [{ ...rule, cmnd: "*" }];
|
|
@@ -16130,12 +16159,26 @@ var RAN_ONCE = "sudo: ran once; this command line can't be recorded as always";
|
|
|
16130
16159
|
var ROOT_ONLY_MAX = 64;
|
|
16131
16160
|
var OPERANDS_MAX = 256;
|
|
16132
16161
|
var PATH_MAX = 4096;
|
|
16162
|
+
function userWritable(bound3) {
|
|
16163
|
+
const files = Object.entries(bound3).map(([path, hex4]) => ({ path, sha256: hex4 }));
|
|
16164
|
+
return files.length > 0 ? { userWritable: files } : {};
|
|
16165
|
+
}
|
|
16133
16166
|
function stdinMatches(rule, stdin) {
|
|
16134
16167
|
return rule.stdin === void 0 || stdin === "tty" || stdin === "none";
|
|
16135
16168
|
}
|
|
16136
16169
|
function recordable(cwd, argv) {
|
|
16137
16170
|
return !hasControl(cwd) && !argv.some(hasControl);
|
|
16138
16171
|
}
|
|
16172
|
+
function changedText(file) {
|
|
16173
|
+
return `sudo: ${file} changed since it was approved`;
|
|
16174
|
+
}
|
|
16175
|
+
function changedFile(approved, now) {
|
|
16176
|
+
const files = /* @__PURE__ */ new Set([...Object.keys(approved), ...Object.keys(now)]);
|
|
16177
|
+
return [...files].find((file) => approved[file] !== now[file]);
|
|
16178
|
+
}
|
|
16179
|
+
function pinned(rule, bound3) {
|
|
16180
|
+
return rule.sha256 === void 0 || changedFile(rule.sha256, bound3) === void 0;
|
|
16181
|
+
}
|
|
16139
16182
|
var VISUDO_FILES_MAX = 64;
|
|
16140
16183
|
var VISUDO_TEXT_MAX = 1024 * 1024;
|
|
16141
16184
|
function visudoCall(req) {
|
|
@@ -16266,11 +16309,13 @@ function usable(parsed2) {
|
|
|
16266
16309
|
function policyOf(settings) {
|
|
16267
16310
|
return { type: settings.timestampType, minutes: settings.timestampTimeout };
|
|
16268
16311
|
}
|
|
16269
|
-
function described(rule) {
|
|
16312
|
+
function described(rule, writable2) {
|
|
16270
16313
|
const cmnd = rule.cmnd === "*" ? "ALL" : commandText(rule.cmnd);
|
|
16271
16314
|
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
16272
16315
|
const stdin = rule.stdin === void 0 ? "" : "STDIN=none ";
|
|
16273
|
-
|
|
16316
|
+
const sums = Object.entries(rule.sha256 ?? {}).map(([path, hex4]) => `SHA256=${quoteWord(path)}:${hex4} `).join("");
|
|
16317
|
+
const flag = writable2 ? " # user-writable command" : "";
|
|
16318
|
+
return ` (${rule.target}) ${cwd}${stdin}${sums}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}${flag}`;
|
|
16274
16319
|
}
|
|
16275
16320
|
var Sudo = class {
|
|
16276
16321
|
o;
|
|
@@ -16461,15 +16506,31 @@ var Sudo = class {
|
|
|
16461
16506
|
if (walked.denied !== void 0 || walked.missing) return false;
|
|
16462
16507
|
return (await this.o.fs.stat(cwd).catch(() => void 0))?.isDirectory === true;
|
|
16463
16508
|
}
|
|
16464
|
-
async
|
|
16465
|
-
const
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16470
|
-
|
|
16509
|
+
async real(file) {
|
|
16510
|
+
const { fs } = this.o;
|
|
16511
|
+
return await fs.realpath?.(file, true).catch(() => file) ?? file;
|
|
16512
|
+
}
|
|
16513
|
+
async digests(files) {
|
|
16514
|
+
const { fs } = this.o;
|
|
16515
|
+
const found = {};
|
|
16516
|
+
for (const file of new Set(files)) {
|
|
16517
|
+
if (await this.trusted(file)) continue;
|
|
16518
|
+
const real = await this.real(file);
|
|
16519
|
+
found[real] = await fs.readFileBuffer(real).then(sha2562, () => "");
|
|
16471
16520
|
}
|
|
16472
|
-
return
|
|
16521
|
+
return found;
|
|
16522
|
+
}
|
|
16523
|
+
async bound(path, cwd) {
|
|
16524
|
+
const files = this.o.backing ? await this.o.backing(path, cwd) : [];
|
|
16525
|
+
const bound3 = files && await this.digests([path, ...files]);
|
|
16526
|
+
return bound3 && !Object.values(bound3).includes("") ? bound3 : void 0;
|
|
16527
|
+
}
|
|
16528
|
+
async writable(rule) {
|
|
16529
|
+
if (rule.cmnd === "*") return false;
|
|
16530
|
+
const { path } = rule.cmnd;
|
|
16531
|
+
const bound3 = await this.bound(path, "/");
|
|
16532
|
+
if (bound3) return Object.keys(bound3).length > 0;
|
|
16533
|
+
return !await this.trusted(await this.existing(path));
|
|
16473
16534
|
}
|
|
16474
16535
|
async locate(word, cwd) {
|
|
16475
16536
|
const { fs } = this.o;
|
|
@@ -16514,7 +16575,7 @@ var Sudo = class {
|
|
|
16514
16575
|
const root = cred.euid === 0;
|
|
16515
16576
|
const rules = root ? [] : policy.rules;
|
|
16516
16577
|
const mine = rules.filter((rule) => applies(rule.who));
|
|
16517
|
-
if (parsed2.list) return this.listed(self, root, mine, settings.matching);
|
|
16578
|
+
if (parsed2.list) return await this.listed(self, root, mine, settings.matching);
|
|
16518
16579
|
const session = { caller, self, target, owner, policy: policyOf(settings), parsed: parsed2, signal };
|
|
16519
16580
|
if (parsed2.validate) return this.validate(session, root, mine, call.cwd);
|
|
16520
16581
|
return this.command(session, root, mine, call);
|
|
@@ -16531,14 +16592,13 @@ var Sudo = class {
|
|
|
16531
16592
|
);
|
|
16532
16593
|
}
|
|
16533
16594
|
const path = await this.locate(word, cwd);
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
if (untrusted2) return untrusted2;
|
|
16595
|
+
const bound3 = path && await this.bound(path, cwd);
|
|
16596
|
+
if (!path || !bound3) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
16537
16597
|
const argv = [path, ...args];
|
|
16538
16598
|
const matching = mine.filter(
|
|
16539
|
-
(rule) => (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv)
|
|
16599
|
+
(rule) => (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv) && pinned(rule, bound3)
|
|
16540
16600
|
);
|
|
16541
|
-
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
16601
|
+
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term, bound3);
|
|
16542
16602
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
16543
16603
|
const quoted = argv.map(quoteWord).join(" ");
|
|
16544
16604
|
if (matching.length === 0) {
|
|
@@ -16554,14 +16614,15 @@ var Sudo = class {
|
|
|
16554
16614
|
}
|
|
16555
16615
|
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
16556
16616
|
return this.pendingFor(cred.ruid, async () => {
|
|
16557
|
-
const answer2 = await this.ask(s, { argv: parsed2.command, path, cwd });
|
|
16617
|
+
const answer2 = await this.ask(s, { argv: parsed2.command, path, cwd, bound: bound3 });
|
|
16558
16618
|
if ("error" in answer2) return answer2;
|
|
16559
16619
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
16560
16620
|
return failed2("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
16561
16621
|
}
|
|
16562
|
-
const
|
|
16563
|
-
if (
|
|
16564
|
-
const
|
|
16622
|
+
const now = await this.bound(path, cwd);
|
|
16623
|
+
if (!now) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
16624
|
+
const shown2 = recordable(cwd, [...parsed2.command, ...Object.keys(bound3)]);
|
|
16625
|
+
const result = answer2.answer === "once" ? grant() : await this.always(self, target, { cwd, argv, bound: bound3 }, now, shown2, grant);
|
|
16565
16626
|
if (!("error" in result)) this.stamped(s, answer2);
|
|
16566
16627
|
return result;
|
|
16567
16628
|
});
|
|
@@ -16580,7 +16641,7 @@ var Sudo = class {
|
|
|
16580
16641
|
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
16581
16642
|
const cwd = await this.canonical(dir) ?? normalizePath(dir);
|
|
16582
16643
|
return this.pendingFor(s.caller.cred.ruid, async () => {
|
|
16583
|
-
const answer2 = await this.ask(s, { argv: [], path: "", cwd, validate: true });
|
|
16644
|
+
const answer2 = await this.ask(s, { argv: [], path: "", cwd, bound: {}, validate: true });
|
|
16584
16645
|
if ("error" in answer2) return answer2;
|
|
16585
16646
|
if (!answer2.person) await s.caller.report?.(NOT_STAMPED);
|
|
16586
16647
|
this.stamped(s, answer2);
|
|
@@ -16608,14 +16669,17 @@ var Sudo = class {
|
|
|
16608
16669
|
`sudo: ${self.name} : TTY=${tty} ; PWD=${quoteWord(cwd)} ; USER=${target.name} ; TIMESTAMP=${type} ; COMMAND=${command}`
|
|
16609
16670
|
);
|
|
16610
16671
|
}
|
|
16611
|
-
async always(self, target,
|
|
16672
|
+
async always(self, target, line, now, shown2, grant) {
|
|
16673
|
+
const { cwd, argv, bound: bound3 } = line;
|
|
16612
16674
|
if (!shown2 || !recordable(cwd, argv)) return { ...grant(), notice: RAN_ONCE };
|
|
16613
|
-
|
|
16675
|
+
const changed = changedFile(bound3, now);
|
|
16676
|
+
if (changed !== void 0) return failed2("EPERM", changedText(changed));
|
|
16677
|
+
if (!await this.remember(self, target, line)) {
|
|
16614
16678
|
return failed2("EIO", "sudo: the rule could not be recorded");
|
|
16615
16679
|
}
|
|
16616
16680
|
return grant();
|
|
16617
16681
|
}
|
|
16618
|
-
listed(self, root, rules, defaults2) {
|
|
16682
|
+
async listed(self, root, rules, defaults2) {
|
|
16619
16683
|
const host = this.o.hostname;
|
|
16620
16684
|
if (root) {
|
|
16621
16685
|
return {
|
|
@@ -16627,7 +16691,9 @@ var Sudo = class {
|
|
|
16627
16691
|
if (rules.length === 0) {
|
|
16628
16692
|
return failed2("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
|
|
16629
16693
|
}
|
|
16630
|
-
const
|
|
16694
|
+
const shown2 = [];
|
|
16695
|
+
for (const rule of rules) shown2.push(described(rule, await this.writable(rule)));
|
|
16696
|
+
const lines2 = shown2.join("\n");
|
|
16631
16697
|
const params = defaults2.flatMap((d) => d.params).join(", ");
|
|
16632
16698
|
const matching = params === "" ? "" : `Matching Defaults entries for ${self.name} on ${host}:
|
|
16633
16699
|
${params}
|
|
@@ -16660,9 +16726,10 @@ ${lines2}
|
|
|
16660
16726
|
...caller.tty ? { tty: caller.tty } : {},
|
|
16661
16727
|
createdAt,
|
|
16662
16728
|
expiresAt: createdAt + timeout,
|
|
16663
|
-
always: asked.validate ? false : recordable(cwd, [path, ...argv]),
|
|
16729
|
+
always: asked.validate ? false : recordable(cwd, [path, ...argv, ...Object.keys(asked.bound)]),
|
|
16664
16730
|
stdin: caller.stdin,
|
|
16665
16731
|
rootOnly: asked.validate ? {} : await this.rootOnly(cwd, argv.slice(1)),
|
|
16732
|
+
...userWritable(asked.bound),
|
|
16666
16733
|
...asked.validate ? { validate: true } : {},
|
|
16667
16734
|
timestamp: true
|
|
16668
16735
|
};
|
|
@@ -16682,7 +16749,7 @@ ${lines2}
|
|
|
16682
16749
|
requester.removeEventListener("abort", withdraw);
|
|
16683
16750
|
}
|
|
16684
16751
|
}
|
|
16685
|
-
async remember(self, target, cwd, argv) {
|
|
16752
|
+
async remember(self, target, { cwd, argv, bound: bound3 }) {
|
|
16686
16753
|
const { fs } = this.o;
|
|
16687
16754
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
16688
16755
|
if (!NAME3.test(self.name)) return false;
|
|
@@ -16693,7 +16760,7 @@ ${lines2}
|
|
|
16693
16760
|
if (st && !await this.trusted(path)) return false;
|
|
16694
16761
|
const old = st ? await fs.readFile(path) : "";
|
|
16695
16762
|
const words2 = recordedCommand(argv);
|
|
16696
|
-
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none Cmnd ${words2}
|
|
16763
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none ${sha256Text(bound3)}Cmnd ${words2}
|
|
16697
16764
|
`;
|
|
16698
16765
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
16699
16766
|
${line}`;
|
|
@@ -16704,7 +16771,7 @@ ${line}`;
|
|
|
16704
16771
|
return false;
|
|
16705
16772
|
}
|
|
16706
16773
|
}
|
|
16707
|
-
grant(self, target, cred, argv, file, cwd, term) {
|
|
16774
|
+
grant(self, target, cred, argv, file, cwd, term, files) {
|
|
16708
16775
|
const env = {
|
|
16709
16776
|
...this.o.env(),
|
|
16710
16777
|
...userEnv(target, this.o.pnpmHome),
|
|
@@ -16717,7 +16784,9 @@ ${line}`;
|
|
|
16717
16784
|
SUDO_GID: String(cred.rgid),
|
|
16718
16785
|
SUDO_COMMAND: [file, ...argv.slice(1)].join(" ")
|
|
16719
16786
|
};
|
|
16720
|
-
return {
|
|
16787
|
+
return {
|
|
16788
|
+
grant: { file, argv: [...argv], env, cwd, cred: credOf(target), caller: cred, files }
|
|
16789
|
+
};
|
|
16721
16790
|
}
|
|
16722
16791
|
};
|
|
16723
16792
|
|
|
@@ -24887,14 +24956,20 @@ var WasmProcess = class {
|
|
|
24887
24956
|
if (!("grant" in answer2)) return answer2;
|
|
24888
24957
|
if (this.dying) throw new KernelError("EINTR");
|
|
24889
24958
|
if (answer2.notice !== void 0) await this.complainLine(answer2.notice);
|
|
24890
|
-
const { file, argv, env, cwd, cred, caller } = answer2.grant;
|
|
24959
|
+
const { file, argv, env, cwd, cred, caller, files } = answer2.grant;
|
|
24891
24960
|
const stdio = [{ fd: 0 }, { fd: 1 }, { fd: 2 }];
|
|
24892
|
-
|
|
24893
|
-
|
|
24894
|
-
|
|
24895
|
-
|
|
24896
|
-
|
|
24897
|
-
|
|
24961
|
+
try {
|
|
24962
|
+
return {
|
|
24963
|
+
pid: await this.children.spawn({ file, argv, env, cwd, pgid: 0 }, stdio, [], {
|
|
24964
|
+
cred,
|
|
24965
|
+
caller,
|
|
24966
|
+
files
|
|
24967
|
+
})
|
|
24968
|
+
};
|
|
24969
|
+
} catch (err) {
|
|
24970
|
+
if (err instanceof ChangedError) return { error: err.notice, errno: err.code };
|
|
24971
|
+
throw err;
|
|
24972
|
+
}
|
|
24898
24973
|
}
|
|
24899
24974
|
stdinKind() {
|
|
24900
24975
|
if (!this.fds.has(0)) return "none";
|
|
@@ -32466,6 +32541,10 @@ function describe(req, tty) {
|
|
|
32466
32541
|
};
|
|
32467
32542
|
return { argv: [req.argv0, ...req.args], tty, started: Date.now(), ...exe };
|
|
32468
32543
|
}
|
|
32544
|
+
function refuseChanged(approved, now) {
|
|
32545
|
+
const changed = changedFile(approved, now);
|
|
32546
|
+
if (changed !== void 0) throw new ChangedError(changedText(changed));
|
|
32547
|
+
}
|
|
32469
32548
|
function linksOf2(req) {
|
|
32470
32549
|
return req.links === void 0 ? {} : { links: req.links };
|
|
32471
32550
|
}
|
|
@@ -33599,6 +33678,27 @@ var Launcher = class {
|
|
|
33599
33678
|
}
|
|
33600
33679
|
return true;
|
|
33601
33680
|
}
|
|
33681
|
+
async unchanged(planned, file, cwd, grant) {
|
|
33682
|
+
const approved = grant?.files;
|
|
33683
|
+
if (!approved) return {};
|
|
33684
|
+
const files = await this.backingOf(planned, file, cwd, "");
|
|
33685
|
+
refuseChanged(approved, await this.sudoer.digests([file, ...files]));
|
|
33686
|
+
return { pinned: approved };
|
|
33687
|
+
}
|
|
33688
|
+
async pinOf(path, caller) {
|
|
33689
|
+
const { pinned: pinned2 } = caller;
|
|
33690
|
+
if (!pinned2) return {};
|
|
33691
|
+
const real = await this.sudoer.real(path);
|
|
33692
|
+
const hex4 = pinned2[real];
|
|
33693
|
+
if (hex4 !== void 0) return { [real]: hex4 };
|
|
33694
|
+
if (await this.sudoer.trusted(real)) return {};
|
|
33695
|
+
throw new ChangedError(changedText(real));
|
|
33696
|
+
}
|
|
33697
|
+
async pinnedBytes(pin, bytes) {
|
|
33698
|
+
const [real = ""] = Object.keys(pin);
|
|
33699
|
+
refuseChanged(pin, { [real]: await sha2562(bytes) });
|
|
33700
|
+
return bytes;
|
|
33701
|
+
}
|
|
33602
33702
|
async grantedCwd(caller, cwd) {
|
|
33603
33703
|
const real = await physicalPathAsync(this.base, cwd).catch(() => void 0);
|
|
33604
33704
|
return real === cwd && await this.sudoer.reachable(caller, cwd);
|
|
@@ -33687,13 +33787,19 @@ var Launcher = class {
|
|
|
33687
33787
|
return found;
|
|
33688
33788
|
}
|
|
33689
33789
|
async module(path, caller, asked) {
|
|
33690
|
-
const
|
|
33790
|
+
const pin = await this.pinOf(path, caller);
|
|
33791
|
+
const sum = Object.values(pin)[0];
|
|
33792
|
+
const key = sum === void 0 ? await this.cacheKey(path, asked) : `${path}:sha256:${sum}`;
|
|
33691
33793
|
return this.cached(this.compiled, key, async () => {
|
|
33692
|
-
const { bytes, key:
|
|
33794
|
+
const { bytes: read, key: readKey } = await this.keyed(path, caller, asked);
|
|
33795
|
+
const bytes = sum === void 0 ? read : await this.pinnedBytes(pin, read);
|
|
33693
33796
|
const memory = importedMemory(bytes);
|
|
33694
33797
|
const foreign = foreignImports(bytes);
|
|
33695
33798
|
const compiled = await WebAssembly.compile(bytes);
|
|
33696
|
-
return {
|
|
33799
|
+
return {
|
|
33800
|
+
value: { module: compiled, ...memory ? { memory } : {}, foreign },
|
|
33801
|
+
key: sum === void 0 ? readKey : key
|
|
33802
|
+
};
|
|
33697
33803
|
});
|
|
33698
33804
|
}
|
|
33699
33805
|
async checkedSources(planned, caller) {
|
|
@@ -33718,6 +33824,11 @@ var Launcher = class {
|
|
|
33718
33824
|
}
|
|
33719
33825
|
}
|
|
33720
33826
|
async text(path, caller, asked) {
|
|
33827
|
+
const pin = await this.pinOf(path, caller);
|
|
33828
|
+
if (Object.keys(pin).length > 0) {
|
|
33829
|
+
const { bytes } = await this.keyed(path, caller, asked);
|
|
33830
|
+
return new TextDecoder().decode(await this.pinnedBytes(pin, bytes));
|
|
33831
|
+
}
|
|
33721
33832
|
if (!this.integrity) return this.base.readFile(path);
|
|
33722
33833
|
const key = await this.cacheKey(path, asked);
|
|
33723
33834
|
return this.cached(this.texts, key, async () => {
|
|
@@ -33906,7 +34017,12 @@ var Launcher = class {
|
|
|
33906
34017
|
const own = env.HOSTNAME;
|
|
33907
34018
|
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
33908
34019
|
const planned = chosen2(asked, env);
|
|
33909
|
-
const caller = {
|
|
34020
|
+
const caller = {
|
|
34021
|
+
pid: req.ppid ?? 0,
|
|
34022
|
+
uid: req.cred.euid,
|
|
34023
|
+
tag: req.tags?.[0],
|
|
34024
|
+
pinned: req.pinned
|
|
34025
|
+
};
|
|
33910
34026
|
if (this.integrity) await this.checkedSources(planned, caller);
|
|
33911
34027
|
const [program, exeId] = await this.loaded(planned.target, env, caller);
|
|
33912
34028
|
if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
|
|
@@ -34421,6 +34537,7 @@ var Launcher = class {
|
|
|
34421
34537
|
const scope = grant ? "" : await this.scopeOf(cred.euid);
|
|
34422
34538
|
const file = booked === void 0 ? req.file : await this.ticketFile(req, fds);
|
|
34423
34539
|
const planned = await this.checkedPlan({ ...req, file }, { ppid, cred, scope }, fds);
|
|
34540
|
+
const pin = await this.unchanged(planned, file, req.cwd, grant);
|
|
34424
34541
|
const { recheck, ...redeemed } = await this.redeemed(
|
|
34425
34542
|
{ ...req, file },
|
|
34426
34543
|
{ ppid, cred, scope, booked },
|
|
@@ -34432,6 +34549,7 @@ var Launcher = class {
|
|
|
34432
34549
|
const replan = () => this.planOrSearch({ ...req, file }, { ppid, cred, scope });
|
|
34433
34550
|
const again = { ...planned, replan, recheck };
|
|
34434
34551
|
const handle = await this.launch(again, {
|
|
34552
|
+
...pin,
|
|
34435
34553
|
...deciding ? { decided: deciding.promise } : {},
|
|
34436
34554
|
cwd: req.cwd,
|
|
34437
34555
|
cwdFrom: inheritedCwd(req.chdir, this.cwdSlots.get(ppid)),
|