@ai-ecoverse/slicc-kernel 1.125.8 → 1.125.10
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 +2 -2
- package/dist/kernel-worker.js +65 -14
- package/dist/kernel-worker.js.map +2 -2
- package/dist/node-process-worker.js +35 -40
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +65 -14
- package/dist/node.js.map +2 -2
- package/dist/process-worker.js +35 -40
- package/dist/process-worker.js.map +3 -3
- package/dist/types/process/wasi/wasi-host.d.ts +2 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -426,7 +426,7 @@ The module's default export (or its `main` export) is called with a context and
|
|
|
426
426
|
- With `rejectUnauthorized: false`, `chainError` says what is wrong with the chain apart from the name, with Node's names, and is absent when the chain is fine:
|
|
427
427
|
- a self-signed leaf alone is `DEPTH_ZERO_SELF_SIGNED_CERT`;
|
|
428
428
|
- an untrusted chain ending in a self-signed root is `SELF_SIGNED_CERT_IN_CHAIN`;
|
|
429
|
-
- self-signed means the certificate's own key verifies its signature (RSA PKCS#1 v1.5, ECDSA P-256/384/521 or Ed25519), not just that its issuer and subject names match, so a self-issued certificate signed by another key, such as a CA rollover certificate, is not self-signed, as in Node ([#1059](https://github.com/ai-ecoverse/slicc-kernel/issues/1059));
|
|
429
|
+
- self-signed means the certificate's own key verifies its signature (RSA PKCS#1 v1.5, RSA-PSS, ECDSA P-256/384/521 or Ed25519; a signature the kernel can't verify is not self-signed), not just that its issuer and subject names match, so a self-issued certificate signed by another key, such as a CA rollover certificate, is not self-signed, as in Node ([#1059](https://github.com/ai-ecoverse/slicc-kernel/issues/1059));
|
|
430
430
|
- a lone leaf whose issuer is unknown is `UNABLE_TO_VERIFY_LEAF_SIGNATURE`;
|
|
431
431
|
- an untrusted longer chain is `UNABLE_TO_GET_ISSUER_CERT_LOCALLY`;
|
|
432
432
|
- otherwise it's the reason's code, such as `CERT_HAS_EXPIRED`.
|
|
@@ -635,7 +635,7 @@ The proxy answers `200` with `Content-Type: application/vnd.slicc.raw-fetch`: a
|
|
|
635
635
|
|
|
636
636
|
## Filesystem
|
|
637
637
|
|
|
638
|
-
`/` is the OPFS root. Each process mounts the top-level directories that exist when it starts (plus `/usr` and `/bin`), so files in them are shared by all processes and visible through the OPFS API as soon as the process that wrote them has closed them; `run` resolves only after that. `createKernel` creates `/tmp` and `/home` in OPFS, so they are shared too. Files directly in `/`, and directories created there after a process started, are OPFS as well, the same for Emscripten and WASI programs; only `/dev` and `/proc` live in each process's memory. A program's `mkdir` (WASI `path_create_directory`, Emscripten's `mkdir`) is exclusive, as on Linux: it fails with `EEXIST` when the name exists, and of several processes or threads making one name at once exactly one succeeds, so a directory works as a lock. Under a missing directory it fails with `ENOENT`, as on Linux (`mkdir -p` and `os.makedirs` make the parents in the program); a JS program's `ctx.fs.mkdir` makes parents itself. The kernel makes the system `PNPM_HOME` (`/usr/local/share/pnpm`, or the embedder's) when it starts, since pnpm makes only its `bin` directory there. A full origin storage (`QuotaExceededError`, which also comes early in a browser's private or off-the-record contexts, whatever `navigator.storage.estimate()` says) is `ENOSPC`, never retried. An OPFS or IndexedDB failure that has no POSIX counterpart is `EIO`; its message names the DOM error and the operation (`lookup`, `read`, `write`, `commit` or `sidecar`), and the kernel worker logs the first of each kind to its console. File contents are buffered per open file and written back on close, `fsync` and exit, so a refused write (`ENOSPC`, `EIO`) surfaces at that close or `fsync`, and a program that ignores close errors doesn't see it (`echo x > f` can exit 0 with `f` empty, as with any buffered write-back). A write-back error a close has already reported to a WASI program isn't raised again when it exits, so the program keeps its own exit status. Metadata operations (`mkdir`, `rename`, `rm`, …) go straight to OPFS. The kernel worker is the only writer.
|
|
638
|
+
`/` is the OPFS root. Each process mounts the top-level directories that exist when it starts (plus `/usr` and `/bin`), so files in them are shared by all processes and visible through the OPFS API as soon as the process that wrote them has closed them; `run` resolves only after that. `createKernel` creates `/tmp` and `/home` in OPFS, so they are shared too. Files directly in `/`, and directories created there after a process started, are OPFS as well, the same for Emscripten and WASI programs; only `/dev` and `/proc` live in each process's memory. A program's `mkdir` (WASI `path_create_directory`, Emscripten's `mkdir`) is exclusive, as on Linux: it fails with `EEXIST` when the name exists, and of several processes or threads making one name at once exactly one succeeds, so a directory works as a lock. Under a missing directory it fails with `ENOENT`, as on Linux (`mkdir -p` and `os.makedirs` make the parents in the program); a JS program's `ctx.fs.mkdir` makes parents itself. The kernel makes the system `PNPM_HOME` (`/usr/local/share/pnpm`, or the embedder's) when it starts, since pnpm makes only its `bin` directory there. A full origin storage (`QuotaExceededError`, which also comes early in a browser's private or off-the-record contexts, whatever `navigator.storage.estimate()` says) is `ENOSPC`, never retried. A read that meets `NotFoundError` while a writer outside the kernel swaps the file in with `createWritable` (and a `stat`, `lstat` or `utimes` that meets it) looks the name up again, up to three times, before it fails ([#1075](https://github.com/ai-ecoverse/slicc-kernel/issues/1075)), so a program whose package is overwritten in place keeps starting. An OPFS or IndexedDB failure that has no POSIX counterpart is `EIO`; its message names the DOM error and the operation (`lookup`, `read`, `write`, `commit` or `sidecar`), and the kernel worker logs the first of each kind to its console. File contents are buffered per open file and written back on close, `fsync` and exit, so a refused write (`ENOSPC`, `EIO`) surfaces at that close or `fsync`, and a program that ignores close errors doesn't see it (`echo x > f` can exit 0 with `f` empty, as with any buffered write-back). A write-back error a close has already reported to a WASI program isn't raised again when it exits, so the program keeps its own exit status. Metadata operations (`mkdir`, `rename`, `rm`, …) go straight to OPFS. The kernel worker is the only writer.
|
|
639
639
|
|
|
640
640
|
A lookup follows at most 40 symlinks, as Linux does: the 41st is `ELOOP`, for WASI programs, JS programs and the kernel API alike, with or without `..` in a link's target. Emscripten programs resolve paths in their glue, which stops one link earlier, at 40.
|
|
641
641
|
|
package/dist/kernel-worker.js
CHANGED
|
@@ -1077,6 +1077,17 @@ var S_IFIFO = 4096;
|
|
|
1077
1077
|
var PERM_MASK = 4095;
|
|
1078
1078
|
var S_ISGID2 = 1024;
|
|
1079
1079
|
var READ_ATTEMPTS = 3;
|
|
1080
|
+
async function swapped(op) {
|
|
1081
|
+
for (let attempt = 1; ; attempt++) {
|
|
1082
|
+
try {
|
|
1083
|
+
return await op();
|
|
1084
|
+
} catch (err) {
|
|
1085
|
+
if (err?.name !== "NotFoundError" || attempt >= READ_ATTEMPTS) {
|
|
1086
|
+
throw err;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1080
1091
|
var MAX_LINKS2 = 40;
|
|
1081
1092
|
var CHECK_MS = 1e3;
|
|
1082
1093
|
var ABSENT_MS = 2;
|
|
@@ -1862,10 +1873,14 @@ var OpfsFs = class {
|
|
|
1862
1873
|
return { ...stat, ...ownOf(meta) ?? inherit(entries) };
|
|
1863
1874
|
}
|
|
1864
1875
|
stat(path) {
|
|
1865
|
-
return this.unreplaced(
|
|
1876
|
+
return this.unreplaced(
|
|
1877
|
+
() => swapped(async () => this.describe(await this.located(path, true)))
|
|
1878
|
+
);
|
|
1866
1879
|
}
|
|
1867
1880
|
lstat(path) {
|
|
1868
|
-
return this.unreplaced(
|
|
1881
|
+
return this.unreplaced(
|
|
1882
|
+
() => swapped(async () => this.describe(await this.located(path, false)))
|
|
1883
|
+
);
|
|
1869
1884
|
}
|
|
1870
1885
|
async exists(path) {
|
|
1871
1886
|
return this.locate(path, true).then(
|
|
@@ -1891,8 +1906,17 @@ var OpfsFs = class {
|
|
|
1891
1906
|
}
|
|
1892
1907
|
reading(path, op) {
|
|
1893
1908
|
return this.unreplaced(async () => {
|
|
1894
|
-
|
|
1895
|
-
|
|
1909
|
+
for (let attempt = 1; ; attempt++) {
|
|
1910
|
+
const found = await this.locate(path, true);
|
|
1911
|
+
const handle = found.handle;
|
|
1912
|
+
if (handle.kind === "directory") throw fsError("EISDIR", path);
|
|
1913
|
+
try {
|
|
1914
|
+
return await this.retrying(path, () => op(handle), false);
|
|
1915
|
+
} catch (err) {
|
|
1916
|
+
if (err.code !== "ENOENT" || attempt >= READ_ATTEMPTS) throw err;
|
|
1917
|
+
this.files.delete(found.path);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1896
1920
|
});
|
|
1897
1921
|
}
|
|
1898
1922
|
async existing(path, writing = false) {
|
|
@@ -2396,10 +2420,10 @@ var OpfsFs = class {
|
|
|
2396
2420
|
}));
|
|
2397
2421
|
}
|
|
2398
2422
|
async utimes(path, atime, mtime) {
|
|
2399
|
-
await this.setTimes(await this.locate(path, true), atime, mtime);
|
|
2423
|
+
await swapped(async () => this.setTimes(await this.locate(path, true), atime, mtime));
|
|
2400
2424
|
}
|
|
2401
2425
|
async lutimes(path, atime, mtime) {
|
|
2402
|
-
await this.setTimes(await this.locate(path, false), atime, mtime);
|
|
2426
|
+
await swapped(async () => this.setTimes(await this.locate(path, false), atime, mtime));
|
|
2403
2427
|
}
|
|
2404
2428
|
async setTimes(found, atime, mtime) {
|
|
2405
2429
|
this.refuse(found.path);
|
|
@@ -6632,7 +6656,7 @@ function satisfies(version, range2) {
|
|
|
6632
6656
|
}
|
|
6633
6657
|
|
|
6634
6658
|
// src/version.ts
|
|
6635
|
-
var KERNEL_VERSION = true ? "1.125.
|
|
6659
|
+
var KERNEL_VERSION = true ? "1.125.10" : "0.0.0-dev";
|
|
6636
6660
|
var OS_RELEASE = "6.0.0-slicc";
|
|
6637
6661
|
function procVersion() {
|
|
6638
6662
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -17313,8 +17337,32 @@ var HASHES = {
|
|
|
17313
17337
|
"2a8648ce3d040302": ["ECDSA", "SHA-256"],
|
|
17314
17338
|
"2a8648ce3d040303": ["ECDSA", "SHA-384"],
|
|
17315
17339
|
"2a8648ce3d040304": ["ECDSA", "SHA-512"],
|
|
17316
|
-
"2b6570": ["Ed25519", ""]
|
|
17340
|
+
"2b6570": ["Ed25519", ""],
|
|
17341
|
+
"2a864886f70d01010a": ["RSA-PSS", "SHA-1"]
|
|
17317
17342
|
};
|
|
17343
|
+
var PSS_HASHES = {
|
|
17344
|
+
"2b0e03021a": "SHA-1",
|
|
17345
|
+
"608648016503040201": "SHA-256",
|
|
17346
|
+
"608648016503040202": "SHA-384",
|
|
17347
|
+
"608648016503040203": "SHA-512"
|
|
17348
|
+
};
|
|
17349
|
+
function pssOf(der, algorithm) {
|
|
17350
|
+
const params = children2(der, algorithm, 2)?.[1];
|
|
17351
|
+
let hash = "SHA-1";
|
|
17352
|
+
let salt = 20;
|
|
17353
|
+
for (const field4 of params && der[params.start] === 48 ? children2(der, params, 3) ?? [] : []) {
|
|
17354
|
+
const inner = tlv2(der, field4.body);
|
|
17355
|
+
if (!inner) return void 0;
|
|
17356
|
+
if (der[field4.start] === 160) {
|
|
17357
|
+
const known = PSS_HASHES[oidOf(der, inner) ?? ""];
|
|
17358
|
+
if (!known) return void 0;
|
|
17359
|
+
hash = known;
|
|
17360
|
+
} else if (der[field4.start] === 162) {
|
|
17361
|
+
salt = der.subarray(inner.body, inner.end).reduce((n, b) => n * 256 + b, 0);
|
|
17362
|
+
}
|
|
17363
|
+
}
|
|
17364
|
+
return { hash, salt };
|
|
17365
|
+
}
|
|
17318
17366
|
var CURVES = {
|
|
17319
17367
|
"2a8648ce3d030107": ["P-256", 32],
|
|
17320
17368
|
"2b81040022": ["P-384", 48],
|
|
@@ -17349,10 +17397,13 @@ function signedOf(der) {
|
|
|
17349
17397
|
const spki = parts2?.tbs[5];
|
|
17350
17398
|
if (!tbs || !algorithm || !value2 || !spki || der[value2.start] !== 3) return void 0;
|
|
17351
17399
|
const known = HASHES[oidOf(der, algorithm) ?? ""];
|
|
17352
|
-
if (!known) return
|
|
17353
|
-
const [scheme
|
|
17400
|
+
if (!known) return void 0;
|
|
17401
|
+
const [scheme] = known;
|
|
17402
|
+
const pss = scheme === "RSA-PSS" ? pssOf(der, algorithm) : void 0;
|
|
17403
|
+
if (scheme === "RSA-PSS" && !pss) return void 0;
|
|
17404
|
+
const hash = pss?.hash ?? known[1];
|
|
17354
17405
|
const curve = scheme === "ECDSA" ? curveOf(der, spki) : void 0;
|
|
17355
|
-
if (scheme === "ECDSA" && !curve) return
|
|
17406
|
+
if (scheme === "ECDSA" && !curve) return void 0;
|
|
17356
17407
|
const signature = der.subarray(value2.body + 1, value2.end);
|
|
17357
17408
|
return {
|
|
17358
17409
|
tbs: raw(der, tbs),
|
|
@@ -17360,7 +17411,8 @@ function signedOf(der) {
|
|
|
17360
17411
|
signature,
|
|
17361
17412
|
scheme,
|
|
17362
17413
|
hash,
|
|
17363
|
-
...curve ? { curve } : {}
|
|
17414
|
+
...curve ? { curve } : {},
|
|
17415
|
+
...pss ? { salt: pss.salt } : {}
|
|
17364
17416
|
};
|
|
17365
17417
|
}
|
|
17366
17418
|
async function verifiesItself(s) {
|
|
@@ -17371,13 +17423,12 @@ async function verifiesItself(s) {
|
|
|
17371
17423
|
]);
|
|
17372
17424
|
const signature = s.curve ? fixedEcdsa(s.signature, s.curve[1]) : s.signature;
|
|
17373
17425
|
if (!signature) return false;
|
|
17374
|
-
const params = s.scheme === "ECDSA" ? { name: "ECDSA", hash: s.hash } : { name: s.scheme };
|
|
17426
|
+
const params = s.scheme === "ECDSA" ? { name: "ECDSA", hash: s.hash } : s.salt === void 0 ? { name: s.scheme } : { name: s.scheme, saltLength: s.salt };
|
|
17375
17427
|
return crypto.subtle.verify(params, key, new Uint8Array(signature), new Uint8Array(s.tbs));
|
|
17376
17428
|
}
|
|
17377
17429
|
async function selfSigned(der) {
|
|
17378
17430
|
if (!selfIssued(der)) return false;
|
|
17379
17431
|
const signed = signedOf(der);
|
|
17380
|
-
if (signed === "unknown") return true;
|
|
17381
17432
|
if (!signed) return false;
|
|
17382
17433
|
return verifiesItself(signed).catch(() => false);
|
|
17383
17434
|
}
|