libceph: fix out-of-bounds reads from repeated CRUSH bucket entries

decode_choose_arg() assumes that its destination is zero-initialized.
Although decode_choose_args() zeroes the argument array, it does not reject
a repeated bucket_index and can decode into an already populated entry.

Repeating a bucket with weight_set_size=0 preserves its existing weight_set
pointer but clears the count. Placement then reads weight_set[-1].weights
and dereferences the resulting pointer.

A malformed monitor OSDMap triggers this during RBD placement:

  BUG: KASAN: slab-out-of-bounds in crush_bucket_choose+0xdd1/0xf90
  Read of size 8 at addr ffff88800290df70 by task init/75

Reject populated arguments before decoding another entry, so the error
path can free their original allocations.

Cc: stable@vger.kernel.org
Fixes: c7ed1a4bf4 ("crush: assume weight_set != null imples weight_set_size > 0")
Assisted-by: Codex:gpt-5
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Jérémy Jean 2026-09-23 08:07:21 +00:00 committed by Ilya Dryomov
parent 52913831ba
commit 569a9bb1e5

View File

@ -385,6 +385,8 @@ static int decode_choose_args(void **p, void *end, struct crush_map *c)
goto e_inval;
arg = &arg_map->args[bucket_index];
if (arg->ids || arg->weight_set)
goto e_inval;
ret = decode_choose_arg(p, end, arg);
if (ret)
goto fail;