Skip to content

feat(v0.5.0): CI-gate the MPU enforcement oracle, and make its control mechanical - #349

Merged
avrabe merged 2 commits into
mainfrom
feat/ci-gate-mpu-fault-oracle
Sep 4, 2026
Merged

feat(v0.5.0): CI-gate the MPU enforcement oracle, and make its control mechanical#349
avrabe merged 2 commits into
mainfrom
feat/ci-gate-mpu-fault-oracle

Conversation

@avrabe

@avrabe avrabe commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

REQ-OS-MPU-001's kill-criterion — "a crafted tenant writes outside its region
without a fault"
— now executes on every PR.

What I found

VER-OS-ISO-001 is verified and cites a qemu fault-injection oracle: a cross-region
write takes a real MemManage fault, CFSR=0x82 DACCVIOL+MMARVALID,
"handler-flag-gated, non-vacuous (granting the hole flips it to FAIL)".

Two things were true at once.

The oracle is real and it works. I ran it before touching anything — about a
second:

gust-iso-fault-probe OK: inside-write ok, outside-write denied @0x20008000
(CFSR=0x00000082 DACCVIOL+MMARVALID; MPU programmed via verified switch_to_partition)

And no workflow ran it. The artifact says so honestly — "evidence is local qemu,
not yet CI-gated"
— which is the difference between this and #324. But it still meant
the only MPU enforcement evidence gale held ran on somebody's laptop.

The part that needed fixing first

"Granting the hole flips it to FAIL" was performed by a manual edit. A control
CI cannot run is not a control CI has. Wiring the probe up as-is would have installed
precisely the gate this sweep keeps removing: green, with nothing establishing it can
distinguish.

So the control is now a cargo feature. grant-hole adds region 3 over exactly the
denied range — region 3 is free, since the verified core emits 3–7 disabled — still
through switch_to_partition, never by hand:

output exit
control off OK … denied @0x20008000 (CFSR=0x00000082) 0
control on FAIL: write to denied 0x20008000 fell through — MPU not enforcing 1

The denial is now proven caused by the region table, rather than by a bad address, a
stray handler, or an MPU that was never enabled. The CI job runs the control first
and separately
, as the other five jobs in this workflow do.

A distinction worth having in the open

The neighbouring Renode gate (gust_iso.robot) executes the region programmer's
computation and the seam order — iso-region-ok, iso-mpu-seam-ok,
iso-nointerfere-ok — on cortex-m3 over plain MappedMemory. I checked it: it
contains no fault or exception assertion at all.

Computation and enforcement are different claims. Only one was gated. Now both are.

What this does and does not do

It does answer the venue question I raised on synth#1145: gale can execute this
kill-criterion in CI today, not only on a bench. That removes a dependency I had
flagged as "not mine to schedule".

It does not discharge REQ-OS-MPU-001. That needs synth RQ-62-MEMISOLATE for
real per-tenant regions, and silicon. The fault-containment vs security-containment
boundary in VER-OS-ISO-001 is unchanged — the demo tenant runs privileged and the
PPB is not MPU-checked.

rivet validate: PASS (333 warnings, unchanged baseline).

Kill-criterion for this gate: the probe passes with grant-hole enabled.

🤖 Generated with Claude Code

https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo

…l mechanical

VER-OS-ISO-001 is `verified` and cites a qemu fault-injection oracle as evidence:
a cross-region write takes a REAL MemManage fault, CFSR=0x82 DACCVIOL+MMARVALID,
"handler-flag-gated, non-vacuous (granting the hole flips it to FAIL)".

Two things were true about that at once. The oracle is real and it works -- it runs
in about a second and I confirmed it before touching anything:

  gust-iso-fault-probe OK: inside-write ok, outside-write denied @0x20008000
  (CFSR=0x00000082 DACCVIOL+MMARVALID; MPU programmed via verified switch_to_partition)

And no workflow ran it. The artifact says so honestly ("evidence is local qemu, not
yet CI-gated"), which is the difference between this and gale#324 -- but it still
meant the only MPU ENFORCEMENT evidence gale held ran on somebody's laptop.

The non-vacuity claim was worse: "granting the hole flips it to FAIL" was performed
by a MANUAL EDIT. A control CI cannot run is not a control CI has. Wiring the probe
up without fixing that would have installed exactly the gate this sweep keeps
removing -- green, with nothing establishing it can distinguish.

So the control is now a cargo feature. `grant-hole` adds region 3 over exactly the
denied range -- region 3 is free, the verified core emits 3-7 disabled -- still
through switch_to_partition, never by hand. Measured both directions:

  control OFF: OK ... denied @0x20008000 (CFSR=0x00000082)        exit 0
  control ON:  FAIL: write to denied 0x20008000 fell through
               -- MPU not enforcing                                exit 1

So the denial is PROVEN caused by the region table rather than by a bad address, a
stray handler, or an MPU that was never enabled.

The CI job runs the control FIRST and separately, as the other five jobs here do.

Worth separating while I am here: the neighbouring Renode gate (gust_iso.robot)
executes the region programmer's COMPUTATION and the seam order -- iso-region-ok,
iso-mpu-seam-ok, iso-nointerfere-ok -- on cortex-m3 over plain MappedMemory, and
asserts no fault anywhere. I checked: it contains no fault or exception assertion at
all. Computation and enforcement are different claims, and only one of them was
gated. Now both are.

This is REQ-OS-MPU-001's kill-criterion ("a crafted tenant writes outside its region
without a fault") executing on every PR. It does not discharge the requirement --
that needs synth RQ-62-MEMISOLATE for real per-tenant regions, and silicon -- but the
venue question I raised on synth#1145 is answered: gale can execute this criterion in
CI today.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

I wrote "See gale#348" guessing the PR number before opening it. The PR is #349;
#348 is an unrelated issue filed minutes later (jess's MPU-primitive packaging gap).
A code comment pointing at the wrong issue is a small defect that ages badly.

Replaced with the stable artifact IDs it actually concerns — REQ-OS-MPU-001 for the
kill-criterion and VER-OS-ISO-001 for the oracle this control makes non-vacuous.
Those do not move when a PR number does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo
@avrabe
avrabe merged commit 6664df9 into main Sep 4, 2026
75 checks passed
@avrabe
avrabe deleted the feat/ci-gate-mpu-fault-oracle branch September 4, 2026 16:24
avrabe added a commit that referenced this pull request Sep 4, 2026
Both new jobs in kill-criteria.yml — the composed-graph env sweep (#346) and the MPU
enforcement oracle (#349) — were running on every PR and gating nothing. Every other
job in that workflow is a required context; these two were not, because I added them to
the workflow and never to branch protection.

That is the gale#294 defect class, reintroduced by me, in the workflow built to hold
that line, on the day I closed #294 saying the invariant was now watched.

The check-required-contexts gate did not catch it, and correctly so: it asserts that
every REQUIRED context can report, not that every gate worth requiring IS required.
Those are different properties and I had only built the first. Worth stating plainly
because "we have a gate for that" was exactly the reasoning that let this through.

Added to protection only after confirming both complete `success` on main
(kill-criteria run, all six jobs green) — requiring a context not proven producible is
the deadlock #340 was about, and doing it twice would be careless.

Adding them to protection first made the committed list lag at 20 against 22, and the
gate's own --protection direction reported it:

  NOT_LISTED  a denied write really faults (REQ-OS-MPU-001 kill-criterion)
  NOT_LISTED  no raw env import survives in the composed graph
  FAIL: 2 required context(s) may not be produced on a PR    exit 1

Second time that direction has caught real drift rather than a planted one. This commit
closes it: 22 contexts, list and protection matching exactly.


Claude-Session: https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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