CVE-2026-58856 AI-generated analysis
platform/frameworks/av, cameraserver (libcameraservice device3 Camera3StreamSplitter)
Adds a range check on the output slot index, a null check on the slot's GraphicBuffer, and a checked lookup in mBuffers in Camera3StreamSplitter::returnOutputBufferLocked. It also changes the outputSlots local from a copy to a reference.
Root cause
In services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp, returnOutputBufferLocked() takes an int slot and used it directly as an index into the per-output slot vector (*mOutputSlots[from]) with no range check. The caller shown in the context (lines 678-689) gets this slot from from->dequeueBuffer() on an output IGraphicBufferProducer. The returned sp<GraphicBuffer> was then dereferenced (buffer->getId()) without a null check. Its id was used with mBuffers[...] and the result was dereferenced right away, without checking that the buffer was tracked. Per the commit message the slot index is app-supplied, so an out-of-range value leads to an out-of-bounds read and type confusion in cameraserver. In addition, outputSlots was a by-value copy, so the later outputSlots[slot] = nullptr in the detach path changed only the copy and was never written back to mOutputSlots[from].
How the fix works
- Camera3StreamSplitter.cpp:Camera3StreamSplitter::returnOutputBufferLocked: 'auto outputSlots = *mOutputSlots[from]' becomes 'auto& outputSlots = *mOutputSlots[from]'. The vector is now used in place, so later writes (outputSlots[slot] = nullptr after a successful detachBuffer) persist.
- Same function: a new check 'if (slot < 0 || static_cast<size_t>(slot) >= outputSlots.size())' logs via SP_LOGE and returns before indexing, which removes the out-of-bounds read.
- Same function: after 'buffer = outputSlots[slot]', a new 'if (buffer == nullptr)' check logs and returns before buffer->getId() is called.
- Same function: 'BufferTracker& tracker = *(mBuffers[buffer->getId()])' is replaced by mBuffers.find(buffer->getId()). If the id is not found, the function logs and returns; otherwise tracker is taken from it->second.
- Single commit; the diff changes no header or other file.
Completeness
- Covers the three hazards at the start of returnOutputBufferLocked: an out-of-range slot, a null buffer in a valid slot, and a buffer id missing from mBuffers.
- The code that follows in the same function (mDetachedBuffers lookup, from->detachBuffer(slot), outputSlots[slot] = nullptr) now runs on a validated slot and buffer, and on the real vector rather than a copy.
- Only returnOutputBufferLocked is changed. Other uses of mOutputSlots or mBuffers elsewhere in Camera3StreamSplitter.cpp are not shown in the material and are not touched by this diff.
- On Android 16 and 17 the fix is applied only to device3/deprecated/DeprecatedCamera3StreamSplitter.cpp. The material does not show whether a non-deprecated splitter exists there or whether it needs the same change.
Behavior changes
- An out-of-range slot, a null buffer, or an untracked buffer id now causes an early return with an SP_LOGE message instead of a memory access. In those cases the fence merge, the detach and the rest of the processing for that buffer are skipped.
- Because outputSlots is now a reference, clearing a slot after a successful detachBuffer persists in mOutputSlots[from]. Before the fix the clear was lost on the copy.
- No API, return value or interface change; the function is still void.
Per major
- Android 14: same fix: platform/frameworks/av d74fdb8ae7d4 (RESTRICT AUTOMERGE) in android-security-14.0.0_r29, services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp. At android-security-14.0.0_r30, 4/6 lines of the patched region match, and the code context shows the fixed code.
- Android 15: same fix: platform/frameworks/av de6bd248af67 (RESTRICT AUTOMERGE) in android-security-15.0.0_r17. Same file and identical hunk at a different line offset (704). At android-security-15.0.0_r18, 4/6 lines of the patched region match.
- Android 16: adapted fix: platform/frameworks/av 6e240fe4061a in android-security-16.0.0_r8, applied to services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp in DeprecatedCamera3StreamSplitter::returnOutputBufferLocked with identical logic. At android-security-16.0.0_r9, 5/6 lines of the patched region match.
- Android 17: adapted fix: platform/frameworks/av db4f7fd08e40 in android-security-17.0.0_r1, same deprecated file and class as Android 16. At android-security-17.0.0_r2, 5/6 lines of the patched region match.
Unknowns
- The material does not show the declared types of mOutputSlots and mBuffers (for example the map value types), only how they are used, so the exact behavior of mBuffers[] for an untracked id is not shown.
- The material does not show whether Android 16/17 contain a non-deprecated Camera3StreamSplitter alongside the deprecated one, or, if they do, whether it has the same pattern.
- The exact app-facing path by which an untrusted slot value reaches returnOutputBufferLocked is not shown beyond the commit message statement that the slot index is app-supplied.
- Whether returnOutputBufferLocked has callers other than the one shown in the context is not shown.