CVE-2026-55269 AI-generated analysis
platform/packages/modules/Bluetooth, system/gd/hal SnoopLogger (btsnoop filtered logging)
Corrects an inverted size guard in SnoopLogger::FilterCapturedPacket. Short HCI ACL packets are now padded by EXTRA_BUF_SIZE before profile filtering writes the fixed "PROHIBITED" magic string into the packet buffer. The fix also clamps the output length to packet.size() + PACKET_TYPE_LENGTH.
Root cause
In system/gd/hal/snoop_logger.cc, SnoopLogger::FilterCapturedPacket is meant to grow the captured HciPacket by EXTRA_BUF_SIZE when the PBAP or MAP profile filter is enabled. That padding gives FilterProfiles (and SnoopLogger::PayloadStrip, per the commit message) room to write the fixed magic string "PROHIBITED" over the payload. The guard was written as `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE`, the opposite of the intent: only large packets were resized, and small packets (for example an 8-byte ACL packet) kept their original size. Per the commit message, the magic-string write then went past the end of the heap-allocated buffer.
How the fix works
- system/gd/hal/snoop_logger.cc:SnoopLogger::FilterCapturedPacket: the resize guard changes from `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE` to `packet.size() + EXTRA_BUF_SIZE <= DEFAULT_PACKET_SIZE`. Packets that still fit within DEFAULT_PACKET_SIZE after padding are now resized by EXTRA_BUF_SIZE before FilterProfiles is called on packet.data(), which gives the magic-string overwrite enough backing storage.
- system/gd/hal/snoop_logger.cc:SnoopLogger::FilterCapturedPacket: a new final statement `length = std::min(length, static_cast<uint32_t>(packet.size() + PACKET_TYPE_LENGTH));` caps the output length at the packet buffer size plus the packet type byte, on every path that reaches the end of the function. The early-return paths (A2DP media, and FilterProfiles returning 0) skip the clamp and leave length at 0. The commit message does not mention the clamp, and the material does not show how the caller uses length.
- system/gd/hal/snoop_logger_test.cc: two 8-byte ACL test packets (incoming CID 0x0041, outgoing CID 0x0040) are appended to kTestData. profiles_filtered_pbap_magic_test, profiles_filtered_pbap_header_test and profiles_filtered_pbap_fullfilter_test now create the logger with 20 instead of 15 as the first NewSnoopLogger argument, most likely to make room for the extra packets.
Completeness
- Covers the only resize site in FilterCapturedPacket that feeds FilterProfiles. The inverted guard is corrected, and a length clamp is added at the end of the function; paths that return early with length 0 do not reach it.
- Packets for which `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE` are still not resized, so the fix relies on such packets already being large enough for the magic string. The material does not show FilterProfiles or PayloadStrip gaining their own bounds checks, so safety depends on EXTRA_BUF_SIZE being at least the length of "PROHIBITED".
- The function still modifies the packet copy (the TODO b/335520123 in Capture about stopping this remains); the fix does not restructure that.
- The short-packet case is tested only through the PBAP filter tests; the diff adds no MAP-specific short-packet test.
Behavior changes
- Small ACL packets processed under PBAP/MAP filtering are now grown by EXTRA_BUF_SIZE. Large packets near DEFAULT_PACKET_SIZE are no longer grown (the inverted guard used to grow only those).
- For filtered ACL packets that reach the end of FilterCapturedPacket, the output length is now capped at packet.size() + PACKET_TYPE_LENGTH.
- In the PBAP filter unit tests, the first NewSnoopLogger argument changes from 15 to 20.
Per major
- Android 14: not affected per the bulletin. The per-major facts report 8/8 lines of the patched region present at android-security-14.0.0_r30; whether those lines are the pre-fix or post-fix code is not shown.
- Android 15: not affected per the bulletin. The per-major facts report 8/8 lines of the patched region present at android-security-15.0.0_r18; whether those lines are the pre-fix or post-fix code is not shown.
- Android 16: same fix: commit 6effdf3d7c13 in android-security-16.0.0_r8, cherry-picked from 0083751f4ce0 (Change-Id I3fae8e1b8af9f05970de542317bcdcc3d020bf9e). android-security-16.0.0_r9 has the corrected guard and the length clamp in place.
- Android 17: same fix: commit 62418c92b1bb in android-security-17.0.0_r1 with identical code changes. Only hunk line offsets and test fixture details differ (`auto snoop_logger`, and no Start() call in the tests).
Unknowns
- The values of EXTRA_BUF_SIZE and DEFAULT_PACKET_SIZE are not shown, nor are the bodies of FilterProfiles and PayloadStrip. That EXTRA_BUF_SIZE is enough for the magic string is taken from the commit message.
- The material does not show how Capture uses the length output when it writes the snoop record.
- The per-major facts give 7/8 lines at the fixed 16 and 17 tags but 8/8 at the unlisted 14 and 15 tags. The material does not explain the difference or say whether the 14/15 code is pre-fix or post-fix.
- Whether the vulnerable guard exists in the 14 and 15 branches is not shown.