Re: [PATCH 1/5] uaccess: fix ignored_trailing logic in copy_struct_to_user()

From: Aleksa Sarai

Date: Thu Apr 09 2026 - 02:34:06 EST


On 2026-04-07, Stefan Metzmacher <metze@xxxxxxxxx> wrote:
> Currently all callers pass ignored_trailing=NULL, but I have
> code that will make use of.
>
> Now it actually behaves like documented:
>
> * If @usize < @ksize, then the kernel is trying to pass userspace a newer
> struct than it supports. Thus we only copy the interoperable portions
> (@usize) and ignore the rest (but @ignored_trailing is set to %true if
> any of the trailing (@ksize - @usize) bytes are non-zero).

Good catch, though I want to mention that the current API design for
copy_struct_to_user() is a bit of a compromise -- I was trying to think
of a way of making it generic but what information you need really
depends on your API.

For request-flag APIs (like statx) then you can just unset the bits in
the response mask for fields past usize and so it is a non-fatal error,
but it requires knowing which field offsets map to which flags.

My initial idea for ignored_trailing was for it to return the offset
memchr_inv() gives you -- but unfortunately, this doesn't help in the
more generic case where you have multiple non-zero bits that need to
unset multiple flags.

Out of interest, how did you plan on using it? It might be a good idea
to rethink this API before it starts getting used "in anger" in a way
that leaks to uAPIs we can't change.

In any case, for this patch feel free to take my

Reviewed-by: Aleksa Sarai <aleksa@xxxxxxxxxxxx>

> Fixes: 424a55a4a908 ("uaccess: add copy_struct_to_user helper")
> 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 | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
> index 4fe63169d5a2..1234b5fa4761 100644
> --- a/include/linux/uaccess.h
> +++ b/include/linux/uaccess.h
> @@ -505,7 +505,7 @@ copy_struct_to_user(void __user *dst, size_t usize, const void *src,
> return -EFAULT;
> }
> if (ignored_trailing)
> - *ignored_trailing = ksize < usize &&
> + *ignored_trailing = usize < ksize &&
> memchr_inv(src + size, 0, rest) != NULL;
> /* Copy the interoperable parts of the struct. */
> if (copy_to_user(dst, src, size))
> --
> 2.43.0
>

--
Aleksa Sarai
https://www.cyphar.com/

Attachment: signature.asc
Description: PGP signature