1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
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 |