Re: [PATCH 01/11] params: bound array element output to the caller's page buffer

David Laight <[email protected]> Tue, 2 Jun 2026 14:04:51 +0100
Newsgroups gmane.linux.ports.ppc64.devel,gmane.linux.kernel.stable,gmane.comp.emulators.kvm.devel,gmane.linux.kernel.modules,gmane.linux.kernel.mm,gmane.comp.security.apparmor,gmane.linux.kernel.lsm,gmane.linux.uml.devel,gmane.linux.acpi.devel,gmane.linux.kernel.openipmi,gmane.comp.emulators.qemu,gmane.comp.freedesktop.xorg.drivers.intel,gmane.comp.video.dri.devel,gmane.linux.drivers.rdma,gmane.linux.drivers.video-input-infrastructure,gmane.linux.kernel.pci,gmane.linux.scsi,gmane.linux.power-management.general,gmane.linux.serial,gmane.linux.usb.general,gmane.linux.kernel,gmane.linux.kernel.cross-arch,gmane.linux.network,gmane.linux.file-systems
Message-ID <20260602140451.2e3e6622@pumpkin>
On Tue, 2 Jun 2026 14:26:46 +0300
Andy Shevchenko <[email protected]> wrote:

> On Thu, May 21, 2026 at 06:33:14AM -0700, Kees Cook wrote:
> > 
> > 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.  
> 
> ...
> 
> > +	elem_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);  
> 
> get_free_page() (or how it is called)?

The kmalloc() should be faster and I think has to be aligned.
There is another patch set to replace get_free_pages() with kmalloc().

Although all these 'show' functions should really head to using a safer
interface.
Although, at the moment, it is really difficult to find the ones that
are guaranteed to be passed a page aligned buffer.

-- David

> 
> > +	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));  
> 
> It's usually discouraged to use castings in min/max/clamp. Can we make ret long
> or do something different here?
> 
> > +		if (!ret)
> > +			break;  
> 
> > +		/* Replace the previous element's trailing newline with a comma. */
> > +		if (i)
> > +			buffer[off - 1] = ',';  
> 
> Can't we do this after with help of strreplace()?
> 
> > +		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;  
>