diff options
| author | Himanshu Rawat <rwt@google.com> | 2024-04-08 17:46:18 +0000 |
|---|---|---|
| committer | aoleary <seanm187@gmail.com> | 2024-11-15 14:32:07 +0000 |
| commit | d6a3f95546cdc20458d24a9293dd7365ce6a508b (patch) | |
| tree | 33c6e0b793134655984b894b77aee47172aacdc7 | |
| parent | 8812dc772ebeeacf7bc9db875514fdae8272002b (diff) | |
RESTRICT AUTOMERGE Disallow unexpected incoming HID connections
HID profile accepted any new incoming HID connection. Even when the
connection policy disabled HID connection, remote devices could initiate
HID connection.
This change ensures that incoming HID connection are accepted only if
application was interested in that HID connection.
This vulnerarbility no longer exists on the main because of feature
request b/324093729.
Test: mmm packages/modules/Bluetooth
Test: Manual | Pair and connect a HID device, disable HID connection
from Bluetooth device setting, attempt to connect from the HID device.
Bug: 308429049
Ignore-AOSP-First: security
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:03dca3305311096f157da3ab9cfed5cc30f2c135)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:431ef0346302dec8fa8c7d89c4696931e2bbac9a)
Merged-In: I013d0528fb18ee87195fb3c8aab553c6a8da5ae4
Change-Id: I013d0528fb18ee87195fb3c8aab553c6a8da5ae4
| -rw-r--r-- | android/app/jni/com_android_bluetooth_hid_host.cpp | 8 | ||||
| -rw-r--r-- | android/app/src/com/android/bluetooth/hid/HidHostService.java | 7 | ||||
| -rw-r--r-- | system/btif/include/btif_hh.h | 4 | ||||
| -rw-r--r-- | system/btif/include/btif_storage.h | 23 | ||||
| -rw-r--r-- | system/btif/src/btif_hh.cc | 86 | ||||
| -rw-r--r-- | system/btif/src/btif_storage.cc | 51 | ||||
| -rw-r--r-- | system/gd/rust/linux/stack/src/bluetooth.rs | 2 | ||||
| -rw-r--r-- | system/gd/rust/topshim/src/profiles/hid_host.rs | 2 | ||||
| -rw-r--r-- | system/include/hardware/bt_hh.h | 2 |
9 files changed, 170 insertions, 15 deletions
diff --git a/android/app/jni/com_android_bluetooth_hid_host.cpp b/android/app/jni/com_android_bluetooth_hid_host.cpp index 7a164233bc..18ba315129 100644 --- a/android/app/jni/com_android_bluetooth_hid_host.cpp +++ b/android/app/jni/com_android_bluetooth_hid_host.cpp @@ -282,7 +282,8 @@ static jboolean connectHidNative(JNIEnv* env, jobject object, } static jboolean disconnectHidNative(JNIEnv* env, jobject object, - jbyteArray address) { + jbyteArray address, + jboolean reconnect_allowed) { jbyte* addr; jboolean ret = JNI_TRUE; if (!sBluetoothHidInterface) return JNI_FALSE; @@ -293,7 +294,8 @@ static jboolean disconnectHidNative(JNIEnv* env, jobject object, return JNI_FALSE; } - bt_status_t status = sBluetoothHidInterface->disconnect((RawAddress*)addr); + bt_status_t status = + sBluetoothHidInterface->disconnect((RawAddress*)addr, reconnect_allowed); if (status != BT_STATUS_SUCCESS) { ALOGE("Failed disconnect hid channel, status: %d", status); ret = JNI_FALSE; @@ -509,7 +511,7 @@ static JNINativeMethod sMethods[] = { {"initializeNative", "()V", (void*)initializeNative}, {"cleanupNative", "()V", (void*)cleanupNative}, {"connectHidNative", "([B)Z", (void*)connectHidNative}, - {"disconnectHidNative", "([B)Z", (void*)disconnectHidNative}, + {"disconnectHidNative", "([BZ)Z", (void*)disconnectHidNative}, {"getProtocolModeNative", "([B)Z", (void*)getProtocolModeNative}, {"virtualUnPlugNative", "([B)Z", (void*)virtualUnPlugNative}, {"setProtocolModeNative", "([BB)Z", (void*)setProtocolModeNative}, diff --git a/android/app/src/com/android/bluetooth/hid/HidHostService.java b/android/app/src/com/android/bluetooth/hid/HidHostService.java index 7352d5833b..ffd6b0a70b 100644 --- a/android/app/src/com/android/bluetooth/hid/HidHostService.java +++ b/android/app/src/com/android/bluetooth/hid/HidHostService.java @@ -186,7 +186,10 @@ public class HidHostService extends ProfileService { break; case MESSAGE_DISCONNECT: { BluetoothDevice device = (BluetoothDevice) msg.obj; - if (!disconnectHidNative(getByteAddress(device))) { + int connectionPolicy = getConnectionPolicy(device); + boolean reconnectAllowed = + connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED; + if (!disconnectHidNative(getByteAddress(device), reconnectAllowed)) { broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); break; @@ -1023,7 +1026,7 @@ public class HidHostService extends ProfileService { private native boolean connectHidNative(byte[] btAddress); - private native boolean disconnectHidNative(byte[] btAddress); + private native boolean disconnectHidNative(byte[] btAddress, boolean reconnectAllowed); private native boolean getProtocolModeNative(byte[] btAddress); diff --git a/system/btif/include/btif_hh.h b/system/btif/include/btif_hh.h index b2e125053b..6e5fc80679 100644 --- a/system/btif/include/btif_hh.h +++ b/system/btif/include/btif_hh.h @@ -106,6 +106,7 @@ typedef struct { uint8_t dev_handle; RawAddress bd_addr; tBTA_HH_ATTR_MASK attr_mask; + bool reconnect_allowed; } btif_hh_added_device_t; /** @@ -130,7 +131,8 @@ extern btif_hh_cb_t btif_hh_cb; extern btif_hh_device_t* btif_hh_find_connected_dev_by_handle(uint8_t handle); extern void btif_hh_remove_device(RawAddress bd_addr); extern bool btif_hh_add_added_dev(const RawAddress& bda, - tBTA_HH_ATTR_MASK attr_mask); + tBTA_HH_ATTR_MASK attr_mask, + bool reconnect_allowed); extern bt_status_t btif_hh_virtual_unplug(const RawAddress* bd_addr); extern void btif_hh_disconnect(RawAddress* bd_addr); extern void btif_hh_setreport(btif_hh_device_t* p_dev, diff --git a/system/btif/include/btif_storage.h b/system/btif/include/btif_storage.h index 5ffb9daf4a..fd76d581f5 100644 --- a/system/btif/include/btif_storage.h +++ b/system/btif/include/btif_storage.h @@ -200,6 +200,29 @@ bt_status_t btif_storage_load_bonded_devices(void); /******************************************************************************* * + * Function btif_storage_set_hid_connection_policy + * + * Description Stores connection policy info in nvram + * + * Returns BT_STATUS_SUCCESS + * + ******************************************************************************/ +bt_status_t btif_storage_set_hid_connection_policy(const RawAddress& addr, + bool reconnect_allowed); +/******************************************************************************* + * + * Function btif_storage_get_hid_connection_policy + * + * Description get connection policy info from nvram + * + * Returns BT_STATUS_SUCCESS + * + ******************************************************************************/ +bt_status_t btif_storage_get_hid_connection_policy(const RawAddress& addr, + bool* reconnect_allowed); + +/******************************************************************************* + * * Function btif_storage_add_hid_device_info * * Description BTIF storage API - Adds the hid information of bonded hid diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index 38986b951a..f3753a5786 100644 --- a/system/btif/src/btif_hh.cc +++ b/system/btif/src/btif_hh.cc @@ -308,6 +308,24 @@ btif_hh_device_t* btif_hh_find_connected_dev_by_handle(uint8_t handle) { return &btif_hh_cb.devices[i]; } } + return nullptr; +} + +/******************************************************************************* + * + * Function btif_hh_find_added_dev + * + * Description Return the added device pointer of the specified address + * + * Returns Added device entry + ******************************************************************************/ +btif_hh_added_device_t* btif_hh_find_added_dev(const RawAddress& addr) { + for (int i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) { + btif_hh_added_device_t* added_dev = &btif_hh_cb.added_devices[i]; + if (added_dev->bd_addr == addr) { + return added_dev; + } + } return NULL; } @@ -351,6 +369,23 @@ static btif_hh_device_t* btif_hh_find_connected_dev_by_bda( return NULL; } +static bool btif_hh_connection_allowed(const RawAddress& bda) { + /* Accept connection only if reconnection is allowed for the known device, or + * outgoing connection was requested */ + btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(bda); + if (added_dev != nullptr && added_dev->reconnect_allowed) { + LOG_VERBOSE("Connection allowed %s", PRIVATE_ADDRESS(bda)); + return true; + } else if (btif_hh_cb.pending_conn_address == bda) { + LOG_VERBOSE("Device connection was pending for: %s, status: %s", + PRIVATE_ADDRESS(bda), + btif_hh_status_text(btif_hh_cb.status).c_str()); + return true; + } + + return false; +} + /******************************************************************************* * * Function btif_hh_stop_vup_timer @@ -396,7 +431,8 @@ void btif_hh_start_vup_timer(const RawAddress* bd_addr) { * * Returns true if add successfully, otherwise false. ******************************************************************************/ -bool btif_hh_add_added_dev(const RawAddress& bda, tBTA_HH_ATTR_MASK attr_mask) { +bool btif_hh_add_added_dev(const RawAddress& bda, tBTA_HH_ATTR_MASK attr_mask, + bool reconnect_allowed) { int i; for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) { if (btif_hh_cb.added_devices[i].bd_addr == bda) { @@ -410,6 +446,7 @@ bool btif_hh_add_added_dev(const RawAddress& bda, tBTA_HH_ATTR_MASK attr_mask) { btif_hh_cb.added_devices[i].bd_addr = bda; btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE; btif_hh_cb.added_devices[i].attr_mask = attr_mask; + btif_hh_cb.added_devices[i].reconnect_allowed = reconnect_allowed; return true; } } @@ -784,9 +821,26 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { p_data->status); break; - case BTA_HH_OPEN_EVT: + case BTA_HH_OPEN_EVT: { BTIF_TRACE_WARNING("%s: BTA_HH_OPN_EVT: handle=%d, status =%d", __func__, p_data->conn.handle, p_data->conn.status); + + if (!btif_hh_connection_allowed(p_data->conn.bda)) { + LOG_WARN("Reject incoming HID Connection, device: %s", + PRIVATE_ADDRESS(p_data->conn.bda)); + btif_hh_device_t* p_dev = + btif_hh_find_connected_dev_by_handle(p_data->conn.handle); + if (p_dev != nullptr) { + p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED; + } + + btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED; + BTA_HhClose(p_data->conn.handle); + HAL_CBACK(bt_hh_callbacks, connection_state_cb, &p_data->conn.bda, + BTHH_CONN_STATE_DISCONNECTED); + return; + } + btif_hh_cb.pending_conn_address = RawAddress::kEmpty; if (p_data->conn.status == BTA_HH_OK) { p_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle); @@ -845,6 +899,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED; } break; + } case BTA_HH_CLOSE_EVT: BTIF_TRACE_DEBUG("BTA_HH_CLOSE_EVT: status = %d, handle = %d", @@ -1018,7 +1073,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { p_data->dscp_info.version, p_data->dscp_info.ctry_code, len, p_data->dscp_info.descriptor.dsc_list); - if (btif_hh_add_added_dev(p_dev->bd_addr, p_dev->attr_mask)) { + if (btif_hh_add_added_dev(p_dev->bd_addr, p_dev->attr_mask, true)) { tBTA_HH_DEV_DSCP_INFO dscp_info; bt_status_t ret; btif_hh_copy_hid_info(&dscp_info, &p_data->dscp_info); @@ -1034,6 +1089,8 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { p_data->dscp_info.ssr_min_tout, len, p_data->dscp_info.descriptor.dsc_list); + btif_storage_set_hid_connection_policy(p_dev->bd_addr, true); + ASSERTC(ret == BT_STATUS_SUCCESS, "storing hid info failed", ret); BTIF_TRACE_WARNING("BTA_HH_GET_DSCP_EVT: Called add device"); @@ -1321,6 +1378,13 @@ static bt_status_t init(bthh_callbacks_t* callbacks) { ******************************************************************************/ static bt_status_t connect(RawAddress* bd_addr) { if (btif_hh_cb.status != BTIF_HH_DEV_CONNECTING) { + /* If the device was already added, ensure that reconnections are allowed */ + btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(*bd_addr); + if (added_dev != nullptr && !added_dev->reconnect_allowed) { + added_dev->reconnect_allowed = true; + btif_storage_set_hid_connection_policy(*bd_addr, true); + } + btif_transfer_context(btif_hh_handle_evt, BTIF_HH_CONNECT_REQ_EVT, (char*)bd_addr, sizeof(RawAddress), NULL); return BT_STATUS_SUCCESS; @@ -1341,7 +1405,7 @@ static bt_status_t connect(RawAddress* bd_addr) { * Returns bt_status_t * ******************************************************************************/ -static bt_status_t disconnect(RawAddress* bd_addr) { +static bt_status_t disconnect(RawAddress* bd_addr, bool reconnect_allowed) { CHECK_BTHH_INIT(); BTIF_TRACE_EVENT("BTHH: %s", __func__); btif_hh_device_t* p_dev; @@ -1351,6 +1415,17 @@ static bt_status_t disconnect(RawAddress* bd_addr) { btif_hh_cb.status); return BT_STATUS_FAIL; } + + if (!reconnect_allowed) { + LOG_INFO("Incoming reconnections disabled for device %s", + PRIVATE_ADDRESS((*bd_addr))); + btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(*bd_addr); + if (added_dev != nullptr && added_dev->reconnect_allowed) { + added_dev->reconnect_allowed = false; + btif_storage_set_hid_connection_policy(added_dev->bd_addr, false); + } + } + p_dev = btif_hh_find_connected_dev_by_bda(*bd_addr); if (p_dev != NULL) { return btif_transfer_context(btif_hh_handle_evt, BTIF_HH_DISCONNECT_REQ_EVT, @@ -1482,9 +1557,10 @@ static bt_status_t set_info(RawAddress* bd_addr, bthh_hid_info_t hid_info) { (uint8_t*)osi_malloc(dscp_info.descriptor.dl_len); memcpy(dscp_info.descriptor.dsc_list, &(hid_info.dsc_list), hid_info.dl_len); - if (btif_hh_add_added_dev(*bd_addr, hid_info.attr_mask)) { + if (btif_hh_add_added_dev(*bd_addr, hid_info.attr_mask, true)) { BTA_HhAddDev(*bd_addr, hid_info.attr_mask, hid_info.sub_class, hid_info.app_id, dscp_info); + btif_storage_set_hid_connection_policy(*bd_addr, true); } osi_free_and_reset((void**)&dscp_info.descriptor.dsc_list); diff --git a/system/btif/src/btif_storage.cc b/system/btif/src/btif_storage.cc index fc7a4375e9..4cac3c1a5a 100644 --- a/system/btif/src/btif_storage.cc +++ b/system/btif/src/btif_storage.cc @@ -114,6 +114,8 @@ using bluetooth::groups::DeviceGroups; #define BTIF_STORAGE_LEAUDIO_SOURCE_SUPPORTED_CONTEXT_TYPE \ "SourceSupportedContextType" +#define BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED "HidReConnectAllowed" + /* This is a local property to add a device found */ #define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF @@ -1515,6 +1517,49 @@ bool btif_storage_get_remote_device_type(const RawAddress& remote_bd_addr, /******************************************************************************* * + * Function btif_storage_set_hid_connection_policy + * + * Description Stores connection policy info in nvram + * + * Returns BT_STATUS_SUCCESS + * + ******************************************************************************/ +bt_status_t btif_storage_set_hid_connection_policy(const RawAddress& addr, + bool reconnect_allowed) { + std::string bdstr = addr.ToString(); + + if (btif_config_set_int(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED, + reconnect_allowed)) { + return BT_STATUS_SUCCESS; + } else { + return BT_STATUS_FAIL; + } +} + +/******************************************************************************* + * + * Function btif_storage_get_hid_connection_policy + * + * Description get connection policy info from nvram + * + * Returns BT_STATUS_SUCCESS + * + ******************************************************************************/ +bt_status_t btif_storage_get_hid_connection_policy(const RawAddress& addr, + bool* reconnect_allowed) { + std::string bdstr = addr.ToString(); + + // For backward compatibility, assume that the reconnection is allowed in the + // absence of the key + int value = 1; + btif_config_get_int(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED, &value); + *reconnect_allowed = (value != 0); + + return BT_STATUS_SUCCESS; +} + +/******************************************************************************* + * * Function btif_storage_add_hid_device_info * * Description BTIF storage API - Adds the hid information of bonded hid @@ -1608,8 +1653,11 @@ bt_status_t btif_storage_load_bonded_hid_info(void) { (uint8_t*)dscp_info.descriptor.dsc_list, &len); } + bool reconnect_allowed = false; + btif_storage_get_hid_connection_policy(bd_addr, &reconnect_allowed); + // add extracted information to BTA HH - if (btif_hh_add_added_dev(bd_addr, attr_mask)) { + if (btif_hh_add_added_dev(bd_addr, attr_mask, reconnect_allowed)) { BTA_HhAddDev(bd_addr, attr_mask, sub_class, app_id, dscp_info); } } @@ -1641,6 +1689,7 @@ bt_status_t btif_storage_remove_hid_info(const RawAddress& remote_bd_addr) { btif_config_remove(bdstr, "HidSSRMaxLatency"); btif_config_remove(bdstr, "HidSSRMinTimeout"); btif_config_remove(bdstr, "HidDescriptor"); + btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED); btif_config_save(); return BT_STATUS_SUCCESS; } diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs index 28216ff39a..a58e68e7d8 100644 --- a/system/gd/rust/linux/stack/src/bluetooth.rs +++ b/system/gd/rust/linux/stack/src/bluetooth.rs @@ -1412,7 +1412,7 @@ impl IBluetooth for Bluetooth { if self.uuid_helper.is_profile_enabled(&p) { match p { Profile::Hid | Profile::Hogp => { - self.hh.as_ref().unwrap().disconnect(&mut addr.unwrap()); + self.hh.as_ref().unwrap().disconnect(&mut addr.unwrap(), true); } Profile::A2dpSink | Profile::A2dpSource => { diff --git a/system/gd/rust/topshim/src/profiles/hid_host.rs b/system/gd/rust/topshim/src/profiles/hid_host.rs index db447be9d2..15f1f27a1b 100644 --- a/system/gd/rust/topshim/src/profiles/hid_host.rs +++ b/system/gd/rust/topshim/src/profiles/hid_host.rs @@ -208,7 +208,7 @@ impl HidHost { pub fn disconnect(&self, addr: &mut RawAddress) -> BtStatus { let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress); - BtStatus::from(ccall!(self, disconnect, ffi_addr)) + BtStatus::from(ccall!(self, disconnect, ffi_addr, true)) } pub fn virtual_unplug(&self, addr: &mut RawAddress) -> BtStatus { diff --git a/system/include/hardware/bt_hh.h b/system/include/hardware/bt_hh.h index dfe47f778a..c64e465e37 100644 --- a/system/include/hardware/bt_hh.h +++ b/system/include/hardware/bt_hh.h @@ -173,7 +173,7 @@ typedef struct { bt_status_t (*connect)(RawAddress* bd_addr); /** dis-connect from hid device */ - bt_status_t (*disconnect)(RawAddress* bd_addr); + bt_status_t (*disconnect)(RawAddress* bd_addr, bool reconnect_allowed); /** Virtual UnPlug (VUP) the specified HID device */ bt_status_t (*virtual_unplug)(RawAddress* bd_addr); |
