360 likes | 528 Views
Secure Execution of Untrusted Code. Motivation. Mobile code scenarios Java applet / Javascript in web page Postscript / PDF file Email attachment BPF Active networks Agent technology. Untrusted Code. My Secure PC. Challenges. Untrusted code may
E N D
Motivation • Mobile code scenarios • Java applet / Javascript in web page • Postscript / PDF file • Email attachment • BPF • Active networks • Agent technology Untrusted Code My Secure PC
Challenges • Untrusted code may • Read sensitive memory regions(password, cryptographic keys, db records) • Write memory areas, violate integrity(overwrite public verification key) • Jump to arbitrary location (jump past password verification) • Perform arbitrary system calls (execute arbitrary local programs, access file system) • Waste resources, DoS (memory, computation, network bandwidth), thrash OS (while 1 do fork()) • Crash program, OS
Solution 1: Separate Process • Run untrusted code in separate process • Advantages • Memory separation through VM system • Disadvantages • Inter-Process Communication (IPC) is expensive • Context switch has high overhead (TLB, cache) • Untrusted code can do any system calls • To protect file system, use chroot
Solution 2: Signed Code • Only accept code digitally signed by trusted entity • Advantages • Simple security policy • Can be secure if trusted entity creates “secure code” • Disadvantages • Security relies on secrecy of private key • Security relies on authenticity of public key • Coarse-grained access control
Solution 3: Sandboxing • Run code in limited environment • Verify each system call • Verify each memoryreference • Advantage • Fine-grained control • Disadvantages • Efficiency • Expressing security policy • Sandbox may have security vulnerabilities Sandbox Untrusted Code Application
Solution 4: SFI • Provide memory safety efficiently • Can only r/w legitimate memory locations • Software fault isolation (SFI): transform untrusted code into safe code • Compiler: generates safe code • Ship source code, or • Generate code that verifier can easily check • Loader (binary patching): rewrite untrusted code
SFI • Load each module into its own fault domain • Code is in read-only part • Module can r/w anything within fault domain • Code can only jump within fault domain • Two parts • Efficient Software Encapsulation • Fast Communication Across Fault Domains Untrusted Code Untrusted Code Untrusted Code Application
Efficient Software Encapsulation • Goal • Only allow writes within data part of fault domain • Only allow jumps within code segment of fault domain • Mechanisms • Split memory space into segments, each segment has a segment identifier (high-order bits of address), and comprises all addresses for any low-order bits • Separate code and data segments • Dedicated registers are only used by inserted code, cannot be modified by untrusted code • Tame unsafe instructions by segment matching or address sandboxing • PC-relative jumps often safe, static stores are safe • Other stores and jumps are unsafe
RISC Instruction Set Simplifies SFI • Memory accessed with load / store instruction (no add to memory) • All instructions have fixed size, and are aligned • Simplifies instruction verification • Simplifies jump target verification • Usually large number of registers • Can tolerate giving up 5 dedicated registers
Segment Matching • Verifies correctness of memory accesses • Advantage • Can pinpoint address of offending instruction, useful in debugging • Disadvantage • Slow dedicated-reg target address scratch-reg (dedicated-reg >> shift reg) compare scratch-reg and segment-reg trap if not equal store instruction uses dedicated-reg
Address Sandboxing • Set segment identifier for each memory access / jump instruction • Overwrite segment identifier with fault domain’s segment identifier • Advantage: efficient • Disadvantage: cannot pinpoint flaw, only enforces that accesses are within domain dedicated-reg target-reg & and-mask-reg dedicated-reg dedicated-reg | segment-reg store instruction uses dedicated-reg
Puzzles • What about the following transformation, not using dedicated register? target-reg target-reg & and-mask-reg target-reg target-reg | segment-reg store instruction uses target-reg • What about jumps into SFI verification instructions? Could we jump outside of fault domain? Could we write to code segment? Could we jump to data segment? • What if we only used 4 dedicated registers (sandboxing case, i.e., 1 dedicated-reg for code/data)?
4-Register Attack jump target-reg dedicated-reg target-reg & and-mask-reg dedicated-reg dedicated-reg | segment-reg-c jump instruction uses dedicated-reg target-reg = r2 dedicated-reg target-reg & and-mask-reg dedicated-reg dedicated-reg | segment-reg-d store instruction uses dedicated-reg
Verification of Instrumented Code • Problem: given instrumented binary, how can we verify that all rules are met? • Verify that all unsafe stores and jumps use dedicated registers to form address • Verify that all inserted code has correct pattern (identify inserted code by use of dedicated registers)
Fast Communication Across Fault Domains • Use Jump Table with legal entry points outside fault domain • For each call between fault domains, a customized stub procedure is created • Stubs run unprotected outside fault domain • Trusted stub directly copies arguments to destination domain • Switch execution stack • Set up register context and validate dedicated registers
SFI Discussion • System calls from fault domain? • Issues and solutions • Allowing arbitrary memory reads? • Could we improve the granulartiy of memory protection? • Missing read protection a problem? • Is granularity of jump protection sufficient? • Flexibility for segment size? Internal fragmentation? • Can SFI prevent buffer overruns? • Is self-modifying code possible? • SFI on CISC processors? • Can we change compiler once verifier is deployed?
Solution 5: PCC • Proof-carrying code (PCC) developed @ CMU by George Necula and Peter Lee • Goal: safely run code in unsafe languages • Approach: create efficiently verifiable proof that untrusted code satisfies safety policy • May not need instrumentation code (no execution overhead!) if we can prove code safety • Slides based on George Necula’s OSDI96 talk
Legend: code proof oracle bits Proof-Carrying Code: An Analogy
untrusted application code certification native code safety proof proof validation formal safety policy CPU Proof-Carrying Code (PCC) code producer code consumer PCC binary
Benefits of PCC • Wide range of safety policies • memory safety • resource usage guarantees (CPU, locks, etc.) • concurrency properties • data abstraction boundaries • Wide range of languages • assembly languages • high-level languages • Simple, fast, easy-to-trust validation • Tamper-proof
Experimentation • Goal: • Test feasibility of PCC concept • Measure costs (proof size and validation time) • Choose simple but practical applications • Network Packet Filters • IP Checksum • Extensions to the TIL run-time system for Standard ML
Experimentation (2) • Use DEC Alpha assembly language (hand-optimized for speed) • Network Packet Filters • BPF safety policy: “The packet is read-only and the scratch memory is read-write. No backward branches. Only aligned memory accesses.”
PCC Implementation (1) • Formalize the safety policy: • Use first-order predicate logic extended with can_rd(addr) and can_wr(addr) • Kernel specifies safety preconditions • Calling convention • Guaranteed by the kernel to hold on entry • Use tagged memory to define access
PCC Implementation (2) • Compute a safety predicate for the code • Use Floyd-style verification conditions (VCgen) • One pass through the code, for example: • For each LD r,n[rb] add can_rd(rb+n) • For each ST r,n[rb] add can_wr(rb+n) • Prove the safety predicate • Use a general purpose theorem prover
PCC Implementation (3) • Formal proofs are trees: • the leaves are axiom instances • the internal nodes are inference rule instances • at the root is the proved predicate • Example:
PCC Implementation (4) • Proof Representation: Edinburgh Logical Framework (LF) • Proofs encoded as LF expressions • Proof Checking is LF type checking • simple, fast and easy-to-trust (14 rules) • 5 pages of C code • independent of the safety policy or application • based on well-established results from type-theory and logic • Large design space, not yet explored
Packet Filter Experiments • 4 assembly language packet filters (hand-optimized for speed): • Accepts IP packets (8 instr.) • Accepts IP packets for 128.2.206 (15 instr.) • IP or ARP between 128.2.206 and 128.2.209 • TCP/IP packets for FTP (28 instr.) • Compared with: • Run-Time Checking: Software Fault Isolation • Safe Language: Modula-3 • Interpretation: Berkeley Packet Filter
Performance Comparison • Off-line packet trace on a DEC Alpha 175MHz • PCC packet filters: fastest possible on the architecture • The point: Safety without sacrificing performance!
Cost of PCC for Packet Filters • Proofs are approx. 3 times larger than the code • Validation time: 0.3-1.8ms
Validation Cost (Filter 3) • Conclusion: One-time validation cost amortized quickly
SFI PCC for Memory Safety • Continuum of choices between static checking and run-time checking: • PCC can be also used where run-time checking cannot (e.g., concurrency) Performance Penalty Static Checking Run-Time Checking Proof Complexity
What Can We Check With PCC? • Any property with a sound formalization • if you can prove it, PCC can check it! • One proof-checker for many such policies! • Small commitment for open-ended extensibility • Example: policies defined by safe interpreters • E.g, security monitors, memory safety, resource usage limits, … • … can be enforced statically with PCC • Prove that all run-time checks would succeed • No run-time penalty
Safety policy: • host invokes the agent with: • security clearance level • item and price fields readable only if access £ level • parent • communication permitted only back to parent • must terminate within MAX instructions • wait BNDW * SIZE instructions before sending SIZE bytes agent • level • parent PCC Beyond Memory Safety Example: database with access control access item price pricing server PCC is not limited to memory safety!
Practical Difficulties • Proof generation • Similar to program verification • But: • done off-line • can use run-time checks to simplify the proofs • In restricted cases it is feasible (even automatable) • Proof-size explosion • It is exponential in the worst case • Not a problem in our experiments
PCC Discussion • A very promising framework for ensuring safety of untrusted code • Limitations? • What about generating proof on the fly? • Could verify safety property based on specific arguments • Related problem: how to secure mobile code from malicious host?