ppt

Extensible Verification of Untrusted
Code
Bor-Yuh Evan Chang, Adam Chlipala, Kun Gao,
George Necula, and Robert Schneck
May 14, 2004
OSQ Retreat
Santa Cruz, California
Type Safety as an Assurance Mechanism
type
checker
code
OR
untrusted
trusted
• Type safety is an accepted assurance mechanism
• Today
– Good: Type check source code in a strongly-typed
high-level language (e.g. ML, C#, Java)
– Better: Type check intermediate code (e.g., MS-CLI,
JVML)
5/14/2004
2
Type Systems Today (JVML,MS-CLI,TAL)
• Hard-wired in the verifier
• High-level and tailored to particular source
languages
– E.g, built-in object-oriented features
• Hard to compile other source languages
– Unnatural, loss of performance or expressiveness
– E.g, ML ! JVML or Java ! TAL
• Under constant pressure to become more
complex
– To handle more source languages
– To be able to check more complex code (e.g.
optimizations)
5/14/2004
3
Generality by Customization
• MS-CLI is designed for a multiple languages, but
– quite complex (e.g. 6-9 versions of function call)
– not complex enough (the ILX project adds more calls)
• Still not general enough!
– JVML: native code interface
– MS-CLI: unverifiable subset of the language
• Proposal: Allow multiple type systems and other
verification methods (e.g. PCC) to co-exist
– Fix only the safety policy (e.g. memory safety)
– Not the enforcement mechanism (e.g. a type system)
5/14/2004
4
Design Goals of the Open Verifier
• Should be easy to develop “verifier
extensions”
– Only incrementally more complicated than a
conventional verifier for the same language
– Be able to retrofit existing compilers or
conventional verifiers
• Client should have complete control over
the type system or other conventions
– Calling conventions, exceptions, stack usage,
data layout
5/14/2004
5
Bytecode Verification Example
1 rrv à 0
len : list ! int
0
T
2 rarg = 0
 ::= int | list | nelist
F
3 rrv à rrv + 1
4 rarg à m[rarg]
5 jump [rra]
5/14/2004
6
Bytecode Verification Example
arg : list
Why?
1 rrv à 0
arg : list Æ rv : int
T
2 rarg = 0
F
arg : list Æ
rv : int
arg : nelist Æ rv : int
3 rrv à rrv + 1
4 rarg à m[rarg]
arg : nelist Æ rv : int
5 jump [rra]
5/14/2004
7
Bytecode Verifier Correctness
• How do we know the verifier didn’t forget
any checks?
– Should not need to provide proofs involving
the model of the machine semantics
• Use strongest post-condition generation to
eliminate proof obligations about machine
transitions
– Show at each program point i with next states
N,
post(Ii) ) Çj2N Ij
5/14/2004
8
Verified Bytecode Verification
I1 = arg : list
Why?
1 rrv à 0
I2 = arg : list Æ rv : int
T
2 rarg = 0
post(I1)
F
pc = 2 Æ arg : list Æ rv = 0
3 rrv à rrv + 1
post(I1) ) I2
4 rarg à m[rarg]
new I2 = post(I1) with
add (rv : int) by imm_int
with
drop (rv = 0)
5 jump [rra]
5/14/2004
9
Branch
arg : list
Why?
1 rrv à 0
I2 = arg : list Æ rv : int
T
2 rarg = 0
F
I3 = arg : nelist Æ rv : int
I5 =
arg : list Æ
rv : int
5 jump [rra]
5/14/2004
post(I2)
pc = 3 Æ arg : list Æ rv : int Æ arg  0
Ç
pc = 5 Æ arg : list Æ rv : int Æ arg = 0
3 rrv à rrv + 1
4
post(I2) ) I3 Ç I5
case post(I2) of
where ](pc = 3) ) new I3 = Ifalse with
false m[r
rarg IÃ
arg
let h,h’ = find (arg : list), find (arg  0) in
add (arg : nelist) by (cons h h’)
with drop (arg : list)
with drop (arg  0)
| Itrue where (pc = 5) ) new I5 = Itrue with drop (arg = 0)
10
Arithmetic
arg : list
Why?
1 rrv à 0
arg : list Æ rv : int
T
2 rarg = 0
F
I3 = arg : nelist Æ rv : int
arg : list Æ
rv : int
5 jump [rra]
5/14/2004
3 rrv à rrv + 1
post(I3)
9rv3. pc = 4 Æ arg : nelist
Æ rv3 : int Æ rv = rv3 + 1
I4 = arg : nelist Æ rv : int
4 rarg à m[rarg]
post(I3) ) I4
new I4 = post(I3) with
let h = find (rv3 : int) in
add (rv : int)
by (plus h (imm_int))
with drop (rv3 : int)
with drop (rv = rv3 + 1)
11
Memory Read
arg : list
F = pc = err Æ ?
Why?
lem1:
If (arg : nelist) then (addr arg)
lem2:
If (arg : nelist) then (m[arg] : list)
1 rrv à 0
I2 = arg : list Æ rv : int
T
2 rarg = 0
F
arg : list Æ
rv : int
5 jump [rra]
5/14/2004
post(I4)
9 arg4. pc = 2 Æ arg4 : nelist Æ rv : int
Æ addr arg4 Æ arg = m[arg4]
Ç
arg : nelistpcÆ=rverr: int
Æ arg : nelist Æ rv : int Æ : (addr arg)
3 rrv à rrv + 1
post(I4) ) I2 Ç F
I4 = arg case
: nelist
Æ rv) :of
int
post(I
4 rarg à m[rarg]
4
Iok where _ )
Iok with let h = find (arg4 : nelist) in
add (arg : list) by (lem2 h) with …
| Ierr where : (addr arg) by bad )
Ierr with let h = … in
add ? by (bad (lem1 h)) with …
12
Customizability Yields Controlled Trust
Trust Any Binary (*.exe)
Trust Compilers (javac)
Trust Specialized Verifiers (JVM)
Trust Typing Rules
Trust Model of Machine Semantics
Trust Meter
5/14/2004
13
Summary
• Provide a “natural” language for the verifier to
describe in a checkable form the reasoning it
makes
– Close to conventional type-based verifiers
– Amenable to other safety enforcement mechanisms,
such as PCC
• PCC
– Most of the time, just goes along with post(¢)
– When proof is required, give the proof attached with
the code
– Proof representation can be chosen by the client
5/14/2004
14
Summary
post(¢)
type
checker
code
OR
“preservation
and progress”
untrusted
trusted
• Towards practical extensible verification of
untrusted code
– Ask only for reasoning already done by conventional
verifiers
5/14/2004
15
Conclusion
• We have verifier extensions for
– Cool (“mini-Java”) [Aiken et al.]
• can verify output of existing Cool compilers
– TAL (functional typed assembly language)
• retrofitted TALx86 [Morrisett et al.]
– PCC
• Philosophy:
– To verify complete software systems,
• not a general, super-expressive type system
• rather a framework to allow existing ones to work
together
5/14/2004
16
Return
R = pc = ra0 Æ rv : int
arg : list
Why?
1 rrv à 0
arg : list Æ rv : int
T
2 rarg = 0
F
I5 =
arg : list Æ
rv : int
post(I5)
arg : nelist Æ rv : int
3 rrv à rrv + 1
4 rarg à m[rarg]
pc = ra0 Æ arg : list
Æ rv : int
arg : nelist Æ rv : int
post(I5) ) R
post(I5) with
drop (arg : list)
5 jump [rra]
5/14/2004
18