PCC

SAFE KERNEL EXTENSIONS
WITHOUT RUN-TIME
CHECKING
George C. Necula
Peter Lee
Carnegie Mellon U
Overview
• Paper presents a technique allowing
kernels to check extension safety
– Code receiver defines a set of safety
rules that guarantee safe behavior of
programs,
– Code producer creates a formal
safety proof that its code adheres to
the safety rules
– Code receiver uses a simple and fast
proof validator to check that the
code is safe
Starting Idea
Code
Producer
Untrusted code
Code
Consumer
Verifies safety
of code
• Good idea but …
Starting Idea
Code
Producer
Untrusted code
Code
Consumer
Verifies safety
of code
• Formally proving the safety of untrusted
code requires a large amount of effort
Shift the burden to the
producer
Code
Producer
Untrusted code +
Safety Proof
Proves safety
of its code
• Works better
Code
Receiver
Validates
proof
Proof-carrying code
• Code producer must establish and
prove the safety of the code
– Attaches proof to code
• Code consumer only has to validate the
proof
– Much simpler task
Advantages
• Code producer does most of the
validation work
• Code consumer does not care how the
proofs are constructed
• PCC programs are tamperproof
– Changing the code voids the proof
• No cryptography
• No trusted third parties
• Errors are detected before code is run
Difficulties
• How to encode the formal proof?
• How to check the proof?
– Not an easy task
• How to relate the proof with the
program?
Implementation
• Basic elements:
– Formal specification language used to
express the safety policy
– Formal semantics of the language
used by the untrusted code
– Language used to express the proofs
– Algorithm for validating the proofs
– Method for generating the safety
proofs
Formal Specification
Language
• Expresses the safety policy of the
receiver
• Uses first-order predicate logic
extended with predicates for type safety
and memory safety
Formal semantics of
language
• Describes the language used by the
untrusted code
– A logic relating programs to
specifications
• Untrusted code is DEC Alpha machine
code
– Was at that time the fastest
microprocessor
Proof language
• Variant of Edinburgh Logical Framework
(LF)
– Essentially a typed lambda calculus
– Can easily encode a wide variety of
logics, including higher-order logics
Proof validation
• Simple LF type checker
• Basic tenet of LF is that proofs are
represented as expressions and
predicates as types
– In order to check the validity of a
proof we only need to typecheck its
representation
Generating safety proofs
• Uses a theorem prover
– First, the code is scanned by the
same verification generator that the
consumer uses
– Then the predicate is submitted to a
theorem prover that attempts to
prove that predicate
– In case of success, prover emits an
LF representation of the proof
Application
• Machine code implementation of
network packet filters
• Safety policy was focused on finegrained memory safety
• Safety proofs were smaller than 800
bytes
• Required no more than 3ms on a DEC
Alpha to be validated.
More details
Observe that all four filters are very small
Run time
• Average per packet runtime of the four
PCC packet filters
• Compared with
– BSD Packet Filter Interpreter (will
be slow!)
– Using software fault isolation
– Using a safe subset of Modula 3 plus
the VIEW extension for safe pointer
casting
BFI is worst!
Conclusion
• PCC allows server or kernel to interact
safely with untrusted code
• PCC has no runtime overhead for
receiver
• Safety policies are defined by receiver
– Much more flexible
Too bad that safety proofs
are so hard to construct!