KEYCTL_INSTANTIATE(3)

πŸ’– KEYCTL_INSTANTIATE β€” key instantiation functions (yes bestie, keyctl_instantiate(3), Linux Key Management Calls, come thruuu) πŸ’–


✨ NAME ✨

ok so listen, this page is a whole friend group, not just one function:

  • keyctl_assume_authority
  • keyctl_instantiate
  • keyctl_instantiate_iov
  • keyctl_reject
  • keyctl_negate

…and collectively they're the key instantiation functions. say it with me. πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

#include <keyutils.h>

long keyctl_assume_authority(key_serial_t key);

long keyctl_instantiate(key_serial_t key, const void *payload,
size_t plen, key_serial_t keyring);

long keyctl_instantiate_iov(key_serial_t key,
const struct iovec *payload_iov, unsigned ioc,
key_serial_t keyring);

long keyctl_negate(key_serial_t key, unsigned timeout,
key_serial_t keyring);

long keyctl_reject(key_serial_t key, unsigned timeout,
unsigned error, key_serial_t keyring);

🌸 DESCRIPTION 🌸

πŸ’« keyctl_assume_authority() β€” main character moment

This one makes the calling thread assume the authority to deal with and instantiate the specified uninstantiated key. iconic behavior honestly.

For this to actually work, the calling thread has to have the appropriate authorisation key sitting in one of its keyrings, and that authority must not have been revoked. no expired passes, sorry bestie. 🚫

So where does that authorising key come from? It's allocated by request_key() when it needs to pull userspace in to generate a key for the requesting process. Then it gets attached to one of the keyrings of the userspace process that's been handed the job of instantiating the key. the whole lil pipeline is:

requester -> request_key() -> instantiator

Calling this function modifies the way request_key() works when it's called after that by the calling (instantiator) thread. Once the authority is assumed, the keyrings of the initial process get added to the search path β€” and it uses the initial process's UID, GID, groups and security context. yes, all of it. periodt.

If a thread has multiple instantiations to deal with, it can just call this function again to change which authorisation key is currently in effect. and if you pass a zero key? that de-assumes the currently assumed authority. bye bestie 🫢

NOTE! This is a per-thread setting, not a per-process setting β€” and that's on purpose, so a multithreaded process can be used to instantiate several keys at once. slay for concurrency. πŸ”₯

πŸ’« keyctl_instantiate() β€” the glow-up

This instantiates the payload of an uninstantiated key from the data you specify.

  • payload and plen are the data for the new payload.
  • payload may be NULL and plen may be zero β€” if the key type permits that.
  • The key type may straight up reject the data if it's in the wrong format or invalid in some other way. vibe check failed, moving on. 😭

πŸ’« keyctl_instantiate_iov() β€” same energy, different delivery

Basically the same deal, but the data comes in an array of iovec structs instead of one flat buffer. fancy!

  • payload_iov points to the base of the array.
  • ioc says how many elements there are.
  • payload_iov may be NULL, or ioc may be zero, to indicate that no data is being supplied.

πŸ’« keyctl_reject() β€” not me ghosting a key πŸ’€

This marks a key as negatively instantiated and sets the expiration timer on it.

  • timeout = the lifetime of the key, in seconds.
  • error = the error to be returned when a search hits the key. typically EKEYREJECTED, EKEYREVOKED or EKEYEXPIRED.
heads up: keyctl_reject() falls back to keyctl_negate() if the kernel doesn't support it. it's giving "we'll make it work either way."

πŸ’« keyctl_negate() β€” the lowkey version

Same as keyctl_reject(), but with an error code of ENOKEY.


πŸ”’ the rules, bestie

Only a key for which authority has been assumed may be instantiated or negatively instantiated. And once it's instantiated, the authorisation key will be revoked and the requesting process will be able to resume. closure! πŸ¦‹

Now about the destination keyring β€” if one is given, it's assumed to belong to the initial requester, not the instantiating process. so the special keyring IDs refer to the requesting process's keyrings, not the caller's, and the requester's UID etc. will be used to access them. read that twice, iykyk.

  • The destination keyring can be zero if no extra link is desired.
  • The requester, not the caller, must have write permission on the destination for a link to be made there. not the caller. the requester. okay? πŸ’…

⭐ RETURN VALUE ⭐

On success, keyctl_instantiate() returns 0. πŸ’–

On error, the value -1 will be returned and errno will have been set to an appropriate error. it's giving heartbreak but make it diagnostic.


🚨 ERRORS 🚨

  • ENOKEY β€” The key or keyring specified is invalid.
  • EKEYEXPIRED β€” The keyring specified has expired.
  • EKEYREVOKED β€” The key or keyring specified had been revoked, or the authorisation has been revoked.
  • EINVAL β€” The payload data was invalid.
  • ENOMEM β€” Insufficient memory to store the new payload or to expand the destination keyring.
  • EDQUOT β€” The key quota for the key's user would be exceeded by increasing the size of the key to accommodate the new payload, or the key quota for the keyring's user would be exceeded by expanding the destination keyring.
  • EACCES β€” The key exists, but is not writable by the requester.

πŸ”— LINKING πŸ”—

This is a library function that lives in libkeyutils. When you link, you gotta pass -lkeyutils to the linker. don't forget it, or the linker will simply not know her. 😭


πŸ‘€ SEE ALSO πŸ‘€

keyctl(1), add_key(2), keyctl(2), request_key(2), keyctl(3), keyrings(7), keyutils(7), request-key(8)


and that's the whole page bestie β€” go instantiate something iconic πŸ’–βœ¨πŸŽ€

this page came from the Linux keyutils crew, dated 4 May 2006 β€” and yeah, the manual section is KEYCTL_INSTANTIATE(3). no cap, it still eats. 🫢

πŸ“¦ where this page comes from