CVE-2026-80557: libceph: fix OOB read in decode_watchers() via missing bounds check
In the Linux kernel, the following vulnerability has been resolved:
libceph: fix OOB read in decodewatchers() via missing bounds check
cephstartdecoding() validates that structlen bytes remain in the buffer after the encoding header, but accepts structlen=0 as valid: cephdecodeneed(p, end, 0, bad) always passes. When a malicious or compromised OSD sends an objlistwatchresponset reply with structlen=0, cephstartdecoding() returns success with p == end, leaving zero bytes guaranteed for subsequent reads.
The immediately following cephdecode32(p) in decodewatchers() has no preceding bounds check. With p == end this is a 4-byte read past the validated buffer boundary. The garbage value is then passed directly to kzallocobjs() as the watcher count.
The sibling function decodewatcher() already uses the safe variants (cephdecodecopysafe, cephdecode64safe, cephdecodeskip32) after its own cephstartdecoding() call. decodewatchers() is the only site that uses the bare variant, confirming an oversight.
Fix by replacing cephdecode32(p) with cephdecode32safe(p, end, numwatchers, bad), consistent with the established pattern.
Attacker model: a malicious or compromised OSD in a multi-tenant Ceph deployment (e.g. cloud) can trigger this against any kernel client that calls CEPHOSDOPLISTWATCHERS, without any further privileges beyond OSD session establishment.
[ idryomov: trim changelog ]
Affected Software
Event History
Frequently Asked Questions
Who is exposed to this issue?
Linux kernel systems using libceph and processing object-list watcher responses from an OSD are exposed. Exploitation requires an OSD that is malicious or has been compromised and can send a crafted reply.
What does the crafted response need to contain?
The OSD sends an obj_list_watch_response_t reply whose encoding header specifies struct_len=0. This allows decoding to succeed with the input pointer at the end of the buffer before decode_watchers() performs an unchecked 32-bit read.
What is the effect of the unchecked read?
The kernel reads four bytes beyond the validated buffer boundary and uses the resulting garbage value as the watcher count passed to kzalloc_objs(). The provided fix changes this read to the bounds-checked ceph_decode_32_safe() variant.