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)
