CVE-2024-31311 AI-generated analysis
platform/packages/modules/StatsD, lib/libstatssocket (AStatsEvent native API)
Adds a bounds check in libstatssocket's increment_annotation_count() so that an annotation added after the AStatsEvent buffer has reached its maximum capacity no longer reads and writes the byte at event->buf[lastFieldPos] when lastFieldPos is at or beyond event->bufSize.
Root cause
increment_annotation_count() in lib/libstatssocket/stats_event.c always read event->buf[event->lastFieldPos] to get the field type and the current annotation count, then wrote the updated count back to the same byte. It did not check that lastFieldPos was inside the buffer. The new check (lastFieldPos >= bufSize) shows that lastFieldPos could be at or beyond bufSize once the buffer had grown to its maximum size (50*1024 bytes per the new test) and a further write had been rejected with ERROR_OVERFLOW. A following AStatsEvent_addBoolAnnotation then reached increment_annotation_count and accessed buf[lastFieldPos] out of bounds. The new test TestHeapBufferOverflowError reproduces this sequence: it fills the buffer to the last byte, makes one rejected write that sets ERROR_OVERFLOW, then calls AStatsEvent_addBoolAnnotation.
How the fix works
- lib/libstatssocket/stats_event.c:increment_annotation_count: adds an early return when event->lastFieldPos >= event->bufSize. The return comes before the read of event->buf[event->lastFieldPos] and before the write back of the new annotation count, so one check guards both the read and the write.
- lib/libstatssocket/tests/stats_event_test.cpp: adds TestHeapBufferOverflowError. The test writes a 4039-byte string (buffer size 4060), then a 47135-byte string (buffer size 50*1024), then makes one more rejected write (ERROR_OVERFLOW expected). It then calls AStatsEvent_addBoolAnnotation and AStatsEvent_write and asserts that ERROR_OVERFLOW is still set.
- Single-commit fix. The commit is a cherry-pick of two internal changes (4f6c56889356 and e440696c4fd6), with Merged-In I27c69d9875b494f98a2a961cdd4fe139cd809387.
Completeness
- The guard is inside the shared helper increment_annotation_count, which AStatsEvent_addBoolAnnotation calls (line 360). Other annotation entry points are not shown in the material, so whether they all go through this helper is not shown.
- The check is purely positional (lastFieldPos >= bufSize). It does not look at event->errors or ERROR_OVERFLOW, and it does not reset lastFieldPos when a write is rejected. The material does not show where lastFieldPos is assigned, so the diff cannot tell whether a rejected write could leave lastFieldPos at a stale position inside the buffer.
- The early return sets no error flag, so the annotation count update is silently skipped. The ERROR_OVERFLOW set by the rejected write stays set, and that is what the test asserts.
- The diff does not change the append_* helpers or AStatsEvent_write/build. It touches only increment_annotation_count and the test.
Behavior changes
- When lastFieldPos is at or beyond bufSize, increment_annotation_count returns without touching buf and without adding a new error bit.
- No new error codes and no API signature changes. Nothing changes when lastFieldPos is inside the buffer.
Per major
- Android 14: same fix: commit 2c6cc7816da3 in android-security-14.0.0_r9 (linked by bug_id 330054251). At android-security-14.0.0_r29, 8/8 lines of the patched region are present.
- Android 15: not affected per the bulletin (not listed). The patched region is present 8/8 at android-security-15.0.0_r17.
- Android 16: not affected per the bulletin (not listed). The patched region is present 8/8 at android-security-16.0.0_r8.
- Android 17: not affected per the bulletin (not listed). The patched region is present 8/8 at android-security-17.0.0_r1.
Unknowns
- Where and how event->lastFieldPos is assigned on a rejected write (not in the provided diff or context). So it is not shown whether it can equal bufSize, exceed it, or point to a stale in-bounds position.
- Whether annotation APIs other than AStatsEvent_addBoolAnnotation call increment_annotation_count.
- What the two internal cherry-picked changes contained beyond what landed in 2c6cc7816da3.
- Which privileged processes using libstatssocket the bulletin's EoP rating refers to.