Skip to content

A package granted a folder of the home by grants starts in it and sees it (stage 1 of launch-time consent) - #819

Draft
Japabu wants to merge 4 commits into
mainfrom
wt/toyos-consent
Draft

Japabu wants to merge 4 commits into
mainfrom
wt/toyos-consent

Conversation

@Japabu

@Japabu Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Draft: stage 1 of 2. Launch-time consent, staged as the design has it. The owner ruled that stages 1 and 2 land together ("popup in one go"). This branch holds stage 1 only: grants by command, with gbae's browsing and saving a granted folder, and its tests. It stops at the brief's named clean boundary. Stage 2 (the parked launch, the compositor's prompt layer, filepicker's consent mode and the desktop guest test) is not started, so this pull request must not land as it stands. See Not done.

Head: c190ac79b, on 2b1a0e746 (main with #807).

What changed, per decision

  • The store (toyos_manifest::grants): /state/supervisor/grants, a header line toyos-grants 1, then one grant <user> <package> <sha256> <read-only|read-write> <folder> line per grant.
    • It holds at most 64 grants, one per user and package; a new grant to the same package replaces the old one.
    • Store::parse refuses by name anything render cannot have written: an unknown record, a duplicate, an oversized store, a non-hex digest, a bad name, a bad folder. Any declared row can write /state.
    • The supervisor alone writes it, on its file worker, by writing a name beside it and renaming it over.
  • Grant identity is the exact binary, as the owner ruled: the SHA-256 of the program the supervisor starts. An update holds no grant until it is granted again. decide returns the stored grant for that binary, at most the image's ceiling, or nothing.
  • The folder rules (grants::folder): a canonical directory inside the session user's home. Never the home itself, nor Apps or anything in it. Within the 54-byte grant root (the supervisor asserts it against toyos::fs::MAX_GRANT_ROOT) and std's 4-component capability depth. Each refusal is a whole sentence.
  • Access: a package declares, and the user may grant less. [apps] folder = "read-write" is the image's ceiling. Until signed package entries carry a package's own request, it is also what every package asks for.
    • Why [apps] and not a declaration per package: pkg writes each package's manifest.toml and is outside this change, and gbae's release carries no request. A per-package line in system.toml would be the image naming an app.
    • grants add <package> <folder> read-only grants less. A grant past the ceiling is refused.
    • The build refuses any spelling but read-only and read-write. [apps] now refuses an unknown key, so a misspelt folder cannot become a silent ceiling.
  • The grants port (supervisor-served, in SUPERVISOR_SERVED).
    • Its connector is minted per start with the holder's row and session, as a launcher is. It is endowed under its own label, never in svc.
    • The supervisor answers a login session alone: refused grants in the machine's session: only a login session may ask for grants.
    • The build lets the grants row alone receive the port, and never [apps]. held_by_their_holders_alone now takes a list of (port, holder) pairs.
  • add checks, in this order: the folder rules, then the ceiling. Then, on the worker: the package's manifest, as a launch would start it (so a package named after a declared row is none); that the folder is a directory and not a link (symlink_metadata); and the program's hash.
  • A launch of a package hashes its binary on the worker, in the same job that resolves and prepares it.
    • With a grant for that binary, the folder's View is appended to the package's view (Program::folder, set only on the row the supervisor synthesizes for that launch).
    • The launch is prepared again in the folder: the caller's own working directory where it lies inside the folder, and the folder's root otherwise (grants::cwd). HOME stays the package's own folder.
    • A granted folder that is no longer a directory refuses the launch by name.
    • With no grant, the supervisor says <package> holds no folder; \grants add ` grants it one`.
  • /system/bin/grants list | add <package> <folder> [read-only] | revoke <package>: a new row. The shell and sshserver list it in starts. It is exempt.manages, since grants are ToyOS's own.
  • The fileserver needed no change. It already follows no symlink at a grant's root: DATA's namespace is flat, so a symlink there is no directory. Nothing lists through it, and nothing is opened, made or mkdired under it. A host test (a_symlink_at_a_grant_s_root_is_followed_by_nothing) holds that. The resolver's escape suite now also runs under a granted folder.
  • gbae needs no change (read at bfe8dab). It browses std::env::current_dir() (src/main.rs:471) with list_directory (src/menu.rs:308). It saves <rom>.sav beside the ROM (:157), after a canonicalize that falls back to the given path (:156). From the granted folder, its ../ lists nothing, since the home is not in its view.

Checks: this is a security boundary

Negative control. The whole production change was reverted onto 2b1a0e746, the base the green arm G0 was measured on: toyos-manifest, userland/supervisor, userland/fileserver, src/build.rs, system.toml, Cargo.toml, Cargo.lock and tests/proctreecase/system.toml, with userland/grants removed. app_view.rs, its judge and the temporary QEMU harness were kept.

  • Result: app_view red, EXIT=1. It names every grant arm: grants is missing; the granted launch saw cwd=/ roms=[] saved=Err; no test.sav was written beside the ROM.

Mutations. Each was applied as a checked patch, run, and restored in the same script, leaving the tree clean. All of them, and the control, were run at c190ac79b. The patches, the runner, the summary and each red's named arms are posted as a comment.

arm where it should show result
H1: decide ignores the binary toyos-manifest host test red, EXIT=101
H2: a folder in Apps allowed toyos-manifest host tests red, EXIT=101 (two tests)
H3: grants not held by its holder alone src/build.rs host test red, EXIT=101
G0: harness alone app_view under QEMU green, EXIT=0
G1: the machine's session answered app_view under QEMU red, EXIT=1: grants in the machine's session was answered … appview is granted
G2: the granted folder not put in the view app_view under QEMU red, EXIT=1: granted, it saw cwd=/home/toy/Games roms=[] saved=Err
G3: the launch takes the stored digest for its own app_view under QEMU red, EXIT=1: another binary saw cwd=/home/toy/Games roms=["test.gba"] saved=Ok
NC: the whole change reverted app_view under QEMU red, EXIT=1 (above)

Independent oracle. Two pieces:

  • The resolver's escape suite (the literature's ..-through-a-link cases), run under a root inside the home.
  • gbae's own list_directory, verbatim, as the client whose behaviour the grant has to serve. The guest test spells every expected path itself and asks nothing of toyos-manifest.

There is no external specification for this boundary.

Tests

  • Host:
    • toyos_manifest::grants: the store's round trip at every bound (the longest folder at the longest name, a folder with a space, a full store), and every refusal by name; every folder refused by name; decide as a table (binary, ceiling, access); the cwd rule; revoke takes exactly one grant; the request codec.
    • toyos-manifest: a package's view with a granted folder, spelled out whole at both accesses.
    • src/build.rs: the ceiling's two spellings and its refusals; grants held by its holder alone, never [apps].
    • fileserver: the symlinked root, and the escape suite under a granted folder.
  • app_view, the tests/proctreecase metal row, extended.
    • The refusals: grants add from the job's own session, which is the machine's, is refused. Apps/appview is refused by name, from the login session a shell opens.
    • The grant: granted /home/toy/Games, the package run as game uses gbae's own list_directory and its save. It starts in the folder, lists test.gba, and writes test.sav beside it.
    • The binary key and revoke: one byte appended to the package makes another binary, which holds no folder. Restored, the package holds the folder again. Revoked, its next launch lists no ROM and writes nothing.
    • The judge also requires the supervisor's lines for the refusal, the grant and the revoke.
  • Why a metal row and not a new QEMU test: what is asserted is the supervisor and the file server across a launch, which a host test cannot reach. A metal row on the image An installed app sees its own package read-only and its own folder as HOME, and nothing else of /apps or /home #807 already boots reaches it, and adds no QEMU boot to guest / suite. It ran under QEMU only through An installed app sees its own package read-only and its own folder as HOME, and nothing else of /apps or /home #807's temporary app_view_qemu harness (posted), for G0, the mutations and the control.

Gates (head c190ac79b)

gate command exit
host cargo run -- --ci host 0 (78 steps, all green)
image cargo run -- --build-only 0
whole guest suite cargo test --test toyos-build 0 (41/41); uptime load averages 26.99 / 22.51 / 17.77 before, 35.73 / 26.23 / 19.53 after
T14 staging cargo test --test toyos-build -- --metal --metal-readback <dir> boot:testcases boot:proctreecase 2: three images staged, no machine touched (proctreecase de5b9032…6dda84ae, testcases 5d47aa4f…90fb6968, testcases-watchdog 18a86b20…b8ad8922), each sha256 in request.txt. The T14 reading is the orchestrator's.

Earlier, at 04750cc1b (before the size asserts and app_view's red for a missing grants): the suite was 41/41, EXIT=0. The app_view QEMU run at the first commit was EXIT=0.

Net lines: git diff --shortstat origin/main...HEAD gives 14 files, +1178 −64.

  • toyos-manifest/src/grants.rs: 292 production and 171 test lines.
  • The rest, by --numstat: supervisor +256 −36, userland/grants +95, src/build.rs +64 −16 (about 26 of them tests), toyos-manifest/src/lib.rs +47 −6 (20 tests), system.toml +14 −2. Tests outside those: app_view.rs +169, the fileserver's two tests +45, tests/proctreecase +11, the judge +6.

Not done: stage 2, and why this stops here

Stage 2 is the owner's popup. Its parts:

  • The supervisor parks a launch on the event loop: the caller's hang-up or the consent server's end cancels it, and one ask is outstanding at a time.
  • The screen bit, carried in the launcher badge: the compositor's launches hold the screen, and a login row's other launches never do, so sshserver's shells, even one started from a desktop shell, never prompt.
  • decide's Ask arm and the stored Deny.
  • The compositor launches off its loop, and a prompt port gives a layer above topmost and the taskbar. While a prompt is up, the pure rules route every key and every hit to it, refuse chords and paste, swallow a press made before its first frame was composited, and refuse a second prompt.
  • toyos-window gains a constructor on a named port. That crate is outside this brief's fence.
  • filepicker's consent mode, with Always, Once, Deny and Skip, and a chooser bounded by the folder rules.
  • A desktop guest test: launch from a desktop terminal, a hostile fullscreen topmost client, screendump pixel checks and harness keys.

The guest test alone needs harness pieces this tree does not have: a desktop session driven by keys, and pixel assertions on a composited screen. None of stage 2 is in this branch. The issue issues/an-installed-gbae-browses-to-no-rom.md stays open, since its exit is a ROM picked from the desktop.

What I am unsure of

  • The store is in /state, which any declared row can write. This is the same weakness as /apps (issues/whether-pkg-alone-writes-apps.md): known, tracked, and still true. Isolation stage 2 closes it. A row that writes the store can grant a package any folder the store's parser accepts. It already holds the whole tree itself.
  • The digest is a key, not a seal. The supervisor hashes the binary and then prepare reads it again; std gives no way to start the bytes it hashed. A row that rewrites /apps/<name> between the two reads gets the grant for other bytes. Only a declared row can write /apps, and it already holds the whole tree, so it gains nothing it lacks. This is the /apps hole above.
  • A rename on DATA is atomic to every client, since the server answers one request at a time. It is not crash-atomic: DATA keeps no journal (issues/bcachefs-crate-is-not-bcachefs.md).
  • grants list does not say that a revoked package still running keeps its folder until it ends. The supervisor keeps no process handle for a launch.
  • A launch of a package with no grant says one line. When stage 2 lands, that line becomes the question.

🤖 Generated with Claude Code

https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C

Japabu and others added 4 commits October 9, 2026 21:39
…ees it

Stage 1 of launch-time consent: grants by command.

- `toyos_manifest::grants`: the store the supervisor alone writes
  (`/state/supervisor/grants`), keyed on the user, the package and the
  SHA-256 of the exact binary the supervisor starts, so an update holds no
  grant until it is granted again; the folder rules (a canonical directory
  inside the session's home, never the home, nor `Apps` or anything in it,
  within the 54-byte grant root and std's four-component capability depth),
  each refusal a whole sentence; `decide`, the stored grant for that binary
  at most the image's ceiling; `cwd`, the caller's own inside the folder and
  the folder's root otherwise; and the request codec of the `grants` port.
- `[apps] folder = "read-write"` is the ceiling, and until signed package
  entries carry a package's own request, what every package asks for. It
  lives in `[apps]` and not beside each package because `pkg`, which writes a
  package's `manifest.toml`, is outside this change, gbae's release carries
  no request, and a per-package line in `system.toml` would be the image
  naming an app. The build refuses any other spelling, and `[apps]` now
  refuses an unknown key, so a misspelt `folder` is no silent ceiling.
- The supervisor serves `grants`, minted per start with the holder's row and
  session like a launcher, endowed under a label of its own and never in
  `svc`; it answers a login session alone. `add` checks the folder rules and
  the ceiling, reads the package's manifest, checks the folder is a directory
  and not a link, and hashes the program, all on its file worker; the store
  is written beside itself and renamed over. A launch of a package hashes its
  binary on the worker with the launch's other files, and a grant for it
  appends the folder to the package's view and prepares the launch again in
  the folder; a granted folder no longer a directory refuses the launch.
- `/system/bin/grants list | add <package> <folder> [read-only] | revoke`:
  the one row the build lets receive `grants`; the shell and sshserver list it.
- The fileserver already follows no symlink at a grant's root: DATA's flat
  namespace lists nothing through one and makes nothing under one. A host test
  holds that, and the resolver's escape suite runs under a granted folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…st one answer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
The negative control, the whole change reverted, has no /system/bin/grants;
its launch failing is now one named arm and the others still run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Mutations and the negative control for stage 1, at head c190ac79b. Each patch is checked with git apply --check, applied, run, and restored with git checkout HEAD -- . in the same script (run.sh, below); the tree was clean after each arm (summary.txt). Guest arms run app_view under QEMU through harness.patch, #807's temporary machine test app_view_qemu: the committed verdict is the app_view metal row. The negative control checks out toyos-manifest, userland/supervisor, userland/fileserver, src/build.rs, system.toml, Cargo.toml, Cargo.lock and tests/proctreecase/system.toml at 2b1a0e746 (the base G0 was measured on) and removes userland/grants, keeping app_view.rs, the judge and the harness. Paths scrubbed.

summary.txt

head c190ac79b 21:54  up 10 days,  9:38, 6 users, 
H1-decide-ignores-the-binary: EXIT=101 (cargo test -p toyos-manifest --lib grants::)
  tree after H1-decide-ignores-the-binary:        0 changed path(s)
H2-apps-folder-allowed: EXIT=101 (cargo test -p toyos-manifest --lib grants::)
  tree after H2-apps-folder-allowed:        0 changed path(s)
H3-grants-port-not-held-alone: EXIT=101 (cargo test -p toyos-build --lib only_their_holders_may_hold)
  tree after H3-grants-port-not-held-alone:        0 changed path(s)
G0-harness-alone: EXIT=0 (app_view_qemu)
  tree after G0-harness-alone:        0 changed path(s)
G1-machine-session-answered: EXIT=1 (app_view_qemu)
  tree after G1-machine-session-answered:        0 changed path(s)
G2-folder-not-in-the-view: EXIT=1 (app_view_qemu)
  tree after G2-folder-not-in-the-view:        0 changed path(s)
G3-launch-ignores-the-binary: EXIT=1 (app_view_qemu)
  tree after G3-launch-ignores-the-binary:        0 changed path(s)
NC-whole-change-reverted: EXIT=1 (app_view_qemu)
  tree after NC-whole-change-reverted:        0 changed path(s)
done 21:55  up 10 days,  9:40, 6 users, 

What each guest red named

== G1-machine-session-answered
    "grants in the machine's session was answered Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: \"appview is granted /home/toy/Games read-write\\n\", stderr: \"\" })",
== G2-folder-not-in-the-view
    "granted, it saw cwd=/home/toy/Games roms=[] saved=Err, not cwd=/home/toy/Games roms=[\"test.gba\"] saved=Ok",
    "/home/toy/Games/test.sav holds Err(Kind(NotFound))",
    "the granted binary again saw cwd=/home/toy/Games roms=[] saved=Err, not cwd=/home/toy/Games roms=[\"test.gba\"] saved=Ok",
== G3-launch-ignores-the-binary
    "another binary saw cwd=/home/toy/Games roms=[\"test.gba\"] saved=Ok, not cwd=/ roms=[] saved=Err",
== NC-whole-change-reverted
    "grants in the machine's session was answered Err(Kind(NotFound))",
    "/home/toy/Apps/appview as a grant was answered Output { status: ExitStatus(ExitStatus(127)), stdout: \"/system/bin/grants: not found\\n\", stderr: \"\" }",
    "the grant was answered Output { status: ExitStatus(ExitStatus(127)), stdout: \"/system/bin/grants: not found\\n\", stderr: \"\" }",
    "grants list answered Output { status: ExitStatus(ExitStatus(127)), stdout: \"/system/bin/grants: not found\\n\", stderr: \"\" }",
    "granted, it saw cwd=/ roms=[] saved=Err, not cwd=/home/toy/Games roms=[\"test.gba\"] saved=Ok",
    "/home/toy/Games/test.sav holds Err(Kind(NotFound))",
    "the granted binary again saw cwd=/ roms=[] saved=Err, not cwd=/home/toy/Games roms=[\"test.gba\"] saved=Ok",
    "the revoke was answered Output { status: ExitStatus(ExitStatus(127)), stdout: \"/system/bin/grants: not found\\n\", stderr: \"\" }",

run.sh

#!/bin/zsh
# Each arm: apply a checked patch, run what must see it, record the exit, restore.
cd <worktree>
L=<scratch>/logs
M=$L/mut
BASE=2b1a0e746
summary=$M/summary.txt
echo "head $(git rev-parse --short HEAD) $(uptime)" > $summary
restore() { git checkout -q HEAD -- . ; git status --porcelain --ignore-submodules=none > $M/status-after-$1.txt; echo "  tree after $1: $(wc -l < $M/status-after-$1.txt) changed path(s)" >> $summary; }
host() { # name, command
  git apply --check $M/$1.patch && git apply $M/$1.patch || { echo "$1: patch does not apply" >> $summary; return; }
  zsh -c "$2" > $M/$1.log 2>&1; e=$?; echo "$1: EXIT=$e ($2)" >> $summary; restore $1
}
guest() { # name
  git apply --check $L/harness.patch && git apply $L/harness.patch || { echo "$1: harness does not apply" >> $summary; return; }
  if [ "$1" = "NC-whole-change-reverted" ]; then
    git checkout -q $BASE -- Cargo.toml Cargo.lock src/build.rs system.toml toyos-manifest userland/supervisor userland/fileserver tests/proctreecase/system.toml && git rm -rq userland/grants
  elif [ "$1" != "G0-harness-alone" ]; then
    git apply --check $M/$1.patch && git apply $M/$1.patch || { echo "$1: patch does not apply" >> $summary; restore $1; return; }
  fi
  cargo test --test toyos-build -- app_view_qemu > $M/$1.log 2>&1; e=$?; echo "$1: EXIT=$e (app_view_qemu)" >> $summary; restore $1
}
host H1-decide-ignores-the-binary "cargo test -p toyos-manifest --lib grants::"
host H2-apps-folder-allowed "cargo test -p toyos-manifest --lib grants::"
host H3-grants-port-not-held-alone "cargo test -p toyos-build --lib only_their_holders_may_hold"
guest G0-harness-alone
guest G1-machine-session-answered
guest G2-folder-not-in-the-view
guest G3-launch-ignores-the-binary
guest NC-whole-change-reverted
echo "done $(uptime)" >> $summary

harness.patch

diff --git a/tests/toyos.rs b/tests/toyos.rs
index 008c522ec..a10bbb6d4 100644
--- a/tests/toyos.rs
+++ b/tests/toyos.rs
@@ -334,6 +334,7 @@ const MACHINE_TESTS: &[&str] = &[
     // reads it have no host build, and the T14 boots from a stick beside an
     // NVMe disk that is another system's.
     "nvme_disk_keeps_log_and_home",
+    "app_view_qemu",
 ];
 
 /// **The metal profile**: which registrations run on the ThinkPad T14, what
@@ -3200,6 +3201,7 @@ fn run_machine_test(name: &str, test_config: &Path) -> Result<(), String> {
         "bar_map_again" => bar_map_again(test_config),
         "console_image_boots" => console_image_boots(),
         "nvme_disk_keeps_log_and_home" => nvme_disk_keeps_log_and_home(test_config),
+        "app_view_qemu" => app_view_qemu(),
         other => Err(format!("unknown machine test {other}")),
     }
 }
@@ -3239,6 +3241,18 @@ fn served_by_diskserver(qemu: &mut QemuInstance, console: &mut String) -> Result
     Ok(())
 }
 
+/// `app_view` under QEMU, for mutations and the negative control only: the
+/// verdict is the `app_view` metal row's.
+fn app_view_qemu() -> Result<(), String> {
+    let case = compile::repo_root().join("tests/proctreecase");
+    let (_, job) = suite_bin(qemu::SUITE_ARCH, "app_view");
+    let mut qemu =
+        QemuInstance::boot_with_options(&case, &[], &[("app_view".to_string(), job)], BootOptions::default());
+    let said = job_said(&mut qemu, "test_rs_app_view")?;
+    eprintln!("{said}");
+    Ok(())
+}
+
 /// Run `command` as a job of the boot, to exit 0: what it said.
 fn job_said(qemu: &mut QemuInstance, command: &str) -> Result<String, String> {
     let result = qemu.run_test(command, Duration::from_secs(60));

H1-decide-ignores-the-binary

diff --git a/toyos-manifest/src/grants.rs b/toyos-manifest/src/grants.rs
index 337b2c3cb..6d243269b 100644
--- a/toyos-manifest/src/grants.rs
+++ b/toyos-manifest/src/grants.rs
@@ -133,7 +133,7 @@ pub fn folder(path: &str) -> Result<(), String> {
 /// ceiling, no grant, or a grant to another binary.
 pub fn decide(stored: Option<&Entry>, binary: &str, ceiling: Option<Access>) -> Option<Folder> {
     let ceiling = ceiling?;
-    let entry = stored.filter(|entry| entry.binary == binary)?;
+    let entry = stored?;
     Some(Folder { path: entry.folder.path.clone(), access: entry.folder.access.min(ceiling) })
 }
 

H2-apps-folder-allowed

diff --git a/toyos-manifest/src/grants.rs b/toyos-manifest/src/grants.rs
index 337b2c3cb..8ecd6db3a 100644
--- a/toyos-manifest/src/grants.rs
+++ b/toyos-manifest/src/grants.rs
@@ -116,7 +116,7 @@ pub fn folder(path: &str) -> Result<(), String> {
     let Some(inside) = path.strip_prefix(&home).and_then(|rest| rest.strip_prefix('/')) else {
         return Err(format!("{path} is not inside {home}"));
     };
-    if inside.split('/').next() == Some("Apps") {
+    if inside.split('/').next() == Some("Apps-never") {
         return Err(format!("{path} is {home}/Apps or inside it, where every app keeps its own folder"));
     }
     if path.len() - 1 > MAX_ROOT {

H3-grants-port-not-held-alone

diff --git a/src/build.rs b/src/build.rs
index 6aae599de..1d5333242 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -590,7 +590,7 @@ const SUPERVISOR_SERVED: &[&str] = &[toyos_swap::PORT, "power", toyos_manifest::
 /// the swap port, whose holder replaces any service's binary, and the grants
 /// port, whose holder writes which folder of the home a package sees.
 const HELD_ALONE: &[(&str, &str)] =
-    &[(toyos_swap::PORT, toyos_swap::HOLDER), (toyos_manifest::grants::PORT, toyos_manifest::grants::HOLDER)];
+    &[(toyos_swap::PORT, toyos_swap::HOLDER)];
 
 /// Who may hold the authorities that change what the machine runs or what a
 /// package sees: each of [`HELD_ALONE`]'s ports, its holder and nothing else

G1-machine-session-answered

diff --git a/userland/supervisor/src/main.rs b/userland/supervisor/src/main.rs
index 1269b9dda..521586de9 100644
--- a/userland/supervisor/src/main.rs
+++ b/userland/supervisor/src/main.rs
@@ -892,7 +892,7 @@ impl<'a> Supervisor<'a> {
     /// and the machine's session is every service's.
     fn grant(&mut self, caller: &Caller, msg_type: u32, payload: &[u8]) -> Result<String, String> {
         let request = grants::Request::decode(msg_type, payload).ok_or("the request is not one this port reads")?;
-        if !matches!(caller.session, Session::Login(_)) {
+        if false && !matches!(caller.session, Session::Login(_)) {
             return Err("only a login session may ask for grants".to_string());
         }
         let user = toyos_manifest::USER;

G2-folder-not-in-the-view

diff --git a/userland/supervisor/src/main.rs b/userland/supervisor/src/main.rs
index 1269b9dda..53c77261e 100644
--- a/userland/supervisor/src/main.rs
+++ b/userland/supervisor/src/main.rs
@@ -1775,7 +1775,7 @@ impl Supervisor<'_> {
         if let Some(binary) = binary {
             match self.granted(&program.name, binary, command, request.cwd) {
                 Ok((granted, prepared)) => {
-                    program.folder = granted;
+                    program.folder = granted.filter(|_| false);
                     command = prepared;
                 }
                 Err(why) => {

G3-launch-ignores-the-binary

diff --git a/userland/supervisor/src/main.rs b/userland/supervisor/src/main.rs
index 1269b9dda..ed618e67b 100644
--- a/userland/supervisor/src/main.rs
+++ b/userland/supervisor/src/main.rs
@@ -1853,7 +1853,7 @@ impl Supervisor<'_> {
         mut command: Command,
         cwd: &str,
     ) -> Result<(Option<grants::Folder>, Command), String> {
-        let binary = binary?;
+        let binary = self.store.find(toyos_manifest::USER, name).map_or(binary?, |e| e.binary.clone());
         let Some(folder) = grants::decide(self.store.find(toyos_manifest::USER, name), &binary, self.system.folder) else {
             if self.system.folder.is_some() {
                 say!("supervisor: launcher: {name} holds no folder; `grants add {name} <folder>` grants it one");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant