Skip to content

Commit f161be3

Browse files
pavitrajhagregkh
authored andcommitted
libceph: fix OOB read in decode_watchers() via missing bounds check
commit 00ead17 upstream. ceph_start_decoding() validates that struct_len bytes remain in the buffer after the encoding header, but accepts struct_len=0 as valid: ceph_decode_need(p, end, 0, bad) always passes. When a malicious or compromised OSD sends an obj_list_watch_response_t reply with struct_len=0, ceph_start_decoding() returns success with p == end, leaving zero bytes guaranteed for subsequent reads. The immediately following ceph_decode_32(p) in decode_watchers() 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 kzalloc_objs() as the watcher count. The sibling function decode_watcher() already uses the safe variants (ceph_decode_copy_safe, ceph_decode_64_safe, ceph_decode_skip_32) after its own ceph_start_decoding() call. decode_watchers() is the only site that uses the bare variant, confirming an oversight. Fix by replacing ceph_decode_32(p) with ceph_decode_32_safe(p, end, *num_watchers, 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 CEPH_OSD_OP_LIST_WATCHERS, without any further privileges beyond OSD session establishment. [ idryomov: trim changelog ] Cc: stable@vger.kernel.org Fixes: a4ed38d ("libceph: support for CEPH_OSD_OP_LIST_WATCHERS") Signed-off-by: Pavitra Jha <jhapavitra98@gmail.com> Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com> [ kept the tree's `kcalloc()` context line instead of upstream's `kzalloc_objs()` ] Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2ff70a8 commit f161be3

1 file changed

Lines changed: 4 additions & 1 deletion

File tree

net/ceph/osd_client.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5001,7 +5001,7 @@ static int decode_watchers(void **p, void *end,
50015001
if (ret)
50025002
return ret;
50035003

5004-
*num_watchers = ceph_decode_32(p);
5004+
ceph_decode_32_safe(p, end, *num_watchers, bad);
50055005
*watchers = kcalloc(*num_watchers, sizeof(**watchers), GFP_NOIO);
50065006
if (!*watchers)
50075007
return -ENOMEM;
@@ -5015,6 +5015,9 @@ static int decode_watchers(void **p, void *end,
50155015
}
50165016

50175017
return 0;
5018+
5019+
bad:
5020+
return -EINVAL;
50185021
}
50195022

50205023
/*

0 commit comments

Comments
 (0)