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.
Fixes: c7ed1a4bf4b4 ("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>
---
net/ceph/osdmap.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index cf34b35c9a90..ac0027169b06 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -383,6 +383,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;
--
2.47.3