@ai-ecoverse/slicc-kernel 1.77.0 → 1.77.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 +3 -3
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +126 -2
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +42 -5
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +126 -2
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +42 -5
- package/dist/process-worker.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -416,7 +416,7 @@ The proxy answers `200` with `Content-Type: application/vnd.slicc.raw-fetch`: a
|
|
|
416
416
|
|
|
417
417
|
## Filesystem
|
|
418
418
|
|
|
419
|
-
`/` 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
|
|
419
|
+
`/` 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.
|
|
420
420
|
|
|
421
421
|
Directories are renamed with `FileSystemHandle.move()` where available, else by copy and delete.
|
|
422
422
|
|
|
@@ -590,7 +590,7 @@ With `users: 'enforce'` the kernel checks every file call that reaches it agains
|
|
|
590
590
|
- **Modes and times:** only the owner or root may `chmod` (`EPERM`), and a `chmod` by a user that isn't in the file's group clears its setgid bit. Only the owner or root may set a file's times (`EPERM`); setting them to now (`touch`, `utimensat` with `UTIME_NOW` or no times, WASI's `*_NOW` flags) is also allowed to anyone who may write the file (`EACCES` otherwise).
|
|
591
591
|
- **Opening a file:** an open needs `r` to read and `w` to write or truncate, checked once when the file is opened, in every runtime: Emscripten, WASI (a second open of a path the program already has open is checked as well), JS programs' `ctx.open` and `ctx.fs.writeFile`, and the kernel's own opens. A file the open itself creates is not checked (only its directory is), so `open(O_CREAT | O_WRONLY, 0444)` works. An open descriptor keeps the access it was opened with, through a later `chmod`, and so do descriptors a child inherits. Reads and writes without a descriptor (`ctx.fs.readFile`, `ctx.sync.fs.readFile`) are checked each time.
|
|
592
592
|
- **`access(2)`:** `faccessat` (bash's `[ -r ]`, `test -w`) answers from the same checks, with the real uid and gid, or the effective ones with `AT_EACCESS`, for Emscripten programs, and for WASI programs through `slicc_fs.path_access` (see [File modes and the umask](#file-modes-and-the-umask)).
|
|
593
|
-
- **Exec:** running a program by path needs `x` on it, and `r` too when it's a script (`#!` or a `binfmt` suffix); a WASI or Emscripten binary needs only `x`. Root needs an `x` bit as well. Commands found by name, and `/usr/bin` and `/bin`, are always executable; a user's own commands in `~/.local/share/pnpm/bin` are reached through the user's home, so another user gets `EACCES` there, as for any file. A refused exec is `EACCES` (126 in bash).
|
|
593
|
+
- **Exec:** running a program by path needs `x` on it, and `r` too when it's a script (`#!` or a `binfmt` suffix); a WASI or Emscripten binary needs only `x`. Root needs an `x` bit as well. WASI and WASIX have no mode for a new file, so a file a WASI program creates gets the `x` bits its umask at creation allows (`0755` at `022`), as a native linker's `open(…, 0777)` would, once the kernel sees it written from its start with a wasm module (and loses them again if its start is rewritten with anything else); a `chmod` of it wins from then on, and the kernel stops when the creating process ends. A compiler's output (zig, rustc, cargo) then runs by path. Commands found by name, and `/usr/bin` and `/bin`, are always executable; a user's own commands in `~/.local/share/pnpm/bin` are reached through the user's home, so another user gets `EACCES` there, as for any file. A refused exec is `EACCES` (126 in bash).
|
|
594
594
|
- **The layout:** with `users: 'report'` or `'enforce'`, the kernel gives its own paths an owner and a mode when they have no owner record yet: on a fresh root, and once on a root from before owners. These are `/` `0755`, `/root` `0700`, `/home` `0755`, `/etc` `0755`, `/etc/passwd` and `/etc/group` `0644`, `/usr` and `/usr/local` `0755`, `/node_modules` (or the `modules` option) and the system `PNPM_HOME` `0755`, all root's. A path that has a record keeps it, so an admin's `chmod 711 /home` or `chown cone /node_modules` lasts across restarts; a mounted path is left to its mount, and a path below a symlinked directory is stamped where it really is. Only a root that records owners is stamped: the OPFS root with its sidecar, which the page and the Node entry (in memory) both use; a custom root file system without owner records is left as it is. The directory for files removed while open, `/.slicc-unlinked`, is made root's `0700`. `/tmp` is the exception: it is set to `1777` at every start, and the first time owners are on for a root from before owners, what is in it without an owner of its own is removed (as a boot empties `/tmp` on Linux; a file that is open is kept, a symlinked `/tmp` is left alone, and one `console.warn` line says how many entries went), since it would otherwise be root's, and a program that made it for its user, such as pnpm's lock directories, would find it isn't its own. Emscripten programs see `/` at `0755`, `/dev` at `0755`, `null`, `zero`, `full`, `random`, `urandom` and `tty` at `0666`, and `/dev/shm` at `1777`. With `users: 'off'` nothing is stamped. Paths the embedder makes (bios's `/opt` and `/var/lib/slicc`) are the embedder's to set. `/etc/sudoers` and `/etc/sudoers.d` are written when missing (see [Sudo](#sudo)).
|
|
595
595
|
- **Terminals:** a terminal from `openTerminal` belongs to its session's user, with group `tty` when `/etc/group` has one (the user's own group otherwise), mode `0620`; a pseudo-terminal's slave `/dev/pts/N` belongs to the uid and gid that opened `/dev/ptmx`, mode `0620`. Opening one by name (`/dev/ttyN`, `/dev/pts/N`, from every runtime) needs both `r` and `w`, so only its owner and root open it: the kernel's terminal descriptor always reads and writes, so the group's `w` bit (`write`, `wall` on Linux) does not let a group member open it. `/dev/tty` is the opener's own controlling terminal and is not checked, and descriptors a process inherited (across `sudo` or a `setresuid` too) keep working. Emscripten programs' `stat` of `/dev/ttyN` and `/dev/pts/N` shows the owner and mode. With `users: 'off'` terminals have no owner, as before.
|
|
596
596
|
- **A client's `fs`:** checked as the client's user; a page's client (root) passes.
|
|
@@ -637,7 +637,7 @@ A character device (`0666`, major 10, minor 251), there in every `users` mode, t
|
|
|
637
637
|
|
|
638
638
|
`createKernel({ protect: { paths: ['/node_modules', '/os'] } })` makes those directories read-only for every process, root included, in every `users` mode. They hold code every later process runs, which only the embedder writes, straight to OPFS.
|
|
639
639
|
- **What fails:** any change under a path fails with `EROFS` ("Read-only file system"): a write, a create, a truncate, `mkdir`, removing or renaming (from or to), a hard or symbolic link created there, `chmod`, `chown` and setting times. So does removing or renaming a directory that holds one (`rm -rf /`). A missing working directory for `run` or `openTerminal` isn't created there either. Reads are unaffected. `'/'` protects the whole file system.
|
|
640
|
-
- **Stats and symlinks:** files under a path show as on a read-only mount, so opens for writing fail at once
|
|
640
|
+
- **Stats and symlinks:** files under a path show as on a read-only mount, also when reached through a symlink or a symlinked directory, so opens for writing fail at once, and `access(W_OK)` (`[ -w ]`) answers `EROFS`. A change refused there fails with `EROFS` before any permission check, as on Linux, so a user sees "Read-only file system" rather than "Permission denied". `paths` must be a list of absolute paths.
|
|
641
641
|
- **Where it's checked:** the root file system itself checks every change, from the moment the kernel is constructed, inside the change and against the path it really lands on. So a symlink swapped mid-way can't redirect a write. The kernel's own writes there are refused too, so don't protect what the kernel writes after it starts:
|
|
642
642
|
- `/etc` (`passwd`, `group` and the proxy's CA);
|
|
643
643
|
- `/home` and `/root` (new users' homes);
|