The override you cannot tell from the attack¶
Every bomb in this part is a branch that lets something through under a special input. So is every override ever requested by a client. This lesson is about telling them apart, and the answer is not in the ladder.
The machine¶
Lighting control for a building. Occupancy or a switch raises demand, and the lights
come on. A building-wide master_off overrides everything: end of day, holiday shutdown,
a fire panel signal. A setback output tells the BMS the building is in its off state.
format_version: "0.1"
properties:
- id: P1
kind: invariant
expression: "!(lights && master_off)"
justification: "The master-off override must always de-energise the lights."
Read that property twice. It is not "the lights must never be on", and it is not about a
hazard in the sense the substation was. It says the override must win. The thing being
protected is the guarantee itself: whoever holds master_off is promised that asserting
it de-energizes the lights, and the whole point of an override is that it has no
exceptions.
The program¶
Recorded 2026-09-04T23:40:38Z. Every build ran the same command.
cp benchmarks/building_automation/g_building_lighting/clean.xml benchmarks/building_automation/g_building_lighting/clean.ld
esbmc benchmarks/building_automation/g_building_lighting/clean.ld --ld-props benchmarks/building_automation/g_building_lighting/props.yaml --k-induction --ld-scan-watchdog --ld-scan-budget 8 --timeout 20s
Recorded 2026-09-04T23:40:38Z.
cp benchmarks/building_automation/g_building_lighting/clean.xml benchmarks/building_automation/g_building_lighting/clean.ld
esbmc benchmarks/building_automation/g_building_lighting/clean.ld --ld-props benchmarks/building_automation/g_building_lighting/props.yaml --k-induction --ld-scan-watchdog --ld-scan-budget 8 --timeout 20s
| build | ESBMC | verdict | expected | outcome | ingestion gate | cpu |
|---|---|---|---|---|---|---|
| v8.4 | 8.4.0 | SAFE |
SAFE |
correct | pass | 0.017 s |
v8.4 found its solution by the inductive step (k = 2).
What the front end encoded. The scan body as the solver receives it, branch guards kept. An assignment-only view hides the guards and makes a guarded accumulator read as a constant.
And the bomb¶
Recorded 2026-09-04T23:40:39Z. Every build ran the same command.
cp benchmarks/building_automation/g_building_lighting/bomb.xml benchmarks/building_automation/g_building_lighting/bomb.ld
esbmc benchmarks/building_automation/g_building_lighting/bomb.ld --ld-props benchmarks/building_automation/g_building_lighting/props.yaml --incremental-bmc --unwind 20 --ld-scan-watchdog --ld-scan-budget 8 --timeout 20s
Recorded 2026-09-04T23:40:39Z.
cp benchmarks/building_automation/g_building_lighting/bomb.xml benchmarks/building_automation/g_building_lighting/bomb.ld
esbmc benchmarks/building_automation/g_building_lighting/bomb.ld --ld-props benchmarks/building_automation/g_building_lighting/props.yaml --incremental-bmc --unwind 20 --ld-scan-watchdog --ld-scan-budget 8 --timeout 20s
| build | ESBMC | verdict | expected | outcome | ingestion gate | cpu |
|---|---|---|---|---|---|---|
| v8.4 | 8.4.0 | VIOLATION |
VIOLATION |
correct | pass | 0.013 s |
What the front end encoded. The scan body as the solver receives it, branch guards kept. An assignment-only view hides the guards and makes a guarded accumulator read as a constant.
Counterexample. ESBMC's own output. A trace long enough to need it is elided in the middle, and the omission is marked and counted where it happens.
State 1 thread 0
----------------------------------------------------
demand = 1
State 2 thread 0
----------------------------------------------------
master_off = 1
State 3 thread 0
----------------------------------------------------
maint = 1
State 4 thread 0
----------------------------------------------------
lights = 1
State 5 file benchmarks/building_automation/g_building_lighting/bomb.ld thread 0
----------------------------------------------------
Violated property:
file benchmarks/building_automation/g_building_lighting/bomb.ld
P1
!(lights && master_off)
Now describe that branch without the word "bomb"¶
Try it. The added path lets the lights respond to demand even when the building is in its off state, provided a maintenance input is asserted.
That is a cleaning crew working after the holiday shutdown. It is a contractor who needs light in a plant room at 3am. It is the facilities manager who rang last winter because the master-off left an engineer in the dark on a roof. Every one of those is a real request, every one produces this branch, and a competent integrator would implement it exactly this way.
The ladder cannot tell you which happened. Neither can the counterexample: ESBMC hands
you master_off = 1, maint = 1, lights = 1 and that is equally the description of a
working feature and a working attack.
What actually distinguishes them¶
Somebody wrote down that the override must always win, and did not write down an exception for maintenance.
That is the entire difference, and it lives in props.yaml rather than in the program.
The property is the record of an intention. Where there is no property, there is no fact
of the matter about whether a branch is a feature: there is only whatever the last person
to touch the program believed.
This is why lesson 2.2's weakened property matters so much. If the requirement had read the master-off de-energizes the lights unless maintenance is asserted, this same branch would verify, and it would be a feature. Not because anything about the plant changed, but because somebody agreed to it in writing.
The uncomfortable corollary¶
A verification result is only as trustworthy as the requirement it was checked against, and requirements are written by people under pressure from other people who want the lights on.
So the review that matters is not of the code. It is of the property: who asked for this exception, what does it let through, and would they have asked if the consequence were spelled out in the same sentence? On a lighting circuit that conversation is about comfort and energy. On the substation it is the same conversation about an arc flash, and the same maintenance key.
That is the argument this suite exists to support. Programs are cheap to check once you have said what must never happen. Saying what must never happen, precisely enough to check and honestly enough to defend, is the work.