checker

Program Verification continued:
Proof-Carrying Code
(6EC version only)
Erik Poll
Digital Security
Radboud University Nijmegen
Security from point of view of code consumer
Please install and
execute this.
The problem
Is it ok to run this untrusted, mobile code on my phone?
3
The problem
The original scenario that motivated Proof Carrying Code:
kernel
extension
operating
system
Is it ok to into install this kernel extension?
Or, more specifically:
Is this kernel extension (or device driver) memory safe?
4
Potential solutions
1. Simply trusting the code producer
– in combination with digital signatures to check the origin of
code
2. Baby-sitting/runtime monitoring the application
– aka dynamic analyis
– eg. by OS or Java sandbox
3. Program verification
– compile-time (or load time)
For 2 and 3 we need security requirements or security policy
For 1 we don't
– coming up with requirements/policy is hard!
5
Program verification: pros & cons
Pros
+ no runtime overhead
+ catches problems early (at compile/load time)
+ very expressive
Cons
- complicated formal infrastructure needed as foundation
- huge TCB (Trusted Computing Base),
including a theorem prover + logical theories for it
- lots and lots of work
to come up with all annotations, incl. loop invariant, and then
verify all the resulting verification conditions
6
Proof-Carrying Code (PCC)
• Introduced by George Necula and Peter Lee
[Safe Kernel Extensions Without Runtime checking, OSDI'96]
• A way to make program verification workable in practice, by
– reducing the amount of work for the code consumer
– reducing the size of the TCB
• Original application: certifying that binaries are memory-safe
– no access out of array bounds,
no reading of uninitialised memory
7
The basic observation behind PCC
Finding proof is hard, but checking proof is a lot simpler
8
The basic observation behind PCC
If you give a program, together with
• specifications (incl. eg loop invariants)
• proofs of all the resulting verification conditions
then checking that the program meets the specification is not so
difficult
• although it may be a lot of work
9
Proof-Carrying Code (PCC)
Code
Proof
Proof aka Certificate
Like signature, but with
semantic information, ie
a meaning
Proof
Checker
CPU
10
PCC – pros & cons
Pros
+ very expressive
– though first examples look at relatively weak properties,
namely memory safety
+ no runtime overhead
+ catches problems early (at compile/load time)
+ smaller (but still large) TCB than program verification
– proof checker instead of theorem prover
Cons
- complicated formal infrastucture needed as foundation
- proof terms can be huge (100s times the code)
-/+ less work for code consumer, more for code producer
but we can mitigate this by certifying compiler
11
PCC using a certifying compiler
Object
Source
Code
Annotations
Certifying
Compiler
Code
Proof
Proof
Checker
Producing proofs by hand is too much work,
so should be automated
Annotations could be loop invariants
or method specifications
CPU
12
inside certifying compiler & checker
Code
Annotations
VC generator
VCs
φ
theorem
prover
VC generator
VCs
φ
Proof
Checker
proofs P of φ
CPU
13
Example:
program verification
to ensure memory safety
14
example verification: proving memory safety
int sum := 0, i := 1;
is this program memory safe?
int A [10];
A[0] :=0;
ie. does it (a) stay inside array bounds
and (b) not read uninitialised memory?
while (i < 10) {
A[i] := A[i-1] +i ;
sum := sum + A[i];
i := i + 1
}
printf(A[i]);
15
example verification: proving memory safety
Notions to ensure memory safety
(memory safety incl not accessing uninitialised memory)
• safe_wr(x) memory location x is safe to write to
• safe_rd(x) memory location x is safe to read
if we can verify that a program only reads and writes to safe
locations, we have verified it is memory safe
16
sum==0, i ==1
int sum := 0, i := 1;
safe_wr(A[k]), 0<=k<10
int A [10];
safe_rd(A[0])
to prove: loop-invariant
A[0] :=0;
i<10
while (i < 10) {
A[i] := A[i-1] +i ;
sum := sum + A[i];
i := i + 1;
(i) to prove: safe_wr(A[i]), safe_rd(A[i-1]
ensures safe_rd(A[i])
(ii) to prove: safe_rd(A[i]
}
printf(A[i]);
i>=10
to prove: loop-invariant
(iii) to prove: safe_rd(A[i])
17
PCC successes
• The Touchstone Java compiler produces machine code for Intel
x86 with certificates that these are memory safe.
[Colby, Lee, Necula, Blua, Plesko, Kline. A certifying compiler for Java. PLDI'00]
• Oracle's KVM (JVM for embedded devices) uses certificates for
lightweight bytecode verification
[Eva Rose, Lightweight Bytecode Verification, Journal of Automated Reasoning,
2003]
18
TCB (Trusted Computing Base)
We don't have to trust
• the compiler
• the annotations
• the prover
We do have to trust
• the VCGen
• the proof checker
• the CPU
For example, Touchstone's VCGen is 23,000 lines of C...
To reduce the TCB, one could try to formally verify the
VCGen or the proof checker
19
Please install and
execute this.
Code producer
OK, but let me quickly look
over the instructions first.
Host
Code producer
Host
This store
instruction is
dangerous!
Code producer
Host
Can you prove
that it is always
safe?
Code producer
Host
Yes! Here’s the proof I got
from my certifying Java
compiler!

Code producer
Can you prove
that it is always
safe?
Host

Code producer
Your proof checks out.
I believe you because I
believe in logic.
Host
For you to read
• George C. Necula and Peter Lee
Safe Kernel Extensions without Run-Time Checking
Operating Systems Design and Implementation (OSDI'96), pp
229 - 243, 1996
I don’t expect you to be able to reproduce the technical details at
the exam, eg of operational semantics (Fig 3) or the VCGen (Fig 4)