From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Brian Delwiche Date: Tue, 11 Oct 2022 21:23:22 +0000 Subject: [PATCH] Prevent use-after-free of HID reports BTA sends the the HID report pointer to BTIF and deallocates it immediately. This is now prevented by providing a deep copy callback function for HID reports when tranferring context from BTA to BTIF. This is a backport of change Icef7a7ed1185b4283ee4fe4f812ca154d8f1b825, already merged on T for b/227620181. Bug: 228837201 Test: Validated against researcher POC, ran BT unit tests, played audio manually. Tag: #security Ignore-AOSP-First: Security (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:874c495c886cd8722625756dc5fd0634b16b4f42) Merged-In: Ib837f395883de2369207f1b3b974d6bff02dcb19 Change-Id: Ib837f395883de2369207f1b3b974d6bff02dcb19 --- btif/src/btif_hh.c | 49 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c index a4057cca5..69e87b9f8 100644 --- a/btif/src/btif_hh.c +++ b/btif/src/btif_hh.c @@ -1093,6 +1093,38 @@ static void btif_hh_upstreams_evt(UINT16 event, char* p_param) } } +/******************************************************************************* + * + * Function btif_hh_hsdata_rpt_copy_cb + * + * Description Deep copies the tBTA_HH_HSDATA structure + * + * Returns void + * + ******************************************************************************/ + +static void btif_hh_hsdata_rpt_copy_cb(UINT16 event, char* p_dest, + char* p_src) { + tBTA_HH_HSDATA* p_dst_data = (tBTA_HH_HSDATA*)p_dest; + tBTA_HH_HSDATA* p_src_data = (tBTA_HH_HSDATA*)p_src; + BT_HDR* hdr; + + if (!p_src) { + BTIF_TRACE_ERROR("%s: Nothing to copy", __func__); + return; + } + + memcpy(p_dst_data, p_src_data, sizeof(tBTA_HH_HSDATA)); + + hdr = p_src_data->rsp_data.p_rpt_data; + if (hdr != NULL) { + UINT8* p_data = ((UINT8*)p_dst_data) + sizeof(tBTA_HH_HSDATA); + memcpy(p_data, hdr, BT_HDR_SIZE + hdr->offset + hdr->len); + + p_dst_data->rsp_data.p_rpt_data = (BT_HDR*)p_data; + } +} + /******************************************************************************* ** ** Function bte_hh_evt @@ -1107,6 +1139,7 @@ static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH *p_data) { bt_status_t status; int param_len = 0; + tBTIF_COPY_CBACK* p_copy_cback = NULL; if (BTA_HH_ENABLE_EVT == event) param_len = sizeof(tBTA_HH_STATUS); @@ -1118,16 +1151,26 @@ static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH *p_data) param_len = sizeof(tBTA_HH_CBDATA); else if (BTA_HH_GET_DSCP_EVT == event) param_len = sizeof(tBTA_HH_DEV_DSCP_INFO); - else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_RPT_EVT == event)|| (BTA_HH_GET_IDLE_EVT == event)) + else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_IDLE_EVT == event)) param_len = sizeof(tBTA_HH_HSDATA); - else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) || (BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event)) + else if (BTA_HH_GET_RPT_EVT == event) { + BT_HDR* hdr = p_data->hs_data.rsp_data.p_rpt_data; + param_len = sizeof(tBTA_HH_HSDATA); + + if (hdr != NULL) { + p_copy_cback = btif_hh_hsdata_rpt_copy_cb; + param_len += BT_HDR_SIZE + hdr->offset + hdr->len; + } + } else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) || + (BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event)) param_len = sizeof(tBTA_HH_CBDATA); else if ((BTA_HH_ADD_DEV_EVT == event) || (BTA_HH_RMV_DEV_EVT == event) ) param_len = sizeof(tBTA_HH_DEV_INFO); else if (BTA_HH_API_ERR_EVT == event) param_len = 0; /* switch context to btif task context (copy full union size for convenience) */ - status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL); + status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event, + (void*)p_data, param_len, p_copy_cback); /* catch any failed context transfers */ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);