Three Dark Cloud Over Android Kernel
Three Dark Cloud Over Android Kernel
over
the Android Kernel
1
Contents
04. Conclusion
2
Contents
04. Conclusion
3
Classic attack path
Bypass Arbitrary
Vulnerability Root
KASLR write
• Methods
ret2usr
ROP/JOP
...
4
The ret2dir
CVE-2015-3636 (PingPong)
ret2dir + ROP
ret2dir
5
The ret2dir
• Double Mapping
0xFFFF...
0x4000...
https://cs.brown.edu/~vpk/papers/ret2dir.sec14.pdf
6
The ret2dir
• User can calculate the kernel address
1. Get PFN from /proc/self/pagemap
2. kaddr = (PFN << PAGE_SHIFT) – PHYS_OFFSET
+ PAGE_OFFSET
• The kernel mapping attributes
qcom: RW
mtk: RWX (CVE-2016-0820)
7
The ret2dir
• Hide PFN in the /proc/self/pagemap
https://android.googlesource.com/kernel/msm/+/718c232053ec81a4a732ed50ba0224ae512bb694%5E%21/
8
The ret2dir
• It still works
CVE-2015-3636[1]
CVE-2018-9568[2]
• The key is information leakage
[1] https://www.blackhat.com/docs/us-15/materials/us-15-Xu-Ah-Universal-Android-Rooting-Is-Back.pdf
[2] https://github.com/ThomasKing2014/slides/blob/master/Building%20universal%20Android%1920rootin
g%20with%20a%20type%20confusion%20vulnerability.pdf
9
The KSMA
• Kernel Space Mirror Attack
?
CVE-2017-7533 (ReVent)
PIPE + KSMA
https://i.blackhat.com/briefings/asia/2018/asia-18-WANG-KSMA-Breaking-Android-kernel-isolation-and-
Rooting-with-ARM-MMU-features.pdf
10
The KSMA
• The block entry
https://documentation-service.arm.com/static/5f20515cbb903e39c84dc459?token=
11
The KSMA
• The AP (Access Permissions) attribute
12
The KSMA
• Android: 39-bits VA & 4K page
swapper_pg_dir
13
The KSMA
• The position of the swapper_pg_dir is fixed
arch/arm64/kernel/vmlinux.lds.S
BSS_SECTION(0, 0, 0)
. = ALIGN(PAGE_SIZE);
idmap_pg_dir = .;
. += IDMAP_DIR_SIZE;
swapper_pg_dir = .;
. += SWAPPER_DIR_SIZE;
14
The PIPE
• Proposed in 2017
• Has the characteristics of TOCTOU
• Converts heap problems to arbitrary reading and
writing
https://pacsec.jp/psj17/PSJ2017_DiShen_Pacsec_FINAL.pdf
15
The PIPE
• Allocate iovec on the heap
fs/read_write.c
ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
unsigned long nr_segs, unsigned long fast_segs,
struct iovec *fast_pointer, ...) {
[...]
if (nr_segs > fast_segs) { // UIO_FASTIOV == 8
iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
[...]
}
if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
ret = -EFAULT;
goto out;
}
}
16
The PIPE
• Check the iovec passed in by the user
fs/read_write.c
17
The PIPE
• We can block the pipe
1. There is no contents when reading
2. There is no space when writing
object iovec
18
The PIPE
• Does NOT check when copying from/to the user
lib/iov_iter.c
static size_t copy_page_to_iter_iovec(..) {
[...]
left = __copy_to_user_inatomic(buf, from, copy);
copy -= left;
skip += copy;
from += copy;
bytes -= copy;
[...]
}
19
The PIPE
• Two mitigations
1. UAO (User Access Override)
2. uaccess_mask_ptr()
arch/arm64/include/asm/uaccess.h
https://developer.arm.com/docs/ddi0595/h/aarch64-system-registers/uao
20
The SMA
• SLAB Mirror Attack
Two objects share the same SLAB
Bypass KASLR
Write kernel arbitrary (+KSMA = ROOT)
21
Contents
04. Conclusion
22
CVE-2020-3680
• Timeline
23
CVE-2020-3680
• Qualcomm ADSPRPC driver
drivers/char/adsprpc.c
24
How to exploit
• ROP/JOP 😭
PAN (Privileged Access Never)
CFI (Control Flow Integrity)
• SMA + KSMA 😀
1. Convert UAF to Double Free
2. Bypass KASLR
3. Apply KSMA
25
Convert UAF to Double Free
drivers/char/adsprpc.c
26
Convert UAF to Double Free
• How to bypass hlist_del_init()
include/linux/list.h
static inline void hlist_del_init(struct hlist_node *n) {
if (!hlist_unhashed(n)) {
__hlist_del(n);
INIT_HLIST_NODE(n);
}
}
27
Convert UAF to Double Free
• The object used for heap spray
1. It uses the kmalloc-256 SLAB
2. I can control the map->refs and map->flags
3. The map->hn->pprev is zero
28
Convert UAF to Double Free
• The object used for heap spray
fs/xattr.c
29
Convert UAF to Double Free
• The SLAB appears twice in the freelist
Freelist A A
Freelist A
30
Bypass KASLR
• Use the freelist to modify the object
struct seq_file {
char *buf; // is modified by the freelist
size_t size;
[...]
struct mutex lock;
const struct seq_operations *op; // is leaked
int poll_event;
const struct file *file;
void *private;
}
31
Bypass KASLR
• Users can read the seq_file->buf
32
Bypass KASLR
• Allocate victim_fd0 & victim_fd1
Freelist A A
victim_fd0 victim_fd1
(A) (A)
33
Bypass KASLR
• Allocate the leaked_fd
B
Freelist
(leaked_fd)
34
Bypass KASLR
• Free the victim_fd0
A B
Freelist
(victim_fd0) (leaked_fd)
35
Apply KSMA
• Use the object to modify the freelist
1. It uses the kmalloc-256 SLAB
2. I can control the first 8 bytes
36
Apply KSMA
• Use the object to modify the freelist
struct ipv6_mc_socklist {
struct in6_addr addr;
int ifindex;
struct ipv6_mc_socklist __rcu *next;
rwlock_t sflock;
unsigned int sfmode;
struct ip6_sf_socklist *sflist;
struct rcu_head rcu;
}
37
Apply KSMA
• Use the object to modify the freelist
net/ipv6/mcast.c
38
Apply KSMA
• Allocate the mc_lst
Freelist A A
mc_lst
(A)
Freelist A
39
Apply KSMA
• Update the mc_lst->addr
Freelist A A
mc_lst
(A)
Freelist A
40
Demo
41
Contents
04. Conclusion
42
The ret2dir mitigation
• Exclusive Page-Frame Ownership
Unmap the user page in the kernel
Not yet merged into the mainline
https://lwn.net/Articles/784839/
43
The KSMA mitigation
• The KSMA patch
I submitted it in May 2018
Was merged into the mainline in September 2018
Android has not yet been backported 😭
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/log/?h=v5.8.8&qt=author&q=yaojun
44
The KSMA patch
• Move the page table to the rodata section
arch/arm64/kernel/vmlinux.lds.S
+#define KERNEL_PG_TABLES \
+ . = ALIGN(PAGE_SIZE); \
+ idmap_pg_dir = .; \
+ . += IDMAP_DIR_SIZE; \
+ TRAMP_PG_TABLE \
+ RESERVED_PG_TABLE \
+ swapper_pg_dir = .; \
+ . += PAGE_SIZE; \
+ swapper_pg_end = .;
RO_DATA(PAGE_SIZE)
EXCEPTION_TABLE(8)
NOTES
+ KERNEL_PG_TABLES
45
The KSMA patch
• The kernel assumes the relative offset between the
swapper_pg_dir and the tramp_pg_dir
arch/arm64/kernel/entry.S
.macro tramp_map_kernel, tmp
mrs \tmp, ttbr1_el1
sub \tmp, \tmp, #(SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE)
bic \tmp, \tmp, #USER_ASID_FLAG
msr ttbr1_el1, \tmp
[...]
.endm
46
The KSMA patch
• Update the page table through fixmap
47
The SMA mitigation
• CONFIG_SLAB_FREELIST_HARDENED[1]
Not enabled in the kernel 4.9
Not enabled on the Google Pixel (4.14)
• CONFIG_INIT_ON_FREE_DEFAULT_ON[2]
Not enabled in the Android kernel
[1] https://hardenedlinux.github.io/system-security/2017/12/02/linux_kernel_4.14%E7%9A%84SLAB_FREELIS
T_HARDENED%E7%9A%84%E7%AE%80%E8%A6%81%E5%88%86%E6%9E%90.html
[2] https://outflux.net/blog/archives/2019/11/14/security-things-in-linux-v5-3/
48
SLAB_FREELIST_HARDENED
• Generate a random number
mm/slub.c
int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
{
s->flags = kmem_cache_flags(s->size, flags, s->name, s->ctor);
s->reserved = 0;
#ifdef CONFIG_SLAB_FREELIST_HARDENED
s->random = get_random_long();
#endif
}
49
SLAB_FREELIST_HARDENED
• Obfuscate the address of SLAB
mm/slub.c
void *freelist_ptr(const struct kmem_cache *s, void *ptr, unsigned long ptr_addr)
{
#ifdef CONFIG_SLAB_FREELIST_HARDENED
return (void *)((unsigned long)ptr ^ s->random ^
(unsigned long)kasan_reset_tag((void *)ptr_addr));
#else
return ptr;
#endif
}
50
SLAB_FREELIST_HARDENED
• The obfuscation has weaknesses
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1ad53d9fa3f6168ebcf48a50e08b170
432da2257
51
SLAB_FREELIST_HARDENED
• Improve the obfuscation
mm/slub.c
void *freelist_ptr(const struct kmem_cache *s, void *ptr, unsigned long ptr_addr)
{
#ifdef CONFIG_SLAB_FREELIST_HARDENED
return (void *)((unsigned long)ptr ^ s->random ^
- (unsigned long)kasan_reset_tag((void *)ptr_addr));
+ swab((unsigned long)kasan_reset_tag((void *)ptr_addr)));
#else
return ptr;
#endif
}
52
SLAB_FREELIST_HARDENED
• Check the double free
mm/slub.c
void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
unsigned long freeptr_addr = (unsigned long)object + s->offset;
#ifdef CONFIG_SLAB_FREELIST_HARDENED
BUG_ON(object == fp); // Double free
#endif
*(void **)freeptr_addr = freelist_ptr(s, fp, freeptr_addr);
}
53
INIT_ON_FREE_DEFAULT_ON
• Clear the data in the released SLAB
mm/slub.c
54
Contents
04. Conclusion
55
Conclusion
• The combination of the SMA and the KSMA is powerful
56
Thank You