Presentation is loading. Please wait.

Presentation is loading. Please wait.

Software fault isolation with API integrity and multi-principal modules MIT CSAIL Yandong Mao, Haogang Chen (MIT CSAIL), Tsinghua University IIIS Dong.

Similar presentations


Presentation on theme: "Software fault isolation with API integrity and multi-principal modules MIT CSAIL Yandong Mao, Haogang Chen (MIT CSAIL), Tsinghua University IIIS Dong."— Presentation transcript:

1 Software fault isolation with API integrity and multi-principal modules MIT CSAIL Yandong Mao, Haogang Chen (MIT CSAIL), Tsinghua University IIIS Dong Zhou (Tsinghua University IIIS), MIT CSAIL Xi Wang, Nickolai Zeldovich, Frans Kaashoek (MIT CSAIL)

2 Kernel security is important Kernel is fully privileged Kernel compromises are devastating Remote attacker takes control over the whole machine Local user gains root privilege

3 Linux kernel is vulnerable Vulnerabilities in Linux are routinely discovered CVE 2010: 145 vulnerabilities in Linux kernel Many exploits attack kernel modules 67% of Linux kernel vulnerabilities (CVE 2010) This talk focuses on vulnerabilities in kernel modules

4 Threat Module Module programmer makes mistake Attacker exploits mistake to mount attacks Example: buffer overflow, set current UID to root Kernel memory Module memory UID Privilege escalation!

5 One approach: type safe languages Write kernel and modules in Java, C# No reference to UID object => cannot directly change UID Attacker cannot synthesize references Module UID Most kernels are not written in type safe language!

6 Software Fault Isolation (SFI[SOSP93]) char *p = 0xf7; sfi_check_memory(p); *p = 0; Module SFI Runtime Can not bypass SFI check Module memory UID void sfi_check_memory(p) { if p not in “Module memory” stop_module(); }

7 Memory safety is insufficient for stopping attacks! spinlock_t mylock; spin_lock_init(&mylock); Spin_module void spin_lock_init(spinlock_t *lock) { lock->v = 0; } Core Kernel Module memory UID Challenge: module needs to call kernel functions

8 Problem: API abuse Attacker tricks fully-privileged kernel code to overwrite UID spin_lock_init(&cur_proc->uid); Spin_module void spin_lock_init(spinlock_t *lock) { lock->v = 0; } Core Kernel Module memory UID Privilege escalation!

9 Challenge: lack of API integrity Kernel APIs are not written defensively Assume the calling module to obey implicit rules Do not check arguments, permissions, etc Problem: modules cannot be trusted to follow rules Module can trick kernel into performing unexpected actions Ideal system would enforce rules for kernel API Analogy: system call code assumes nothing about caller, checks every assumption

10 State of the art for protecting APIs SFI[SOSP93]: memory safety XFI[OSDI06]: no argument checks BGI[SOSP09]: manually wrap functions, make kernel defensive when kernel code invokes callbacks Error-prone and time-consuming Works if kernel code is well-structured (not Linux)

11 Our approach: annotation language Helps enforce two types of API integrity: Argument integrity: programmer controls what arguments a module can pass to functions Callback integrity: kernel invokes callback only if the module could have invoked callback directly Allows programmers to specify principals for privilege separation within a module Less error-prone than manual wrapping, applicable to complex APIs such as those in Linux

12 Contributions LXFI: software fault isolation system for Linux kernel modules Annotation language for Argument integrity Callback integrity Privilege separation within a module Evaluation Few annotations for 10 Linux kernel modules Stop three real exploits 2-4X CPU overhead for netperf

13 Goals for annotation language Enforce argument integrity, callback integrity and privilege separation within a module Minimize programmer effort, e.g.: Few annotations Avoid data structure and API changes Compatible with C

14 Preventing module exploits Programmer annotates core kernel LXFI translates annotations to runtime checks LXFI performs checks Using compiler plugins; Provide safe default: reject a module if it calls an unannotated API If annotations capture all implicit rules, compromised module cannot violate rules to gain additional privileges. Consulting a dynamic table of capabilities for each module Compile time Runtime

15 Design of annotation language Argument integrity annotations Using the spin_lock_init example Callback integrity annotations Not discussed; see paper Privilege separation annotations Using dm_crypt (real Linux kernel module)

16 Enforce argument integrity spin_lock_init: three annotations are required PartSyntaxDescription Capability write(ptr,size) Write [ ptr,ptr+size ] Capability Action check(cap) Checks cap Location pre(action) Perform action before function call

17 Example: enforce argument integrity for spin_lock_init Core Kernel Spin_module void spin_lock_init(spinlock_t *lock) pre(check(write(lock, sizeof(spinlock_t))) lxfi_check_write(&cur_proc->uid, 8); spin_lock_init(&cur_proc->uid) capability table write(mylock, 8) Module memory UID LXFI Runtime lxfi_check_write(mylock, 8); spin_lock_init(mylock) Privilege escalation prevented ……

18 Where does the capability come from? PartSyntaxDescription Capability write(ptr,size) Write [ ptr,ptr+size ] Capability Action check(cap) Check cap copy(cap) Grant a copy of cap Location pre(action) Perform action before function call post(action) Perform action after function return Granted on allocation Two more annotations are required

19 Core KernelSpin_module spinlock_t *mylock = kmalloc(8); lxfi_copy_write(mylock, 8); void *kmalloc(size) post(copy(write(return, size)) capability table write(mylock, 8) Example: grant spinlock LXFI Runtime ……

20 What happens when memory is freed? Need to revoke capability to safely reuse memory Strawman: revoke capability from caller Insufficient! Other modules may have copies of capability PartSyntaxDescription Capability write(ptr,size) Write [ ptr,ptr+size ] Capability Action copy(cap) Grant a copy of cap check(cap) Check cap transfer(cap) Revoke cap from all modules, and grant Location pre(action) Perform action before function call post(action) Perform action after function return No other copies of the capability remain

21 Core KernelSpin_module void kfree(void *p) pre(transfer(write(p, no_size))) capability table write(mylock, 8) Example: safely free a spinlock LXFI Runtime capability table write(mylock, 8) other_module lxfi_transfer_write(mylock, -1); kfree(mylock); ……

22 Why is spin_module able to call spin_lock_init, kmalloc, kfree? Call capability Granted initially according to the module’s symbol table Trust module author not to call unnecessary functions Dynamically granted when a callback function is passed PartSyntaxDescription Capability write(ptr,size) Write [ ptr,ptr+size ] call(a) Call a Capability Action copy(cap) Grant a copy of cap check(cap) Check cap transfer(cap) Revoke cap from all modules, and grant Location pre(action) Perform action before function call post(action) Perform action after function return

23 Core KernelSpin_module void *kmalloc(size) post(copy(write(return, size)) void spin_lock_init(spinlock_t *lock) pre(check(write(lock, sizeof(spinlock_t))) void kfree(void *p) pre(transfer(write(p, no_size)) capability table call(kmalloc) call(spin_lock_init) call(kfree) LXFI Runtime spinlock_t *mylock = kmalloc(8); lxfi_copy_write(mylock, 8); lxfi_check_write(mylock, 8); spin_lock_init(mylock)l lxfi_check_write(&cur_proc->uid, 8); spin_lock_init(&cur_proc->uid); lxfi_transfer_write(mylock, -1); kfree(mylock); ……

24 SFI ensures memory safety Call capabilities ensure only 3 functions are allowed None of the functions can modify UID because: kmalloc never modifies allocated memory spin_lock_init can only be called with writable memory (from kmalloc) kfree ensures no capabilities remain after free spin_module can not modify UID! No way for compromised spin_module to gain root privilege

25 PartSyntaxDescription Capability write(ptr,size) Write [ ptr,ptr+size ] call(a) Call a ref(a, t) Pass a as t Capability Action copy(cap) Grant a copy of cap check(cap) Check cap transfer(cap) Revoke cap from all principals, and grant Location pre(action) Perform action before function call post(action) Perform action after function return Privilege separation within a module dm_crypt: transparent encryption service for block devices This example requires a third type of capability Pass argument a as type t

26 Privilege separation Core Kernel User space Kernel space write(“/etc/secret.txt”, “foo”) int bdev_write(block_device *dev, const char * data, …) pre(check(ref(block_device), dev) dm_crypt write(enc_disk, “foo”, …) LXFI Runtime capability table ref(block_device, enc_disk->bdev) lxfi_check_ref(block_device, enc_disk->bdev) bdev_write(enc_disk->bdev, E(“foo”), …) Writing block device does not require writing to memory of enc_disk->bdev.

27 Privilege separation Core Kernel User space Kernel space int bdev_write(block_device *dev, const char * data, …) pre(check(ref(block_device), dev) dm_crypt LXFI Runtime capability table ref(block_device, enc_disk->bdev) ref(block_device, enc_usb->bdev) lxfi_check_ref(block_device, enc_disk->bdev) bdev_write(enc_disk->bdev, “/etc/pwd”, “foo”) Decrypt capability table ref(block_device, enc_disk->bdev) capability table ref(block_device, enc_usb->bdev) /etc/pwd: rootpwd=foo read(…)

28 How to define principals Associate a principal with every instance a module supports (e.g. block device in dm_crypt) Problem: how to specify and name principals? Recall goal: minimize changes to existing data structures Idea: re-use address of data structure as the name of the principal Can typically identify principal from one of the function arguments

29 Specifying principals PartSyntaxDescription Capability write(ptr,size) Write [ ptr,ptr+size ] ref(a, t) Pass a as t call(a) Call a Capability Action copy(cap) Grant a copy of cap check(cap) Check cap transfer(cap) Revoke cap from all principals, and grant Location pre(action) Perform action before function call post(action) Perform action after function return Principal principal(ptr) Run with privileges of principal ptr

30 Privilege separation Core Kernel User space Kernel space dm_crypt LXFI Runtime lxfi_check_write(enc_disk->bdev, 100) bdev_write(enc_disk->bdev, “/etc/pwd”, “foo”) Decrypt capability table write(enc_disk->bdev, 100) capability table write(enc_usb->bdev, 100) struct dm_type { int (*map)(struct dm_target *di); principal(di) }; lxfi_set_princ(enc_usb) dm_crypt.map(enc_usb) /etc/pwd: rootpwd=foo

31 Principal name aliasing Problem: Kernel identifies a LXFI principal by multiple addresses Insert code into module to create alias The same principal now has multiple names int e1000_probe(struct pci_dev *pcidev) { struct net_device *ndev = alloc_etherdev(...); ndev->pcidev = pcidev;... } int e1000_xmit(struct net_device *dev) { … } lxfi_princ_alias(pcidev, ndev);

32 Other annotation language features PartSyntaxDescription Capability write(ptr,size) Write [ ptr,ptr+size ] ref(a, t) Pass a as t call(a) Call a cap_iterator(obj)A function iterates all cap. of obj Capability Action copy(cap) Grant a copy of cap if(c-expr) action Perform action only if c-expr check(cap) Check cap transfer(cap) Revoke cap from all principals, grant cap Location pre(action) Perform action before function call post(action) Perform action after function return Principal principal(ptr) Run with privileges of principal ptr ( global, shared ) Global: principal with full privilige Shared: principal with minimal privilege Save annotation effort for complex objects that need multiple capabilities Express conditional action such as grant a privilege if return value is OK

33 Implementation Linux 2.6.36, x64, single-core gcc plugin: kernel rewriting for callback integrity Clang/LLVM plugin: module rewriting Annotation propagation saves effort by inferring annotations of module functions

34 Example: annotation propagation //from linux/include/pci_driver.h struct pci_driver { int (*probe)(struct pci_dev *pcidev) principal(pcidev) pre(copy(ref(struct pci_dev), pcidev) } //linux/drivers/net/e1000/e1000_main.c int e1000_probe(struct pci_dev *pcidev) { …. } struct pci_driver e1000_driver = {.probe = e1000_probe }; //linux/drivers/net/ixgbe/ixgbe_main.c int ixgbe_probe(struct pci_dev *pcidev) { …. } struct pci_driver ixgbe_driver = {.probe = ixgbe_probe }; LXFI propagates annotation on probe to modules

35 Evaluation Security Annotation effort Performance overhead

36 Security Test LXFI with three real privilege escalation exploits Stopping real attacks requires API integrity ExploitCVE IDViolated Property Unmodified Linux LXFI CAN_BCMCVE-2010-2959Memory Safety Econet CVE-2010-3849 API Integrity CVE-2010-3850 CVE-2010-4258 RDSCVE-2010-3904API Integrity

37 Annotation effort Annotate kernel APIs for 10 modules, one at a time Count: # of annotated core kernel functions a module calls # of function pointer declarations a module exports to core kernel

38 Sharing reduces annotation effort CategoryModule #Functions# Function Pointers All UniqueAllUnique net device drivere100081495247 sound device driver snd-intel8x05927122 snd-ens13704813122 net protocol driver rds77304226 can53773 can-bcm5115171 econet5415203 block device driver dm-crypt5024 14 dm-zero6320 dm-snapshot55162818 Total334155

39 LXFI performance netperf, 1 Gigabit e1000 network card, LAN Stresses LXFI Test ThroughputCPU % StockLXFIStockLXFI TCP_STREAM TX UDP_STREAM TX 836 M bits/sec 3.1 M/3.1 M pkt/sec 828 M bits/sec 2.0 M/2.0 M pkt/sec 13% 54% 48% 100% ~30% decrease

40 Room for improvement 80% CPU time of LXFI actions for netperf

41 Future work Improve performance Faster capability management such as BGI’s Extend annotation language to enforce other types of API integrity Perhaps based on Singularity’s contracts

42 Related work Type-safe kernels: Singularity [MSR-TR05] LXFI provides similar guarantees in C Good support for revocation (transfer) and principals Software fault isolation LXFI extends existing SFI systems (SFI, XFI, BGI) with annotation language

43 Conclusion Extend SFI with annotation language for: Argument integrity Callback integrity Principals LXFI: Prototype for Linux Annotated 10 kernel modules Prevented 3 real privilege escalation exploits 2-4X CPU overhead when stressing with netperf

44 Q & A


Download ppt "Software fault isolation with API integrity and multi-principal modules MIT CSAIL Yandong Mao, Haogang Chen (MIT CSAIL), Tsinghua University IIIS Dong."

Similar presentations


Ads by Google