CVE-2023-40088 AI-generated analysis
platform/packages/modules/Bluetooth, android/app/jni (AdapterService JNI callback thread / CallbackEnv)
Adds `callbackEnv = NULL;` after `vm->DetachCurrentThread()` in the DISASSOCIATE_JVM branch of callback_thread_event in the Bluetooth AdapterService JNI. After the callback thread is detached, the code no longer keeps a dangling JNIEnv pointer.
Root cause
In android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp, callback_thread_event(ASSOCIATE_JVM) attaches the callback thread with vm->AttachCurrentThread(&callbackEnv, &args). This stores the thread's JNIEnv* in the file-scope variable callbackEnv. On DISASSOCIATE_JVM, the code called vm->DetachCurrentThread() and cleared sHaveCallbackThread, but it left callbackEnv pointing at the environment. Per the commit message, detaching frees that environment context. The commit message says the stale variable allows a UAF 'under certain conditions', and its title ('Fix UAF in ~CallbackEnv') names the CallbackEnv destructor as the place where the UAF happens.
How the fix works
- android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp:callback_thread_event, DISASSOCIATE_JVM branch: after vm->DetachCurrentThread() and sHaveCallbackThread = false, the fix adds callbackEnv = NULL;. Code that reads callbackEnv later sees a null pointer instead of a dangling pointer to the freed JNIEnv.
- Single one-line commit (d45432ee9620). The commit message says a custom JNI unit test was written but deliberately left out of the merged change.
Completeness
- The fix only clears the global callbackEnv in the detach path. It does not change CallbackEnv itself or the attach path. Whether it is effective depends on CallbackEnv (constructor, valid(), destructor) treating a NULL callbackEnv as invalid. The CallbackEnv implementation is not in the provided material, so the code shown cannot confirm this.
- Nulling callbackEnv after DetachCurrentThread() is not atomic, and the diff adds no locking. The diff does not address whether another thread can observe callbackEnv between the two statements. The isCallbackThread() check does limit the detach to the callback thread itself.
- Only this JNI file is changed. Other JNI files in the Bluetooth app that may keep their own JNIEnv globals are not part of this fix and are not shown in the material.
Behavior changes
- After the callback thread is disassociated from the JVM, callbackEnv is NULL instead of stale. The diff adds no new error codes, log messages or API changes. How CallbackEnv reacts to the NULL value is not shown.
Per major
- Android 14: same fix: commit d45432ee9620 in android-security-14.0.0_r3. At android-security-14.0.0_r29 the patched region is fully present (2/2 lines), with callbackEnv = NULL at line 765.
- Android 15: not affected (not listed by the bulletin). The patched region is present at android-security-15.0.0_r17 (2/2 lines).
- Android 16: not affected (not listed by the bulletin). The patched region is present at android-security-16.0.0_r8 (2/2 lines).
- Android 17: not affected (not listed by the bulletin). The patched region is present at android-security-17.0.0_r1 (2/2 lines).
Unknowns
- The CallbackEnv class implementation (constructor, valid(), ~CallbackEnv) is not in the provided material, so the exact place where the stale callbackEnv is dereferenced is not shown, nor is how a NULL value is handled.
- The commit message only says 'under certain conditions'; it does not describe when DISASSOCIATE_JVM races with or comes before a CallbackEnv use.
- The per-major facts do not show which security-13 tag carries the fix for Android 13.