diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 00eb1e4baf633d837c72bcff71cccbafdc720113..51503631100de567d1a13be1440fa64550304a6f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,11 @@ stages: - auto-merge-main + - update-from-upstream + include: - project: 'e/templates' ref: master file: '/gitlab-ci/.gitlab-ci-auto-merge-main.yml' + - project: 'e/templates' + ref: master + file: '/gitlab-ci/.gitlab-ci-import-updates-from-upstream.yml' diff --git a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp index f25e208d977c2e8c79c101f5bd961f880a1fe41c..cffd1c614535ecedc5da6333ec5a863d7c7af976 100644 --- a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +++ b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp @@ -673,6 +673,7 @@ static void callback_thread_event(bt_cb_thread_evt event) { } vm->DetachCurrentThread(); sHaveCallbackThread = false; + callbackEnv = NULL; } } diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp index 03517fc645eba3800b4585cdd92e95987c22a4da..d553e795d138811cb5f9551416ef8fc2026ece45 100644 --- a/android/app/jni/com_android_bluetooth_gatt.cpp +++ b/android/app/jni/com_android_bluetooth_gatt.cpp @@ -1714,7 +1714,7 @@ static void gattClientScanFilterAddNative(JNIEnv* env, jobject object, curr.company_mask = env->GetIntField(current.get(), companyMaskFid); - curr.ad_type = env->GetByteField(current.get(), adTypeFid); + curr.ad_type = env->GetIntField(current.get(), adTypeFid); ScopedLocalRef data( env, (jbyteArray)env->GetObjectField(current.get(), dataFid)); diff --git a/android/app/jni/com_android_bluetooth_hid_host.cpp b/android/app/jni/com_android_bluetooth_hid_host.cpp index 7a164233bc1b5d7e315691c80f0e5364db3b3666..18ba315129c1376610fb79264cbe4ad14b8d6e22 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/Utils.java b/android/app/src/com/android/bluetooth/Utils.java index b22b3aa03384a13a604fce1602454f495a60eef9..6b56600c1f7b04aa26cc63609b988f6b8c68debc 100644 --- a/android/app/src/com/android/bluetooth/Utils.java +++ b/android/app/src/com/android/bluetooth/Utils.java @@ -466,10 +466,10 @@ public final class Utils { } // STOPSHIP(b/188391719): enable this security enforcement // attributionSource.enforceCallingUid(); - AttributionSource currentAttribution = new AttributionSource - .Builder(context.getAttributionSource()) - .setNext(attributionSource) - .build(); + AttributionSource currentAttribution = + new AttributionSource.Builder(context.getAttributionSource()) + .setNext(Objects.requireNonNull(attributionSource)) + .build(); PermissionManager pm = context.getSystemService(PermissionManager.class); if (pm == null) { return false; @@ -718,10 +718,10 @@ public final class Utils { Log.e(TAG, "Permission denial: Location is off."); return false; } - AttributionSource currentAttribution = new AttributionSource - .Builder(context.getAttributionSource()) - .setNext(attributionSource) - .build(); + AttributionSource currentAttribution = + new AttributionSource.Builder(context.getAttributionSource()) + .setNext(Objects.requireNonNull(attributionSource)) + .build(); // STOPSHIP(b/188391719): enable this security enforcement // attributionSource.enforceCallingUid(); PermissionManager pm = context.getSystemService(PermissionManager.class); @@ -752,10 +752,10 @@ public final class Utils { return false; } - final AttributionSource currentAttribution = new AttributionSource - .Builder(context.getAttributionSource()) - .setNext(attributionSource) - .build(); + final AttributionSource currentAttribution = + new AttributionSource.Builder(context.getAttributionSource()) + .setNext(Objects.requireNonNull(attributionSource)) + .build(); // STOPSHIP(b/188391719): enable this security enforcement // attributionSource.enforceCallingUid(); PermissionManager pm = context.getSystemService(PermissionManager.class); @@ -790,10 +790,10 @@ public final class Utils { return false; } - AttributionSource currentAttribution = new AttributionSource - .Builder(context.getAttributionSource()) - .setNext(attributionSource) - .build(); + AttributionSource currentAttribution = + new AttributionSource.Builder(context.getAttributionSource()) + .setNext(Objects.requireNonNull(attributionSource)) + .build(); // STOPSHIP(b/188391719): enable this security enforcement // attributionSource.enforceCallingUid(); PermissionManager pm = context.getSystemService(PermissionManager.class); diff --git a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java index c6633daab224af12794f2e0903d9fc526903a226..6d64cfd1113a1743d2830408dcd18c027e3c62cb 100644 --- a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java +++ b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.Message; import android.os.UserHandle; import android.util.Log; +import android.util.Pair; import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.Utils; @@ -48,6 +49,7 @@ import com.android.internal.util.StateMachine; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -384,7 +386,37 @@ final class BondStateMachine extends StateMachine { return false; } + // Defining these properly would break current api + private static int PERIPHERAL_GAMEPAD = BluetoothClass.Device.Major.PERIPHERAL | 0x08; + private static int PERIPHERAL_REMOTE = BluetoothClass.Device.Major.PERIPHERAL | 0x0C; + + private static List> accConfirmSkip = new ArrayList<>(); + + static { + // Jarvis, SHIELD Remote 2015 + accConfirmSkip.add(new Pair<>("SHIELD Remote", PERIPHERAL_REMOTE)); + // Thunderstrike, SHIELD Controller 2017 + accConfirmSkip.add(new Pair<>("NVIDIA Controller v01.04", PERIPHERAL_GAMEPAD)); + }; + + private boolean isSkipConfirmationAccessory(BluetoothDevice device) { + for (Pair entry : accConfirmSkip) { + if (device.getName().equals(entry.first) + && device.getBluetoothClass().getDeviceClass() == entry.second) { + return true; + } + } + + return false; + } + private void sendDisplayPinIntent(byte[] address, Optional maybePin, int variant) { + BluetoothDevice device = mRemoteDevices.getDevice(address); + if (device != null && device.isBondingInitiatedLocally() + && isSkipConfirmationAccessory(device)) { + device.setPairingConfirmation(true); + return; + } Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevices.getDevice(address)); maybePin.ifPresent(pin -> intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin)); diff --git a/android/app/src/com/android/bluetooth/hid/HidHostService.java b/android/app/src/com/android/bluetooth/hid/HidHostService.java index 7352d5833bc9bf2c5a59ce5518b3ee6fde79e8a6..ffd6b0a70bd4a3b88bd02c2c6256afb58bec9d36 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 b2e125053bc672458d27159cd075de0e3bb73d26..6e5fc80679648e56bd635480902047a73266378f 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 5ffb9daf4ac5e6d1d2dda90c6491c39d1e35832e..fd76d581f51aecda7ef72183607e0c332ffd469f 100644 --- a/system/btif/include/btif_storage.h +++ b/system/btif/include/btif_storage.h @@ -198,6 +198,29 @@ void btif_storage_load_le_devices(void); ******************************************************************************/ 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 diff --git a/system/btif/src/btif_avrcp_audio_track.cc b/system/btif/src/btif_avrcp_audio_track.cc index 8ca5c979855302389d10d63848ccd007febca0a2..e17f80f5f74d7097627055c95a110971c4c77420 100644 --- a/system/btif/src/btif_avrcp_audio_track.cc +++ b/system/btif/src/btif_avrcp_audio_track.cc @@ -23,6 +23,8 @@ #include #include +#include + #include "bt_target.h" #include "osi/include/log.h" @@ -152,7 +154,7 @@ static size_t transcodeQ15ToFloat(uint8_t* buffer, size_t length, BtifAvrcpAudioTrack* trackHolder) { size_t sampleSize = sampleSizeFor(trackHolder); size_t i = 0; - for (; i <= length / sampleSize; i++) { + for (; i < std::min(trackHolder->bufferLength, length / sampleSize); i++) { trackHolder->buffer[i] = ((int16_t*)buffer)[i] * kScaleQ15ToFloat; } return i * sampleSize; @@ -162,7 +164,7 @@ static size_t transcodeQ23ToFloat(uint8_t* buffer, size_t length, BtifAvrcpAudioTrack* trackHolder) { size_t sampleSize = sampleSizeFor(trackHolder); size_t i = 0; - for (; i <= length / sampleSize; i++) { + for (; i < std::min(trackHolder->bufferLength, length / sampleSize); i++) { size_t offset = i * sampleSize; int32_t sample = *((int32_t*)(buffer + offset - 1)) & 0x00FFFFFF; trackHolder->buffer[i] = sample * kScaleQ23ToFloat; @@ -174,7 +176,7 @@ static size_t transcodeQ31ToFloat(uint8_t* buffer, size_t length, BtifAvrcpAudioTrack* trackHolder) { size_t sampleSize = sampleSizeFor(trackHolder); size_t i = 0; - for (; i <= length / sampleSize; i++) { + for (; i < std::min(trackHolder->bufferLength, length / sampleSize); i++) { trackHolder->buffer[i] = ((int32_t*)buffer)[i] * kScaleQ31ToFloat; } return i * sampleSize; diff --git a/system/btif/src/btif_gatt_util.cc b/system/btif/src/btif_gatt_util.cc index 55788b094ef9bf59af67af919b21a53a0e9350a1..1d341d85558e549d6ccc8bab76f9c30c7d564833 100644 --- a/system/btif/src/btif_gatt_util.cc +++ b/system/btif/src/btif_gatt_util.cc @@ -18,6 +18,8 @@ #define LOG_TAG "bt_btif_gatt" +#include + #include "btif_gatt_util.h" #include @@ -52,9 +54,9 @@ using bluetooth::Uuid; void btif_to_bta_response(tGATTS_RSP* p_dest, btgatt_response_t* p_src) { p_dest->attr_value.auth_req = p_src->attr_value.auth_req; p_dest->attr_value.handle = p_src->attr_value.handle; - p_dest->attr_value.len = p_src->attr_value.len; + p_dest->attr_value.len = std::min(p_src->attr_value.len, GATT_MAX_ATTR_LEN); p_dest->attr_value.offset = p_src->attr_value.offset; - memcpy(p_dest->attr_value.value, p_src->attr_value.value, GATT_MAX_ATTR_LEN); + memcpy(p_dest->attr_value.value, p_src->attr_value.value, p_dest->attr_value.len); } /******************************************************************************* diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index 38986b951a0c474a7ba9bbf3c47329957fb25acb..f3753a5786506720915f0c75eb0cefcc2d8d802a 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 7be5f37e66b40eddb54de85e7f6222ac5f13dc1f..4cac3c1a5ac549b8eb02ab6f9cf77cebd8ae0724 100644 --- a/system/btif/src/btif_storage.cc +++ b/system/btif/src/btif_storage.cc @@ -92,10 +92,13 @@ using bluetooth::groups::DeviceGroups; #define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode" #define BTIF_STORAGE_KEY_LOCAL_IO_CAPS "LocalIOCaps" #define BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE "LocalIOCapsBLE" +#define BTIF_STORAGE_KEY_MAX_SESSION_KEY_SIZE "MaxSessionKeySize" #define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout" #define BTIF_STORAGE_KEY_GATT_CLIENT_SUPPORTED "GattClientSupportedFeatures" #define BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH "GattClientDatabaseHash" #define BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED "GattServerSupportedFeatures" +#define BTIF_STORAGE_KEY_SECURE_CONNECTIONS_SUPPORTED \ + "SecureConnectionsSupported" #define BTIF_STORAGE_DEVICE_GROUP_BIN "DeviceGroupBin" #define BTIF_STORAGE_CSIS_AUTOCONNECT "CsisAutoconnect" #define BTIF_STORAGE_CSIS_SET_INFO_BIN "CsisSetInfoBin" @@ -111,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 @@ -291,6 +296,14 @@ static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) { btif_config_set_int(bdstr, BT_CONFIG_KEY_REMOTE_VER_SUBVER, info->sub_ver); } break; + case BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED: + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_SECURE_CONNECTIONS_SUPPORTED, + *(uint8_t*)prop->val); + break; + case BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE: + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_MAX_SESSION_KEY_SIZE, + *(uint8_t*)prop->val); + break; default: BTIF_TRACE_ERROR("Unknown prop type:%d", prop->type); @@ -417,6 +430,26 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { } } break; + case BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED: { + int val; + + if (prop->len >= (int)sizeof(uint8_t)) { + ret = btif_config_get_int( + bdstr, BTIF_STORAGE_KEY_SECURE_CONNECTIONS_SUPPORTED, &val); + *(uint8_t*)prop->val = (uint8_t)val; + } + } break; + + case BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE: { + int val; + + if (prop->len >= (int)sizeof(uint8_t)) { + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_MAX_SESSION_KEY_SIZE, + &val); + *(uint8_t*)prop->val = (uint8_t)val; + } + } break; + default: BTIF_TRACE_ERROR("Unknow prop type:%d", prop->type); return false; @@ -1482,6 +1515,49 @@ bool btif_storage_get_remote_device_type(const RawAddress& remote_bd_addr, return ret; } +/******************************************************************************* + * + * 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 @@ -1577,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); } } @@ -1610,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 28216ff39ac4010fad886a85dfa99e2331aedac2..a58e68e7d865c194eff9bd5d14e11881bb90f3de 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 db447be9d247db4a5e71df1969fc6f7f5a588545..15f1f27a1b3ecb98146fcd5c537504acbb231d4e 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/bluetooth.h b/system/include/hardware/bluetooth.h index 4fbc628de6720de075de13133573f453579f8c89..fcbe63d3f9f4131a92773d1c9408d257da18a205 100644 --- a/system/include/hardware/bluetooth.h +++ b/system/include/hardware/bluetooth.h @@ -339,6 +339,20 @@ typedef enum { */ BT_PROPERTY_REMOTE_IS_COORDINATED_SET_MEMBER, + /** + * Description - Whether remote device supports Secure Connections mode + * Access mode - GET and SET. + * Data Type - uint8_t. + */ + BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED, + + /** + * Description - Maximum observed session key for remote device + * Access mode - GET and SET. + * Data Type - uint8_t. + */ + BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE, + BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF, } bt_property_type_t; diff --git a/system/include/hardware/bt_hh.h b/system/include/hardware/bt_hh.h index dfe47f778aac0b5a5259cb243afed7f72d477177..c64e465e374df48b3a5f7a41eb49da2c391dde18 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); diff --git a/system/main/Android.bp b/system/main/Android.bp index 8f8a245a095fb3168569addab8ac4a3db8717bcf..e64f62d3055973ae6c9d132038017dff10b6ab61 100644 --- a/system/main/Android.bp +++ b/system/main/Android.bp @@ -188,6 +188,7 @@ cc_test { "shim/metrics_api.cc", "shim/shim.cc", "shim/stack.cc", + "shim/utils.cc", "test/common_stack_test.cc", "test/main_shim_dumpsys_test.cc", "test/main_shim_test.cc", diff --git a/system/main/shim/Android.bp b/system/main/shim/Android.bp index b8aca32fa18548d73398eb5013d16a8df5516c3f..ce39d300ac37a2df805a498b55bf57f6ad93c470 100644 --- a/system/main/shim/Android.bp +++ b/system/main/shim/Android.bp @@ -29,5 +29,6 @@ filegroup { "metrics_api.cc", "shim.cc", "stack.cc", - ] + "utils.cc", + ], } diff --git a/system/main/shim/BUILD.gn b/system/main/shim/BUILD.gn index 8362dd8c95f2a7a34cca59efdb5451bc194b41ba..2c6a88b8648e313e748fc602bd11129dd6ac44fd 100644 --- a/system/main/shim/BUILD.gn +++ b/system/main/shim/BUILD.gn @@ -35,6 +35,7 @@ source_set("LibBluetoothShimSources") { "metrics_api.cc", "shim.cc", "stack.cc", + "utils.cc", ] include_dirs = [ diff --git a/system/main/shim/le_advertising_manager.cc b/system/main/shim/le_advertising_manager.cc index 317d2db6dc396667f717352fb012ebd6e2526ced..82648762fc99bf2150df74a3934c8e14dba74db2 100644 --- a/system/main/shim/le_advertising_manager.cc +++ b/system/main/shim/le_advertising_manager.cc @@ -17,6 +17,7 @@ #define LOG_TAG "bt_shim_advertiser" #include "le_advertising_manager.h" +#include "utils.h" #include #include @@ -43,6 +44,7 @@ using bluetooth::hci::AddressType; using bluetooth::hci::ErrorCode; using bluetooth::hci::GapData; using bluetooth::hci::OwnAddressType; +using bluetooth::shim::parse_gap_data; using std::vector; namespace { @@ -88,23 +90,8 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, void SetData(int advertiser_id, bool set_scan_rsp, vector data, StatusCallback cb) override { LOG(INFO) << __func__ << " in shim layer"; - - size_t offset = 0; std::vector advertising_data = {}; - - while (offset < data.size()) { - GapData gap_data; - uint8_t len = data[offset]; - auto begin = data.begin() + offset; - auto end = begin + len + 1; // 1 byte for len - auto data_copy = std::make_shared>(begin, end); - bluetooth::packet::PacketView packet( - data_copy); - GapData::Parse(&gap_data, packet.begin()); - advertising_data.push_back(gap_data); - offset += len + 1; // 1 byte for len - } - + parse_gap_data(data, advertising_data); bluetooth::shim::GetAdvertising()->SetData(advertiser_id, set_scan_rsp, advertising_data); } @@ -128,33 +115,8 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, bluetooth::hci::ExtendedAdvertisingConfig config{}; parse_parameter(config, params); - size_t offset = 0; - while (offset < advertise_data.size()) { - GapData gap_data; - uint8_t len = advertise_data[offset]; - auto begin = advertise_data.begin() + offset; - auto end = begin + len + 1; // 1 byte for len - auto data_copy = std::make_shared>(begin, end); - bluetooth::packet::PacketView packet( - data_copy); - GapData::Parse(&gap_data, packet.begin()); - config.advertisement.push_back(gap_data); - offset += len + 1; // 1 byte for len - } - - offset = 0; - while (offset < scan_response_data.size()) { - GapData gap_data; - uint8_t len = scan_response_data[offset]; - auto begin = scan_response_data.begin() + offset; - auto end = begin + len + 1; // 1 byte for len - auto data_copy = std::make_shared>(begin, end); - bluetooth::packet::PacketView packet( - data_copy); - GapData::Parse(&gap_data, packet.begin()); - config.scan_response.push_back(gap_data); - offset += len + 1; // 1 byte for len - } + parse_gap_data(advertise_data, config.advertisement); + parse_gap_data(scan_response_data, config.scan_response); bluetooth::shim::GetAdvertising()->StartAdvertising( advertiser_id, config, timeout_s * 100, cb, timeout_cb, scan_callback, @@ -180,47 +142,9 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, periodic_params.periodic_advertising_properties; config.periodic_advertising_parameters = periodic_parameters; - size_t offset = 0; - while (offset < advertise_data.size()) { - GapData gap_data; - uint8_t len = advertise_data[offset]; - auto begin = advertise_data.begin() + offset; - auto end = begin + len + 1; // 1 byte for len - auto data_copy = std::make_shared>(begin, end); - bluetooth::packet::PacketView packet( - data_copy); - GapData::Parse(&gap_data, packet.begin()); - config.advertisement.push_back(gap_data); - offset += len + 1; // 1 byte for len - } - - offset = 0; - while (offset < scan_response_data.size()) { - GapData gap_data; - uint8_t len = scan_response_data[offset]; - auto begin = scan_response_data.begin() + offset; - auto end = begin + len + 1; // 1 byte for len - auto data_copy = std::make_shared>(begin, end); - bluetooth::packet::PacketView packet( - data_copy); - GapData::Parse(&gap_data, packet.begin()); - config.scan_response.push_back(gap_data); - offset += len + 1; // 1 byte for len - } - - offset = 0; - while (offset < periodic_data.size()) { - GapData gap_data; - uint8_t len = periodic_data[offset]; - auto begin = periodic_data.begin() + offset; - auto end = begin + len + 1; // 1 byte for len - auto data_copy = std::make_shared>(begin, end); - bluetooth::packet::PacketView packet( - data_copy); - GapData::Parse(&gap_data, packet.begin()); - config.periodic_data.push_back(gap_data); - offset += len + 1; // 1 byte for len - } + parse_gap_data(advertise_data, config.advertisement); + parse_gap_data(scan_response_data, config.scan_response); + parse_gap_data(periodic_data, config.periodic_data); bluetooth::hci::AdvertiserId id = bluetooth::shim::GetAdvertising()->ExtendedCreateAdvertiser( @@ -249,23 +173,8 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, void SetPeriodicAdvertisingData(int advertiser_id, std::vector data, StatusCallback cb) override { LOG(INFO) << __func__ << " in shim layer"; - - size_t offset = 0; std::vector advertising_data = {}; - - while (offset < data.size()) { - GapData gap_data; - uint8_t len = data[offset]; - auto begin = data.begin() + offset; - auto end = begin + len + 1; // 1 byte for len - auto data_copy = std::make_shared>(begin, end); - bluetooth::packet::PacketView packet( - data_copy); - GapData::Parse(&gap_data, packet.begin()); - advertising_data.push_back(gap_data); - offset += len + 1; // 1 byte for len - } - + parse_gap_data(data, advertising_data); bluetooth::shim::GetAdvertising()->SetPeriodicData(advertiser_id, advertising_data); } diff --git a/system/main/shim/utils.cc b/system/main/shim/utils.cc new file mode 100644 index 0000000000000000000000000000000000000000..9f18ddc4f76ee49b2c50f9fd5e5b1f7c828cebea --- /dev/null +++ b/system/main/shim/utils.cc @@ -0,0 +1,44 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils.h" + +namespace bluetooth { +namespace shim { +void parse_gap_data(const std::vector &raw_data, + std::vector &output) { + size_t offset = 0; + while (offset < raw_data.size()) { + hci::GapData gap_data; + uint8_t len = raw_data[offset]; + + if (offset + len + 1 > raw_data.size()) { + break; + } + + auto begin = raw_data.begin() + offset; + auto end = begin + len + 1; // 1 byte for len + auto data_copy = std::make_shared>(begin, end); + bluetooth::packet::PacketView packet( + data_copy); + hci::GapData::Parse(&gap_data, packet.begin()); + output.push_back(gap_data); + offset += len + 1; // 1 byte for len + } +} + +} // namespace shim +} // namespace bluetooth diff --git a/system/main/shim/utils.h b/system/main/shim/utils.h new file mode 100644 index 0000000000000000000000000000000000000000..56da2a0a0ae42740642addd02ed2f2abf935b56e --- /dev/null +++ b/system/main/shim/utils.h @@ -0,0 +1,32 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include + +#include "hci/hci_packets.h" + +namespace bluetooth { +namespace shim { +/** + * @brief Parsing gap data from raw bytes + * + * @param raw_data input, raw bytes + * @param output vector of GapData + */ +void parse_gap_data(const std::vector &raw_data, + std::vector &output); +} // namespace shim +} // namespace bluetooth diff --git a/system/service/logging_helpers.cc b/system/service/logging_helpers.cc index 78a24e600f5b4c47cf6cf804d4ae3557c2e9b14e..0c3644d2baaabfe731857f421a8124b70a07499c 100644 --- a/system/service/logging_helpers.cc +++ b/system/service/logging_helpers.cc @@ -118,6 +118,8 @@ const char* BtPropertyText(const bt_property_type_t prop) { CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_VERSION_INFO); CASE_RETURN_TEXT(BT_PROPERTY_LOCAL_LE_FEATURES); CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP); + CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED); + CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE); default: return "Invalid property"; } diff --git a/system/stack/btm/btm_ble.cc b/system/stack/btm/btm_ble.cc index 1227f99425d60efa5071c5d75802e60a03e5f821..d331d6505f4189cfe2d61beade85e0b4bb47255c 100644 --- a/system/stack/btm/btm_ble.cc +++ b/system/stack/btm/btm_ble.cc @@ -25,12 +25,15 @@ #define LOG_TAG "bt_btm_ble" +#include + #include #include "device/include/controller.h" #include "main/shim/btm_api.h" #include "main/shim/l2c_api.h" #include "main/shim/shim.h" +#include "openssl/mem.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" #include "stack/btm/btm_dev.h" @@ -48,8 +51,6 @@ #include "stack/include/smp_api.h" #include "types/raw_address.h" -#include - extern tBTM_CB btm_cb; extern bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, @@ -2061,7 +2062,7 @@ bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig, crypto_toolbox::aes_cmac(p_rec->ble.keys.pcsrk, p_orig, len, BTM_CMAC_TLEN_SIZE, p_mac); - if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) { + if (CRYPTO_memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) { btm_ble_increment_sign_ctr(bd_addr, false); verified = true; } diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc index d58ed8f4cac52eac399f2c0920fde2e5a3491966..3d334a0f0818f11d8b0cf9ef0a1f9422496d0ffa 100644 --- a/system/stack/btm/btm_ble_gap.cc +++ b/system/stack/btm/btm_ble_gap.cc @@ -935,6 +935,12 @@ void btm_ble_start_sync_request(uint8_t sid, RawAddress addr, uint16_t skip, uint8_t options = 0; uint8_t cte_type = 7; int index = btm_ble_get_psync_index(sid, addr); + + if (index == MAX_SYNC_TRANSACTION) { + LOG_ERROR("Failed to get sync transfer index"); + return; + } + tBTM_BLE_PERIODIC_SYNC* p = &btm_ble_pa_sync_cb.p_sync[index]; p->sync_state = PERIODIC_SYNC_PENDING; @@ -1008,6 +1014,11 @@ static void btm_ble_start_sync_timeout(void* data) { int index = btm_ble_get_psync_index(adv_sid, address); + if (index == MAX_SYNC_TRANSACTION) { + LOG_ERROR("Failed to get sync transfer index"); + return; + } + tBTM_BLE_PERIODIC_SYNC* p = &btm_ble_pa_sync_cb.p_sync[index]; if (BleScanningManager::IsInitialized()) { @@ -1211,11 +1222,14 @@ void BTM_BleStartPeriodicSync(uint8_t adv_sid, RawAddress address, SyncLostCb lostCb) { LOG_DEBUG("%s", "[PSync]"); int index = btm_ble_get_free_psync_index(); - tBTM_BLE_PERIODIC_SYNC* p = &btm_ble_pa_sync_cb.p_sync[index]; + if (index == MAX_SYNC_TRANSACTION) { syncCb.Run(BTM_NO_RESOURCES, 0, adv_sid, BLE_ADDR_RANDOM, address, 0, 0); return; } + + tBTM_BLE_PERIODIC_SYNC* p = &btm_ble_pa_sync_cb.p_sync[index]; + p->in_use = true; p->remote_bda = address; p->sid = adv_sid; @@ -1347,6 +1361,12 @@ void BTM_BlePeriodicSyncTransfer(RawAddress addr, uint16_t service_data, } int index = btm_ble_get_free_sync_transfer_index(); + if (index == MAX_SYNC_TRANSACTION) { + BTM_TRACE_ERROR("Failed to get sync transfer index"); + cb.Run(BTM_ILLEGAL_VALUE, addr); + return; + } + tBTM_BLE_PERIODIC_SYNC_TRANSFER* p_sync_transfer = &btm_ble_pa_sync_cb.sync_transfer[index]; p_sync_transfer->in_use = true; @@ -1386,6 +1406,12 @@ void BTM_BlePeriodicSyncSetInfo(RawAddress addr, uint16_t service_data, } int index = btm_ble_get_free_sync_transfer_index(); + if (index == MAX_SYNC_TRANSACTION) { + BTM_TRACE_ERROR("Failed to get sync transfer index"); + cb.Run(BTM_ILLEGAL_VALUE, addr); + return; + } + tBTM_BLE_PERIODIC_SYNC_TRANSFER* p_sync_transfer = &btm_ble_pa_sync_cb.sync_transfer[index]; p_sync_transfer->in_use = true; @@ -1411,6 +1437,16 @@ void btm_ble_biginfo_adv_report_rcvd(uint8_t* p, uint16_t param_len) { uint16_t sync_handle, iso_interval, max_pdu, max_sdu; uint8_t num_bises, nse, bn, pto, irc, phy, framing, encryption; uint32_t sdu_interval; + + // 2 bytes for sync handle, 1 byte for num_bises, 1 byte for nse, 2 bytes for + // iso_interval, 1 byte each for bn, pto, irc, 2 bytes for max_pdu, 3 bytes + // for sdu_interval, 2 bytes for max_sdu, 1 byte each for phy, framing, + // encryption + if (param_len < 19) { + LOG_ERROR("Insufficient data"); + return; + } + STREAM_TO_UINT16(sync_handle, p); STREAM_TO_UINT8(num_bises, p); STREAM_TO_UINT8(nse, p); @@ -2540,20 +2576,27 @@ void btm_ble_process_ext_adv_pkt(uint8_t data_len, const uint8_t* data) { advertising_sid; int8_t rssi, tx_power; uint16_t event_type, periodic_adv_int, direct_address_type; + size_t bytes_to_process; /* Only process the results if the inquiry is still active */ if (!btm_cb.ble_ctr_cb.is_ble_scan_active()) return; + bytes_to_process = 1; + + if (data_len < bytes_to_process) { + LOG(ERROR) << "Malformed LE extended advertising packet: not enough room " + "for num reports"; + return; + } + /* Extract the number of reports in this event. */ STREAM_TO_UINT8(num_reports, p); - constexpr int extended_report_header_size = 24; while (num_reports--) { - if (p + extended_report_header_size > data + data_len) { - // TODO(jpawlowski): we should crash the stack here - BTM_TRACE_ERROR( - "Malformed LE Extended Advertising Report Event from controller - " - "can't loop the data"); + bytes_to_process += 24; + if (data_len < bytes_to_process) { + LOG(ERROR) << "Malformed LE extended advertising packet: not enough room " + "for metadata"; return; } @@ -2573,8 +2616,11 @@ void btm_ble_process_ext_adv_pkt(uint8_t data_len, const uint8_t* data) { const uint8_t* pkt_data = p; p += pkt_data_len; /* Advance to the the next packet*/ - if (p > data + data_len) { - LOG(ERROR) << "Invalid pkt_data_len: " << +pkt_data_len; + + bytes_to_process += pkt_data_len; + if (data_len < bytes_to_process) { + LOG(ERROR) << "Malformed LE extended advertising packet: not enough room " + "for packet data"; return; } @@ -2607,18 +2653,28 @@ void btm_ble_process_adv_pkt(uint8_t data_len, const uint8_t* data) { const uint8_t* p = data; uint8_t legacy_evt_type, addr_type, num_reports, pkt_data_len; int8_t rssi; + size_t bytes_to_process; /* Only process the results if the inquiry is still active */ if (!btm_cb.ble_ctr_cb.is_ble_scan_active()) return; + bytes_to_process = 1; + + if (data_len < bytes_to_process) { + LOG(ERROR) + << "Malformed LE advertising packet: not enough room for num reports"; + return; + } + /* Extract the number of reports in this event. */ STREAM_TO_UINT8(num_reports, p); - constexpr int report_header_size = 10; while (num_reports--) { - if (p + report_header_size > data + data_len) { - // TODO(jpawlowski): we should crash the stack here - BTM_TRACE_ERROR("Malformed LE Advertising Report Event from controller"); + bytes_to_process += 9; + + if (data_len < bytes_to_process) { + LOG(ERROR) + << "Malformed LE advertising packet: not enough room for metadata"; return; } @@ -2630,8 +2686,12 @@ void btm_ble_process_adv_pkt(uint8_t data_len, const uint8_t* data) { const uint8_t* pkt_data = p; p += pkt_data_len; /* Advance to the the rssi byte */ - if (p > data + data_len - sizeof(rssi)) { - LOG(ERROR) << "Invalid pkt_data_len: " << +pkt_data_len; + + // include rssi for this check + bytes_to_process += pkt_data_len + 1; + if (data_len < bytes_to_process) { + LOG(ERROR) << "Malformed LE advertising packet: not enough room for " + "packet data and/or RSSI"; return; } diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc index 22d4ad45a52ab4e61daff9970278d9ee3c590f28..c2efbd55b98a51ffb0508778009d6be1ed1d1230 100644 --- a/system/stack/btm/btm_sec.cc +++ b/system/stack/btm/btm_sec.cc @@ -217,6 +217,127 @@ static bool btm_dev_16_digit_authenticated(tBTM_SEC_DEV_REC* p_dev_rec) { return (false); } +/******************************************************************************* + * + * Function btm_sec_is_device_sc_downgrade + * + * Description Check for a stored device record matching the candidate + * device, and return true if the stored device has reported + * that it supports Secure Connections mode and the candidate + * device reports that it does not. Otherwise, return false. + * + * Returns bool + * + ******************************************************************************/ +static bool btm_sec_is_device_sc_downgrade(uint16_t hci_handle, + bool secure_connections_supported) { + if (secure_connections_supported) return false; + + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle); + if (p_dev_rec == nullptr) return false; + + uint8_t property_val = 0; + bt_property_t property = { + .type = BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED, + .len = sizeof(uint8_t), + .val = &property_val}; + + bt_status_t cached = + btif_storage_get_remote_device_property(&p_dev_rec->bd_addr, &property); + + if (cached == BT_STATUS_FAIL) return false; + + return (bool)property_val; +} + +/******************************************************************************* + * + * Function btm_sec_store_device_sc_support + * + * Description Save Secure Connections support for this device to file + * + ******************************************************************************/ + +static void btm_sec_store_device_sc_support(uint16_t hci_handle, + bool secure_connections_supported) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle); + if (p_dev_rec == nullptr) return; + + uint8_t property_val = (uint8_t)secure_connections_supported; + bt_property_t property = { + .type = BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED, + .len = sizeof(uint8_t), + .val = &property_val}; + + btif_storage_set_remote_device_property(&p_dev_rec->bd_addr, &property); +} + +/******************************************************************************* + * + * Function btm_sec_is_session_key_size_downgrade + * + * Description Check if there is a stored device record matching this + * handle, and return true if the stored record has a lower + * session key size than the candidate device. + * + * Returns bool + * + ******************************************************************************/ +bool btm_sec_is_session_key_size_downgrade(uint16_t hci_handle, + uint8_t key_size) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle); + if (p_dev_rec == nullptr) return false; + + uint8_t property_val = 0; + bt_property_t property = {.type = BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE, + .len = sizeof(uint8_t), + .val = &property_val}; + + bt_status_t cached = + btif_storage_get_remote_device_property(&p_dev_rec->bd_addr, &property); + + if (cached == BT_STATUS_FAIL) return false; + + return property_val > key_size; +} + +/******************************************************************************* + * + * Function btm_sec_update_session_key_size + * + * Description Store the max session key size to disk, if possible. + * + ******************************************************************************/ +void btm_sec_update_session_key_size(uint16_t hci_handle, uint8_t key_size) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle); + if (p_dev_rec == nullptr) return; + + uint8_t property_val = key_size; + bt_property_t property = {.type = BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE, + .len = sizeof(uint8_t), + .val = &property_val}; + + btif_storage_set_remote_device_property(&p_dev_rec->bd_addr, &property); +} + +/******************************************************************************* + * + * Function access_secure_service_from_temp_bond + * + * Description a utility function to test whether an access to + * secure service from temp bonding is happening + * + * Returns true if the aforementioned condition holds, + * false otherwise + * + ******************************************************************************/ +static bool access_secure_service_from_temp_bond(const tBTM_SEC_DEV_REC* p_dev_rec, + bool locally_initiated, + uint16_t security_req) { + return !locally_initiated && (security_req & BTM_SEC_IN_AUTHENTICATE) && + p_dev_rec->is_bond_type_temporary(); +} + /******************************************************************************* * * Function BTM_SecRegister @@ -1619,9 +1740,14 @@ tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( } if (rc == BTM_SUCCESS) { + if (access_secure_service_from_temp_bond(p_dev_rec, is_originator, security_required)) { + LOG_ERROR("Trying to access a secure service from a temp bonding, rejecting"); + rc = BTM_FAILED_ON_SECURITY; + } + if (p_callback) - (*p_callback)(&bd_addr, transport, (void*)p_ref_data, BTM_SUCCESS); - return (BTM_SUCCESS); + (*p_callback)(&bd_addr, transport, (void*)p_ref_data, rc); + return (rc); } } @@ -1637,15 +1763,15 @@ tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( btm_cb.security_mode == BTM_SEC_MODE_SC) { if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) { if (is_originator) { - /* SM4 to SM4 -> always authenticate & encrypt */ - security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT); + /* SM4 to SM4 -> always encrypt */ + security_required |= BTM_SEC_OUT_ENCRYPT; } else /* acceptor */ { /* SM4 to SM4: the acceptor needs to make sure the authentication is * already done */ chk_acp_auth_done = true; - /* SM4 to SM4 -> always authenticate & encrypt */ - security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT); + /* SM4 to SM4 -> always encrypt */ + security_required |= BTM_SEC_IN_ENCRYPT; } } else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) { /* the remote features are not known yet */ @@ -1884,6 +2010,11 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, security_required, p_callback, p_ref_data); } else /* rc == BTM_SUCCESS */ { + if (access_secure_service_from_temp_bond(p_dev_rec, + is_originator, security_required)) { + LOG_ERROR("Trying to access a secure rfcomm service from a temp bonding, reject"); + rc = BTM_FAILED_ON_SECURITY; + } if (p_callback) { LOG_DEBUG("Notifying client that security access has been granted"); (*p_callback)(&bd_addr, transport, p_ref_data, rc); @@ -3981,6 +4112,13 @@ void btm_sec_link_key_notification(const RawAddress& p_bda, } } + if (p_dev_rec->is_bond_type_persistent() && + (p_dev_rec->is_device_type_br_edr() || + p_dev_rec->is_device_type_dual_mode())) { + btm_sec_store_device_sc_support(p_dev_rec->get_br_edr_hci_handle(), + p_dev_rec->SupportsSecureConnections()); + } + /* If name is not known at this point delay calling callback until the name is */ /* resolved. Unless it is a HID Device and we really need to send all link @@ -4394,48 +4532,67 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) { /* If connection is not authenticated and authentication is required */ /* start authentication and return PENDING to the caller */ - if ((((!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) && - ((p_dev_rec->IsLocallyInitiated() && - (p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)) || - (!p_dev_rec->IsLocallyInitiated() && - (p_dev_rec->security_required & BTM_SEC_IN_AUTHENTICATE)))) || - (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) && - (!p_dev_rec->IsLocallyInitiated() && - (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) && - (p_dev_rec->hci_handle != HCI_INVALID_HANDLE)) { - /* - * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use, - * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the - * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM - * authenticated connections, hence we cannot distinguish here. - */ - - LOG_DEBUG("Security Manager: Start authentication"); + if (p_dev_rec->hci_handle != HCI_INVALID_HANDLE) { + bool start_auth = false; + + // Check link status of BR/EDR + if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) { + if (p_dev_rec->IsLocallyInitiated()) { + if (p_dev_rec->security_required & + (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) { + LOG_DEBUG("Outgoing authentication/encryption Required"); + start_auth = true; + } + } else { + if (p_dev_rec->security_required & + (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) { + LOG_DEBUG("Incoming authentication/encryption Required"); + start_auth = true; + } + } + } - /* - * If we do have a link-key, but we end up here because we need an - * upgrade, then clear the link-key known and authenticated flag before - * restarting authentication. - * WARNING: If the controller has link-key, it is optional and - * recommended for the controller to send a Link_Key_Request. - * In case we need an upgrade, the only alternative would be to delete - * the existing link-key. That could lead to very bad user experience - * or even IOP issues, if a reconnect causes a new connection that - * requires an upgrade. - */ - if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) && - (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) && - (!p_dev_rec->IsLocallyInitiated() && - (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) { - p_dev_rec->sec_flags &= - ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | - BTM_SEC_AUTHENTICATED); + if (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)) { + /* + * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use, + * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the + * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM + * authenticated connections, hence we cannot distinguish here. + */ + if (!p_dev_rec->IsLocallyInitiated()) { + if (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) { + LOG_DEBUG("BTM_SEC_IN_MIN_16_DIGIT_PIN Required"); + start_auth = true; + } + } } - btm_sec_wait_and_start_authentication(p_dev_rec); - return (BTM_CMD_STARTED); - } else { - LOG_DEBUG("Authentication not required"); + if (start_auth) { + LOG_DEBUG("Security Manager: Start authentication"); + + /* + * If we do have a link-key, but we end up here because we need an + * upgrade, then clear the link-key known and authenticated flag before + * restarting authentication. + * WARNING: If the controller has link-key, it is optional and + * recommended for the controller to send a Link_Key_Request. + * In case we need an upgrade, the only alternative would be to delete + * the existing link-key. That could lead to very bad user experience + * or even IOP issues, if a reconnect causes a new connection that + * requires an upgrade. + */ + if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) && + (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) && + (!p_dev_rec->IsLocallyInitiated() && + (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) { + p_dev_rec->sec_flags &= + ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | + BTM_SEC_AUTHENTICATED); + } + + btm_sec_wait_and_start_authentication(p_dev_rec); + return (BTM_CMD_STARTED); + } } /* If connection is not encrypted and encryption is required */ @@ -4463,6 +4620,13 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) { return (BTM_FAILED_ON_SECURITY); } + if (access_secure_service_from_temp_bond(p_dev_rec, + p_dev_rec->IsLocallyInitiated(), + p_dev_rec->security_required)) { + LOG_ERROR("Trying to access a secure service from a temp bonding, rejecting"); + return (BTM_FAILED_ON_SECURITY); + } + /* All required security procedures already established */ p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE | @@ -5041,6 +5205,16 @@ void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported, tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle); if (p_dev_rec == nullptr) return; + // Drop the connection here if the remote attempts to downgrade from Secure + // Connections mode. + if (btm_sec_is_device_sc_downgrade(hci_handle, sc_supported)) { + acl_set_disconnect_reason(HCI_ERR_HOST_REJECT_SECURITY); + btm_sec_send_hci_disconnect( + p_dev_rec, HCI_ERR_AUTH_FAILURE, hci_handle, + "attempted to downgrade from Secure Connections mode"); + return; + } + p_dev_rec->remote_feature_received = true; p_dev_rec->remote_supports_hci_role_switch = hci_role_switch_supported; diff --git a/system/stack/btm/btm_sec.h b/system/stack/btm/btm_sec.h index 0acb6ca19404570a55dc58d6eacc9fa576e79c11..282cb3c95e80dcf4b603a5fed2d09e592d2c576a 100644 --- a/system/stack/btm/btm_sec.h +++ b/system/stack/btm/btm_sec.h @@ -805,5 +805,28 @@ void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported, void btm_sec_cr_loc_oob_data_cback_event(const RawAddress& address, tSMP_LOC_OOB_DATA loc_oob_data); +/******************************************************************************* + * + * Function btm_sec_is_session_key_size_downgrade + * + * Description Check if there is a stored device record matching this + * handle, and return true if the stored record has a lower + * session key size than the candidate device. + * + * Returns bool + * + ******************************************************************************/ +bool btm_sec_is_session_key_size_downgrade(uint16_t hci_handle, + uint8_t key_size); + +/******************************************************************************* + * + * Function btm_sec_update_session_key_size + * + * Description Store the max session key size to disk, if possible. + * + ******************************************************************************/ +void btm_sec_update_session_key_size(uint16_t hci_handle, uint8_t key_size); + // Return DEV_CLASS (uint8_t[3]) of bda. If record doesn't exist, create one. const uint8_t* btm_get_dev_class(const RawAddress& bda); diff --git a/system/stack/btu/btu_hcif.cc b/system/stack/btu/btu_hcif.cc index ec05df2e13dd5f40cf24c7c320e3ae4537466b00..a64878bc93f8c37c86f7a675eea95f595f383a1c 100644 --- a/system/stack/btu/btu_hcif.cc +++ b/system/stack/btu/btu_hcif.cc @@ -1035,6 +1035,20 @@ static void read_encryption_key_size_complete_after_encryption_change(uint8_t st return; } + if (btm_sec_is_session_key_size_downgrade(handle, key_size)) { + LOG_ERROR( + "encryption key size lower than cached value, disconnecting. " + "handle: 0x%x attempted key size: %d", + handle, key_size); + acl_disconnect_from_handle( + handle, HCI_ERR_HOST_REJECT_SECURITY, + "stack::btu::btu_hcif::read_encryption_key_size_complete_after_" + "encryption_change Key Size Downgrade"); + return; + } + + btm_sec_update_session_key_size(handle, key_size); + // good key size - succeed btm_acl_encrypt_change(handle, static_cast(status), 1 /* enable */); @@ -1693,6 +1707,12 @@ static void btu_ble_data_length_change_evt(uint8_t* p, uint16_t evt_len) { return; } + // 2 bytes each for handle, tx_data_len, TxTimer, rx_data_len + if (evt_len < 8) { + LOG_ERROR("Event packet too short"); + return; + } + STREAM_TO_UINT16(handle, p); STREAM_TO_UINT16(tx_data_len, p); p += 2; /* Skip the TxTimer */ diff --git a/system/stack/gatt/att_protocol.cc b/system/stack/gatt/att_protocol.cc index ef4a3a6846038b4ba3ee90e7e584f40c38a472e1..a0e48e386ace85633cec9470530db85e49554259 100644 --- a/system/stack/gatt/att_protocol.cc +++ b/system/stack/gatt/att_protocol.cc @@ -164,7 +164,13 @@ static BT_HDR* attp_build_read_by_type_value_cmd( uint16_t payload_size, tGATT_FIND_TYPE_VALUE* p_value_type) { uint8_t* p; uint16_t len = p_value_type->value_len; - BT_HDR* p_buf = + BT_HDR* p_buf = nullptr; + + if (payload_size < 5) { + return nullptr; + } + + p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -280,46 +286,80 @@ static BT_HDR* attp_build_opcode_cmd(uint8_t op_code) { static BT_HDR* attp_build_value_cmd(uint16_t payload_size, uint8_t op_code, uint16_t handle, uint16_t offset, uint16_t len, uint8_t* p_data) { - uint8_t *p, *pp, pair_len, *p_pair_len; + uint8_t *p, *pp, *p_pair_len; + size_t pair_len; + size_t size_now = 1; + +#define CHECK_SIZE() \ + do { \ + if (size_now > payload_size) { \ + LOG_ERROR("payload size too small"); \ + osi_free(p_buf); \ + return nullptr; \ + } \ + } while (false) + BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET); p = pp = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; + + CHECK_SIZE(); UINT8_TO_STREAM(p, op_code); p_buf->offset = L2CAP_MIN_OFFSET; - p_buf->len = 1; if (op_code == GATT_RSP_READ_BY_TYPE) { - p_pair_len = p; + p_pair_len = p++; pair_len = len + 2; - UINT8_TO_STREAM(p, pair_len); - p_buf->len += 1; + size_now += 1; + CHECK_SIZE(); + // this field will be backfilled in the end of this function } + if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) { + size_now += 2; + CHECK_SIZE(); UINT16_TO_STREAM(p, handle); - p_buf->len += 2; } if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE) { + size_now += 2; + CHECK_SIZE(); UINT16_TO_STREAM(p, offset); - p_buf->len += 2; } if (len > 0 && p_data != NULL) { /* ensure data not exceed MTU size */ - if (payload_size - p_buf->len < len) { - len = payload_size - p_buf->len; + if (payload_size - size_now < len) { + len = payload_size - size_now; /* update handle value pair length */ - if (op_code == GATT_RSP_READ_BY_TYPE) *p_pair_len = (len + 2); + if (op_code == GATT_RSP_READ_BY_TYPE) { + pair_len = (len + 2); + } LOG(WARNING) << StringPrintf( "attribute value too long, to be truncated to %d", len); } + size_now += len; + CHECK_SIZE(); ARRAY_TO_STREAM(p, p_data, len); - p_buf->len += len; } + // backfill pair len field + if (op_code == GATT_RSP_READ_BY_TYPE) { + if (pair_len > UINT8_MAX) { + LOG_ERROR("pair_len greater than %d", UINT8_MAX); + osi_free(p_buf); + return nullptr; + } + + *p_pair_len = (uint8_t)pair_len; + } + +#undef CHECK_SIZE + + p_buf->len = (uint16_t)size_now; return p_buf; } diff --git a/system/stack/include/sec_hci_link_interface.h b/system/stack/include/sec_hci_link_interface.h index dce3c479fd8afaf02ccaf25e6d1e12bc456a1990..1fecde74ed1d91d59f014b3d46953d35a9fb42ef 100644 --- a/system/stack/include/sec_hci_link_interface.h +++ b/system/stack/include/sec_hci_link_interface.h @@ -37,6 +37,8 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status); void btm_sec_disconnected(uint16_t handle, tHCI_STATUS reason, std::string); void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, uint8_t encr_enable); +bool btm_sec_is_session_key_size_downgrade(uint16_t hci_handle, + uint8_t key_size); void btm_sec_link_key_notification(const RawAddress& p_bda, const Octet16& link_key, uint8_t key_type); void btm_sec_link_key_request(const uint8_t* p_event); @@ -46,4 +48,5 @@ void btm_sec_rmt_name_request_complete(const RawAddress* bd_addr, const uint8_t* bd_name, tHCI_STATUS status); void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset); +void btm_sec_update_session_key_size(uint16_t hci_handle, uint8_t key_size); void btm_simple_pair_complete(const uint8_t* p); diff --git a/system/stack/sdp/sdp_utils.cc b/system/stack/sdp/sdp_utils.cc index 79bb131d794ff6e6a24dc126f78a83fb2d389032..d67e77441d35dcd557385e587082a3e724fbb494 100644 --- a/system/stack/sdp/sdp_utils.cc +++ b/system/stack/sdp/sdp_utils.cc @@ -1114,8 +1114,28 @@ bool sdpu_compare_uuid_arrays(const uint8_t* p_uuid1, uint32_t len1, ******************************************************************************/ bool sdpu_compare_uuid_with_attr(const Uuid& uuid, tSDP_DISC_ATTR* p_attr) { int len = uuid.GetShortestRepresentationSize(); - if (len == 2) return uuid.As16Bit() == p_attr->attr_value.v.u16; - if (len == 4) return uuid.As32Bit() == p_attr->attr_value.v.u32; + if (len == 2) { + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == Uuid::kNumBytes16) { + return uuid.As16Bit() == p_attr->attr_value.v.u16; + } else { + LOG(ERROR) << "invalid length for discovery attribute"; + return (false); + } + } + if (len == 4) { + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == Uuid::kNumBytes32) { + return uuid.As32Bit() == p_attr->attr_value.v.u32; + } else { + LOG(ERROR) << "invalid length for discovery attribute"; + return (false); + } + } + + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) != Uuid::kNumBytes128) { + LOG(ERROR) << "invalid length for discovery attribute"; + return (false); + } + if (memcmp(uuid.To128BitBE().data(), (void*)p_attr->attr_value.v.array, Uuid::kNumBytes128) == 0) return (true); diff --git a/system/stack/smp/smp_act.cc b/system/stack/smp/smp_act.cc index 3c8218e9fec7567b0cc42c26e0f95f6acca14147..d6021bbecd2ec95d28d9b495f5691f7c408712cf 100644 --- a/system/stack/smp/smp_act.cc +++ b/system/stack/smp/smp_act.cc @@ -291,6 +291,7 @@ void smp_send_pair_rsp(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_send_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { SMP_TRACE_DEBUG("%s", __func__); smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb); + p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM_SENT; } /******************************************************************************* @@ -436,6 +437,13 @@ void smp_send_ltk_reply(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description process security request. ******************************************************************************/ void smp_proc_sec_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { + if (smp_command_has_invalid_length(p_cb)) { + tSMP_INT_DATA smp_int_data; + smp_int_data.status = SMP_INVALID_PARAMETERS; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); + return; + } + tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ*)p_data->p_data; tBTM_BLE_SEC_REQ_ACT sec_req_act; @@ -658,6 +666,17 @@ void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { return; } + if (!((p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) && + (p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT)) && + !(p_cb->flags & SMP_PAIR_FLAGS_CMD_CONFIRM_SENT)) { + // in legacy pairing, the peer should send its rand after + // we send our confirm + tSMP_INT_DATA smp_int_data{}; + smp_int_data.status = SMP_INVALID_PARAMETERS; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); + return; + } + /* save the SRand for comparison */ STREAM_TO_ARRAY(p_cb->rrand.data(), p, OCTET16_LEN); } diff --git a/system/stack/smp/smp_int.h b/system/stack/smp/smp_int.h index 5e731806de77e70e1735e43debf2fa91e2c9a370..b2ab4776421bbd6d15819baef338f4917668b002 100644 --- a/system/stack/smp/smp_int.h +++ b/system/stack/smp/smp_int.h @@ -222,6 +222,7 @@ typedef union { (1 << 7) /* used to resolve race condition */ #define SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY \ (1 << 8) /* used on peripheral to resolve race condition */ +#define SMP_PAIR_FLAGS_CMD_CONFIRM_SENT (1 << 9) /* check if authentication requirement need MITM protection */ #define SMP_NO_MITM_REQUIRED(x) (((x)&SMP_AUTH_YN_BIT) == 0) diff --git a/system/test/mock/mock_stack_btm_sec.cc b/system/test/mock/mock_stack_btm_sec.cc index ea6ce175058b18553724ba17695d4acaa15a52cf..eeea0bd5827f259c9fdaa944ada1e8ac28294961 100644 --- a/system/test/mock/mock_stack_btm_sec.cc +++ b/system/test/mock/mock_stack_btm_sec.cc @@ -113,6 +113,11 @@ bool btm_sec_is_a_bonded_dev(const RawAddress& bda) { mock_function_count_map[__func__]++; return false; } +bool btm_sec_is_session_key_size_downgrade(uint16_t hci_handle, + uint8_t key_size) { + mock_function_count_map[__func__]++; + return false; +} bool is_sec_state_equal(void* data, void* context) { mock_function_count_map[__func__]++; return false; @@ -313,6 +318,9 @@ void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported, void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset) { mock_function_count_map[__func__]++; } +void btm_sec_update_session_key_size(uint16_t hci_handle, uint8_t key_size) { + mock_function_count_map[__func__]++; +} void btm_simple_pair_complete(const uint8_t* p) { mock_function_count_map[__func__]++; }