@@ -403,6 +403,103 @@ copy_struct_from_user(void *dst, size_t ksize, const void __user *src,
403403 return 0 ;
404404}
405405
406+ /**
407+ * copy_struct_to_user: copy a struct to userspace
408+ * @dst: Destination address, in userspace. This buffer must be @ksize
409+ * bytes long.
410+ * @usize: (Alleged) size of @dst struct.
411+ * @src: Source address, in kernel space.
412+ * @ksize: Size of @src struct.
413+ * @ignored_trailing: Set to %true if there was a non-zero byte in @src that
414+ * userspace cannot see because they are using an smaller struct.
415+ *
416+ * Copies a struct from kernel space to userspace, in a way that guarantees
417+ * backwards-compatibility for struct syscall arguments (as long as future
418+ * struct extensions are made such that all new fields are *appended* to the
419+ * old struct, and zeroed-out new fields have the same meaning as the old
420+ * struct).
421+ *
422+ * Some syscalls may wish to make sure that userspace knows about everything in
423+ * the struct, and if there is a non-zero value that userspce doesn't know
424+ * about, they want to return an error (such as -EMSGSIZE) or have some other
425+ * fallback (such as adding a "you're missing some information" flag). If
426+ * @ignored_trailing is non-%NULL, it will be set to %true if there was a
427+ * non-zero byte that could not be copied to userspace (ie. was past @usize).
428+ *
429+ * While unconditionally returning an error in this case is the simplest
430+ * solution, for maximum backward compatibility you should try to only return
431+ * -EMSGSIZE if the user explicitly requested the data that couldn't be copied.
432+ * Note that structure sizes can change due to header changes and simple
433+ * recompilations without code changes(!), so if you care about
434+ * @ignored_trailing you probably want to make sure that any new field data is
435+ * associated with a flag. Otherwise you might assume that a program knows
436+ * about data it does not.
437+ *
438+ * @ksize is just sizeof(*src), and @usize should've been passed by userspace.
439+ * The recommended usage is something like the following:
440+ *
441+ * SYSCALL_DEFINE2(foobar, struct foo __user *, uarg, size_t, usize)
442+ * {
443+ * int err;
444+ * bool ignored_trailing;
445+ * struct foo karg = {};
446+ *
447+ * if (usize > PAGE_SIZE)
448+ * return -E2BIG;
449+ * if (usize < FOO_SIZE_VER0)
450+ * return -EINVAL;
451+ *
452+ * // ... modify karg somehow ...
453+ *
454+ * err = copy_struct_to_user(uarg, usize, &karg, sizeof(karg),
455+ * &ignored_trailing);
456+ * if (err)
457+ * return err;
458+ * if (ignored_trailing)
459+ * return -EMSGSIZE:
460+ *
461+ * // ...
462+ * }
463+ *
464+ * There are three cases to consider:
465+ * * If @usize == @ksize, then it's copied verbatim.
466+ * * If @usize < @ksize, then the kernel is trying to pass userspace a newer
467+ * struct than it supports. Thus we only copy the interoperable portions
468+ * (@usize) and ignore the rest (but @ignored_trailing is set to %true if
469+ * any of the trailing (@ksize - @usize) bytes are non-zero).
470+ * * If @usize > @ksize, then the kernel is trying to pass userspace an older
471+ * struct than userspace supports. In order to make sure the
472+ * unknown-to-the-kernel fields don't contain garbage values, we zero the
473+ * trailing (@usize - @ksize) bytes.
474+ *
475+ * Returns (in all cases, some data may have been copied):
476+ * * -EFAULT: access to userspace failed.
477+ */
478+ static __always_inline __must_check int
479+ copy_struct_to_user (void __user * dst , size_t usize , const void * src ,
480+ size_t ksize , bool * ignored_trailing )
481+ {
482+ size_t size = min (ksize , usize );
483+ size_t rest = max (ksize , usize ) - size ;
484+
485+ /* Double check if ksize is larger than a known object size. */
486+ if (WARN_ON_ONCE (ksize > __builtin_object_size (src , 1 )))
487+ return - E2BIG ;
488+
489+ /* Deal with trailing bytes. */
490+ if (usize > ksize ) {
491+ if (clear_user (dst + size , rest ))
492+ return - EFAULT ;
493+ }
494+ if (ignored_trailing )
495+ * ignored_trailing = ksize < usize &&
496+ memchr_inv (src + size , 0 , rest ) != NULL ;
497+ /* Copy the interoperable parts of the struct. */
498+ if (copy_to_user (dst , src , size ))
499+ return - EFAULT ;
500+ return 0 ;
501+ }
502+
406503bool copy_from_kernel_nofault_allowed (const void * unsafe_src , size_t size );
407504
408505long copy_from_kernel_nofault (void * dst , const void * src , size_t size );
0 commit comments