Re: [PATCH 3/5] uaccess: add copy_struct_{from,to}_bounce_buffer() helpers
From: David Laight
Date: Tue Apr 07 2026 - 14:26:01 EST
On Tue, 7 Apr 2026 18:03:15 +0200
Stefan Metzmacher <metze@xxxxxxxxx> 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 <0x7f454c46@xxxxxxxxx>
> Cc: Dmitry Safonov <dima@xxxxxxxxxx>
> Cc: Francesco Ruggeri <fruggeri@xxxxxxxxxx>
> Cc: Salam Noureddine <noureddine@xxxxxxxxxx>
> Cc: David Ahern <dsahern@xxxxxxxxxx>
> Cc: David S. Miller <davem@xxxxxxxxxxxxx>
> Cc: Michal Luczaj <mhal@xxxxxxx>
> Cc: David Wei <dw@xxxxxxxxxxx>
> Cc: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>
> Cc: Luiz Augusto von Dentz <luiz.dentz@xxxxxxxxx>
> Cc: Marcel Holtmann <marcel@xxxxxxxxxxxx>
> Cc: Xin Long <lucien.xin@xxxxxxxxx>
> Cc: Eric Dumazet <edumazet@xxxxxxxxxx>
> Cc: Kuniyuki Iwashima <kuniyu@xxxxxxxxxx>
> Cc: Paolo Abeni <pabeni@xxxxxxxxxx>
> Cc: Willem de Bruijn <willemb@xxxxxxxxxx>
> Cc: Neal Cardwell <ncardwell@xxxxxxxxxx>
> Cc: Jakub Kicinski <kuba@xxxxxxxxxx>
> Cc: Simon Horman <horms@xxxxxxxxxx>
> Cc: Aleksa Sarai <cyphar@xxxxxxxxxx>
> Cc: Christian Brauner <brauner@xxxxxxxxxx>
> CC: Kees Cook <keescook@xxxxxxxxxxxx>
> Cc: netdev@xxxxxxxxxxxxxxx
> Cc: linux-bluetooth@xxxxxxxxxxxxxxx
> Cc: linux-kernel@xxxxxxxxxxxxxxx
> Signed-off-by: Stefan Metzmacher <metze@xxxxxxxxx>
> ---
> 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);