CVE-2024-49747 AI-generated analysis
platform/packages/modules/Bluetooth, GATT server (system/stack/gatt/gatt_sr.cc)
Adds an early return in four GATT server request handlers in system/stack/gatt/gatt_sr.cc when the transmit payload size returned for the channel is 0 (channel already closed), so a response buffer sized from that zero length is never allocated and written past.
Root cause
In gatt_sr.cc, gatts_process_primary_service_req, gatts_process_find_info, gatts_process_read_by_type_req and gatts_process_read_req obtain payload_size from gatt_tcb_get_payload_size_tx(tcb, cid) (gatt_tcb_get_payload_size on Android 15) and use it to size the response buffer: sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET. Per the commit message, in exceptional cases the channel can already be closed when the function is called, so it returns 0. The handlers then build the response into a buffer with no room for payload, and subsequent processing writes out of bounds.
How the fix works
- system/stack/gatt/gatt_sr.cc:gatts_process_primary_service_req: after payload_size = gatt_tcb_get_payload_size_tx(tcb, cid), return immediately if payload_size == 0, before msg_len is computed and p_msg is allocated.
- system/stack/gatt/gatt_sr.cc:gatts_process_find_info: same zero check inserted after obtaining payload_size and before buf_len is computed.
- system/stack/gatt/gatt_sr.cc:gatts_process_read_by_type_req: same zero check inserted before msg_len / osi_calloc.
- system/stack/gatt/gatt_sr.cc:gatts_process_read_req: same zero check inserted before buf_len is computed.
- All four checks are identical trivial validity checks (no flag, 'Flag: EXEMPT trivial validity checks'). No error response is sent; the request is simply dropped.
Completeness
- Covers the four handlers in the diff that allocate a response buffer from the transmit payload size: primary service request, find information, read by type, and read request.
- gatt_build_primary_service_rsp (code context at android-security-14.0.0_r29, line 540) also calls gatt_tcb_get_payload_size_tx and uses payload_size only in a 'p_msg->len + p_msg->offset > payload_size' bounds check, after already writing the opcode and length byte into p_msg. This commit does not change it. Whether it can be reached with a zero payload size depends on its callers, which the material does not show.
- Other handlers in gatt_sr.cc (for example write, execute write or MTU paths) are not shown in the material, so it is unknown whether any of them size buffers from the same function without a zero check.
Behavior changes
- Primary service, find info, read by type and read requests received when the channel payload size resolves to 0 (channel closed) are now silently dropped: no response and no ATT error response is sent, and no buffer is allocated.
- No other behavioral change is visible in the diff. Requests on an open channel are processed as before.
Per major
- Android 14: same fix: commit c7468e64bb5e in android-security-14.0.0_r15 (cherry-pick of 7de5617f7d52), four zero checks after gatt_tcb_get_payload_size_tx; 8/8 patched lines present at android-security-14.0.0_r29.
- Android 15: same fix: commit 339ea2fc1905 in android-security-15.0.0_r3, identical four checks; the existing accessor on this branch is gatt_tcb_get_payload_size(tcb, cid). 8/8 patched lines present at android-security-15.0.0_r17.
- Android 16: not affected (not listed by the bulletin); 5/8 lines of the patched region present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin); 5/8 lines of the patched region present at android-security-17.0.0_r1.
Unknowns
- The exact sequence by which the channel becomes closed while a request is still being dispatched to these handlers (the commit only says 'exceptional cases').
- Whether gatt_tcb_get_payload_size_tx can return 0 in any situation other than a closed channel.
- Whether other gatt_sr.cc handlers not shown in the material use the payload size without a zero check.
- Why only 5/8 patched-region lines match on Android 16/17; that code is not shown.