Static EXtended Checking for Cyclone - PowerPoint PPT Presentation

1 / 48
About This Presentation
Title:

Static EXtended Checking for Cyclone

Description:

1988: Buffer overrun exploited by Morris Worm. 1999: Buffer overruns in Active-X. ... Nintendo DS! Cyclone compiler, tools, & libraries. Over 100 KLOC ... – PowerPoint PPT presentation

Number of Views:80
Avg rating:3.0/5.0
Slides: 49
Provided by: gregm161
Category:

less

Transcript and Presenter's Notes

Title: Static EXtended Checking for Cyclone


1
Static EXtended CheckingforCyclone
  • Greg Morrisett

2
The Legacy of C
  • 1988 Buffer overrun exploited by Morris Worm.
  • . . .
  • 1999 Buffer overruns in Active-X.
  • 2001 Buffer overruns in WU-FTP.
  • 2002 Buffer overruns in Windows RPC.
  • 2003 Buffer overruns in MS SQL server.
  • 2004 Buffer overruns in RealPlayer.
  • 2005 Buffer overrun in LSASS.
  • 2006 Buffer overruns in ATI Nvidia drivers.
  • 2007 Buffer overrun in Vista ANI code.

3
Not the Only Problem...
  • C suffers from many problems...
  • Must bypass the type system to do simple things
    (e.g., allocate and initialize an object).
  • Libraries put the onus on the users (e.g., check
    return codes).
  • Not enough info at runtime for needed
    checks.(e.g., printf is passed arguments of the
    right type).
  • Programmer controlled memory management (leads
    to data corruption, leaks).
  • ifdef-testing-hell

4
Why not throw out the C code?
  • Alas, theres a lot of it.
  • Vista gt 50 million lines of code
  • Suns Java runtime gt 700 thousand lines
  • Java is only portable thanks to ifdef
  • Besides, C occupies a useful space
  • Its ported to every architecture in the world.
  • It gives programmers control over data structure
    layout, memory management, instructions, etc.
  • Useful for devices, kernels, runtimes, etc.
  • It makes costs manifest.
  • Crucial for embedded or real-time systems.

5
Cyclone
  • A type-safe dialect of C.
  • Goals
  • well-typed program won't crash
  • in particular, rule out buffer overruns the
    like
  • looks behaves like C
  • familiar syntax and semantics
  • retain control over boxing, allocation,
    bit-twiddling, and to some degree, memory
    management.
  • some useful additions polymorphism, subtyping,
    tagged unions, pattern matching, exceptions, etc.
  • plays nicely with C

6
Cyclone Users
  • In-kernel Network Monitoring Penn
  • MediaNet Maryland Cornell
  • Open Kernel Environment Leiden
  • RBClick Router Utah
  • xTCP Utah Washington
  • GeekOS Maryland
  • Protocol Parsing ATT
  • Minix modules Netherlands
  • Ported to a variety of platforms
  • Nintendo DS!
  • Cyclone compiler, tools, libraries
  • Over 100 KLOC
  • Plus many sample apps, benchmarks, etc.
  • Good to eat your own dog food

7
Lots of other tools for C
  • e.g., SPLint, Jeckyll, Metal, Deputy, Prefast,
    ...
  • But Ccured Cyclone focus on soundness.
  • Ccured Scheme
  • no annotation by programmer
  • insert meta-data tests
  • use global optimizer to eliminate overheads
  • Cyclone Modula
  • programmer must annotate types
  • no run-time type tests
  • local analysis only

8
Cyclone/GCC vs. Java/GCC
9
  • Macro-benchmarks
  • Ported a variety of security-critical apps
  • little overhead (e.g., 2 for the Boa
    Webserver.)
  • lots of bugs found

10
AES C version
  • int cipherUpdateRounds(cipherInstance cipher,
    keyInstance key, BYTE input,
  • int inputLen, BYTE
    outBuffer, int rounds)
  • int j, t
  • word8 block4MAXBC
  • if (cipher NULL key NULL
    cipher-gtblockLen ! key-gtblockLen)
  • return BAD_CIPHER_STATE
  • for (j 0 j lt cipher-gtblockLen/32 j)
  • for(t 0 t lt 4 t) blocktj
    input4jt 0xFF
  • switch (key-gtdirection)
  • case DIR_ENCRYPT rijndaelEncryptRound(block,
    key-gtkeyLen, cipher-gtblockLen,
    key-gtkeySched, rounds)
  • break
  • case DIR_DECRYPT rijndaelDecryptRound(block,
    key-gtkeyLen, cipher-gtblockLen,
    key-gtkeySched, rounds)
  • break
  • default return BAD_KEY_DIR
  • for (j 0 j lt cipher-gtblockLen/32 j)
  • for(t 0 t lt 4 t) outBuffer4jt
    (BYTE) blocktj

11
AES Cyclone version
  • int cipherUpdateRounds(cipherInstance cipher,
    keyInstance key, BYTE ?input,
  • int inputLen, BYTE
    ?outBuffer, int rounds)
  • int j, t
  • word8 block4MAXBC
  • if (cipher NULL key NULL
    cipher-gtblockLen ! key-gtblockLen)
  • return BAD_CIPHER_STATE
  • for (j 0 j lt cipher-gtblockLen/32 j)
  • for(t 0 t lt 4 t) blocktj
    input4jt 0xFF
  • switch (key-gtdirection)
  • case DIR_ENCRYPT rijndaelEncryptRound(block,
    key-gtkeyLen, cipher-gtblockLen,
    key-gtkeySched, rounds)
  • break
  • case DIR_DECRYPT rijndaelDecryptRound(block,
    key-gtkeyLen, cipher-gtblockLen,
    key-gtkeySched, rounds)
  • break
  • default return BAD_KEY_DIR
  • for (j 0 j lt cipher-gtblockLen/32 j)
  • for(t 0 t lt 4 t) outBuffer4jt
    (BYTE) blocktj

12
Refined pointer qualifiers
  • Fat pointers arbitrary arithmetic but the
    representation is different (3 words)
  • char ? a "fat" pointer to a sequence of
    characters.
  • numelts(s) returns number of elements in
    sequence s (0 when s
    NULL)
  • Thin pointers same representation as C, but
    restrictions on pointer arithmetic.
  • char NULL or a pointer to at least one
    character.
  • char _at_ a pointer to at least one character.
  • char _at_numelts42 pointer to a sequence of 42
    characters.

13
Fat pointers
  • To support dynamic checks, we must insert extra
    information (e.g., bounds for an array)
  • Similar to Ccureds representation.

14
Can we eliminate fat pointers?
  • Fat pointers are convenient, but
  • expensive
  • break compatibility
  • give us failure points

15
Aha!
  • int f(int n, int A)_at_requires(n
    numelts(A))_at_ensures(0 lt result lt n)
  • Hoare-Style Specifications.
  • Say, like ESC/Java, Spec, or SPLint.

16
Static EXtended Checking
  • Add support for specifications to types
  • _at_requires, _at_ensures, _at_throws
  • quantifier-free 1st-order, multi-sorted logic
  • Calculate verification conditions (VCs)
  • For each possible failure point,
  • compute a predicate of the form A ? C
  • where A describes the state of the machine
  • and C is a condition ensuring the failure cannot
    occur (e.g., index in bounds)
  • Throw at VCs at a prover
  • if prover can show VC is true, can omit check

17
Example strcpy
  • strcpy(char ?d, char ?s)
  • while (s ! 0)
  • d s
  • s
  • d
  • d 0

Run-time checks are inserted to ensure that s
and d are not NULL and in bounds. 6 words
passed in instead of 2.
18
Better
  • strcpy(char ?d, char ?s)
  • unsigned i, n numelts(s)
  • assert(n lt numelts(d))
  • for (i0 i lt n si ! 0 i)
  • di si
  • di 0

This assert is dynamic. But its presenceis
enough to eliminate the checks.
19
Even Better
  • strncpy(char d, char s, uint n)
  • _at_assert(n lt numelts(d) n lt
    numelts(s))
  • unsigned i
  • for (i0 i lt n si ! 0 i)
  • di si
  • di 0

No fat pointers or dynamic checks. But caller
must check the pre-condition.
20
Ensures Throws Specs
  • val_t lookup(key_t x)
  • _at_ensures(result ! NULL x ! NULL)
  • _at_throws(x NULL exn NullExn
  • x ! NULL exn LookupFail)
  • void insert(key_t k, val_t v)
  • _at_requires(k!NULL v!NULL)
  • _at_throws(false)

21
How Effective?
  • For the 165 files (78 Kloc) that make up the
    standard libraries and compiler
  • CLibs stdio, string,
  • CycLib list, array, splay, dict, set, bignum,
  • Compiler lex, parse, typing, analyze, xlate to
    C,
  • with almost no specifications, eliminated 96 of
    the (static) checks
  • null 33,121 out of 34,437 (96)
  • bounds 13,402 out of 14,022 (95)
  • 225s for bootstrap compared to 221s with all
    checks turned off (2 slower) on this laptop.
  • Optimization standpoint seems pretty good.

22
Not all Rosy
  • Don't do as well at array-intensive code.
  • For instance, on the AES reference
  • 75 of the checks (377 out of 504)
  • 2 slower than all checks turned off.
  • 24 slower than original C code.(still passing
    around fat pointers)
  • The primary culprits
  • loop invariants are too weak.
  • lack of context (i.e., pre/post-conditions).
  • prover only understands limited constraints.

23
Challenges
  • Assumed I could use off-the-shelf technology.
  • But ran into a few problems
  • scalable VC generation
  • textbooks dont tell you this stuff!
  • usable theorem provers
  • (not the real focus.)
  • some foundational issues
  • semantic model, soundness
  • see ICFP06 and ESOP07 papers on Hoare
    Type-Theory.

24
Verification-Condition Generation
  • We started with textbook strongest
    post-conditions
  • SPx e A Aa/x ? xea /x (a fresh)
  • SPS1S2 A SPS2 (SPS1 A)
  • SPif (e) S1 else S2 A
  • SPS1(A ? e?0) ? SPS2(A ? e0)

25
1st Problem with Textbook SP
  • SPx e A Aa/x ? xea/x
  • What if e has effects?
  • In particular, what if e is itself an assignment?
  • Solution use a monadic interpretation
  • SP Exp ? Assn ? Term ? Assn
  • Terms are pure (i.e., logic).

26
For Example
  • SPx A (x, A)
  • SPe1 e2 A let (t1,A1) SPe1 A
  • (t2,A2) SPe2 A1
  • in (t1 t2, A2)
  • SPx e A let (t,A1) SPe A
  • in (ta/x, A1a/x ? x ta/x)

27
One Issue
  • Of course, this over sequentializes the code.
  • C has very liberal order of evaluation rules
    which are hopelessly unusable for any sound
    analysis.
  • So our back-end forces the evaluation to be
    left-to-right to match our analysis.

28
Next Problem Diamonds
  • SPif (e1) S11 else S12
  • if (e2) S21 else S22
  • ...
  • if (en) Sn1 else Sn2A
  • Textbook approach explodes paths into a tree.
  • SPif (e) S1 else S2 A
  • SPS1(A ? e?0) ? SPS2(A ? e0)
  • This simply doesn't scale.
  • e.g., one procedure had assn with 1.5B nodes.
  • WP has same problem. (see Flanagan Leino)

29
Solution
  • Factor out a local environment A xe1 ?
    ye2 ? ? Bwhere neither B nor ei contains
    program variables (i.e., x,y,)
  • Only the environment needs to change on update
    SPx 3 xe1 ? ye2 ? ? B
    x3 ? ye2 ? ? B
  • So most of the assertion (B) remains unchanged
    and can be shared.

30
Diamond Problem Revisited
  • SPif (e) S1 else S2 xe1 ? ye2 ? ? B
  • (SPS1 xe1 ? ye2 ? ?B?e?0) ?
  • (SPS2 xe1 ? ye2 ? ?B?e0)
  • (xt1 ?yt2? ? B1) ?
  • (xu1?yu2 ? ? B2)
  • xax ? yay ? ?
  • ((ax t1 ? ay t2 ? ? B1) ?
  • (ax u1 ? ay u2? ? B2))

31
How does the environment help?
SPif (a) x3 else x y if (b) x5 else
skip xe1 ? ye2 ? B
?
xv ? ye2
?
?
?
b0 ? vt
b?0 ? v5
?
?
?
a?0 ? t3
B
a0 ? te2
32
Tah-Dah!
  • I've rediscovered SSA.
  • monadic translation sequentializes and names
    intermediate results.
  • only need to add fresh variables when two paths
    compute different values for a variable.
  • so the added equations for conditionals
    correspond to ?-nodes.
  • Like SSA, worst-case O(n2) but in practice O(n).
  • Best part all of the VCs for a given procedure
    share the same assertion DAG.

33
Scaling
34
Space Scaling
35
So far so good
  • Of course, I've glossed over the hard bits
  • memory
  • loops
  • procedures
  • Let's talk about memory first

36
What about Memory?
  • As in ESC, use a functional array
  • t upd(tm,ta,tv) sel(tm,ta)
  • with McCarthy axioms
  • sel(upd(m,a,e),a) e
  • (a1 ltgt a2) ? sel(upd(m,a1,e),a2) sel(m,a2)
  • upd(upd(m,a,e1),a,e2) upd(m,a,e2)
  • Then reading writing treated as access to a
    distinguished mem variable
  • SPp e A Aa/mem ? memupd(a?p,e)

37
Widening
  • Given A?B, calculate some C such that A ? C and
    B ? C and C lt A, B.
  • Then we can compute a fixed-point for loop
    invariants iteratively
  • start with pre-condition P
  • process loop-test body to get P'
  • see if P' ? P. If so, we're done.
  • if not, widen P?P' and iterate.
  • (glossing over variable scope issues.)

38
Our Widening
  • Conceptually, to widen A?B
  • Calculate the DNF
  • really only traverse assertion DAG by memoizing
  • Factor out syntactically common primitive
    relations
  • In practice, we do a bit of closure first.
  • e.g., normalize terms relations.
  • e.g., xe expands to x ? e ? x ? e.
  • Captures any primitive relation that was found on
    every path.

39
Back to Loops
  • The invariants we generate aren't great.
  • worst case is that we get "true"
  • we do catch loop-invariant variables.
  • if x starts off at i, is incremented and is
    guarded by x lt e lt MAXINT then we can get x gt
    i.
  • But
  • covers simple for-loops well
  • it's fast only a couple of iterations
  • user can override with explicit invariant

40
Procedures
  • Originally, intra-procedural only
  • Programmers could specify pre/post-conditions.
  • Recently, extended to inter-procedural
  • Calculate SP's and propagate to callers.
  • If too large, we widen it.
  • Go back and strengthen pre-condition of
    (non-escaping) callee's by taking "disjunction"
    of all call sites' assertions.

41
Proving
  • Original plan was to use off-the-shelf
    technology.
  • eg., Simplify, SAT solvers, etc.
  • But ran into problems
  • Simplify unsound treatment of ints
  • SAT too slow (esp. with 64-bits)

42
Proving done in two stages
  • First stage
  • Given a VC A ? C
  • Widen A to a set of primitive relns.
  • Calculate DNF for C and check that each
    disjunct is a subset of A.
  • (C is quite small so no blowup here.)
  • This catches a lot
  • all but about 2 of the checks we eliminate!
  • void f(int _at_x) x
  • if (x ! NULL) x
  • for (i0 i lt numelts(A) i)Ai

43
2nd Stage
  • Given A ? C, try to show A ? ?C inconsistent.
  • Conceptually
  • explore DNF tree (i.e., program paths)
  • the real exponential blow up is here.
  • so we have a programmer-controlled throttle on
    the number of paths we'll explore (default 33).
  • accumulate a set of primitive facts.
  • at leaves, run difference constraint algorithm
  • Convert facts to constraints of form (x - y) lt
    c.
  • Calculate shortest paths, look for negative
    cycles.

44
Summary of SEXC-Cyclone
  • Simple assertions aimed at type errors.
  • Started with strongest post-conditions.
  • Effects Rewrote as monadic translation.
  • Diamond Factored variables into an environment
    to preserve sharing (SSA).
  • Memory use functional arrays
  • Loops Simple but effective widening for
    calculating invariants.
  • Extended to inter-procedural summaries.
  • Simple, but fast custom prover.
  • From 75-95 of checks eliminated.

45
Currently
  • Memory
  • The functional array encoding of memory doesn't
    work well -- should incorporate alias analysis.
  • e.g., cant accomodate malloc/free
  • doesnt yield modular specs (need modifies)
  • Can we adapt separation logic? Will it actually
    help?
  • Whats the full type theory look like?
  • Work with A. Nanevski L. Birkedal a start.

46
False Positives
  • We still have 2,000 checks left.
  • I suspect that most are not needed.
  • How to draw the eye to the ones that are?
  • strengthen pre-conditions artificially(e.g.,
    assume no aliasing, overflow, etc.)
  • if we still can't prove the check, then it should
    be moved up to a "higher-rank" warning.

47
Lots of Borrowed Ideas
  • ESC M3 Java
  • Touchstone, Special-J, Ccured
  • SPLint (LCLint)

48
More info...
  • http//cyclone.thelanguage.org
  • Acks
  • Yanling Wang (Cornell)
  • Aleks Nanevski (MSR)
  • Mike Hicks, Nikhil Swamy (Maryland)
  • Trevor Jim (ATT)
  • Dan Grossman (Washington)
Write a Comment
User Comments (0)
About PowerShow.com