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