CVE-2026-58880 AI-generated analysis
platform/packages/modules/Bluetooth, system/btif AVRCP controller (btif_rc.cc, bt_rc.h HAL interface, com_android_bluetooth_avrcp_controller.cpp JNI)
Removes the num_ext_attr/ext_attrs parameters from the AVRCP controller playerapplicationsetting_cb HAL callback, so the callback no longer carries a pointer to ext_attrs data that handle_app_attr_val_txt_response frees. It also makes that free (cleanup_app_attr_val_txt_response) synchronous instead of posting it to the JNI thread.
Root cause
In system/btif/src/btif_rc.cc, the final branch of handle_app_attr_val_txt_response (reached after all extended attribute value texts were received) bound bt_rc_ctrl_callbacks->playerapplicationsetting_cb with the raw pointers p_app_settings->attrs and p_app_settings->ext_attrs. On Android 16 it posted the callback to the JNI thread with do_in_jni_thread; on Android 17 it dispatched it through the CTRL_HAL_CBACK macro. It also arranged for cleanup_app_attr_val_txt_response(p_app_settings) to free memory held inside the ext_attrs structure. Per the commit message, the callback runs asynchronously on the JNI thread while the calling thread frees the ext_attrs memory, so the callback can see a dangling ext_attrs pointer. The JNI implementation btavrcp_playerapplicationsetting_callback never used num_ext_attr/ext_attrs: both are commented out, next to a "TODO ext attrs" note.
How the fix works
- system/include/hardware/bt_rc.h: the btrc_ctrl_playerapplicationsetting_callback typedef drops the uint8_t num_ext_attr and btrc_player_app_ext_attr_t* ext_attrs parameters. The HAL callback now takes only (bd_addr, num_attr, app_attrs).
- system/btif/src/btif_rc.cc: all four call sites are updated. handle_app_val_response, handle_app_attr_txt_response and the first branch of handle_app_attr_val_txt_response used to pass (0, nullptr) and now pass only (rc_addr, num_attrs, attrs). The final branch of handle_app_attr_val_txt_response used to pass p_app_settings->num_ext_attrs and p_app_settings->ext_attrs and now passes only attrs, so the callback no longer receives an ext_attrs pointer.
- system/btif/src/btif_rc.cc:handle_app_attr_val_txt_response: the deferred do_in_jni_thread(base::BindOnce(cleanup_app_attr_val_txt_response, p_app_settings)) is replaced by a direct synchronous call to cleanup_app_attr_val_txt_response(p_app_settings). As before, p_app_settings->num_attrs = 0 follows.
- android/app/jni/com_android_bluetooth_avrcp_controller.cpp:btavrcp_playerapplicationsetting_callback: the signature is reduced to (bd_addr, num_attr, app_attrs) to match the new typedef. The body is unchanged and only flattens app_attrs.
- system/btif/test/btif_rc_test.cc: callback lambdas are updated to the new signature. The btif_transfer_context test stub now copies parameters (through p_copy_cback when provided) and calls p_cback directly. On Android 17, more per-test lambdas are updated, and one assertion in btif_rc_transaction_timer_timeout_passthru flips from ASSERT_TRUE to ASSERT_FALSE on transaction_set.transaction[1].in_use.
Completeness
- Covers every caller of playerapplicationsetting_cb in btif_rc.cc (four sites), because the HAL typedef change forces all of them to change. The JNI callback is also updated. The compiler now rejects any call site that still passes ext_attrs.
- The callback still receives a raw pointer to p_app_settings->attrs (part of p_dev->rc_app_settings). The material shows neither the definition of btif_rc_player_app_settings_t nor what cleanup_app_attr_val_txt_response frees. So the diff cannot confirm that attrs stays valid while the JNI task is pending, now that cleanup runs synchronously. The fix assumes attrs remains valid and that only ext_attrs memory was freed.
- The extended attribute data is now dropped at the HAL boundary. No replacement path delivers ext_attrs to Java (the JNI side never consumed it).
Behavior changes
- HAL/JNI interface change: btrc_ctrl_playerapplicationsetting_callback takes three parameters instead of five. Any out-of-tree implementation of this callback must be updated or it will fail to compile.
- cleanup_app_attr_val_txt_response now runs synchronously on the thread handling the AVRCP response instead of being queued on the JNI thread.
- Test-only: the btif_transfer_context stub now calls p_cback directly. On Android 17, one assertion in btif_rc_transaction_timer_timeout_passthru was flipped from ASSERT_TRUE to ASSERT_FALSE.
Per major
- Android 14: Not listed by the bulletin (not affected per the bulletin). The resolver finds 4/8 lines of the patched region at android-security-14.0.0_r30. No fix commit is linked for this branch.
- Android 15: Not listed by the bulletin (not affected per the bulletin). The resolver finds 6/8 lines of the patched region at android-security-15.0.0_r18. No fix commit is linked for this branch.
- Android 16: Same fix: af2fe681d88d in android-security-16.0.0_r9, a cherry-pick of 3e7ec1e85fec (Change-Id Ib2f73a3bed18eeb835404073d3fc2ae1ef746aa1). Call sites use do_in_jni_thread(base::BindOnce(...)).
- Android 17: Adapted fix: df3b47977847 in android-security-17.0.0_r2. Same subject and same logic, but call sites use the CTRL_HAL_CBACK macro, btif_transfer_context returns BtStatus, more test lambdas are updated, and one test assertion is flipped.
Unknowns
- The definition of btif_rc_player_app_settings_t and the body of cleanup_app_attr_val_txt_response are not shown, so exactly which allocations are freed (ext_attrs text strings or the array) is not visible.
- Before the fix on Android 16, both the callback and the cleanup were posted to the JNI thread, callback first. Why that ordering still led to a use-after-free is explained only by the commit message, not by code in the material.
- Whether CTRL_HAL_CBACK (Android 17) dispatches synchronously or asynchronously is not shown.
- Whether p_app_settings->attrs can be modified by later responses before the posted JNI task runs is not shown.
- Whether Android 14/15 contain the pre-fix pattern in a reachable form. The bulletin does not list them.