diff --git a/Cargo.lock b/Cargo.lock index 53f8161a3ce..e139e2ed673 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3050,10 +3050,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proctest" -version = "0.1.0" - [[package]] name = "quick-xml" version = "0.41.0" diff --git a/Cargo.toml b/Cargo.toml index 2a017c15115..333021bd1b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,7 +124,6 @@ members = [ "system/usbd", "tests/guest/kernelprobe", "tests/guest/metalprobe", - "tests/guest/proctest", "tests/guest/test-runner", "tests/metal", ] diff --git a/images/system.toml b/images/system.toml index c8ee4a37757..bb677b274be 100644 --- a/images/system.toml +++ b/images/system.toml @@ -41,7 +41,6 @@ folder = "read-write" # its own `/state/` and makes that directory first. Every other row runs # with the session user's home. [programs] -proctest = {} # The installer. It holds nothing: it writes under `/apps` because `/apps` is # writable to it, and a row that gave it more would make that untrue. pkg = {} @@ -100,7 +99,7 @@ devices = ["pci:1af4:1041"] [programs.sshserver] service = true receives = ["netstack"] -starts = ["toybox", "shell", "terminal", "doom", "snake", "calc", "editor", "paint", "files", "host", "inspect", "pkg", "proctest", "sshserver", "swap", "toyfetch", "update", "grants", "/apps"] +starts = ["toybox", "shell", "terminal", "doom", "snake", "calc", "editor", "paint", "files", "host", "inspect", "pkg", "sshserver", "swap", "toyfetch", "update", "grants", "/apps"] login = true # `swap` is the authority to replace a running service's binary; the build @@ -160,7 +159,7 @@ starts = ["shell"] [programs.shell] receives = ["surface"] -starts = ["toybox", "shell", "terminal", "doom", "snake", "calc", "editor", "paint", "files", "host", "inspect", "pkg", "proctest", "sshserver", "swap", "toyfetch", "update", "grants", "/apps"] +starts = ["toybox", "shell", "terminal", "doom", "snake", "calc", "editor", "paint", "files", "host", "inspect", "pkg", "sshserver", "swap", "toyfetch", "update", "grants", "/apps"] [programs.doom] receives = ["compositor", "soundserver"] @@ -199,7 +198,7 @@ receives = ["compositor", "filepicker"] [programs.toybox] receives = ["compositor", "soundserver", "surface", "power"] syscap = ["roster"] -starts = ["toybox", "shell", "terminal", "doom", "snake", "calc", "editor", "paint", "files", "host", "inspect", "pkg", "proctest", "sshserver", "swap", "toyfetch", "update", "/apps"] +starts = ["toybox", "shell", "terminal", "doom", "snake", "calc", "editor", "paint", "files", "host", "inspect", "pkg", "sshserver", "swap", "toyfetch", "update", "/apps"] # Symlinks created on ROOT at build time. # Keys are ROOT-relative; targets are the guest paths they resolve to. @@ -214,14 +213,12 @@ starts = ["toybox", "shell", "terminal", "doom", "snake", "calc", "editor", "pai "bin/ls" = "/system/bin/toybox" "bin/mkdir" = "/system/bin/toybox" "bin/mv" = "/system/bin/toybox" -"bin/net" = "/system/bin/toybox" "bin/ps" = "/system/bin/toybox" "bin/pwd" = "/system/bin/toybox" "bin/reboot" = "/system/bin/toybox" "bin/rm" = "/system/bin/toybox" "bin/screen" = "/system/bin/toybox" "bin/shutdown" = "/system/bin/toybox" -"bin/spin" = "/system/bin/toybox" "bin/stats" = "/system/bin/toybox" "bin/tone" = "/system/bin/toybox" diff --git a/issues/consent-prompts-click-on-an-open-launchers-row-made-no-launch.md b/issues/consent-prompts-click-on-an-open-launchers-row-made-no-launch.md new file mode 100644 index 00000000000..fdc879d7f13 --- /dev/null +++ b/issues/consent-prompts-click-on-an-open-launchers-row-made-no-launch.md @@ -0,0 +1,35 @@ +--- +status: open +kind: defect +opened: 2026-10-12 +--- + +# `consent_prompt`'s click on an open launcher's row made no launch + +A whole guest suite (`cargo test`) on the development host, on pull request +#889's tree at `c24bee1db`, went red on `consent_prompt` alone, 62 of 63 +green, while the host's load average read 34.22, 38.33 and 47.31 a minute +after it ended, on 14 cores. The suite had scaled its liveness ceilings by +1.00x. Of what that test boots or runs, the tree differs from `main`'s at +`ab655a115` only in a doc comment of `toyos_manifest::launch::refused`. + +The steps `always`, `again`, `deny` and `denied` passed. At `skip` the host +clicked `+`, saw the launcher's row change on the panel within its 20 s, and +clicked the row. Nothing launched: the supervisor said nothing more of +`consentee`, no window opened, and the compositor logged only idle frames +until the job's 600 s ceiling ended it. With no launch there was no prompt, +so `Consent::prompt_up`, which only the prompt's line starts, never ran. The +log: +https://github.com/ToyOSOrg/evidence/blob/c7a625ddef468380faaca0e94f0be7ffb52dfed3/build/guest.log#L1259 + +The host waits for the launcher before its second click because two clicks +in one read are one click +(`issues/two-clicks-the-compositor-reads-at-once-are-one-click.md`). That +wait ends when any pixel of the row's rectangle changes (`Consent::begin`, +`tests/toyos.rs`), which is not the row being drawn. + +Owner: the desktop track, `issues/toyos-has-a-desktop.md`. + +**Exit**: why a click on the open launcher's row made no launch is named and +fixed, and the host's step reds by name, within a bound of its own, when its +click launches nothing. diff --git a/issues/nothing-holds-that-a-child-spawned-directly-holds-no-launcher.md b/issues/nothing-holds-that-a-child-spawned-directly-holds-no-launcher.md new file mode 100644 index 00000000000..f37b5d8d250 --- /dev/null +++ b/issues/nothing-holds-that-a-child-spawned-directly-holds-no-launcher.md @@ -0,0 +1,25 @@ +--- +status: open +kind: tooling +opened: 2026-10-12 +--- + +# Nothing holds that a child spawned directly holds no launcher + +The `launch_authority` metal row, deleted by the owner's ruling on pull +request #889, ended by spawning its own binary, which no row declares, and +asserting the child held no launcher: none under the `launcher` label, and +none in the `svc` namespace it inherits. No test at any tier asserts that +now. + +This file owes std's half of it: a direct spawn endows the child a copy of +the caller's `svc` and only what the caller endowed, never the caller's +launcher (`sdk/std/sys/process.rs`). The supervisor's half, a row's launcher +endowed under `launcher` and never in `svc`, is owed by stage 2 of +`issues/the-supervisor-is-host-tested-and-owns-the-stop.md`. + +**Owner**: the orchestrator. + +**Exit**: a test on the cheapest tier that reaches std's direct spawn holds +that it endows the child no launcher, and a mutation named in its pull +request reds it: a direct spawn endowing the child its caller's launcher. diff --git a/issues/the-shipped-image-carries-two-test-programs.md b/issues/the-shipped-image-carries-two-test-programs.md deleted file mode 100644 index 77dd0b228d2..00000000000 --- a/issues/the-shipped-image-carries-two-test-programs.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -status: open -kind: defect -opened: 2026-09-30 ---- - -# The shipped image carries two test programs - -"Nothing ships for tests alone" (`.claude/agents/reviewer.md`, Fit) is untrue -of the shipped `images/system.toml` in two rows: - -- `proctest = {}`: `tests/guest/proctest/README.md` calls it a test harness, and - nothing in the tree runs `/system/bin/proctest` but `proctest` itself. -- `"bin/spin" = "/system/bin/toybox"`: `system/toybox/src/spin.rs` loops - forever, and nothing in the tree runs it; its one named use is a test, the - metal `sshd_exec` row - `issues/the-guest-suite-runs-only-what-no-cheaper-tier-reaches.md` owes. - -Found by `git grep -n -w -e proctest` and -`git grep -n -w -e spin -- system.toml tests userland issues/build`. - -**Exit condition**: the shipped `images/system.toml` names neither, and a test that -needs one carries it in its own image alone. diff --git a/issues/the-supervisor-is-host-tested-and-owns-the-stop.md b/issues/the-supervisor-is-host-tested-and-owns-the-stop.md index b235919cbe1..8e57885ed84 100644 --- a/issues/the-supervisor-is-host-tested-and-owns-the-stop.md +++ b/issues/the-supervisor-is-host-tested-and-owns-the-stop.md @@ -59,8 +59,12 @@ nothing. **Exit**: the crate's tests pass in `cargo test --workspace --exclude toyos-build`; a host test refuses a manifest whose dependencies form an undeclared cycle; each refusal and - each decision above has a mutation that reds a host test, named in the PR; - and the stage deletes each decision from `system/supervisor`, which calls + each decision above has a mutation that reds a host test, named in the PR, + namespace selection's among them: a row's launcher endowed as an entry of + `svc` (`launcher_namespace`), which a child its holder spawns directly + would inherit, and no such child holding one is what the `launch_authority` + metal row, deleted in #889, last asserted; and the stage deletes each + decision from `system/supervisor`, which calls the crate for it, named per decision in the PR; `toyos_manifest::launch`, who may start what and the launcher's badge codec, moves into the crate and out of `toyos-manifest`. No decision exists in two places. diff --git a/issues/toybox-net-cannot-reach-netstack.md b/issues/toybox-net-cannot-reach-netstack.md deleted file mode 100644 index 7fbb638d60b..00000000000 --- a/issues/toybox-net-cannot-reach-netstack.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -status: open -kind: defect -opened: 2026-09-26 ---- - -# toybox's `net` applet cannot reach netd - -`/bin/net` (`system/toybox/src/net.rs`) fetches a URL with -`TcpStream::connect`, but `[programs.toybox]` in `system.toml` receives -`compositor`, `soundd` and `surface` and not `netd`. Every connect it makes is -answered `NetdNotFound` by the SDK, so the applet can only ever print -`net: connection failed`. Endowing the row with `netd` would hand every other -toybox applet the network too, the same granularity `system.toml`'s own comment -on the row names. - -Exit condition: `net` fetches from a host, or is removed. diff --git a/lib/manifest/src/launch.rs b/lib/manifest/src/launch.rs index 09f8c55375a..03645af006c 100644 --- a/lib/manifest/src/launch.rs +++ b/lib/manifest/src/launch.rs @@ -252,11 +252,6 @@ pub fn may_start(caller: &Program, session: Session, target: Target<'_>) -> Resu Ok(starts) } -/// The supervisor's line for a refused launch, which the metal judge reads whole. -pub fn refused(caller: &str, session: Session, target: &str, why: Refusal) -> String { - format!("supervisor: launcher: {caller} in {session} may not start {target}: {why}") -} - #[cfg(test)] mod tests { use std::collections::BTreeSet; diff --git a/system/supervisor/src/main.rs b/system/supervisor/src/main.rs index 3bcec5fa71b..642c7e58b1d 100644 --- a/system/supervisor/src/main.rs +++ b/system/supervisor/src/main.rs @@ -1903,7 +1903,7 @@ impl Supervisor<'_> { let (starts, binary, prepared) = match verdict { Ok(judged) => judged, Err(why) => { - say!("{}", authority::refused(&caller.row.name, caller.session, &program.name, why)); + say!("supervisor: launcher: {} in {} may not start {}: {why}", caller.row.name, caller.session, program.name); let _ = conn.try_signal(launch::MSG_REFUSED); return; } diff --git a/system/toybox/src/main.rs b/system/toybox/src/main.rs index 9e3df687707..ad92fea301b 100644 --- a/system/toybox/src/main.rs +++ b/system/toybox/src/main.rs @@ -8,14 +8,12 @@ mod locale; mod ls; mod mkdir; mod mv; -mod net; mod ps; mod pwd; mod reboot; mod rm; mod screen; mod shutdown; -mod spin; mod stats; mod tone; @@ -30,7 +28,7 @@ macro_rules! commands { }; } -commands!(cat, cp, echo, free, grep, hexdump, locale, ls, mkdir, mv, net, ps, pwd, reboot, rm, screen, shutdown, spin, stats, tone); +commands!(cat, cp, echo, free, grep, hexdump, locale, ls, mkdir, mv, ps, pwd, reboot, rm, screen, shutdown, stats, tone); fn main() { let args: Vec = std::env::args().collect(); diff --git a/system/toybox/src/net.rs b/system/toybox/src/net.rs deleted file mode 100644 index ccc5c234b7e..00000000000 --- a/system/toybox/src/net.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::io::{Read, Write}; -use std::net::TcpStream; -use std::time::Duration; - -pub fn main(args: Vec) { - let (host, port, path) = if args.len() > 1 { - parse_url(&args[1]) - } else { - ("example.com".into(), 80, "/".into()) - }; - - println!("Connecting to {host}:{port}..."); - - let mut stream = match TcpStream::connect((&*host, port)) { - Ok(s) => s, - Err(e) => { - eprintln!("net: connection failed: {e}"); - return; - } - }; - stream.set_read_timeout(Some(Duration::from_secs(10))).ok(); - - println!("Connected! Sending HTTP request..."); - - let request = format!("GET {path} HTTP/1.0\r\nHost: {host}\r\n\r\n"); - if let Err(e) = stream.write_all(request.as_bytes()) { - eprintln!("net: write failed: {e}"); - return; - } - - let mut response = Vec::new(); - if let Err(e) = stream.read_to_end(&mut response) { - eprintln!("net: read failed: {e}"); - return; - } - - let text = String::from_utf8_lossy(&response); - let preview = if text.len() > 1000 { &text[..1000] } else { &text }; - println!("{preview}"); - if text.len() > 1000 { - println!("... ({} bytes total)", text.len()); - } -} - -fn parse_url(url: &str) -> (String, u16, String) { - // Simple URL parser: "http://host:port/path" or just "host" - let url = url.strip_prefix("http://").unwrap_or(url); - let (host_port, path) = match url.find('/') { - Some(i) => (&url[..i], &url[i..]), - None => (url, "/"), - }; - let (host, port) = match host_port.rfind(':') { - Some(i) => (&host_port[..i], host_port[i+1..].parse().unwrap_or(80)), - None => (host_port, 80), - }; - (host.to_string(), port, path.to_string()) -} diff --git a/system/toybox/src/spin.rs b/system/toybox/src/spin.rs deleted file mode 100644 index 1ce01bbd268..00000000000 --- a/system/toybox/src/spin.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub fn main(_args: Vec) { - println!("spinning forever..."); - loop {} -} diff --git a/tests/guest/proctest/Cargo.toml b/tests/guest/proctest/Cargo.toml deleted file mode 100644 index 794beee24d0..00000000000 --- a/tests/guest/proctest/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "proctest" -description = "Test-only: subprocess creation, piped I/O and an interactive child, checked from inside a ToyOS guest." -version = "0.1.0" -edition = "2021" -license = "MIT OR Apache-2.0" - -[package.metadata.toyos.host] -fails = ["linux", "macos", "windows"] -issue = "issues/apps-that-build-or-run-on-toyos-alone.md" diff --git a/tests/guest/proctest/README.md b/tests/guest/proctest/README.md deleted file mode 100644 index 6fbc02b9350..00000000000 --- a/tests/guest/proctest/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# proctest - -Test harness that validates subprocess creation, piped I/O, and interactive communication with child processes. diff --git a/tests/guest/proctest/src/main.rs b/tests/guest/proctest/src/main.rs deleted file mode 100644 index 8c076700359..00000000000 --- a/tests/guest/proctest/src/main.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::io::{BufRead, BufReader, Read, Write}; -use std::process::{Command, Stdio}; - -fn main() { - let args: Vec = std::env::args().collect(); - match args.get(1).map(|s| s.as_str()) { - Some("echo") => subcmd_echo(), - Some("repl") => subcmd_repl(), - _ => run_tests(), - } -} - -fn run_tests() { - test_status(); - test_output(); - test_piped_stdout(); - test_piped_stdin_stdout(); - test_interactive(); - - println!("all tests passed"); -} - -fn subcmd_echo() { - std::os::toyos::io::set_stdin_raw(true); - let mut buf = Vec::new(); - std::io::stdin().read_to_end(&mut buf).unwrap(); - std::io::stdout().write_all(&buf).unwrap(); -} - -fn subcmd_repl() { - std::os::toyos::io::set_stdin_raw(true); - let stdin = std::io::stdin(); - for line in stdin.lock().lines() { - let line = line.unwrap(); - let (cmd, arg) = line.split_once(' ').unwrap_or((&line, "")); - match cmd { - "echo" => println!("you said {}", arg), - "exit" => { - println!("exiting"); - return; - } - _ => println!("unknown command: {}", cmd), - } - } -} - -fn test_status() { - print!("test Command::status()... "); - let status = Command::new("/system/bin/echo") - .arg("hi") - .status() - .expect("failed to run echo"); - assert!(status.success(), "echo exited with failure"); - println!("ok"); -} - -fn test_output() { - print!("test Command::output()... "); - let output = Command::new("/system/bin/echo") - .args(&["hello", "world"]) - .output() - .expect("failed to run echo"); - assert!(output.status.success()); - let stdout = String::from_utf8_lossy(&output.stdout); - assert!(stdout.contains("hello world"), "unexpected output: {stdout:?}"); - println!("ok (got: {})", stdout.trim()); -} - -fn test_piped_stdout() { - print!("test spawn() with piped stdout... "); - let mut child = Command::new("/system/bin/echo") - .args(&["piped", "test"]) - .stdout(Stdio::piped()) - .spawn() - .expect("failed to spawn echo"); - let mut output = String::new(); - child.stdout.take().unwrap().read_to_string(&mut output).unwrap(); - let status = child.wait().expect("failed to wait"); - assert!(status.success()); - assert!(output.contains("piped test"), "unexpected output: {output:?}"); - println!("ok (got: {})", output.trim()); -} - -fn test_piped_stdin_stdout() { - print!("test spawn() with piped stdin+stdout... "); - let mut child = Command::new("/system/bin/proctest") - .arg("echo") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .expect("failed to spawn proctest echo"); - - let msg = "hello from parent\n"; - child.stdin.take().unwrap().write_all(msg.as_bytes()).unwrap(); - - let mut output = String::new(); - child.stdout.take().unwrap().read_to_string(&mut output).unwrap(); - let status = child.wait().expect("failed to wait"); - assert!(status.success()); - assert_eq!(output, msg, "echo mismatch: {output:?}"); - println!("ok (echoed: {})", output.trim()); -} - -fn test_interactive() { - print!("test interactive subprocess... "); - let mut child = Command::new("/system/bin/proctest") - .arg("repl") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .expect("failed to spawn proctest repl"); - - let mut stdin = child.stdin.take().unwrap(); - let mut stdout = BufReader::new(child.stdout.take().unwrap()); - let mut line = String::new(); - - stdin.write_all(b"echo hello\n").unwrap(); - line.clear(); - stdout.read_line(&mut line).unwrap(); - assert_eq!(line, "you said hello\n", "unexpected: {line:?}"); - - stdin.write_all(b"echo world\n").unwrap(); - line.clear(); - stdout.read_line(&mut line).unwrap(); - assert_eq!(line, "you said world\n", "unexpected: {line:?}"); - - stdin.write_all(b"exit\n").unwrap(); - line.clear(); - stdout.read_line(&mut line).unwrap(); - assert_eq!(line, "exiting\n", "unexpected: {line:?}"); - - let status = child.wait().expect("failed to wait"); - assert!(status.success()); - println!("ok"); -} diff --git a/tests/guest/rust-tests/src/bin/launch_authority.rs b/tests/guest/rust-tests/src/bin/launch_authority.rs deleted file mode 100644 index 3e10361eb16..00000000000 --- a/tests/guest/rust-tests/src/bin/launch_authority.rs +++ /dev/null @@ -1,90 +0,0 @@ -//! A launch starts only what the caller's row lists, and `swap` and `update` -//! only in a login session. -//! -//! This job holds test-runner's launcher, in the machine's session, and asks -//! the supervisor for: -//! -//! - `toybox` as `ps`, which test-runner's row lists: it runs under its row, -//! which alone gives it the roster `ps` exits 0 with; -//! - `proctest`, which the row does not list, and `swap` and `update`, which -//! it lists and which start only in a login session: each is refused, and -//! nothing is spawned in its place; -//! - `toybox stats swap`: toybox's row lists `swap` and opens no session, so -//! it asks in the session it was launched in, the machine's, and is refused; -//! - a shell, whose row opens a login session, running `toybox stats swap`: -//! toybox asks in that session, and `swap` starts. -//! -//! `stats` exits 1 when its command does not start, and 0 once it has run. -//! -//! And a child it spawns directly holds no launcher, under its label or in -//! the namespace it inherits: the chain where any program a shell spawned -//! could ask for `swap` is gone. - -use std::process::{Command, Stdio}; - -use toyos::endow::{self, EndowError, Endowments}; -use toyos::launch::LAUNCHER; - -const SELF_PATH: &str = "/system/bin/test_rs_launch_authority"; -const STATS_SWAP: &str = "/system/bin/toybox stats /system/bin/swap"; -const CHILD: &str = "child"; -/// What the child exits with holding no launcher, and holding one. -const HOLDS_NONE: i32 = 0; -const HOLDS_ONE: i32 = 1; - -fn main() { - match std::env::args().nth(1).as_deref() { - Some(CHILD) => child(), - _ => test(), - } -} - -fn test() { - // Every arm runs, so one run says each one that is red. - let mut red = Vec::new(); - - let ps = Command::new("/system/bin/toybox").arg("ps").output().expect("launch toybox as ps"); - if ps.status.code() != Some(0) { - red.push(format!("a listed row did not run under its row: {ps:?}")); - } - - for program in ["/system/bin/proctest", "/system/bin/swap", "/system/bin/update"] { - match Command::new(program).stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null()).spawn() { - Err(_) => println!(" {program}: refused"), - Ok(mut started) => { - let _ = started.kill(); - let _ = started.wait(); - red.push(format!("{program} started for a caller in the machine's session")); - } - } - } - - let from_machine = Command::new("/system/bin/toybox") - .args(["stats", "/system/bin/swap"]) - .output() - .expect("launch toybox as stats"); - match from_machine.status.code() { - Some(1) => println!(" toybox in the machine's session: swap refused"), - _ => red.push(format!("toybox launched in the machine's session started swap: {from_machine:?}")), - } - - let from_login = Command::new("/system/bin/shell").args(["-c", STATS_SWAP]).output().expect("launch a shell"); - match from_login.status.code() { - Some(0) => println!(" toybox in a login session: swap started"), - _ => red.push(format!("toybox launched in a login session did not start swap: {from_login:?}")), - } - - let child = Command::new(SELF_PATH).arg(CHILD).status().expect("spawn this binary as a child"); - if child.code() != Some(HOLDS_NONE) { - red.push(format!("a child spawned directly holds a launcher ({child:?})")); - } - - assert!(red.is_empty(), "launch_authority:\n {}", red.join("\n ")); - println!("launch_authority: PASS"); -} - -fn child() -> ! { - let labelled = Endowments::get().labels().any(|label| label == LAUNCHER); - let inherited = !matches!(endow::service(LAUNCHER), Err(EndowError::NotEndowed)); - std::process::exit(if labelled || inherited { HOLDS_ONE } else { HOLDS_NONE }) -} diff --git a/tests/images/proctreecase.toml b/tests/images/proctreecase.toml index c55ff8182cc..92fb92a96a1 100644 --- a/tests/images/proctreecase.toml +++ b/tests/images/proctreecase.toml @@ -7,12 +7,6 @@ # # `launch_toctou` rides it too: a launch of `toybox` through a link it re-points. # -# And `launch_authority`: test-runner's row lists `swap` and `update`, which a -# job is refused outside a login session, and not `proctest`, which it is -# refused outright; `toybox`, which opens no session, starts `swap` in the -# session it was launched in: refused in the machine's, started in the one the -# shell opens. -# # And `fs_share`: a shell test-runner launches opens no session and spends # test-runner's share of DATA's server; a shell that shell launches is in a # login session its row opens, which has a share of its own, and so is every @@ -42,13 +36,12 @@ syscap = ["logread"] # because test-runner hands each binary a duplicate of its capability. [programs.test-runner] syscap = ["dup", "roster"] -starts = ["toybox", "shell", "swap", "update", "grants", "/apps"] +starts = ["toybox", "shell", "grants", "/apps"] # `roster`, which a child the job spawns itself never holds: a child holding # it ran under this row, and `launch_toctou` asks which bytes that child was. [programs.toybox] syscap = ["roster"] -starts = ["swap"] [programs.shell] starts = ["toybox", "shell", "grants"] @@ -57,14 +50,6 @@ login = true [programs.grants] receives = ["grants"] -[programs.swap] -receives = ["swap"] - -[programs.update] -slots = true - -[programs.proctest] - [symlinks] "bin/cat" = "/system/bin/toybox" diff --git a/tests/toyos.rs b/tests/toyos.rs index cd15262ff57..c5b2f432033 100644 --- a/tests/toyos.rs +++ b/tests/toyos.rs @@ -124,10 +124,6 @@ const RUST_SKIP: &[&str] = &[ // `tests/images/testcases.toml` does not give: the `launch_toctou` metal row runs it on // tests/images/proctreecase.toml. "launch_toctou", - // Needs a launcher whose row lists `swap` and `update` and not `proctest`, - // and a shell that opens a login session: the `launch_authority` metal row - // runs it on tests/images/proctreecase.toml. - "launch_authority", // A kernel primitive with no use for any one boot's devices: the // `port_badge` metal row runs it on tests/images/proctreecase.toml. "port_badge", @@ -883,12 +879,6 @@ const METAL: &[(&str, metal::Metal)] = &[ "launch_toctou", metal::Metal { arms: PROCTREECASE, judge: |b| b[0].job_passed("test_rs_launch_toctou") }, ), - ( - // A launch starts only what the caller's row lists, and `swap` and - // `update` only in a login session. - "launch_authority", - metal::Metal { arms: PROCTREECASE, judge: |b| launch_authority(b[0]) }, - ), ( // A connection's badge is the minted bytes, read back by its own // port's acceptor alone. @@ -1181,9 +1171,8 @@ const METALCASE: &[metal::Arm] = &[metal::once("metalcase", "tests/images/metalc /// A launcher and a declared `cat` and shell, which `process_tree`'s subtree /// launches, a `toybox` row holding `roster`, which `launch_toctou` races, the -/// rows `launch_authority` is refused and started, the shells `fs_share` -/// asks DATA's server through, under its share and in a login session, and -/// the `/apps` `app_view` launches its package from. +/// shells `fs_share` asks DATA's server through, under its share and in a +/// login session, and the `/apps` `app_view` launches its package from. const PROCTREECASE: &[metal::Arm] = &[metal::once( "proctreecase", "tests/images/proctreecase.toml", @@ -1191,7 +1180,6 @@ const PROCTREECASE: &[metal::Arm] = &[metal::once( &[ "test_rs_process_tree", "test_rs_launch_toctou", - "test_rs_launch_authority", "test_rs_port_badge", "test_rs_fs_share", "test_rs_app_view", @@ -5013,28 +5001,6 @@ fn process_tree(back: &metal::Readback) -> Result<(), String> { Ok(()) } -/// `launch_authority` passed, and the supervisor refused each launch for its -/// own reason: `proctest` as unlisted, `swap` and `update` as outside a login -/// session, for test-runner and for the toybox it launched. The guest sees -/// only that each was refused. -fn launch_authority(back: &metal::Readback) -> Result<(), String> { - use toyos_manifest::launch::{refused, Refusal, Sessions}; - back.job_passed("test_rs_launch_authority")?; - let log = back.log(); - for (caller, target, why) in [ - ("test-runner", "proctest", Refusal::NotListed), - ("test-runner", "swap", Refusal::OutsideLogin), - ("test-runner", "update", Refusal::OutsideLogin), - ("toybox", "swap", Refusal::OutsideLogin), - ] { - let line = refused(caller, Sessions::default().machine(), target, why); - if !log.text().lines().any(|l| l.contains(&line)) { - return Err(format!("the supervisor never said `{line}`\n{}", log.text())); - } - } - Ok(()) -} - /// `app_view` passed, every arm its package asks held, and the supervisor /// refused each of the two launches for its own reason: a package named after /// the shell's row, and one whose folder is a file. The guest sees only that