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]: [1528150218]
[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-00202-1802061358]
[ro.build.expect.bootloader]: [mw8998-002.0069.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 = 0000000000000000
[ 997.010537] [fffffff2873e1180] *pgd=0000000000000000, *pud=0000000000000000
[ 997.010632] c7 1718 ------------[ cut here ]------------
[ 997.010646] c7 1718 Kernel BUG at 0000000000000000 [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: 0000000000000000 task.stack: 0000000000000000
[ 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: 0000000000000001
[ 997.010912] x23: fffffff2089c9b80 x22: fffffff239402b00
[ 997.010930] x21: fffffff2873e1180 x20: 00000000024000c0
[ 997.010952] x19: ffffff9f4de4e054 x18: 0000000000001600
[ 997.010959] x17: 0000007ea408ae34 x16: 00000000b0000000
[ 997.010965] x15: 000000017e4c0000 x14: 0000000000000006
[ 997.010972] x13: ffffff9f5008f490 x12: 0000000000000000
[ 997.010978] x11: 000000000012abd7 x10: 000000000012abcf
[ 997.010984] x9 : 0000000000000000 x8 : 000000000012abcf
[ 997.010990] x7 : 00000007fdcf4000 x6 : fffffff2058ebc28
[ 997.010996] x5 : fffffff2058ebc28 x4 : 0000000000000001
[ 997.011002] x3 : 0000000082cb5000 x2 : 0000000000000018
[ 997.011008] x1 : 00000000024000c0 x0 : fffffff239402b00
[ 997.011015] c7 1718
[ 997.011015] c7 1718 PC: 0xffffff9f4d9df14c:
[ 997.011019] f14c b9401ae9 51000529 b9001ae9 35000069 f94002e9 37080449 f94002c9 d538d08a
[ 997.011040] f16c 8b090149 f940052a eb0a011f 54fffdc1 f9400135 b4000bb5 b98022c9 9100210b
[ 997.011060] f18c f8696ab8 b9401ae9 11000529 b9001ae9 f94002c9 d538d08a 8b090149 f9800131
[ 997.011080] f1ac c87f652a ca15014a ca080339 aa190159 b5000079 c82a2d38 35ffff4a b9401ae8
[ 997.011101] c7 1718
[ 997.011101] c7 1718 LR: 0xffffff9f4de4e014:
[ 997.011105] e014 b40004ca aa1703e1 2a1f03e2 97ee702c 910023e0 aa1603e1 aa1703e2 97f50b24
[ 997.011125] e034 b5000420 b94023e4 12000888 34000408 f9471360 52801801 72a04801 97ee442d
[ 997.011145] e054 aa0003e8 b40005a8 f9400be9 11000718 2a1f03e0 6b14031f f9001109 f9400fe9
[ 997.011164] e074 910082d6 f9001509 b94027e9 b9001109 f94007e9 f9000d09 b94023e9 a9037d09
[ 997.011185] c7 1718
[ 997.011185] c7 1718 SP: 0xfffffff2058ebb70:
[ 997.011189] bb70 4de4e054 ffffff9f 058ebbb0 fffffff2 4d9df18c ffffff9f 60400145 00000000
[ 997.011209] bb90 4fe2f270 ffffff9f 4fe2fe98 ffffff9f 00000000 00000080 4fe2cee8 ffffff9f
[ 997.011230] bbb0 8e07a448 fffffff1 a2257020 fffffff1 00000001 00000000 00000020 00000000
[ 997.011250] bbd0 0a083ac8 0000007e 4fe2cee8 ffffff9f 00000002 00000000 8e07a400 fffffff1
[ 997.011270] c7 1718
[ 997.011274] c7 1718 Process GLThread 41 (pid: 1718, stack limit = 0x0000000000000000)
[ 997.011278] c7 1718 Call trace:
[ 997.011283] c7 1718 Exception stack(0xfffffff2058eba80 to 0xfffffff2058ebbb0)
[ 997.011288] c7 1718 ba80: fffffff239402b00 00000000024000c0 0000000000000018 0000000082cb5000
[ 997.011292] c7 1718 baa0: 0000000000000001 fffffff2058ebc28 fffffff2058ebc28 00000007fdcf4000
[ 997.011297] c7 1718 bac0: 000000000012abcf 0000000000000000 000000000012abcf 000000000012abd7
[ 997.011301] c7 1718 bae0: 0000000000000000 ffffff9f5008f490 0000000000000006 000000017e4c0000
[ 997.011306] c7 1718 bb00: 00000000b0000000 0000007ea408ae34 0000000000001600 ffffff9f4de4e054
[ 997.011310] c7 1718 bb20: 00000000024000c0 fffffff2873e1180 fffffff239402b00 fffffff2089c9b80
[ 997.011315] c7 1718 bb40: 0000000000000001 fffffff18e07a448 fffffff2089c9b80 ffffff9f501f4000
[ 997.011319] c7 1718 bb60: fffffff2089c9b80 fffffff2058ebbf0 ffffff9f4de4e054 fffffff2058ebbb0
[ 997.011323] c7 1718 bb80: ffffff9f4d9df18c 0000000060400145 ffffff9f4fe2f270 ffffff9f4fe2fe98
[ 997.011327] c7 1718 bba0: 0000008000000000 ffffff9f4fe2cee8
[ 997.011332] c7 1718 [<ffffff9f4d9df18c>] kmem_cache_alloc+0x88/0x228
[ 997.011337] c7 1718 [<ffffff9f4de4e054>] kgsl_drawobj_cmd_add_cmdlist+0x120/0x1e4
[ 997.011342] c7 1718 [<ffffff9f4de3f3d8>] kgsl_ioctl_gpu_command+0x114/0x288
[ 997.011347] c7 1718 [<ffffff9f4de4eb4c>] kgsl_ioctl_helper+0x134/0x1b8
[ 997.011351] c7 1718 [<ffffff9f4de4ec00>] kgsl_ioctl+0x30/0xbc
[ 997.011357] c7 1718 [<ffffff9f4da00dd0>] do_vfs_ioctl+0x434/0x884
[ 997.011361] c7 1718 [<ffffff9f4da012a8>] SyS_ioctl+0x88/0x94
[ 997.011367] c7 1718 [<ffffff9f4d883b0c>] __sys_trace_return+0x0/0x4
[ 997.011373] c7 1718 Code: f9400135 b4000bb5 b98022c9 9100210b (f8696ab8)
[ 997.011417] c7 1718 ---[ end trace aea07a0c0fb86e0d ]---
[ 997.015389] c7 1718 Kernel panic - not syncing: Fatal exception
================================================================================
Note that another possible way in which the memory corruption can happen is
corruption of a spinlock - in that case, the phone won't panic, but messages
about a soft kernel lockup will start appearing in dmesg after some time.
Experimentally, that seems to happen if the chaos_worker thread is removed from
the PoC.
I have verified that this bug can also be triggered from a normal Android app.
To reproduce that, follow these steps:
- install https://play.google.com/store/apps/details?id=org.connectbot on the
phone
- run "adb shell mkdir /sdcard/Android/data/org.connectbot"
- run "/usr/local/google/home/jannh/my-android-toolchain/bin/aarch64-linux-android-gcc -static -o poc poc.c -pthread"
- run "adb push poc /sdcard/Android/data/org.connectbot/"
- on the phone, open a local terminal in connectbot
- in the terminal:
$ cd /data/data/org.connectbot
$ cp /sdcard/Android/data/org.connectbot/poc .
$ chmod +x poc
$ ./poc
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/45558.zip