Re: [PATCH net] libceph: bound pg_temp/pg_upmap osd list length to CEPH_PG_MAX_SIZE

From: Xiang Mei

Date: Tue Jun 09 2026 - 00:41:13 EST


Thanks for your attention to this bug. We have a PoC that can trigger
the KASAN crash. Please DM if you need it to reproduce the issue.

Xiang

On Mon, Jun 8, 2026 at 9:40 PM Xiang Mei <xmei5@xxxxxxx> wrote:
>
> __decode_pg_temp() decodes an user-controlled length but only rejects
> values large enough to overflow the allocation; it does not bound it to
> CEPH_PG_MAX_SIZE. The helper backs both pg_temp and pg_upmap decoding, and
> apply_upmap()/get_temp_osds() later copy the decoded list into the fixed-size
> on-stack array struct ceph_osds.osds[CEPH_PG_MAX_SIZE]. A monitor that sends
> an OSDMap with a pg_temp/pg_upmap entry longer than 32 thus causes a stack
> out-of-bounds write.
>
> An OSD set for a single PG can never exceed CEPH_PG_MAX_SIZE, so reject longer
> entries at decode time. The bound is well below the old overflow threshold, so
> it also covers the allocation-size overflow the previous check guarded against.
>
> BUG: KASAN: stack-out-of-bounds in ceph_pg_to_up_acting_osds
> Write of size 4 ... by task exploit
> kasan_report (mm/kasan/report.c:595)
> ceph_pg_to_up_acting_osds (net/ceph/osdmap.c:2617 net/ceph/osdmap.c:2833)
> calc_target (net/ceph/osd_client.c:1638)
> __submit_request (net/ceph/osd_client.c:2394)
> ceph_osdc_start_request (net/ceph/osd_client.c:2490)
> ceph_osdc_call (net/ceph/osd_client.c:5164)
> rbd_dev_image_probe (drivers/block/rbd.c:6899)
> do_rbd_add (drivers/block/rbd.c:7138)
> ...
> kernel BUG at net/ceph/osdmap.c:2670!
>
> Fixes: a303bb0e5834 ("libceph: introduce and switch to decode_pg_mapping()")
> Reported-by: Weiming Shi <bestswngs@xxxxxxxxx>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Xiang Mei <xmei5@xxxxxxx>
> ---
> net/ceph/osdmap.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
> index 8b5b0587a0cf..e35d8abe1773 100644
> --- a/net/ceph/osdmap.c
> +++ b/net/ceph/osdmap.c
> @@ -1436,7 +1436,7 @@ static struct ceph_pg_mapping *__decode_pg_temp(void **p, void *end,
> ceph_decode_32_safe(p, end, len, e_inval);
> if (len == 0 && incremental)
> return NULL; /* new_pg_temp: [] to remove */
> - if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / sizeof(u32))
> + if (len > CEPH_PG_MAX_SIZE)
> return ERR_PTR(-EINVAL);
>
> ceph_decode_need(p, end, len * sizeof(u32), e_inval);
> --
> 2.43.0
>