CVE-2024-43096 AI-generated analysis
platform/packages/modules/Bluetooth, GATT server (system/stack/gatt) and EATT (system/stack/eatt)
Adds an mtu == 0 rejection at the top of build_read_multi_rsp in system/stack/gatt/gatt_sr.cc and clamps the EATT channel tx MTU to at least EATT_MIN_MTU_MPS in EattChannel::EattChannelSetTxMTU, so the Read Multiple response buffer is never allocated with zero payload room before the opcode byte is written.
Root cause
build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) allocates a BT_HDR buffer of size sizeof(BT_HDR) + L2CAP_MIN_OFFSET + mtu, sets p to (p_buf + 1) + L2CAP_MIN_OFFSET, and unconditionally writes the response opcode (GATT_RSP_READ_MULTI or GATT_RSP_READ_MULTI_VAR) at *p++ and sets p_buf->len = 1. With mtu == 0 the allocation has no payload bytes, so the opcode write lands one byte past the end of the osi_calloc'd buffer. Nothing validated mtu before the write. On the EATT side, EattChannelSetTxMTU only applied an upper clamp (std::min with EATT_MAX_TX_MTU), so a tx_mtu_ of 0 (or anything below the EATT minimum) could be stored. The code context shows it is called at eatt.h line 70, apparently from the EattChannel constructor. Per index search, it is also called with the peer-provided p_cfg->mtu in eatt_impl.h eatt_l2cap_reconfig_completed when !is_local_cfg.
How the fix works
- system/stack/gatt/gatt_sr.cc:build_read_multi_rsp: before computing len and calling osi_calloc, the fix checks `if (mtu == 0)`, logs "Invalid MTU" at ERROR, sets p_cmd->status = GATT_ILLEGAL_PARAMETER and returns. This prevents the zero-payload allocation and the subsequent opcode write past the buffer end.
- system/stack/eatt/eatt.h:EattChannel::EattChannelSetTxMTU: after the existing std::min clamp to EATT_MAX_TX_MTU, the fix adds `this->tx_mtu_ = std::max<uint16_t>(this->tx_mtu_, EATT_MIN_MTU_MPS)`, establishing a lower bound so an EATT channel's tx_mtu_ cannot be stored below EATT_MIN_MTU_MPS regardless of the value passed in.
- Both hunks are in a single commit (bfe316cf9f02 on Android 14, 5318ec44af65 on Android 15). The gatt_sr.cc check is the direct guard. The eatt.h clamp hardens the EATT tx MTU value, but the material does not show that this value is what is passed as mtu to build_read_multi_rsp.
Completeness
- Covers: the exact mtu == 0 case in build_read_multi_rsp, which is the only value for which the one-byte opcode write at offset L2CAP_MIN_OFFSET exceeds the allocation; and the EATT tx_mtu_ setter, which is now floored at EATT_MIN_MTU_MPS.
- The check only rejects 0; values of 1 or more leave room for the opcode byte. The context shows an is_overflow variable declared in the function, but the per-handle overflow handling itself is not shown.
- The fix does not change how the caller obtains mtu for the non-EATT (fixed ATT channel) path; the material does not show that caller or whether its MTU source can be zero. The gatt_sr.cc check applies to all callers since it is inside build_read_multi_rsp.
- What the caller does when p_cmd->status is GATT_ILLEGAL_PARAMETER with no response built is not shown in the material.
Behavior changes
- build_read_multi_rsp with mtu == 0 now logs "Invalid MTU" at ERROR, sets p_cmd->status = GATT_ILLEGAL_PARAMETER, and returns without allocating or building a Read Multiple response.
- EattChannelSetTxMTU now clamps tx_mtu_ into [EATT_MIN_MTU_MPS, EATT_MAX_TX_MTU]; a peer-requested EATT MTU below EATT_MIN_MTU_MPS is raised to that minimum locally (per index search, this setter is used on the remote reconfiguration path in eatt_impl.h eatt_l2cap_reconfig_completed).
Per major
- Android 14: same fix: commit bfe316cf9f02 in android-security-14.0.0_r15 (Change-Id I18e4325dbc9d6814220332288c85b114d0415c2f, cherry-picked from internal commits cad927034a37, e5ab6c617683, 8d5c170681e7); at android-security-14.0.0_r29 all 6/6 lines of the patched region are present.
- Android 15: same fix: commit 5318ec44af65 in android-security-15.0.0_r3, identical hunks (only line offsets differ: gatt_sr.cc @@ -162 vs -149, eatt.h @@ -100 vs -99); at android-security-15.0.0_r17 6/6 lines present.
- Android 16: not affected (not listed by the bulletin); at android-security-16.0.0_r8 the patched region is present 6/6.
- Android 17: not affected (not listed by the bulletin); at android-security-17.0.0_r1 the patched region is present 6/6.
Unknowns
- The caller of build_read_multi_rsp, how it computes the mtu argument (EATT and fixed ATT channel paths), and what it does after status is set to GATT_ILLEGAL_PARAMETER are not shown.
- Whether the vulnerable condition requires pairing/bonding or is reachable pre-authentication is not stated in the material.
- Fix status and commit identifiers for Android 12, 12L and 13 (listed as affected) are not provided.
- The value of EATT_MIN_MTU_MPS is not shown in the material.