Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=986
The lgdrmserver binder service (/system/bin/lgdrmserver) implements a handle
system to store pointers to objects allocated by the drm implementation
(/system/lib/liblgdrm.so).
In several places, these handles are retrieved from a received binder Parcel, looked up in a SortedVector under a global lock, the lock is
then released and the handle is passed to one of the DRM_xyz functions in
liblgdrm.so which then uses the handle without holding any locks.
The attached PoC simply creates a number of process instances using the function
DRM_ProcessInit (lgdrm binder ordinal 2), then triggers the race condition by
trying to cause a double free on one of these instances using DRM_ProcessEnd
(lgdrm binder ordinal 8). The race window looks something like the following:
ILGDrmService::ProcessEnd(void* handle) {
lock(gLock); // <-- second thread takes this lock
void* process = gProcesses.find(handle); // <-- handle is still valid
unlock(gLock);
DRM_ProcessEnd(process);
lock(gLock); // <-- before first thread takes this lock
gProcesses.remove(handle);
unlock(gLock);
}
This will result in heap corruption during the second call to DRM_ProcessEnd
with the (now invalid) process object, which will eventually crash the
lgdrmserver process (usually during a subsequent call to malloc).
Several other functions in lgdrmserver follow a similar pattern, and require
additional locking to be safe.
The PoC has been tested on an LG G4 running build-id MRA58K
Build fingerprint: 'lge/p1_global_com/p1:6.0/MRA58K/1624210305d45:user/release-keys'
Revision: '11'
ABI: 'arm'
pid: 32314, tid: 32314, name: lgdrmserver >>> /system/bin/lgdrmserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xf6e801d8
r0 00000003 r1 f6b4012c r2 00000008 r3 00000001
r4 0000001f r5 f6b4012c r6 f6e40140 r7 f6b40134
r8 f6b40000 r9 000d0027 sl 00000005 fp 00000000
ip f700f10c sp ffd0c2c8 lr f6b4013c pc f6fd46c2 cpsr 000f0030
backtrace:
#00 pc 0004b6c2 /system/lib/libc.so (arena_dalloc_bin_locked_impl.isra.27+365)
#01 pc 0005c85f /system/lib/libc.so (je_tcache_bin_flush_small+206)
#02 pc 00055917 /system/lib/libc.so (ifree+290)
#03 pc 000587a3 /system/lib/libc.so (je_free+374)
#04 pc 000241c9 /system/lib/liblgdrm.so (DRMPart_ProcessEnd+340)
#05 pc 00018331 /system/lib/liblgdrm.so (DRM_ProcessEnd+72)
#06 pc 000056a5 /system/bin/lgdrmserver
#07 pc 00005fbd /system/bin/lgdrmserver
#08 pc 00019931 /system/lib/libbinder.so (_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j+60)
#09 pc 0001eccb /system/lib/libbinder.so (_ZN7android14IPCThreadState14executeCommandEi+550)
#10 pc 0001ee35 /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+64)
#11 pc 0001ee99 /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+48)
#12 pc 00004661 /system/bin/lgdrmserver
#13 pc 000174a9 /system/lib/libc.so (__libc_init+44)
#14 pc 00004784 /system/bin/lgdrmserver
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41351.zip