CVE-2023-40131 AI-generated analysis
platform/frameworks/native, services/gpuservice (GpuService)
Converts the two detached async-initialization threads spawned in the GpuService constructor into owned std::thread members and adds a GpuService destructor that joins them, so the threads can no longer run against a destroyed GpuService object.
Root cause
In services/gpuservice/GpuService.cpp, GpuService::GpuService() created two std::thread objects (gpuMemAsyncInitThread and gpuWorkAsyncInitThread) whose lambdas captured `this` and dereferenced members (mGpuMem->initialize(), mGpuMemTracer->initialize(mGpuMem), mGpuWork->initialize()), then immediately called detach() on both. Nothing tied the lifetime of those threads to the GpuService object, so if the GpuService was destroyed (last sp<> reference dropped) before the initializers finished, the threads could access freed memory. The commit message states this heap-use-after-free was reported by libfuzzer.
How the fix works
- services/gpuservice/include/gpuservice/GpuService.h (renamed from services/gpuservice/GpuService.h): adds `#include <thread>`, declares `~GpuService();`, and adds two private members `std::unique_ptr<std::thread> mGpuMemAsyncInitThread` and `std::unique_ptr<std::thread> mGpuWorkAsyncInitThread`.
- services/gpuservice/GpuService.cpp GpuService::GpuService(): replaces the local std::thread objects with `mGpuMemAsyncInitThread = std::make_unique<std::thread>(...)` and `mGpuWorkAsyncInitThread = std::make_unique<std::thread>(...)`; the detach() calls are removed so the threads stay joinable and owned by the object. Lambda bodies are unchanged.
- services/gpuservice/GpuService.cpp GpuService::~GpuService(): new destructor that calls mGpuWorkAsyncInitThread->join() then mGpuMemAsyncInitThread->join(). Because the destructor body runs before member destruction, mGpuMem, mGpuMemTracer and mGpuWork are still valid while the init threads finish, and the object memory is not released until both have joined.
- services/gpuservice/Android.bp: adds `export_include_dirs: ["include"]` to libgpuservice so the header is reachable from tests; services/gpuservice/main_gpuservice.cpp and GpuService.cpp update the include to "gpuservice/GpuService.h".
- services/gpuservice/tests/unittests/Android.bp and GpuServiceTest.cpp: new test onInitializeShouldNotCauseUseAfterFree creates a GpuService, clears the sp<> immediately, sleeps 3 seconds and passes if no crash; the test links libgpuservice.
Completeness
- Covers both detached threads created in the constructor (GpuMem/GpuMemTracer init and GpuWork init); no other detached threads appear in the shown GpuService code.
- Both thread members are unconditionally assigned in the constructor, so the unconditional join() calls in the destructor do not dereference a null unique_ptr in the shown code paths.
- The join is unconditional and has no timeout, so if an initialize() call never returns, GpuService destruction blocks indefinitely rather than freeing the object.
- The fix does not change what the initializer lambdas do or add any synchronization between the init threads and other GpuService methods that may run concurrently via binder while initialization is in progress; the material does not show whether such concurrent access exists.
Behavior changes
- GpuService destruction now blocks until both asynchronous initialization threads have completed.
- The init threads are no longer detached; their std::thread objects live as members for the lifetime of the GpuService.
- GpuService.h moved to services/gpuservice/include/gpuservice/GpuService.h and is exported from libgpuservice via export_include_dirs; includers must use "gpuservice/GpuService.h".
- gpuservice_unittest gains a new test and a new shared_libs dependency on libgpuservice.
Per major
- Android 14: same fix: commit a2030f098afa in android-security-14.0.0_r1 (and identical commit e562203ac243 in android-security-14.0.0_r2, same Change-Id I4d1d2d4658b575bf2c8f425f91f68f03114ad029), cherry-picked from 3c00cbc0f119. At android-security-14.0.0_r29 the shown context has the moved header, the ~GpuService() declaration, the <thread>/<memory> includes, export_include_dirs and the new test; 7/8 patched lines matched.
- Android 15: not affected per the bulletin; the patched region is present at android-security-15.0.0_r17 (7/8 lines matched).
- Android 16: not affected per the bulletin; the patched region is present at android-security-16.0.0_r8 (7/8 lines matched).
- Android 17: not affected per the bulletin; the patched region is present at android-security-17.0.0_r1 (7/8 lines matched).
Unknowns
- How the libfuzzer harness caused the GpuService object to be destroyed, and whether any production path in the gpuservice process can destroy the service while initialization is in progress.
- Which single line of the 8-line patched region differs at the later security tags (14.0.0_r29, 15.0.0_r17, 16.0.0_r8, 17.0.0_r1); the shown context excerpts do not include the destructor body or the thread member declarations.
- Whether the originating AOSP commit 3c00cbc0f119 landed in 13 and 12/12L branches, which the bulletin lists as affected; the material only shows the 14 branch commits.