copy_struct_from_user(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’– copy_struct_from_user β€” Kernel API Manual (yes, the 9 one) πŸ’–

okay bestie, so this page lives in the Kernel API Manual and it's about one tiny little function that is carrying the entire weight of struct syscall backwards-compatibility on its shoulders. icon behavior honestly. 🫢


✨ NAME ✨

copy_struct_from_user β€” copy a struct from userspace. that's it, that's the whole name, and it's giving exactly what it says on the tin. πŸŽ€


🌸 SYNOPSIS 🌸

int copy_struct_from_user (void *dst , size_t ksize , const void __user
* src , size_t usize );

πŸ¦‹ ARGUMENTS πŸ¦‹

  • dst β€” destination address, but in kernel space. heads up: this buffer must be ksize bytes long. no sneaky short buffers, she will notice. πŸ’…
  • ksize β€” size of the dst struct. yes it's just sizeof(*dst), we'll get there.
  • src β€” source address, over in userspace where things are scary and untrusted. πŸ™ˆ
  • usize β€” the (alleged) size of the src struct. alleged!! because userspace is out here lying for sport. 😭

🌈 DESCRIPTION 🌈

Copies a struct from userspace into kernel space, in a way that guarantees backwards-compatibility for struct syscall arguments. and like, that guarantee is the whole point, so listen up:

it only holds as long as future struct extensions are made such that all new fields are appended to the old struct, and zeroed-out new fields have the same meaning as the old struct. so, append-only, zeroes mean "not set", no cap. 🧚

ksize is literally just sizeof(*dst), and usize should've been passed by userspace. the recommended usage? something like this, bestie, take notes: πŸ“

SYSCALL_DEFINE2(foobar, const struct foo __user *, uarg, size_t, usize)
{ int err; struct foo karg = {};

if (usize > PAGE_SIZE) return -E2BIG; if (usize < FOO_SIZE_VER0) return
-EINVAL;

err = copy_struct_from_user(karg, sizeof(karg), uarg, usize); if (err)
return err;

// ...  }

There are three cases to consider, and honestly each one is a whole vibe:

  • If usize == ksize, then it's copied verbatim. same size, same struct, no drama. slay. πŸ‘‘
  • If usize < ksize, then userspace has passed an old struct to a newer kernel. the rest of the trailing bytes in dst (ksize - usize) are to be zero-filled. old soul, new kernel, we make it work. πŸ₯Ί
  • If usize > ksize, then userspace has passed a new struct to an older kernel. those trailing bytes the kernel doesn't know about (usize - ksize) get checked to make sure they're zeroed β€” otherwise -E2BIG comes back at you. so: unknown bytes must be zeroes or you're getting yeeted. πŸ’€

Returns (and in all of these cases, some data may have been copied β€” no takebacks):

  • -E2BIG: (usize > ksize) and there are non-zero trailing bytes in src. the audacity.
  • -EFAULT: access to userspace failed. it happens to the best of us. πŸ˜”

πŸ”₯ SEE ALSO πŸ”₯

Kernel file ./include/linux/uaccess.h β€” plus a whole friend group of friends:

go read them, they're all iconic in their own way πŸ’œ


that's the whole page, bestie!! straight from ./include/linux, cheerfully dated October 2026 β€” so yeah, from the future, we love that for us ⭐ follow for more uaccess lore, mwah πŸ’…πŸ’–

πŸ“¦ where this page comes from