Subject: Re: [PATCH 3/5] uaccess: add copy_struct_{from,to}_bounce_buffer() helpers

From: David Laight <[email-masked]>
Date: Tue, 7 Apr 2026 19:25:40 +0100

On Tue,  7 Apr 2026 18:03:15 +0200
Stefan Metzmacher <[email-masked]> wrote:

> These are similar to copy_struct_{from,to}_user() but operate
> on kernel buffers instead of user buffers.
> 
> They can be used when there is a temporary bounce buffer used,
> e.g. in msg_control or similar places.
> 
> It allows us to have the same logic to handle old vs. current
> and current vs. new structures in the same compatible way.
> 
> copy_struct_from_sockptr() will also be able to
> use copy_struct_from_bounce_buffer() for the kernel
> case as follow us patch.
> 
> I'll use this in my IPPROTO_SMBDIRECT work,
> but maybe it will also be useful for others...
> IPPROTO_QUIC will likely also use it.
> 
> Cc: Dmitry Safonov <[email-masked]>
> Cc: Dmitry Safonov <[email-masked]>
> Cc: Francesco Ruggeri <[email-masked]>
> Cc: Salam Noureddine <[email-masked]>
> Cc: David Ahern <[email-masked]>
> Cc: David S. Miller <[email-masked]>
> Cc: Michal Luczaj <[email-masked]>
> Cc: David Wei <[email-masked]>
> Cc: Luiz Augusto von Dentz <[email-masked]>
> Cc: Luiz Augusto von Dentz <[email-masked]>
> Cc: Marcel Holtmann <[email-masked]>
> Cc: Xin Long <[email-masked]>
> Cc: Eric Dumazet <[email-masked]>
> Cc: Kuniyuki Iwashima <[email-masked]>
> Cc: Paolo Abeni <[email-masked]>
> Cc: Willem de Bruijn <[email-masked]>
> Cc: Neal Cardwell <[email-masked]>
> Cc: Jakub Kicinski <[email-masked]>
> Cc: Simon Horman <[email-masked]>
> Cc: Aleksa Sarai <[email-masked]>
> Cc: Christian Brauner <[email-masked]>
> CC: Kees Cook <[email-masked]>
> Cc: [email-masked]
> Cc: [email-masked]
> Cc: [email-masked]
> Signed-off-by: Stefan Metzmacher <[email-masked]>
> ---
>  include/linux/uaccess.h | 63 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 63 insertions(+)
> 
> diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
> index 1234b5fa4761..a6cd4f48bb99 100644
> --- a/include/linux/uaccess.h
> +++ b/include/linux/uaccess.h
> @@ -513,6 +513,69 @@ copy_struct_to_user(void __user *dst, size_t usize, const void *src,
>  	return 0;
>  }
>  
> +static __always_inline void
> +__copy_struct_generic_bounce_buffer(void *dst, size_t dstsize,
> +				    const void *src, size_t srcsize,
> +				    bool *ignored_trailing)
> +{
> +	size_t size = min(dstsize, srcsize);
> +	size_t rest = max(dstsize, srcsize) - size;
> +
> +	/* Deal with trailing bytes. */
> +	if (dstsize > srcsize)
> +		memset(dst + size, 0, rest);
> +	if (ignored_trailing)
> +		*ignored_trailing = dstsize < srcsize &&
> +			memchr_inv(src + size, 0, rest) != NULL;
> +	/* Copy the interoperable parts of the struct. */
> +	memcpy(dst, src, size);
> +}

Return 'ignored_trailing' rather than pass by reference.
And this is probably too big to inline.

	David

> +
> +/**
> + * This is like copy_struct_from_user(), but the
> + * src buffer was already copied into a kernel
> + * bounce buffer, so it will never return -EFAULT.
> + */
> +static __always_inline __must_check int
> +copy_struct_from_bounce_buffer(void *dst, size_t dstsize,
> +			       const void *src, size_t srcsize)
> +{
> +	bool ignored_trailing;
> +
> +	/* Double check if ksize is larger than a known object size. */
> +	if (WARN_ON_ONCE(dstsize > __builtin_object_size(dst, 1)))
> +		return -E2BIG;
> +
> +	__copy_struct_generic_bounce_buffer(dst, dstsize,
> +					    src, srcsize,
> +					    &ignored_trailing);
> +	if (unlikely(ignored_trailing))
> +		return -E2BIG;
> +
> +	return 0;
> +}
> +
> +/**
> + * This is like copy_struct_to_user(), but the
> + * dst buffer is a kernel bounce buffer instead
> + * of a direct userspace buffer, so it will never return -EFAULT.
> + */
> +static __always_inline __must_check int
> +copy_struct_to_bounce_buffer(void *dst, size_t dstsize,
> +			     const void *src,
> +			     size_t srcsize,
> +			     bool *ignored_trailing)
> +{
> +	/* Double check if srcsize is larger than a known object size. */
> +	if (WARN_ON_ONCE(srcsize > __builtin_object_size(src, 1)))
> +		return -E2BIG;
> +
> +	__copy_struct_generic_bounce_buffer(dst, dstsize,
> +					    src, srcsize,
> +					    ignored_trailing);
> +	return 0;
> +}
> +
>  bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size);
>  
>  long copy_from_kernel_nofault(void *dst, const void *src, size_t size);