CVE-2024-43766 AI-generated analysis
platform/packages/modules/Bluetooth, system/stack (ACL/BTM/SMP/L2CAP LE security)
Makes the Bluetooth stack start LE link encryption as soon as an ACL connection to an already-bonded LE device is established (in StackAclBtmAcl::btm_establish_continue). Follow-up commits suppress spurious SMP failure handling, fix the order of the L2CAP link-state update and save the peer CSRK with the correct security level.
Root cause
In system/stack/acl/btm_acl.cc, StackAclBtmAcl::btm_establish_continue only did BR/EDR-specific work after connection (packet types, link policy) and did nothing for the LE transport. When an LE ACL came up to a peer with a security record and a known LE link key, the stack did not start link encryption itself. Encryption depended on later security requests, such as the L2CAP LE security check in btm_ble.cc that sets BTM_BLE_SEC_ENCRYPT or returns L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP. The commit message states that the LE link must be encrypted immediately on connection if the devices are already bonded. The bulletin classifies the issue as information disclosure (ID), High severity.
How the fix works
- Commit 796182896347 (android-security-14.0.0_r15), system/stack/acl/btm_acl.cc: StackAclBtmAcl::btm_establish_continue gains an `else if (p_acl->is_transport_ble())` branch. It looks up the security record with btm_find_dev(p_acl->remote_addr). If there is no record, it logs a warning. If p_dev_rec->is_le_link_key_known(), it calls btm_ble_set_encryption(p_acl->remote_addr, BTM_BLE_SEC_ENCRYPT, role), where role is HCI_ROLE_CENTRAL or HCI_ROLE_PERIPHERAL depending on p_dev_rec->role_central. NotifyAclLinkUp(*p_acl) still runs afterwards. The commit message says this is a backport of ag/29056565, placed in a different location because the original relies on recent feature work.
- Commit b6008f926a4e (android-security-14.0.0_r19), system/stack/btm/btm_ble.cc: in btm_ble_set_encryption, case BTM_BLE_SEC_ENCRYPT with link_role == HCI_ROLE_CENTRAL, the function now returns BTM_SUCCESS early if p_rec->is_le_device_encrypted(). This avoids a redundant btm_ble_start_encrypt on a link that is already encrypted.
- Same commit, system/stack/btm/btm_ble.cc: adds a new static function btm_ble_complete_evt_ignore(p_dev_rec, p_data), called at the top of the SMP_COMPLT_EVT case in btm_proc_smp_cback. It applies when all of these hold: the SMP completion failed (reason != SMP_SUCCESS); the local device is peripheral (!role_central); btm_cb.pairing_bda matches neither bd_addr nor ble.pseudo_addr; the LE link key is known; and key_type != BTM_LE_KEY_NONE. In that case, if the device is already encrypted, the failure is ignored. If the reason is SMP_CONN_TOUT, the failure is also ignored and l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle) is called. When the failure is ignored, btm_proc_smp_cback returns BTM_SUCCESS without the normal completion handling. Per the code comment, this covers peripheral-role encryption requests that become SMP Security Requests, where some centrals do not handle the cross-over or the link drops.
- Same commit, system/stack/l2cap/l2c_ble.cc: l2cble_notify_le_connection now sets p_lcb->link_state = LST_CONNECTED before calling btm_establish_continue_from_address(bda, BT_TRANSPORT_LE) rather than after it.
- Commit f80c558b456d (android-security-14.0.0_r24), system/stack/smp/smp_act.cc: smp_proc_srk_info now calls smp_key_distribution_by_transport(p_cb, NULL) right after smp_update_key_mask. Previously the call came after the peer CSRK (le_key.pcsrk_key.sec_level = p_cb->sec_level) was built and saved through btm_sec_save_le_key(..., BTM_LE_KEY_PCSRK, ...). Per the commit message, the security level is set after LTK generation. Saving the CSRK first stored sec_level ZERO, which could clear the MITM_AUTH flag when the key was reloaded in the next session. The commit is a backport of aosp/3254899, included to prevent regressions described in b#428948282.
Completeness
- The new encryption trigger only applies in the LE transport branch of btm_establish_continue, and only when a security record exists and is_le_link_key_known() is true. If btm_find_dev returns nullptr, the code only logs a warning.
- Both roles go through the btm_ble_set_encryption call. In central role this leads to btm_ble_start_encrypt. In peripheral role it leads to an SMP Security Request, per the comment in btm_ble_complete_evt_ignore.
- The early return added in btm_ble_set_encryption is only on the HCI_ROLE_CENTRAL path. The peripheral path of BTM_BLE_SEC_ENCRYPT is unchanged.
- btm_ble_complete_evt_ignore only suppresses SMP failures in peripheral role, outside an active pairing, for bonded devices. Central-role failures still go through the existing completion handling.
- The fix does not change the service-level security checks, such as the L2CAP LE check in btm_ble.cc that returns L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP.
- btm_establish_continue is reached from l2cble_notify_le_connection through btm_establish_continue_from_address. The material does not show whether other connection paths reach it.
Behavior changes
- On every LE ACL connection to a device with a known LE link key, the stack now starts encryption right away instead of waiting for a service to request it. In central role it calls btm_ble_start_encrypt; in peripheral role it sends an SMP Security Request.
- btm_ble_set_encryption(BTM_BLE_SEC_ENCRYPT) in central role returns BTM_SUCCESS without starting encryption again when the device is already encrypted.
- Failed SMP_COMPLT_EVT events for bonded devices in peripheral role, with no pairing in progress, are now ignored in two cases. If the link is already encrypted, the failure is simply ignored. On SMP_CONN_TOUT, the failure is ignored and the L2CAP post-bond timer is started.
- In l2cble_notify_le_connection, the L2CAP link_state is set to LST_CONNECTED before btm_establish_continue_from_address runs.
- The peer CSRK is now saved after smp_key_distribution_by_transport, so the stored record carries the sec_level set at that point instead of zero.
Per major
- Android 14: Adapted fix. The main change sits in StackAclBtmAcl::btm_establish_continue (btm_acl.cc) in android-security-14.0.0_r15 because the original ag/29056565 relies on recent feature work. Regression backports (btm_ble.cc, l2c_ble.cc) landed in r19 and the CSRK ordering fix (smp_act.cc) in r24. At android-security-14.0.0_r29, 3/3 lines of the patched region are present.
- Android 15: Resolved in android-security-15.0.0_r12. The material shows only the CSRK ordering commit d259085c6103 (smp_act.cc, the same two-line move as on 14). Where the main encrypt-on-reconnect change landed on 15 is not shown. At android-security-15.0.0_r17, 8/8 lines of the patched region are present.
- Android 16: Resolved in android-security-16.0.0_r3 by commit 769a3dea8016. It removes the aconfig flag save_peer_csrk_after_ltk_gen (flags/pairing.aconfig) and makes the smp_proc_srk_info ordering unconditional in smp_act.cc. The main encrypt-on-reconnect change on 16 is not shown. At android-security-16.0.0_r8, 5/8 lines of the patched region are present.
- Android 17: Not affected: the bulletin does not list Android 17. At android-security-17.0.0_r1, 0/3 lines of the patched region are present.
Unknowns
- The content and location of the original upstream change ag/29056565, and how the main encrypt-on-reconnect change was applied on Android 15 and 16 (only the CSRK-related commits are shown for those branches).
- What data could be exposed while the link is unencrypted (the bulletin only states type ID, High).
- Why only 5/8 lines of the patched region match at android-security-16.0.0_r8.
- Why the patched region is absent at android-security-17.0.0_r1.
- Whether LE connection paths other than l2cble_notify_le_connection reach btm_establish_continue.