Skip to content

rustup names every file it installs, and the ladder still read the toolchain's cargo as a stranger - #67

Merged
opencdlee-dotcom merged 1 commit into
agent/fable-precision/assemblyfrom
agent/precision-p2b/rustup
Sep 24, 2026
Merged

opencdlee-dotcom merged 1 commit into
agent/fable-precision/assemblyfrom
agent/precision-p2b/rustup

Conversation

@opencdlee-dotcom

Copy link
Copy Markdown
Owner

Follow-up to P2b (#63). Base: agent/fable-precision/assembly.

Why

#539 and #540 are open HIGH "Suspicious running process" incidents on the rustup toolchain's own cargo and rustc. Both binaries are ad-hoc signed and got no custody rung. rustup records every file it installs, and the format below was read from the real install on this Mac before anything was written:

  • ~/.rustup/toolchains/<tc>/lib/rustlib/components lists the installed components, one per line (e.g. cargo-aarch64-apple-darwin).
  • lib/rustlib/manifest-<component> lists what each component wrote, as file:bin/cargo or dir:share/doc/rust/html, relative to the toolchain root.

What

  • _rustup_receipt: when the resolved path is inside <RUSTUP_HOME or ~/.rustup>/toolchains/<tc>/, it answers rustup:<tc>:<component>, but only if an installed component's manifest has a file: line for that path.
    • dir: lines vouch for nothing beneath them.
    • A manifest that components does not name is not read.
    • A component name that contains a separator is refused.
    • A listed file swapped for a link out of the toolchain answers nothing.
  • _cargo_install_receipt: <CARGO_HOME or ~/.cargo>/.crates2.json is cargo's own record of cargo install. A binary it lists in <CARGO_HOME>/bin answers cargo-install:<crate>@<version>. _listed_file_key does not follow a link at the listed path.
  • rustup proxies (~/.cargo/bin/cargo, rustc, ...): left uncovered. On this Mac they are symlinks to ~/.cargo/bin/rustup, and rustup-init leaves no receipt for rustup itself. settings.toml names the default toolchain and update-hashes/<tc> holds a 20-character channel-manifest hash. Neither records rustup's own bytes.
  • The _PACKAGE_RECEIPTS comment now carries the roster of installers on this Mac, each marked covered or not.
  • Both new parses are cached per scan and cleared by _reset_custody_probes.

Both receipts can be forged by anything running as the operator's user, like the Homebrew receipt, so both answer only package-managed, which is in the vouched tier: one step, never to LOW, a 0.25 risk weight, and never for attack-defined evidence. AnInstallerReceiptIsVouchedTierOnly pins this.

Live answers on the reference Mac

'rustup:stable-aarch64-apple-darwin:cargo-aarch64-apple-darwin'           ~/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo
'rustup:stable-aarch64-apple-darwin:rustc-aarch64-apple-darwin'           ~/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rustc
'rustup:stable-aarch64-apple-darwin:rustc-aarch64-apple-darwin'           .../bin/rustdoc
'rustup:stable-aarch64-apple-darwin:clippy-preview-aarch64-apple-darwin'  .../bin/cargo-clippy
None  ~/.cargo/bin/cargo   (proxy -> rustup; no receipt for rustup)
None  ~/.cargo/bin/rustc   (proxy -> rustup)
None  ~/.cargo/bin/rustup

.crates2.json exists here, but the two binaries it lists (gws, watchdog) are no longer in ~/.cargo/bin, so there is no live cargo-install answer. That live test skips.

Backtest replay (--days 30 --reobserve), assembly tip c6bda80 vs this branch

before after
process interrupt 6 4
total interrupt 58 56
open cases 62 (signal 57) 60 (signal 55)
new interrupts from corpus 12 10
noise re-opened 59/214 (re-derived 9, as recorded 50) 59/214 (re-derived 9, as recorded 50)
assay recall 9/21 9/21

To check that the two cases that closed are cargo and rustc, a wrapper recorded every answer _package_receipt gave during the replay. The rustup answers were only on ~/.rustup/.../bin/cargo (2 findings) and .../bin/rustc (6 findings), and open process cases went from 6 to 4. The noise list is unchanged because #539 and #540 have no noise label yet.

Tests

  • tests/test_installer_receipts.py: 48 passed, 1 skipped (the live cargo-install check; no listed binary is present on this Mac).
  • -k "receipt or package or custody": 203 passed, 1 skipped.
  • Full suite: 2436 passed, 8 skipped, 30 xfailed, 1 failed. The tree sha was identical before and after the run.
    • The failure is test_backtest_replay_persistence.py::AnAgentExecTargetIsRegradedAgainstItsRecordedBytes::test_a_target_now_proven_committed_is_demoted (custody_changed 1 != 0). It is pre-existing: it fails identically on a clean git archive of the assembly tip c6bda80.

Not covered

  • The rustup proxies, and rustup itself, are uncovered (see above).
  • CARGO_INSTALL_ROOT and cargo install --root are not read; only CARGO_HOME and ~/.cargo are.
  • Windows .crates2.json bin naming (with or without .exe) is unverified.

🤖 Generated with Claude Code

…olchain's cargo as a stranger

#539 and #540 are HIGH "Suspicious running process" on the toolchain's
own `cargo` and `rustc`. Both are ad-hoc signed and got no rung. rustup keeps
`lib/rustlib/components` in every toolchain, plus a `manifest-<component>` that
lists each file the component wrote (`file:bin/cargo`). The format was read
from the real install on this Mac.

- `_rustup_receipt`: when a path resolves inside
  `<RUSTUP_HOME or ~/.rustup>/toolchains/<tc>/`, it answers
  `rustup:<tc>:<component>` only if an installed component's manifest has a
  `file:` line for it. A `dir:` line vouches for nothing beneath it, a manifest
  that `components` does not name is not read, and a listed file swapped for a
  link out of the toolchain answers nothing.
- `_cargo_install_receipt`: `<CARGO_HOME>/.crates2.json` is cargo's own record
  of `cargo install`. A binary it lists in `<CARGO_HOME>/bin` answers
  `cargo-install:<crate>@<version>`. A link at the listed path is not followed
  (`_listed_file_key`).
- The rustup proxies in `~/.cargo/bin` stay uncovered. They are links to or
  copies of rustup, and rustup-init leaves no receipt for rustup itself.
  settings.toml and update-hashes record the toolchain, not rustup's bytes.
- `_PACKAGE_RECEIPTS` now carries a roster of the installers on the
  reference Mac, each marked covered or not.

Both new receipts are package-managed (vouched tier). They are
same-uid-forgeable like the Homebrew receipt: one step, never to LOW, risk
weight 0.25, and never consulted for attack-defined evidence.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@opencdlee-dotcom
opencdlee-dotcom merged commit 6549d91 into agent/fable-precision/assembly Sep 24, 2026
6 of 9 checks passed
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