Re: [PATCH] net: ceph: Fix a possible null-pointer dereference in decode_choose_args()

From: Viacheslav Dubeyko

Date: Thu Dec 18 2025 - 14:11:36 EST


On Thu, 2025-12-18 at 15:56 +0800, Tuo Li wrote:
> In decode_choose_args(), arg_map->size is updated before memory is
> allocated for arg_map->args using kcalloc(). If kcalloc() fails, execution
> jumps to the fail label, where free_choose_arg_map() is called to release
> resources. However, free_choose_arg_map() unconditionally iterates over
> arg_map->args using arg_map->size, which can lead to a NULL pointer
> dereference when arg_map->args is NULL:
>
> for (i = 0; i < arg_map->size; i++) {
> struct crush_choose_arg *arg = &arg_map->args[i];
>
> for (j = 0; j < arg->weight_set_size; j++)
> kfree(arg->weight_set[j].weights);
> kfree(arg->weight_set);
> kfree(arg->ids);
> }
>
> To prevent this potential NULL pointer dereference, move the assignment to
> arg_map->size to after successful allocation of arg_map->args. This ensures
> that when allocation fails, arg_map->size remains zero and the loop in
> free_choose_arg_map() is not executed.
>
> Signed-off-by: Tuo Li <islituo@xxxxxxxxx>
> ---
> 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 d245fa508e1c..f67a87b3a7c8 100644
> --- a/net/ceph/osdmap.c
> +++ b/net/ceph/osdmap.c
> @@ -363,13 +363,13 @@ static int decode_choose_args(void **p, void *end, struct crush_map *c)
>
> ceph_decode_64_safe(p, end, arg_map->choose_args_index,
> e_inval);
> - arg_map->size = c->max_buckets;

The arg_map->size defines the size of memory allocation. If you remove the
assignment here, then which size kcalloc() will allocate. I assume we could have
two possible scenarios here: (1) arg_map->size is equal to zero -> no allocation
happens, (2) arg_map->size contains garbage value -> any failure could happen.

Have you reproduced the declared issue that you are trying to fix? Are you sure
that your patch can fix the issue? Have you tested your patch at all?

Thanks,
Slava.

> arg_map->args = kcalloc(arg_map->size, sizeof(*arg_map->args),
> GFP_NOIO);
> if (!arg_map->args) {
> ret = -ENOMEM;
> goto fail;
> }
> + arg_map->size = c->max_buckets;
>
> ceph_decode_32_safe(p, end, num_buckets, e_inval);
> while (num_buckets--) {