From 43383c4e497e98a5297ee53cc0026969db5d53fa Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Tue, 17 Nov 2020 15:13:51 -0800 Subject: [PATCH] Introduce LE COC security enforcement shim Tag: #gd-refactor Bug: 141555841 Test: cert/run --host Test: Pair and connect with a headset Change-Id: Iad2d1e71582886c05a4c7df39cc85735cb3f8abf --- gd/l2cap/le/l2cap_le_module.h | 6 +++ main/shim/l2c_api.cc | 97 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 8 deletions(-) diff --git a/gd/l2cap/le/l2cap_le_module.h b/gd/l2cap/le/l2cap_le_module.h index 43df7dbd9..384a5cf69 100644 --- a/gd/l2cap/le/l2cap_le_module.h +++ b/gd/l2cap/le/l2cap_le_module.h @@ -24,6 +24,10 @@ namespace bluetooth { +namespace shim { +void L2CA_UseLegacySecurityModule(); +} + namespace security { class SecurityModule; } @@ -62,6 +66,8 @@ class L2capLeModule : public bluetooth::Module { std::unique_ptr pimpl_; friend security::SecurityModule; + friend void bluetooth::shim::L2CA_UseLegacySecurityModule(); + /** * Only for the LE security module to inject functionality to enforce security level for a connection. When LE * security module is stopping, inject nullptr. Note: We expect this only to be called during stack startup. This is diff --git a/main/shim/l2c_api.cc b/main/shim/l2c_api.cc index 3769753b5..e46bd3f77 100644 --- a/main/shim/l2c_api.cc +++ b/main/shim/l2c_api.cc @@ -40,7 +40,7 @@ std::unordered_map> security_enforce_callback_map = {}; -class SecurityEnforcementShim +class ClassicSecurityEnforcementShim : public bluetooth::l2cap::classic::SecurityEnforcementInterface { public: static void security_enforce_result_callback(const RawAddress* bd_addr, @@ -178,6 +178,14 @@ class SecurityListenerShim } } + bool IsRoleCentral(RawAddress remote) { + if (address_to_interface_.count(remote) == 0) { + return false; + } + return address_to_interface_[remote]->GetRole() == + bluetooth::hci::Role::CENTRAL; + } + std::unordered_map address_to_handle_; std::unordered_map< RawAddress, @@ -187,6 +195,60 @@ class SecurityListenerShim bluetooth::l2cap::classic::SecurityInterface* security_interface_ = nullptr; +std::unordered_map> + le_security_enforce_callback_map = {}; + +class LeSecurityEnforcementShim + : public bluetooth::l2cap::le::SecurityEnforcementInterface { + public: + static void le_security_enforce_result_callback(const RawAddress* bd_addr, + tBT_TRANSPORT trasnport, + void* p_ref_data, + tBTM_STATUS result) { + intptr_t counter = (intptr_t)p_ref_data; + if (le_security_enforce_callback_map.count(counter) == 0) { + LOG_ERROR("Received unexpected callback"); + return; + } + + auto& callback = le_security_enforce_callback_map[counter]; + std::move(callback).Invoke(result == BTM_SUCCESS); + le_security_enforce_callback_map.erase(counter); + } + + void Enforce(bluetooth::hci::AddressWithType remote, + bluetooth::l2cap::le::SecurityPolicy policy, + ResultCallback result_callback) override { + tBTM_BLE_SEC_ACT sec_act = 0; + switch (policy) { + case bluetooth::l2cap::le::SecurityPolicy:: + NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK: + result_callback.Invoke(true); + return; + case bluetooth::l2cap::le::SecurityPolicy::ENCRYPTED_TRANSPORT: + sec_act = BTM_BLE_SEC_ENCRYPT; + break; + case bluetooth::l2cap::le::SecurityPolicy::BEST: + case bluetooth::l2cap::le::SecurityPolicy:: + AUTHENTICATED_ENCRYPTED_TRANSPORT: + sec_act = BTM_BLE_SEC_ENCRYPT_MITM; + break; + default: + result_callback.Invoke(false); + } + auto bd_addr = bluetooth::ToRawAddress(remote.GetAddress()); + le_security_enforce_callback_map[security_enforce_callback_counter_] = + std::move(result_callback); + BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, + le_security_enforce_result_callback, + (void*)security_enforce_callback_counter_, sec_act); + security_enforce_callback_counter_++; + } + + intptr_t security_enforce_callback_counter_ = 100; +} le_security_enforcement_shim_; + bool bluetooth::shim::L2CA_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version, uint16_t* manufacturer, @@ -208,6 +270,9 @@ void bluetooth::shim::L2CA_UseLegacySecurityModule() { security_interface_ = bluetooth::shim::GetL2capClassicModule()->GetSecurityInterface( bluetooth::shim::GetGdShimHandler(), &security_listener_shim_); + + bluetooth::shim::GetL2capLeModule()->InjectSecurityEnforcementInterface( + &le_security_enforcement_shim_); } /** @@ -351,6 +416,7 @@ using bluetooth::l2cap::le::FixedChannelManager; using bluetooth::l2cap::le::FixedChannelService; static constexpr uint16_t kAttCid = 4; +static constexpr uint16_t kSmpCid = 6; struct LeFixedChannelHelper { LeFixedChannelHelper(uint16_t cid) : cid_(cid) {} @@ -444,9 +510,11 @@ struct LeFixedChannelHelper { }; static LeFixedChannelHelper att_helper{4}; +static LeFixedChannelHelper smp_helper{6}; static std::unordered_map le_fixed_channel_helper_{ {4, att_helper}, + {6, smp_helper}, }; /** @@ -455,7 +523,7 @@ static std::unordered_map */ bool bluetooth::shim::L2CA_RegisterFixedChannel(uint16_t cid, tL2CAP_FIXED_CHNL_REG* p_freg) { - if (cid != kAttCid) { + if (cid != kAttCid && cid != kSmpCid) { LOG(ERROR) << "Invalid cid: " << cid; return false; } @@ -479,7 +547,7 @@ bool bluetooth::shim::L2CA_RegisterFixedChannel(uint16_t cid, bool bluetooth::shim::L2CA_ConnectFixedChnl(uint16_t cid, const RawAddress& rem_bda) { - if (cid != kAttCid) { + if (cid != kAttCid && cid != kSmpCid) { LOG(ERROR) << "Invalid cid " << cid; return false; } @@ -504,7 +572,7 @@ bool bluetooth::shim::L2CA_ConnectFixedChnl(uint16_t cid, uint16_t bluetooth::shim::L2CA_SendFixedChnlData(uint16_t cid, const RawAddress& rem_bda, BT_HDR* p_buf) { - if (cid != kAttCid) { + if (cid != kAttCid && cid != kSmpCid) { LOG(ERROR) << "Invalid cid " << cid; return false; } @@ -518,7 +586,7 @@ uint16_t bluetooth::shim::L2CA_SendFixedChnlData(uint16_t cid, bool bluetooth::shim::L2CA_RemoveFixedChnl(uint16_t cid, const RawAddress& rem_bda) { - if (cid != kAttCid) { + if (cid != kAttCid && cid != kSmpCid) { LOG(ERROR) << "Invalid cid " << cid; return false; } @@ -670,6 +738,7 @@ struct LeDynamicChannelHelper { return; } channels_[device]->Close(); + disconnected_by_us_[device] = true; } void Unregister() { @@ -682,18 +751,27 @@ struct LeDynamicChannelHelper { } } - void on_unregistered() {} + void on_unregistered() { + for (const auto& device : channels_) { + device.second->Close(); + } + } void on_channel_close(bluetooth::hci::AddressWithType device, bluetooth::hci::ErrorCode error_code) { channel_enqueue_buffer_[device] = nullptr; channels_[device]->GetQueueUpEnd()->UnregisterDequeue(); - channels_[device] = nullptr; + channels_.erase(device); auto address = bluetooth::ToRawAddress(device.GetAddress()); auto cid_token = find_cid_token_by_psm_address(psm_, address); (appl_info_.pL2CA_DisconnectInd_Cb)(cid_token, false); remove_cid_token_entry(cid_token); initiated_by_us_.erase(device); + + if (channel_service_ == nullptr && channels_.empty()) { + // Try again + bluetooth::shim::L2CA_DeregisterLECoc(psm_); + } } void on_channel_open(std::unique_ptr channel) { @@ -773,6 +851,7 @@ struct LeDynamicChannelHelper { channel_enqueue_buffer_; std::unordered_map cid_map_; std::unordered_map initiated_by_us_; + std::unordered_map disconnected_by_us_; }; std::unordered_map> @@ -800,7 +879,9 @@ void bluetooth::shim::L2CA_DeregisterLECoc(uint16_t psm) { return; } le_dynamic_channel_helper_map_[psm]->Unregister(); - le_dynamic_channel_helper_map_.erase(psm); + if (le_dynamic_channel_helper_map_[psm]->channels_.empty()) { + le_dynamic_channel_helper_map_.erase(psm); + } } uint16_t bluetooth::shim::L2CA_ConnectLECocReq(uint16_t psm, -- 2.11.0