On Thu, 21 May 2026 06:33:14 -0700
Kees Cook <[email protected]> wrote:

> From: Pengpeng Hou <[email protected]>
> 
> param_array_get() appends each element's string representation into the
> shared sysfs page buffer by passing buffer + off to the element getter.
> 
> That works for getters that only write a small bounded string, but
> param_get_charp() and similar helpers format against PAGE_SIZE from the
> pointer they receive. Once off is non-zero, an element getter can
> therefore write past the end of the original sysfs page buffer.
> 
> Collect each element into a temporary PAGE_SIZE buffer first and then
> copy only the remaining space into the caller's page buffer.

Should this be using a 4k buffer on all architectures?
Initially perhaps just using a different name for the constant until
all the associated PAGE_SIZE limits have been removed.

-- David

> 
> Cc: [email protected]
> Reviewed-by: Petr Pavlu <[email protected]>
> Signed-off-by: Pengpeng Hou <[email protected]>
> Signed-off-by: Kees Cook <[email protected]>
> ---
>  kernel/params.c | 26 ++++++++++++++++++++------
>  1 file changed, 20 insertions(+), 6 deletions(-)
> 
> diff --git a/kernel/params.c b/kernel/params.c
> index 74d620bc2521..752721922a15 100644
> --- a/kernel/params.c
> +++ b/kernel/params.c
> @@ -475,22 +475,36 @@ static int param_array_set(const char *val, const 
> struct kernel_param *kp)
>  static int param_array_get(char *buffer, const struct kernel_param *kp)
>  {
>       int i, off, ret;
> +     char *elem_buf;
>       const struct kparam_array *arr = kp->arr;
>       struct kernel_param p = *kp;
>  
> +     elem_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +     if (!elem_buf)
> +             return -ENOMEM;
> +
>       for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
> -             /* Replace \n with comma */
> -             if (i)
> -                     buffer[off - 1] = ',';
>               p.arg = arr->elem + arr->elemsize * i;
>               check_kparam_locked(p.mod);
> -             ret = arr->ops->get(buffer + off, &p);
> +             ret = arr->ops->get(elem_buf, &p);
>               if (ret < 0)
> -                     return ret;
> +                     goto out;
> +             ret = min(ret, (int)(PAGE_SIZE - 1 - off));
> +             if (!ret)
> +                     break;
> +             /* Replace the previous element's trailing newline with a 
> comma. */
> +             if (i)
> +                     buffer[off - 1] = ',';
> +             memcpy(buffer + off, elem_buf, ret);
>               off += ret;
> +             if (off == PAGE_SIZE - 1)
> +                     break;
>       }
>       buffer[off] = '\0';
> -     return off;
> +     ret = off;
> +out:
> +     kfree(elem_buf);
> +     return ret;
>  }
>  
>  static void param_array_free(void *arg)


Reply via email to