CVE-2026-0045 AI-generated analysis
platform/packages/modules/Bluetooth, BTM security manager (system/stack/btm/btm_sec.cc); on 15/16 also BTA JV RFCOMM client (system/bta/jv/bta_jv_act.cc)
In the Bluetooth stack's btm_sec_is_upgrade_possible (system/stack/btm/btm_sec.cc), the fix makes the function return true when a link key is known, the service requires authentication in the relevant direction and the peer's bond is temporary; the code comment says this is meant to trigger pairing.
Root cause
btm_sec_is_upgrade_possible() sets is_possible = false as soon as the device record has BTM_SEC_LINK_KEY_KNOWN. It sets it back to true only when a MITM upgrade is both required (BTM_SEC_OUT_MITM / BTM_SEC_IN_MITM) and feasible given the link key type and IO capabilities. It never looked at the bond type. So if the peer was bonded only temporarily (p_dev_rec->is_bond_type_temporary()) and the service's security_required contained BTM_SEC_OUT_AUTHENTICATE or BTM_SEC_IN_AUTHENTICATE, the function still returned false (no upgrade possible). On Android 16 a partial check already existed, but it was gated behind the aconfig flag upgrade_temp_bonding_on_auth_req and tested only BTM_SEC_OUT_AUTHENTICATE, which left the responder (incoming) direction unhandled.
How the fix works
- system/stack/btm/btm_sec.cc:btm_sec_is_upgrade_possible (Android 14 backport 2e2a7bf09a3f): inside the BTM_SEC_LINK_KEY_KNOWN branch, after the existing MITM-upgrade check, adds a second, independent condition: if (security_required & (is_originator ? BTM_SEC_OUT_AUTHENTICATE : BTM_SEC_IN_AUTHENTICATE)) and p_dev_rec->is_bond_type_temporary(), set is_possible = true. The function then reports that an upgrade is possible, which according to the added comment triggers pairing.
- Android 15 (c1a809d2333e): the same btm_sec.cc check, written with the p_dev_rec->sec_rec.security_required / sec_rec.is_bond_type_temporary() field layout. It also removes from bta_jv_act.cc:bta_jv_rfcomm_connect the BTM_SetSecurityLevel(true, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0) call that was gated by rfcomm_always_use_mitm(), so the RFCOMM client no longer registers a MUX-level security record carrying the client's sec_mask.
- Android 16 (2ad8e1e0e0e5, 'RFCOMM MUX connection request must not start bonding'): in btm_sec.cc:btm_sec_is_upgrade_possible, drops the com::android::bluetooth::flags::upgrade_temp_bonding_on_auth_req() gate and replaces the originator-only BTM_SEC_OUT_AUTHENTICATE test with the direction-aware (is_originator ? BTM_SEC_OUT_AUTHENTICATE : BTM_SEC_IN_AUTHENTICATE). It removes the upgrade_temp_bonding_on_auth_req flag from flags/security.aconfig and removes the unconditional BTM_SetSecurityLevel RFC_MUX call from bta_jv_act.cc:bta_jv_rfcomm_connect.
- Android 17 (92611bfc4d26 in android-17.0.0_r1): the same btm_sec.cc addition as shown for 14.
Completeness
- The new check covers both directions (originator via BTM_SEC_OUT_AUTHENTICATE, responder via BTM_SEC_IN_AUTHENTICATE), unlike the earlier flagged variant on Android 16, which covered the originator only.
- The check sits only inside the BTM_SEC_LINK_KEY_KNOWN branch. When no link key is known, is_possible is already true, so that path needs no change.
- The check looks only at the authenticate bit. MITM requirements are still handled by the existing MITM logic. A requirement that has neither bit (for example encryption only) is not affected by this change.
- The Android 14 backport changes only btm_sec.cc. The bta_jv_act.cc RFC_MUX BTM_SetSecurityLevel removal that is part of the 15 and 16 fixes is not in it, and the material does not show whether that code exists on 14.
Behavior changes
- When a peer is temporarily bonded, a link key is known and the service requires authentication in the relevant direction, btm_sec_is_upgrade_possible now returns true. According to the code comment, this is meant to trigger pairing instead of continuing on the existing temporary bond.
- On Android 15 and 16, bta_jv_rfcomm_connect no longer sets a BTM_SEC_SERVICE_RFC_MUX security record with the client's sec_mask (16 commit title: 'RFCOMM MUX connection request must not start bonding').
- On Android 16 the aconfig flag upgrade_temp_bonding_on_auth_req is deleted, so the behaviour no longer depends on a flag.
Per major
- Android 14: Adapted fix in btm_sec.cc only, using the old field names p_dev_rec->security_required / p_dev_rec->is_bond_type_temporary() and BTM_TRACE_DEBUG logging. Commit 2e2a7bf09a3f in android-security-14.0.0_r28, explicitly a backport of ag/31042219. 4/4 lines of the patched region are present at android-security-14.0.0_r29.
- Android 15: Adapted fix: the same btm_sec.cc check using p_dev_rec->sec_rec.* fields, plus removal of the rfcomm_always_use_mitm()-gated RFC_MUX BTM_SetSecurityLevel block in bta_jv_act.cc:bta_jv_rfcomm_connect. Commit c1a809d2333e in android-security-15.0.0_r16. Only 3/8 lines of the patched region are present at android-security-15.0.0_r17; the material does not explain the partial match.
- Android 16: Adapted fix: the check already existed behind flag upgrade_temp_bonding_on_auth_req and covered the originator only. Commit 2ad8e1e0e0e5 in android-security-16.0.0_r7 removes the flag (from the code and from flags/security.aconfig), adds the BTM_SEC_IN_AUTHENTICATE direction, and removes the unconditional RFC_MUX BTM_SetSecurityLevel call in bta_jv_rfcomm_connect. Only 4/8 lines of the patched region are present at android-security-16.0.0_r8.
- Android 17: The same btm_sec.cc addition is recorded as commit 92611bfc4d26 in the android-17.0.0_r1 base. However, 0/4 patched lines are present at android-security-17.0.0_r1, so the material does not show the current form of the check on 17.
Unknowns
- The material does not show the caller(s) of btm_sec_is_upgrade_possible or how is_possible turns into starting pairing.
- Why the Android 15 and 16 checks show only partial matches (3/8, 4/8), and why Android 17 shows 0/4 at android-security-17.0.0_r1 even though it is resolved in the base. The 17 diff also uses the Android 14 field names, which the material does not reconcile.
- Whether Android 14's bta_jv_rfcomm_connect contains the RFC_MUX BTM_SetSecurityLevel block removed on 15/16.
- Whether the affected path is limited to BR/EDR; the material does not state the transport.
- The concrete trigger beyond what the diff implies (a temporary bond plus a service that requires authentication).