The specification is a promise, Part 2: what happens when they break
When a specification promise breaks, it sometimes matters and sometimes does not. The question is whether a security boundary was crossed. The unveil(2) man page had something to say about this.
Part 1 established what specifications are and how to read them as contracts. This part is about what happens when the contract is not kept — specifically, the difference between a divergence that matters and one that does not, and how to tell which you are looking at.
Not every specification violation is a security issue. Software deviates from specifications constantly, for reasons ranging from misunderstanding to deliberate compatibility choices. Most of these deviations are benign: they affect edge cases nobody exercises, or they implement functionality in a slightly different way that produces the same observable outcome. The question that makes a violation security-relevant is whether it crosses a security boundary — whether it changes what an attacker can do, or changes what a defender is relying on being true.
The test: does the deviation change who can do what?
A deviation from specification matters, in a security context, when it changes the access control model. An authentication protocol that skips a step in some circumstances might still authenticate correctly in those circumstances — in which case the deviation is observable but harmless. Or it might allow an unauthenticated user to complete an exchange that should require authentication — in which case the deviation is the vulnerability.
The question is not whether the code matches the specification. It is whether the mismatch changes the security properties that the specification's users are relying on. This requires understanding what those users are relying on — which requires reading the specification carefully enough to understand what it promises.
The unveil(2) case
The unveil(2) system call in OpenBSD is a pledge for the filesystem: a process can restrict its own view of the filesystem to a set of explicitly permitted paths. The man page describes the semantics as a contract between the process and the kernel. What the man page does not describe, because it was present in the source but not in execution, is an #if 0 block in kern_unveil.c that was intended to prevent privilege escalation through a specific class of path manipulation.
The #if 0 preprocessor directive disables code. Code inside an #if 0 block does not compile, does not execute, and provides no protection. The block was in the source. The block documented the intent to prevent a specific escalation path. The block did not run. For the period during which the block was disabled, the protection it was intended to provide did not exist — despite the fact that the source made it appear that the question had been considered and addressed.
This is a specific kind of specification break: not a deviation from a written specification, but a deviation between the code-as-written and the code-as-executed, where the code-as-written was the specification. The man page described the behaviour of the function. The #if 0 block described the intended protection. Neither accurately described what was actually happening.
BSD examples and the value of reading both documents
OpenBSD's source is public, carefully reviewed, and has decades of security-focused development behind it. Findings in that codebase are not indictments of the development process — they are examples of the kind of subtle divergence that good process can still produce, which makes them instructive without being unfair. The #if 0 pattern appears in other codebases. The condition under which a check is compiled in or out is sometimes configuration-dependent, sometimes platform-dependent, sometimes just wrong.
Reading both the specification (man page, comment, documented behaviour) and the implementation (source code, compiled output, observable behaviour) is the only way to find this class of issue. Neither document alone is sufficient. The finding is in the gap.
Every specification makes a promise about what will happen. Every implementation makes a claim about keeping that promise. When the claim and the reality diverge — when the #if 0 is present, when the SHOULD is ignored, when the boundary is crossed — the PING reveals the gap. Checking for that gap is most of what this kind of work is.