CVE-2024-0031 AI-generated analysis
platform/packages/modules/Bluetooth, system/stack/gatt (ATT protocol PDU builder, att_protocol.cc)
Adds an early return of nullptr in attp_build_read_by_type_value_cmd when payload_size is less than 5, so the fixed 5-byte ATT header (opcode + start handle + end handle) is never written into a heap buffer sized by a too-small payload_size.
Root cause
attp_build_read_by_type_value_cmd allocates a BT_HDR with payload_size + L2CAP_MIN_OFFSET bytes of body and then unconditionally streams 5 bytes (GATT_REQ_FIND_TYPE_VALUE opcode, s_handle, e_handle) plus the UUID and the value. No check ensured payload_size was at least as large as the fixed header. If payload_size was smaller than 5, the header write itself went past the allocation; in addition, the clamp `if (p_value_type->value_len + p_buf->len > payload_size) len = payload_size - p_buf->len;` computes payload_size - p_buf->len, which for payload_size < p_buf->len underflows when stored in the uint16_t len, making the following memcpy copy far more value data than the buffer holds.
How the fix works
- system/stack/gatt/att_protocol.cc:attp_build_read_by_type_value_cmd: p_buf is now initialized to nullptr and, before osi_malloc, the function returns nullptr if payload_size < 5. This guarantees the buffer can hold the 5-byte fixed header and prevents payload_size values below 5 (such as 0) from reaching the header write and the underflowing length clamp.
- Single-commit fix; no other files or functions changed. The commit was cherry-picked internally (Ignore-AOSP-First: security) and landed in android-security-14.0.0_r5.
Completeness
- Covers: payload_size values below the fixed 5-byte header (including 0), which were the direct trigger of writing the header past the allocation.
- Leaves out, judged from the code: the check does not account for the UUID appended by gatt_build_uuid_to_stream (up to 16 bytes, size depends on the UUID). For 5 <= payload_size < p_buf->len after the UUID is appended (for a 16-byte UUID, payload_size between 5 and 20), the UUID write still exceeds payload_size and `len = payload_size - p_buf->len` still underflows in uint16_t, so the subsequent memcpy length is not bounded by the allocation. Whether a caller can supply such a payload_size is not shown in the material.
- Callers are not changed to handle the new nullptr return; the material does not show whether callers already check for a null BT_HDR.
Behavior changes
- attp_build_read_by_type_value_cmd returns nullptr instead of a buffer when payload_size < 5; the Find By Type Value request is therefore not built in that case.
Per major
- Android 14: same fix: commit de53890aaca2 in android-security-14.0.0_r5 (internal cherry-pick, Ignore-AOSP-First); at android-security-14.0.0_r29 all 4 lines of the patched region are present.
- Android 15: not affected per the bulletin; at android-security-15.0.0_r17 4/4 lines of the patched region are present.
- Android 16: not affected per the bulletin; at android-security-16.0.0_r8 only 3/4 lines of the patched region are present; whether the payload_size < 5 check itself is present is not shown.
- Android 17: not affected per the bulletin; at android-security-17.0.0_r1 only 3/4 lines of the patched region are present; whether the payload_size < 5 check itself is present is not shown.
Unknowns
- Which caller(s) can pass payload_size < 5 and under what connection state (the material shows no callers).
- Whether callers check the new nullptr return value.
- Whether payload_size values between 5 and 20 are reachable in practice, which determines whether the residual UUID/clamp underflow path matters.
- Which line of the patched region differs at android-security-16.0.0_r8 and 17.0.0_r1, and whether the check is present there.
- Android 13 fix commit and tag (bulletin lists 13 as affected but no 13 material is provided).