Exploit-DB #46941
Description: Qualcomm Android - Kernel Use-After-Free via Incorrect set_page_dirty() in KGSL
Type: dos
Platform: android
Date: 2019-05-29
Author: Google Security Research

Exploit:
The following issue exists in the android-msm-wahoo-4.4-pie branch of
https://android.googlesource.com/kernel/msm (and possibly others):

When kgsl_mem_entry_destroy() in drivers/gpu/msm/kgsl.c is called for a writable
entry with memtype KGSL_MEM_ENTRY_USER, it attempts to mark the entry's pages
as dirty using the function set_page_dirty(). This function first loads
page->mapping using page_mapping(), then calls the function pointer
mapping->a_ops->set_page_dirty.

The bug is that, as explained in upstream commit e92bb4dd9673
( https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e92bb4dd[PII_REDACTED]b1fc738c9817dd91bfb629),
the mapping of a page can be freed concurrently unless it is protected somehow
(e.g. by holding the page lock, or by holding a reference to the mapping).
For callers who don't hold any such lock or reference, set_page_dirty_lock() is
provided to safely mark a page as dirty:

==================================
/*
 * set_page_dirty() is racy if the caller has no reference against
 * page->mapping->host, and if the page is unlocked.  This is because another
 * CPU could truncate the page off the mapping and then free the mapping.
 *
 * Usually, the page _is_ locked, or the caller is a user-space process which
 * holds a reference on the inode by having an open file.
 *
 * In other cases, the page should be locked before running set_page_dirty().
 */
int set_page_dirty_lock(struct page *page)
{
        int ret;

        lock_page(page);
        ret = set_page_dirty(page);
        unlock_page(page);
        return ret;
}
==================================


To reproduce on a Pixel 2 (walleye):

 - Check out the tree specified above.
 - Enable KASAN in the kernel config.
 - Apply the attached kernel patch kgsl-bigger-race-window.patch to make the
   race window much bigger.
 - Build and boot the kernel.
 - Build the attached poc.c with
   `aarch64-linux-gnu-gcc -static -o poc poc.c -Wall`.
 - Run the PoC on the device (adb push, then run from adb shell).

You should see a kernel crash like this; note KASAN's report of a UAF in
set_page_dirty():

==================================
<6>[  445.698708] c3    688 mdss_fb_blank_sub: mdss_fb_blank+0x1d0/0x2b4 mode:0
<3>[  447.372706] c3   2621 ==================================================================
<3>[  447.372963] c3   2621 BUG: KASAN: use-after-free in set_page_dirty+0x4c/0xd0
<3>[  447.380051] c3   2621 Read of size 8 at addr [PII_REDACTED] by task kworker/3:3/2621
<3>[  447.387059] c3   2621 
<4>[  447.394762] c3   2621 CPU: 3 PID: 2621 Comm: kworker/3:3 Not tainted 4.4.116-gbcd0ecccd040-dirty #45
<4>[  447.397158] c3   2621 Hardware name: Qualcomm Technologies, Inc. MSM8998 v2.1 (DT)
<4>[  447.406473] c3   2621 Workqueue: kgsl-mementry _deferred_put
<4>[  447.418479] c3   2621 Call trace:
<4>[  447.418660] c3   2621 [<ffffffa689e8dfbc>] dump_backtrace+0x0/0x2b4
<4>[  447.421952] c3   2621 [<ffffffa689e8e394>] show_stack+0x14/0x1c
<4>[  447.428066] c3   2621 [<ffffffa68a2f3d2c>] dump_stack+0xa4/0xcc
<4>[  447.433965] c3   2621 [<ffffffa68a07b254>] print_address_description+0x94/0x340
<4>[  447.439870] c3   2621 [<ffffffa68a07b784>] kasan_report+0x1f8/0x340
<4>[  447.447145] c3   2621 [<ffffffa68a079a10>] __asan_load8+0x74/0x90
<4>[  447.453407] c3   2621 [<ffffffa68a0205b4>] set_page_dirty+0x4c/0xd0
<4>[  447.459621] c3   2621 [<ffffffa68a6c5dec>] kgsl_mem_entry_destroy+0x1c0/0x218
<4>[  447.465695] c3   2621 [<ffffffa68a6c63d8>] _deferred_put+0x34/0x3c
<4>[  447.473017] c3   2621 [<ffffffa689edc124>] process_one_work+0x254/0x78c
<4>[  447.479093] c3   2621 [<ffffffa689edc6f4>] worker_thread+0x98/0x718
<4>[  447.485551] c3   2621 [<ffffffa689ee59a4>] kthread+0x114/0x130
<4>[  447.491801] c3   2621 [<ffffffa689e84250>] ret_from_fork+0x10/0x40
<3>[  447.497696] c3   2621 
<3>[  447.503818] c3   2621 Allocated by task 2684:
<4>[  447.506206] c3   2621  [<ffffffa689e8d624>] save_stack_trace_tsk+0x0/0x1b8
<4>[  447.511847] c3   2621  [<ffffffa689e8d7f4>] save_stack_trace+0x18/0x20
<4>[  447.517829] c3   2621  [<ffffffa68a079e74>] kasan_kmalloc.part.5+0x50/0x124
<4>[  447.523494] c3   2621  [<ffffffa68a07a198>] kasan_kmalloc+0xc4/0xe4
<4>[  447.529547] c3   2621  [<ffffffa68a07a964>] kasan_slab_alloc+0x14/0x1c
<4>[  447.534931] c3   2621  [<ffffffa68a078030>] kmem_cache_alloc+0x144/0x27c
<4>[  447.540572] c3   2621  [<ffffffa68a187bdc>] ext4_alloc_inode+0x28/0x234
<4>[  447.546387] c3   2621  [<ffffffa68a0afe94>] alloc_inode+0x34/0xd0
<4>[  447.552112] c3   2621  [<ffffffa68a0b19e8>] new_inode+0x20/0xe8
<4>[  447.557318] c3   2621  [<ffffffa68a154214>] __ext4_new_inode+0xe8/0x1f00
<4>[  447.562360] c3   2621  [<ffffffa68a17087c>] ext4_tmpfile+0xb4/0x230
<4>[  447.568172] c3   2621  [<ffffffa68a09f9e8>] path_openat+0x934/0x1404
<4>[  447.573556] c3   2621  [<ffffffa68a0a1a50>] do_filp_open+0x98/0x188
<4>[  447.579027] c3   2621  [<ffffffa68a089004>] do_sys_open+0x170/0x2d4
<4>[  447.584407] c3   2621  [<ffffffa68a0891a0>] SyS_openat+0x10/0x18
<4>[  447.589787] c3   2621  [<ffffffa689e842b0BCho<D5>
^@^@<90>^A,^A^Hp<D6>M>] el0_svc_naked+0x24/0x28
<3>[  447.594909] c3   2621 
<3>[  447.599065] c3   2621 Freed by task 36:
<4>[  447.601330] c3   2621  [<ffffffa689e8d624>] save_stack_trace_tsk+0x0/0x1b8
<4>[  447.606461] c3   2621  [<ffffffa689e8d7f4>] save_stack_trace+0x18/0x20
<4>[  447.612450] c3   2621  [<ffffffa68a07aa1c>] kasan_slab_free+0xb0/0x1c0
<4>[  447.618091] c3   2621  [<ffffffa68a0770c0>] kmem_cache_free+0x80/0x2f8
<4>[  447.623733] c3   2621  [<ffffffa68a1863f8>] ext4_i_callback+0x18/0x20
<4>[  447.629363] c3   2621  [<ffffffa689f5c430>] rcu_nocb_kthread+0x20c/0x264
<4>[  447.634926] c3   2621  [<ffffffa689ee59a4>] kthread+0x114/0x130
<4>[  447.640726] c3   2621  [<ffffffa689e84250>] ret_from_fork+0x10/0x40
<3>[  447.645765] c3   2621 
<3>[  447.649913] c3   2621 The buggy address bel