precise and scalable detection of double fetch bugs in os
play

Precise and Scalable Detection of Double-Fetch Bugs in OS Kernels - PowerPoint PPT Presentation

Precise and Scalable Detection of Double-Fetch Bugs in OS Kernels Meng Xu , Chenxiong Qian, Kangjie Lu + , Michael Backes*, Taesoo Kim Georgia Tech | University of Minnesota + | CISPA, Germany* 1 What is Double-Fetch? Address Space


  1. Precise and Scalable Detection of Double-Fetch Bugs in OS Kernels Meng Xu , Chenxiong Qian, Kangjie Lu + , Michael Backes*, Taesoo Kim Georgia Tech | University of Minnesota + | CISPA, Germany* � 1

  2. What is Double-Fetch?

  3. Address Space Separation 0x00000000 User / Program 3 GB Address Space 0xC0000000 Kernel 1 GB Address Space 0xFFFFFFFF A Typical Address Space Separation Scheme with a 32-bit Virtual Address Space � 3

  4. No Dereference on Userspace Pointers 0x00000000 User / Program 3 GB Address Space 0xDEADBEEF 0xC0000000 void kfunc (int __user *uptr, int *kptr) { Kernel 1 GB …… Address Space Uninitialized } 0xFFFFFFFF A Typical Address Space Separation Scheme with a 32-bit Virtual Address Space � 4

  5. No Dereference on Userspace Pointers 0x00000000 User / Program 3 GB Address Space 0xDEADBEEF 0xDEADBEEF 0xC0000000 void kfunc (int __user *uptr, int *kptr) { Kernel 1 GB …… Address Space 0xDEADBEEF Uninitialized } 0xFFFFFFFF A Typical Address Space Separation Scheme with a 32-bit Virtual Address Space � 5

  6. No Dereference on Userspace Pointers 0x00000000 User / Program 3 GB Address Space 0xDEADBEEF 0xC0000000 void kfunc (int __user *uptr, int *kptr) { Kernel 1 GB *kptr = *uptr; …… Address Space 0xDEADBEEF Uninitialized } 0xFFFFFFFF A Typical Address Space Separation Scheme with a 32-bit Virtual Address Space � 6

  7. No Dereference on Userspace Pointers 0x00000000 User / Program 3 GB Address Space 0xDEADBEEF 0xC0000000 void kfunc (int __user *uptr, int *kptr) { Kernel 1 GB copy_from_user(kptr, uptr, 4); …… Address Space 0xDEADBEEF Uninitialized } 0xFFFFFFFF A Typical Address Space Separation Scheme with a 32-bit Virtual Address Space � 7

  8. Shared Userspace Pointer Across Threads 0x00000000 …… User / Program 3 GB Address Space 0xDEADBEEF 0xDEADBEEF 0xC0000000 void kfunc (int __user *uptr, int *kptr) { Kernel 1 GB copy_from_user(kptr, uptr, 4); …… Address Space 0xDEADBEEF Uninitialized } 0xFFFFFFFF A Typical Address Space Separation Scheme with a 32-bit Virtual Address Space � 8

  9. Shared Userspace Pointer Across Threads 0x00000000 …… User / Program 3 GB Address Space 0xDEADBEEF 0xDEADBEEF 0xC0000000 void kfunc (int __user *uptr, int *kptr) { Kernel 1 GB copy_from_user(kptr, uptr, 4); …… Address Space 0xDEADBEEF Uninitialized } 0xFFFFFFFF A Typical Address Space Separation Scheme with a 32-bit Virtual Address Space � 9

  10. Why Double-Fetch? 1 static int perf_copy_attr_simplified ?? bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 4 5 u32 size; 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 10

  11. Why Double-Fetch? 1 static int perf_copy_attr_simplified ?? bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 30 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 11

  12. Why Double-Fetch? 1 static int perf_copy_attr_simplified ?? bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 30 30 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 12

  13. Why Double-Fetch? 1 static int perf_copy_attr_simplified ?? bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 30 30 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 13

  14. Why Double-Fetch? 1 static int perf_copy_attr_simplified 30 bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 30 30 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 14

  15. Why Double-Fetch? 1 static int perf_copy_attr_simplified 30 bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 30 30 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 30 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 15

  16. Why Double-Fetch? 1 static int perf_copy_attr_simplified 30 bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 30 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 30 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 16

  17. What Goes Wrong in This Process?

  18. Up-until First-Fetch 1 static int perf_copy_attr_simplified ?? bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 30 30 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 18

  19. Wrong Assumption: Atomicity in Syscall 1 static int perf_copy_attr_simplified 30 bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 65535 30 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 19

  20. Wrong Assumption: Atomicity in Syscall 1 static int perf_copy_attr_simplified 30 bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 65535 65535 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 65535 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later 24 memcpy(buf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 20

  21. When The Exploit Happens 1 static int perf_copy_attr_simplified 30 bytes 2 (struct perf_event_attr __user *uattr, 3 struct perf_event_attr *attr) { 65535 4 5 u32 size; 4 bytes 6 7 // first fetch 8 if (get_user(size, &uattr->size)) 30 9 return -EFAULT; 10 11 // sanity checks 12 if (size > PAGE_SIZE || 13 size < PERF_ATTR_SIZE_VER0) 14 return -EINVAL; 15 16 // second fetch 17 if (copy_from_user(attr, uattr, size)) 65535 18 return -EFAULT; 19 20 ...... 21 } 22 23 // BUG: when attr->size is used later kernel information leak! 24 copy_to_user(ubuf, attr, attr->size); Adapted from perf_copy_attr in file kernel/events/core.c � 21

  22. Why Double-Fetch is Prevalent in Kernels? 1. Size checking 2. Dependency look-up 3. Protocol/signature check 4. Information guessing 5. ……

  23. Double-Fetch: Dependency Lookup Adapted from __mptctl_ioctl in file drivers/message/fusion/mptctl.c � 23

Recommend


More recommend