CVE-2026-49937 AI-generated analysis
platform/system/libfmq, MessageQueueBase (fast message queue read path, include/fmq/MessageQueueBase.h)
Adds bounds validation in libfmq's MessageQueueBase for kSynchronizedReadWrite queues. availableToReadBytes() now rejects a write/read pointer pair that claims more available bytes than the queue size, and beginRead() now rejects up front any read request larger than the queue's quantum count.
Root cause
availableToReadBytes() loads mWritePtr and mReadPtr and rejected only the case writePtr < readPtr. If writePtr - readPtr exceeded the queue size (mDesc->getSize()), the function returned that oversized value unchanged. beginRead() also had no early check that nMessages fits in the queue (getQuantumCount()). The commit is a reapply of an earlier change. Per its message, the beginRead() check was fixed to apply only to kSynchronizedReadWrite, because the unsync flavor is expected to overflow when readers lag the writer. In the diff, both new checks are guarded by the flavor.
How the fix works
- include/fmq/MessageQueueBase.h:availableToReadBytes(): computes queueSizeBytes = mDesc->getSize() and availableBytes = (writePtr >= readPtr) ? writePtr - readPtr : SIZE_MAX. It now returns 0 when writePtr < readPtr OR (flavor == kSynchronizedReadWrite && availableBytes > queueSizeBytes), and logs an error that includes writePtr, readPtr and the queue size. Otherwise it returns availableBytes.
- include/fmq/MessageQueueBase.h:beginRead(): adds a leading check, for kSynchronizedReadWrite only, that nMessages <= getQuantumCount(). If not, it logs an error, emits errorWriteLog(0x534e4554, "514861024") and returns false before the MemTransaction is initialized.
- On Android 15/16/17 the same logic is layered on the existing error-reporting variants: 15 sets *errorDetected = Error::POINTER_CORRUPTION, while 16 and 17 invoke mErrorHandler(Error::POINTER_CORRUPTION, ...). On 17 the beginRead() check omits the errorWriteLog call.
Completeness
- Covers the read side only: availableToReadBytes() and beginRead(). The diff makes no change to write-side functions, and the material does not show whether they need a similar guard.
- Both new checks are limited to flavor == kSynchronizedReadWrite. For the unsynchronized flavor, availableToReadBytes() still rejects only writePtr < readPtr, because the commit message says overflow is expected there.
- On Android 14, availableToReadBytes() signals corruption only by logging and returning 0 (the r30 code context shows no errorDetected/mErrorHandler path), so callers see it as no data available.
- The changed functions are template members defined in include/fmq/MessageQueueBase.h, so they take effect in binaries that instantiate them when those binaries are rebuilt against the patched header.
Behavior changes
- Synchronized queues whose pointers claim more than the queue size in available bytes now report 0 available bytes and log 'The write or read pointer has become corrupted ...' with the pointer values and queue size.
- beginRead()/read() on a synchronized queue with nMessages > getQuantumCount() now fails immediately with false and logs an error, plus an errorWriteLog entry on 14, 15 and 16.
- On Android 14, the error log text in availableToReadBytes() now includes the write pointer, read pointer and queue size.
Per major
- Android 14: Same fix: 452c5e918cde in android-security-14.0.0_r29, applied to the code variant where availableToReadBytes() only logs (no errorDetected/mErrorHandler). The r30 code context confirms the availableToReadBytes() change is present.
- Android 15: Adapted fix: 6d316edf3cc8 in android-security-15.0.0_r17. The same logic is merged into the variant that sets *errorDetected = Error::POINTER_CORRUPTION.
- Android 16: Adapted fix: 3aa82fe2d0a8 in android-security-16.0.0_r8. The same logic is merged into the mErrorHandler variant, including errorWriteLog in beginRead().
- Android 17: Adapted fix: f727482ff0c6 in android-security-17.0.0_r1. The same logic is applied to the mErrorHandler variant, but the beginRead() check omits the errorWriteLog(0x534e4554, ...) call.
Unknowns
- The per-major resolver reports 6/8 lines of the patched region present in each latest security tag. The code context confirms the availableToReadBytes() hunk on 14.0.0_r30 but does not show the beginRead() hunk, so its presence in the latest tags is not directly verified here.
- Whether the write-side functions have an equivalent issue is not shown by the material.
- What the oversized available-byte value led to downstream in beginRead(), and the exact information-disclosure impact, are not shown in the diff.
- Why the original change was reverted is not stated in the material.
- The specific HAL or process involved (bugs 504768739 and 514861024), and how the pointers become corrupted, are not described in the material.