Re: [PATCH 01/11] params: bound array element output to the caller's page buffer
David Laight <[email protected]> Thu, 21 May 2026 17:46:31 +0100
| Newsgroups | org.infradead.lists.linux-um,dev.linux.lists.virtualization,org.freedesktop.lists.dri-devel,org.freedesktop.lists.intel-gfx,org.kernel.vger.dmaengine,org.kernel.vger.kvm,org.kernel.vger.linux-acpi,org.kernel.vger.linux-arch,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-hardening,org.kernel.vger.linux-kernel,org.kernel.vger.linux-media,org.kernel.vger.linux-modules,org.kernel.vger.linux-pci,org.kernel.vger.linux-pm,org.kernel.vger.linux-rdma,org.kernel.vger.linux-scsi,org.kernel.vger.linux-security-module,org.kernel.vger.linux-serial,org.kernel.vger.linux-usb,org.kernel.vger.netdev,org.kernel.vger.stable,org.kvack.linux-mm,org.nongnu.qemu-devel,org.ozlabs.lists.linuxppc-dev |
|---|---|
| Message-ID | <20260521174631.71a06440@pumpkin> |
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)