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 00000003r1 f6b4012cr2 00000008r3 00000001
r4 0000001fr5 f6b4012cr6 f6e40140r7 f6b40134
r8 f6b40000r9 000d0027sl 00000005fp 00000000
ip f700f10csp ffd0c2c8lr f6b4013cpc f6fd46c2cpsr 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