ASA-2019-00083 – Linux: Binder use-after-free of VMA via race between reclaim and munmap


Allele Security Alert

ASA-2019-00083

Identifier(s)

ASA-2019-00083, A-120025196, CVE-2019-1999

Title

Binder use-after-free of VMA via race between reclaim and munmap

Vendor(s)

The Linux foundation
Google

Product(s)

Linux
Android

Affected version(s)

Android Security Patch Level before February 2019

Fixed version(s)

Android Security Patch Level February 2019

Proof of concept

Yes

Description

There is a race condition between the direct reclaim path (enters binder through the binder_shrinker) and the munmap() syscall (enters binder through the ->close handler of binder_vm_ops).

Technical details

Coming from the munmap() syscall:

binder_vma_close() -> binder_alloc_vma_close() -> binder_alloc_set_vma() sets alloc->vma to NULL without taking any extra locks; binder_vma_close() is called from remove_vma() <- remove_vma_list() <- __do_munmap() <- __vm_munmap() <- sys_munmap() with only the mmap_sem held for writing.

Coming through the direct reclaim path:

binder_alloc_free_page() doesn’t hold the mmap_sem on entry. It contains the following code:

enum lru_status binder_alloc_free_page(struct list_head *item,
struct list_lru_one *lru,
spinlock_t *lock,
void *cb_arg)
{
[...]
alloc = page->alloc;
if (!mutex_trylock(&alloc->mutex))
goto err_get_alloc_mutex_failed;

if (!page->page_ptr)
goto err_page_already_freed;

index = page - alloc->pages;
page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
// unprotected pointer read! `vma` can immediately be freed
vma = binder_alloc_get_vma(alloc);
if (vma) {
if (!mmget_not_zero(alloc->vma_vm_mm))
goto err_mmget;
mm = alloc->vma_vm_mm;
if (!down_write_trylock(&mm->mmap_sem))
goto err_down_write_mmap_sem_failed;
// mmap_sem is held at this point, but the vma pointer was read
// before and can be dangling
}

list_lru_isolate(lru, item);
spin_unlock(lock);

if (vma) {
trace_binder_unmap_user_start(alloc, index);

// dangling vma pointer passed to zap_page_range
zap_page_range(vma,
page_addr + alloc->user_buffer_offset,
PAGE_SIZE);

trace_binder_unmap_user_end(alloc, index);

up_write(&mm->mmap_sem);
mmput(mm);
}

Credits

Jann Horn (Google Project Zero)

Reference(s)

1721 – Android: binder use-after-free of VMA via race between reclaim and munmap –  project-zero – Monorail
https://bugs.chromium.org/p/project-zero/issues/detail?id=1721

Android Security Bulletin — February 2019
https://source.android.com/security/bulletin/2019-02-01.html

CVE-2019-1999
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1999

CVE-2019-1999
https://nvd.nist.gov/vuln/detail/CVE-2019-1999

If there is any error in this alert or you wish a comprehensive analysis, let us know.

Last modified: February 18, 2019

We are not responsible for any data loss, device corruption or any other type of issue due to the use of any information mentioned in our security alerts.