Repository navigation
Conversation
Review r1 of #1278 at 50c9da2Architecture. The ask is a kernel fact and an ABI field. The kernel validates it once in Correctness, traced:
Size: about +400 lines of production code (kernel about +330, ABI/SDK/manifest/supervisor about +70) and about +235 of tests. The records and manual grow by about +90 lines. Evidence: host CI fails only on the same recorded BlockingB1 This head does not merge onto main 302fb36. #1252 conflicts in B2
The Trust page should state both. B3 B4 B5 The PR description (the orchestrator's to correct):
SuggestionsS1 S2 S3 S4 S5 S6 S7 SEND BACK |
…d nothing asked costs one branch - The Trust page names SSBD among what a program that asks gets, and says any program may ask for a child it starts (B2). - in_force's doc says what it holds in force by construction (B3, in the commit before this one, rebased). - The per-CPU flag whether IA32_SPEC_CTRL exists is the test kernel's alone, for its debug read (B4). - A CPU whose decision names nothing on request returns from switch_to after one load (S1). install(), called beside report(), gives each CPU its switch state, and the base it installs is the IA32_SPEC_CTRL its bring-up read back rather than a second decision (S2, S7). LastAsked names a pid (S3). - speculationprobe refuses an error answer (S4). speculation_on_request says it holds nothing where CPUID enumerates no IBPB, as TCG's qemu64 does not, and states its targets at its registration (S5); back on the shared CPU after the probe it reads the asked bits clear (S6). Rebased onto main 302fb36: #1252's spawn path takes the job and no labels, and the ask rides PendingHandles beside the pager as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bdb5e461c25e4: rebased onto #1252, the Trust page, the early return; masked
…, and an IBPB goes between it and another The decision named SSBD and STIBP for a program that asks, and an IBPB between two programs one of which asks, and nothing applied them: no program could ask, and no switch read or wrote a speculation control. - A row asks with `isolated-speculation = true` in system.toml. The manifest carries it, the supervisor starts the row with CommandExt::isolated_speculation, and SpawnArgs::isolated_speculation takes it to the kernel: 1 asks, 0 asks nothing of its own, anything else is InvalidArgument. A child asks as its spawner does or because its spawn asked (Speculation::of_child); every thread of a process carries its ask, in its payload and its switch context. A launch runs as its own row says, so the SDK refuses a launch that names the ask. - Decision::on_request names what a CPU applies for a program that asked: SSBD and STIBP in IA32_SPEC_CTRL, SSBD in AMD's VIRT_SPEC_CTRL for a guest that enumerates only that, an IBPB, and the fill after it. report() gives each CPU its own once SMT is known and before any program runs. - arch::x86_64::mitigation::switch_to, beside the port bitmap's switch, sets the asked bits while a thread of a program that asked runs and clears them for any other and for idle, as Intel asks of STIBP and SSBD before a sleep state; it writes a register only when the ask changes and the CPU names a bit. - An IBPB goes on a switch into a program's space where the space last run is another and either asked (LastAsked). A pid names one space: the process table issues none twice, and a process keeps its space. - AMD-SB-1040: an IBPB on an AMD CPU without IBPB_RET leaves the return address predictor, and AMD asks 70586's V2-3 after it. The decision names "return address predictor filled after IBPB" there, enumerated with the IBPB it follows, and the switch follows each IBPB with 32 calls. Intel's IBPB covers the RSB, so no other fill on a switch is a vendor's. - The lines say SSBD, STIBP, IBPB and the fill mitigated where the CPU enumerates them; no register shows them before a program asks. - SYS_DEBUG, on the test kernel alone, reads this CPU's IA32_SPEC_CTRL, the bits it sets on request and the IBPBs its switches issued. speculation_on_request holds them on the shared-debug boot against speculationprobe, a row that asks, and the child it starts without asking; the spawn abuse test refuses an ask of 2. The manual's Trust page says how a program asks. AArch64 applies nothing on request and is recorded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r1 of #1279 (B2): the on-request controls are in force wherever the decision names them and the CPU enumerates them, which no register shows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d nothing asked costs one branch - The Trust page names SSBD among what a program that asks gets, and says any program may ask for a child it starts (B2). - in_force's doc says what it holds in force by construction (B3, in the commit before this one, rebased). - The per-CPU flag whether IA32_SPEC_CTRL exists is the test kernel's alone, for its debug read (B4). - A CPU whose decision names nothing on request returns from switch_to after one load (S1). install(), called beside report(), gives each CPU its switch state, and the base it installs is the IA32_SPEC_CTRL its bring-up read back rather than a second decision (S2, S7). LastAsked names a pid (S3). - speculationprobe refuses an error answer (S4). speculation_on_request says it holds nothing where CPUID enumerates no IBPB, as TCG's qemu64 does not, and states its targets at its registration (S5); back on the shared CPU after the probe it reads the asked bits clear (S6). Rebased onto main 302fb36: #1252's spawn path takes the job and no labels, and the ask rides PendingHandles beside the pager as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r2 of #1278 at 1ab7a9bArchitecture. The architecture is unchanged since r1. The round-2 commit (+106/−46 over 7 files) splits Round 1
FindingsB1 This head does not merge onto main
B2 PR body (the orchestrator's to correct). "On a CPU that names something but where no program asks, it pays the lookup, two loads and about five predictable branches" should say three loads:
Evidence
SEND BACK |
Stacked on #1277: the diff is this PR's commit alone, and it lands after #1277.
Problem
kernel::mitigation::decidenames SSBD and STIBP for a program that asks, and an IBPB between two programs one of which asks. That is ToyOS's policy for protections a vendor prescribes for every program (#1243 and the manual's Trust page). Nothing applied them: no program could ask, and no switch read or wrote a speculation control (issues/no-program-runs-with-speculative-store-bypass-disabled.md,issues/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md).What changes
isolated-speculation = trueon asystem.tomlrow.CommandExt::isolated_speculation.SpawnArgs::isolated_speculationcarries it to the kernel: 1 asks, 0 asks nothing of its own, any other value isInvalidArgument.Speculation::of_child).Decision::on_requestnames SSBD and STIBP inIA32_SPEC_CTRL, AMD'sVIRT_SPEC_CTRLSSBD for a guest that enumerates only that, an IBPB, and the fill after it. Each comes only where the CPU enumerates it.install(), called besidereport(), gives each CPU its set and theIA32_SPEC_CTRLits bring-up read back, once SMT is known and before any program runs.arch::x86_64::mitigation::switch_toruns beside the port bitmap's.LastAsked).toyos_proclife::pids) issues no pid twice for the machine's life, and a process keeps one space; the IBPB site cites that.IBPB_RET(APM Vol. 3 Fn8000_0008_EBX[30]) can leave the return address predictor's entries, and AMD asks for 70586's V2-3 fill after it. The decision names "return address predictor filled after IBPB" there, enumerated together with the IBPB it follows, and the switch follows each IBPB with 32 calls. Intel's IBPB already covers the RSB, so for the CPUs the decision covers no other vendor prescribes a fill on a switch. The record's exit is restated to match, as approved by the orchestrator.issues/no-aarch64-program-runs-with-speculative-store-bypass-disabled.md.Tests
speculation_on_request, a member of theshared-debugboot (it needsSYS_DEBUG, so it runs on the test kernel only). It readsIA32_SPEC_CTRLthrough three new test-only debug actions:speculationprobe, a test row that asks, and for the child the probe starts without asking;qemu64, it says so and holds nothing; the registration states this.an_ibpb_goes_between_two_spaces_one_of_which_asked,a_cpu_applies_on_request_what_its_decision_namesanda_child_asks_as_its_spawner_or_its_start. The manifest round trip now carries the ask, and the SDK's shape tests refuse a launch that asks. The spawn abuse test now refuses an ask of 2.Checks
Head
1ab7a9b0b, on #1277's98c605c46, rebased onto main302fb3698. #1252 rewrote the spawn path:build_child_handlestakes the job and no labels, and the ask still ridesPendingHandlesbeside the pager. Round 2 answers review r1's B1 to B4 and suggestions S1 to S7.cargo run -- --ci hostran at the top of the stack, Every entry from Ring 3 clears branch history where the CPU's decision names it #1279'sc07ac2ef3, which carries this branch: exit 1, 122 of 123 steps green; the red isthe build system, the recorded macOSllvm::testsfailure (issues/the-llvm-environment-test-breaks-git-on-macos.md). Round 1's run at50c9da201exited 1 with 122 of 123 green; the red is the recorded macOSllvm::testsfailure.testcasesimage on the test kernel both build. Every guest binary whose spawn arguments changed, including the members A child's handles are a list its parent names: labels and namespaces leave the kernel #1252 adapted, builds forx86_64-unknown-toyos.an_ibpb_goes_between_two_spaces_one_of_which_askedwith 1 IBPB instead of 2.mitigate-ask-control-inheritat this head plusof_childignoring the spawner's ask, must redspeculation_on_request. It is queued.mitigations_in_a_guest,shared_debug_members_exit_0andtestcases_members_exit_0on x86-64, and on AArch64virt_user_mode,virt_first_entry,virt_jobs_at_el2andvirt_smp, since the loader and the switch are shared code. Runs at earlier heads (43156124553, 43156167715, 43165353231, 43165372000) were cancelled. The heads moved once more after the host round:mitigations_in_a_guestnow prints every line (masked as before), so a green run shows the guest's verdicts too; onlytests/toyos.rsdiffers from the heads the host checks ran at.Evidence: round 1 (host), https://github.com/ToyOSOrg/evidence/tree/4aefff57e0efe9d5cd99ff41c89859988d7673d0/r1. Round 2 (host), https://github.com/ToyOSOrg/evidence/tree/11840d907c119513a48c5971ad125936c8692bff/r2. The guest round follows.
Owed on metal (benches down)
Recorded in the two records above:
speculation_on_request, a member of main'sshared-debugboot, on the T14 and the AMD bench. Main must show it exit 0, naming0x4asked on the T14 and0x6(SSBD and STIBP) on the AMD bench, with at least 2 IBPBs beside the probe and none beside the child that did not ask;of_childignoring the spawner's ask, which must red it.🤖 Generated with Claude Code