Repository navigation
Conversation
Review r1 of #1279 at 5a1d7c8Read: both commits against #1278's ArchitectureOwnership and shape are right. Each CPU's choice is made where its decision is applied ( Correctness: verified
FindingsB1
B2
B3 The PR body's Left, and
B4 The PR body's Tests, and
S1
S2 S3 The test leaves two properties without a probe.
S4
S5 Readability.
Evidence
SEND BACK |
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 the record renamed to what is left - The decision names the short BHB-clearing sequence, Listing 1, only where Intel scopes it: hosts its table gives BHI's mitigation as "Software" alone, the processors before Alder Lake, and guests, whose VMM sets BHI_DIS_S under it. A later or unlisted host without BHI_CTRL, whose microcode predates BHI_DIS_S, says vulnerable and lacking BHI_DIS_S rather than mitigated; the record keeps the gap (B5). The T14 and the guest runner's guest decide as before. - in_force names one set, BY_CONSTRUCTION, for what the kernel applies wherever the decision names it and no register shows: the on-request controls and the entries' clear (B2). - clear_branch_history's returns each go back to a call it made, at most seven deep, so the RSB predicts them and Indirect Target Selection, which reaches a return only through an empty RSB's alternate predictors, does not; the site and the thunks record say so (B3). - The BHB/RSB/IBPB record is renamed to what remains, the gate, the metal runs and the VMM notice, with its three citations moved, and records the NMI/#MC window before a clear finishes (B1, S1). - The build's entry-window gate reads both SYSCALL entries (S2). - The member, now branch_history_cleared_on_each_entry, also holds a clear per page fault on a fresh page, through the IDT's gates (S3). - The table that enters each gate at its prefix is AT_PREFIX (S5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5a1d7c8 to
c07ac2e
Compare
…6b24f30a5152f: the short sequence scoped, the record renamed, both entries gated; masked
…n names it
The decision named the BHB cleared on entry for a CPU with enhanced IBRS
and no BHI_DIS_S, or a guest whose IBRS or returns could be undercut, and
no entry cleared it: user code's branch history reached the kernel's first
indirect branch.
- arch::mitigation::clear_branch_history is Intel's short sequence ("Branch
History Injection and Intra-mode Branch Target Injection", Listing 1),
between a save and a restore of the two registers it writes.
- SYSCALL has two entries, one calling it as soon as the kernel's stack is
under it. Each CPU's LSTAR names the one its decision selects, so a CPU
that does not clear runs no added instruction, not even a branch.
- Every gate the IDT names opens with a fixed 12-byte prefix: a test of the
frame's CS, a short jz over the call, the call. idt::init builds the table
that enters each gate there and a second that enters past it, refusing a
gate that does not open with the prefix; each CPU loads the one its
decision selects (the boot CPU in init, an AP after its own decision, over
the boot CPU's table the trampoline loaded). A jz mispredicted past the
call meets no load through GS and no indirect branch before the gate's
own lfence or serializing wrmsr.
- The #DB that a MOV SS holds over an entry's first instruction is resumed
at either entry of a gate or of SYSCALL.
- The line says the clear in force where the CPU enumerates it, as each
CPU's entries are the ones its decision selects. On the test kernel the
routine counts its runs, and SYS_DEBUG's BRANCH_HISTORY_CLEARS reads them
where this CPU clears; branch_history_cleared_per_syscall holds at least
one per syscall.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d the record renamed to what is left - The decision names the short BHB-clearing sequence, Listing 1, only where Intel scopes it: hosts its table gives BHI's mitigation as "Software" alone, the processors before Alder Lake, and guests, whose VMM sets BHI_DIS_S under it. A later or unlisted host without BHI_CTRL, whose microcode predates BHI_DIS_S, says vulnerable and lacking BHI_DIS_S rather than mitigated; the record keeps the gap (B5). The T14 and the guest runner's guest decide as before. - in_force names one set, BY_CONSTRUCTION, for what the kernel applies wherever the decision names it and no register shows: the on-request controls and the entries' clear (B2). - clear_branch_history's returns each go back to a call it made, at most seven deep, so the RSB predicts them and Indirect Target Selection, which reaches a return only through an empty RSB's alternate predictors, does not; the site and the thunks record say so (B3). - The BHB/RSB/IBPB record is renamed to what remains, the gate, the metal runs and the VMM notice, with its three citations moved, and records the NMI/#MC window before a clear finishes (B1, S1). - The build's entry-window gate reads both SYSCALL entries (S2). - The member, now branch_history_cleared_on_each_entry, also holds a clear per page fault on a fresh page, through the IDT's gates (S3). - The table that enters each gate at its prefix is AT_PREFIX (S5). 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>
c07ac2e to
a9892c2
Compare
Review r2 of #1279 at a9892c2Architecture. The architecture is unchanged since r1. The round-2 commit (+232/−128 over 13 files) does five things:
Round 1
FindingsB1 Rebasing onto main
B2 The guest runner's guest names no clear, so the statements that it does are false.
B3 The decision trusts a guest's signature to say "not affected", and distrusts it when choosing the sequence.
S1 S2
Notes for the orchestrator
Evidence
SEND BACK |
Stacked on #1278: the diff is this PR's commits alone, and it lands after #1278.
Problem
The decision names "BHB cleared on entry" for an Intel CPU with enhanced IBRS and no
BHI_DIS_S(the T14), and for a guest whose IBRS or returns its hypervisor's hardware could undercut. No entry cleared it, so user code's branch history reached the kernel's first indirect branch. The record,issues/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md, is renamed here to what remains:issues/no-gate-holds-the-bhb-clear-and-the-return-fill-to-their-vendors-sequences.md.What changes
arch::x86_64::mitigation::clear_branch_historyis Intel's short sequence ("Branch History Injection and Intra-mode Branch Target Injection", Listing 1: "sufficient to clear the BHB on all processors prior to Alder Lake"). It sits between a save and a restore of the two registers it writes, and the site cites the listing. Intel's guidance puts it after every transition into CPL0, so it runs on every entry from Ring 3, not onlySYSCALL.BHI_DIS_Sunder the short sequence ("Software Mitigations in Migration Pools").BHI_CTRL(microcode older than its BHI update) reportsvulnerable: needs BHI_DIS_S; this CPU enumerates no BHI_DIS_S, never "mitigated".LSTARnames the entry its decision selects. A CPU that does not clear runs no added instruction, not even a branch. The build's entry-window gate now reads both entries.testof the frame'sCS, a shortjzover the call, and the call.idt::initbuildsAT_PREFIX, which enters each gate at the prefix, andPAST_PREFIX, which enters past it. It refuses any gate that does not open with the prefix's bytes.init. An AP does so after its own decision, replacing the boot CPU's table that the trampoline loaded.jzmispredicted past the call reaches no load through GS and no indirect branch before the gate's ownlfenceor serializingwrmsr.#DBthat aMOV SSholds over an entry's first instruction is resumed at either entry of a gate or ofSYSCALL.in_forcenames this, with the on-request controls, as one by-construction set.BRANCH_HISTORY_CLEARSreads the count on a CPU whose decision names the clear.Tests
branch_history_cleared_on_each_entry, ashared-debugmember, holds the count of clears to at least 1000 over 1000 syscalls (throughLSTAR's entry) and at least 256 over 256 page faults on fresh pages (through the IDT's).IBRS_ALL, RSBA by its signature in Intel's Table 5). It stays an inference until this round's run shows the member's "N clears" line and the guest'sbranch_history_injection: mitigated: BHB cleared on entry. If the guest names no clear, both runs prove nothing and the clear is owed on metal alone.the_short_sequence_is_named_only_where_intel_scopes_it. A patch that names the short sequence on every part reds it (patch and log in the evidence). The build gate'sa_hold_in_the_clearing_entry_alone_is_refused.f6 44 24 xx 03 74 05 e8, the sequence as Intel's listing has it, and the clearingSYSCALLentry calling it right after the stack switch (round 1's evidence).Checks
Head
a9892c2a8, on #1278's1ab7a9b0b. Round 2 answers review r1's B1 to B5 and suggestions S1, S2, S3 (the gate half) and S5 (the table's name, and the macro's doc; the macro's shape stays, since an optional operand cannot be left unnamed innaked_asm!).cargo run -- --ci host: 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). The kernel's mitigation tests, the harness's checks, the build gate's tests and clippy (26 invocations) are clean.testcasesimage on the test kernel both build.idt::init's prefix check runs at every boot.mitigate-entry-control-invertedat this head plus an inverted selection (LSTARand the IDT name the entries the decision does not select), must redbranch_history_cleared_on_each_entry. It is queued.mitigations_in_a_guest,shared_debug_members_exit_0,testcases_members_exit_0,ring3_debug_traps_end_their_process,nmi_under_a_user_gs_base,nested_nmi_is_loudanda_user_copy_faults_in_mid_copy_or_ends_as_bad_address. Runs at earlier heads (43158101891, 43158150391, 43165362239, 43165381286) 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. This PR is x86-64 only: AArch64 gains only a test-only stub, which clippy checks.Evidence: round 1 (host), https://github.com/ToyOSOrg/evidence/tree/04f5890cbafd0189b8fe8a4f883cd89a4ce27598/r1. Round 2 (host), https://github.com/ToyOSOrg/evidence/tree/924ae7ba024f24e6a8ec26667ba57941020b391b/r2. The guest round follows.
Left (recorded)
#MCthat lands on an entry from Ring 3 before its clear finishes runs its handler on the user's branch history.MSR_VIRTUAL_MITIGATION_CTRL, that it relies on it.kernel.elfbelongs toissues/no-gate-decodes-kernel-elfs-instructions.md.Owed on metal (benches down)
Recorded in
issues/no-gate-holds-the-bhb-clear-and-the-return-fill-to-their-vendors-sequences.md:branch_history_cleared_on_each_entryandspeculation_on_request, members of main'sshared-debugboot, on the T14 and the AMD bench;mitigationsrow,metalcaseboot of main, withbranch_history_injection: mitigated: BHB cleared on entryon every CPU.The clear's cost on the T14's syscall path is not measured on metal.
🤖 Generated with Claude Code