keyrings(7)

โœจ keyrings(7) โœจ

okay bestie, pull up a chair ๐Ÿซถ this is keyrings(7) from the Miscellaneous Information Manual, and it's literally the lore drop on the in-kernel key management and retention facility. it's long so we're doing this in parts โ€” this is part one, stay with me ๐Ÿ’…


NAME ๐ŸŽ€

keyrings โ€” the in-kernel key management and retention facility. yes, that's the whole name. iconic. โœจ


DESCRIPTION ๐Ÿ’–

so the Linux key-management facility is, at its core, a way for all the various kernel components to retain or cache security data, authentication keys, encryption keys, and honestly just other data, all up inside the kernel. it's giving "vault but make it kernel" ๐Ÿ”

There are system call interfaces so that user-space programs can manage those objects and also just use the facility for their own purposes too. go read add_key(2), request_key(2), and keyctl(2) for that whole situation.

There's also a library and some user-space utilities so you can actually get at the facility. peep keyctl(1), keyctl(3), and keyutils(7) for more info. ๐Ÿ’ซ

Keys ๐Ÿ”‘

A key has these attributes, and no we're not skipping any of them:

  • Serial number (ID) โ€” a unique integer handle that system calls use to refer to a key. sometimes people call the serial number the key ID too, same thing, nickname energy. in code, key serial numbers are represented with the type key_serial_t.
  • Type โ€” the type decides what sort of data the key can hold, how the proposed content of the key gets parsed, and how the payload will get used. there are a bunch of general-purpose types available, plus some specialist types defined by specific kernel components.
  • Description (name) โ€” a printable string used as the search term for the key (along with the key type) AND as a display name. when searching, the description may be partially matched or exactly matched. flexible queen.
  • Payload (data) โ€” the actual content of the key. usually this gets set when the key is created, but the kernel can upcall to user space to finish instantiating a key if that key wasn't already known to the kernel when it was requested. more deets in request_key(2). a key's payload can be read and updated if the key type supports it and if suitable permission is granted to the caller. two ifs, no cap.
  • Access rights โ€” much like files do, every key has an owning user ID, an owning group ID, and a security label. each key also has a set of permissions, though there are more of them than for a normal UNIX file, and there's an additional category (possessor) beyond the usual user, group, and other โ€” see Possession, below. also heads up: keys are quota controlled, because they need unswappable kernel memory ๐Ÿซฃ the owning user ID is the one whose quota gets debited.
  • Expiration time โ€” each key can have an expiration time set. when that time hits, the key is marked as expired and accesses to it fail with the error EKEYEXPIRED. if it's not deleted, updated, or replaced, then after a set amount of time an expired key is automatically removed (garbage collected) along with all links to it, and attempts to access it then fail with the error ENOKEY. so it's a two-stage exit, very dramatic ๐Ÿ’€
  • Reference count โ€” each key has one. keys get referenced by keyrings, by currently active users, and by a process's credentials. when the reference count reaches zero, the key is scheduled for garbage collection. that's the vibe check it doesn't survive ๐Ÿ˜ญ

Key types ๐ŸŒˆ

the kernel provides several basic types of key:

  • "keyring" โ€” keyrings are special keys that store a set of links to other keys (including other keyrings), analogous to a directory holding links to files. the main purpose of a keyring is to prevent other keys from being garbage collected because nothing else refers to them.

keyrings with descriptions (names) that begin with a period ('.') are reserved to the implementation. don't touch, that's theirs ๐Ÿ”’

  • "user" โ€” a general-purpose key type. the key is kept entirely within kernel memory, and the payload may be read and updated by user-space applications.

the payload for keys of this type is a blob of arbitrary data of up to 32,767 bytes.

the description may be any valid string, though it's preferred that it start with a colon-delimited prefix representing the service the key is of interest to (for instance "afs:mykey"). preferred, not required, we're chill about it.

  • "logon" (since Linux 3.3) โ€” essentially the same as "user", but it does not provide reading (i.e., the keyctl(2) KEYCTL_READ operation), meaning the key payload is never visible from user space. perfect if you're storing username-password pairs that should not be readable from user space. secrets stay secret, periodt ๐Ÿ”

the description of a "logon" key must start with a non-empty colon-delimited prefix whose purpose is to identify the service the key belongs to. (heads up that this differs from keys of the "user" type, where including a prefix is recommended but is not enforced.) one of them is a rule, one of them is a suggestion ๐Ÿ’…

  • "big_key" (since Linux 3.13) โ€” similar to the "user" key type, but it may hold a payload of up to 1 MiB. this one's useful for stuff like holding Kerberos ticket caches. it's giving "for when your data ate" ๐Ÿ“

the payload data may be stored in a tmpfs filesystem, rather than in kernel memory, if the data size exceeds the overhead of storing the data in the filesystem. (storing the data in a filesystem requires filesystem structures to be allocated in the kernel. the size of these structures determines the size threshold above which the tmpfs storage method is used.) since Linux 4.8, the payload data is encrypted when stored in tmpfs, which prevents it from being written unencrypted into swap space. glow up fr โœจ

there are more specialized key types available too, but they aren't discussed here because they aren't intended for normal user-space use. mind your business ๐Ÿซถ

key type names that begin with a period ('.') are reserved to the implementation. same energy as above.

Keyrings ๐Ÿงš

as previously mentioned (we love a callback), keyrings are a special type of key that contain links to other keys โ€” and yes, those other keys can be other keyrings. keys may be linked to by multiple keyrings. you can think of keyrings as analogous to UNIX directories, where each directory contains a set of hard links to files.

various operations (system calls) may be applied only to keyrings:

  • Adding โ€” a key may be added to a keyring by system calls that create keys. this prevents the new key from being immediately deleted when the system call releases its last reference to the key. rescue mission ๐Ÿซถ
  • Linking โ€” a link may be added to a keyring pointing to a key that is already known, provided this does not create a self-referential cycle. don't make it weird.
  • Unlinking โ€” a link may be removed from a keyring. when the last link to a key is removed, that key will be scheduled for deletion by the garbage collector. it's over ๐Ÿ’€
  • Clearing โ€” all the links may be removed from a keyring. full reset, main character move.
  • Searching โ€” a keyring may be considered the root of a tree or subtree in which keyrings form the branches and non-keyrings the leaves. this tree may be searched for a key matching a particular type and description.

see keyctl_clear(3), keyctl_link(3), keyctl_search(3), and keyctl_unlink(3) for more information. โœจ

Anchoring keys โš“

to prevent a key from being garbage collected, it must be anchored so its reference count stays elevated while it's not in active use by the kernel.

keyrings are what anchor other keys: each link is a reference on a key. and note that keyrings themselves are just keys, so they're also subject to the same anchoring requirement to avoid getting garbage collected. it's keys all the way down bestie ๐Ÿ˜ญ

the kernel makes available a number of anchor keyrings. note that some of these keyrings will be created only when first accessed. surprise entrances only.

Process keyrings ๐ŸŒธ

process credentials themselves reference keyrings with specific semantics. these keyrings are pinned for as long as the set of credentials exists, which is usually as long as the process exists.

there are three keyrings with different inheritance/sharing rules:

as an alternative to using the actual keyring IDs, in calls to add_key(2), keyctl(2), and request_key(2), you can use the special keyring values KEY_SPEC_SESSION_KEYRING, KEY_SPEC_PROCESS_KEYRING, and KEY_SPEC_THREAD_KEYRING to refer to the caller's own instances of these keyrings. shortcuts, love that for us ๐Ÿ’–

User keyrings ๐ŸŒธ

each UID known to the kernel has a record that contains two keyrings: the user-keyring(7) and the user-session-keyring(7). these exist for as long as the UID record in the kernel exists.

as an alternative to using the actual keyring IDs, in calls to add_key(2), keyctl(2), and request_key(2), you can use the special keyring values KEY_SPEC_USER_KEYRING and KEY_SPEC_USER_SESSION_KEYRING to refer to the caller's own instances of these keyrings.

a link to the user keyring is placed in a new session keyring by pam_keyinit(8) when a new login session is initiated.

Persistent keyrings ๐ŸŒธ

there's a persistent-keyring(7) available to each UID known to the system. it may persist beyond the life of the UID record we just mentioned, but it has an expiration time set so it's automatically cleaned up after a set time. the persistent keyring lets, for example, cron(8) scripts use credentials that are left in the persistent keyring after the user logs out. it's giving "still here, still working" ๐Ÿ‘‘

note that the expiration time of the persistent keyring is reset every time the persistent key is requested. it's immortal until you stop asking.

Special keyrings ๐ŸŒธ

there are special keyrings owned by the kernel that can anchor keys for special purposes. one example is the system keyring used for holding encryption keys for module signature verification.

these special keyrings are usually closed to direct alteration by user space. hands off ๐Ÿ™ˆ


an originally planned "group keyring", for storing keys associated with each GID known to the kernel, is not so far implemented, and is unlikely to be implemented. nevertheless, the constant KEY_SPEC_GROUP_KEYRING has been defined for this keyring. so the name exists but the keyring said "no thanks" ๐Ÿ’€


Possession ๐Ÿ‘‘

the concept of possession is important to understanding the keyrings security model. whether a thread possesses a key is determined by the following rules:

  1. Any key or keyring that does not grant search permission to the caller? Yeah, it gets ignored in every single rule below. Ghosted. ๐Ÿ’€
  2. A thread directly possesses its session-keyring(7), process-keyring(7), and thread-keyring(7) โ€” because those keyrings are literally referred to by its credentials. It's in the group chat already, no invite needed. ๐Ÿซถ
  3. If a keyring is possessed, then everything it links to is also possessed. Passing the aux cord, basically. ๐ŸŽง
  4. And if any key a keyring links to is itself a keyring? Then rule (3) applies recursively. It goes all the way down, bestie. ๐ŸŒ€
  5. If a process gets upcalled from the kernel to instantiate a key (peep request_key(2)), then it also possesses the requester's keyrings, per rule (1), as if it were the requester. Character swap. ๐ŸŽญ
Ngl this part is important: possession is not a fundamental property of a key. It has to be recalculated every single time the key is needed. No caching, no assumptions. ๐Ÿ’…

Possession exists so that set-user-ID programs, run from โ€” say โ€” a user's shell, can get at the user's keys. And granting permissions to the key possessor while denying them to the key owner and group lets you block access to keys based on UID and GID matches. Iconic gatekeeping behavior. ๐Ÿšชโœจ

Oh and when it creates the session keyring, pam_keyinit(8) adds a link to user-keyring(7). Which means the user keyring โ€” and everything inside it โ€” is possessed by default. Automatic yes. ๐ŸŽ€


๐Ÿ”‘ Access rights โœจ

Every key carries these security-related attributes:

  • The owning user ID
  • The ID of a group that is permitted to access the key
  • A security label
  • A permissions mask

So the permissions mask has four sets of rights, and the first three are mutually exclusive โ€” one and only one is in force for any given access check. In order of descending priority, those three are:

user : The set specifies the rights granted if the key's user ID matches the caller's filesystem user ID.

group : The set specifies the rights granted if the user ID didn't match and the key's group ID matches the caller's filesystem GID or one of the caller's supplementary group IDs.

other : The set specifies the rights granted if neither the key's user ID nor group ID matched.

And the fourth set of rights is:

possessor : The set specifies the rights granted if a key is determined to be possessed by the caller.

The complete set of rights for a key = whichever of the first three sets applies, unioned with the fourth set if the key is possessed. Simple math, slay. ๐Ÿ’…

Now here's the set of rights that may be granted in each of those four masks:

view : The attributes of the key may be read. That includes the type, description, and access rights (excluding the security label).

read : For a key: the payload of the key may be read. For a keyring: the list of serial numbers (keys) to which the keyring has links may be read.

write : The payload of the key may be updated and the key may be revoked. For a keyring, links may be added to or removed from the keyring, and the keyring may be cleared completely (all links are removed),

search : For a key (or a keyring): the key may be found by a search. For a keyring: keys and keyrings that are linked to by the keyring may be searched.

link : Links may be created from keyrings to the key. The initial link to a key that is established when the key is created doesn't require this permission.

setattr : The ownership details and security label of the key may be changed, the key's expiration time may be set, and the key may be revoked.

Besides all that, any active Linux Security Module (LSM) may block access to a key if its policy says so. ๐Ÿ˜ญ A key can be handed a security label or other attribute by the LSM, and that label is retrievable via keyctl_get_security(3).

See keyctl_chown(3), keyctl_describe(3), keyctl_get_security(3), keyctl_setperm(3), and selinux(8) for more info.


๐Ÿ” Searching for keys ๐ŸŒธ

One of the key features of the Linux key-management facility is the ability to find a key a process is retaining. request_key(2) is the primary access point for user-space applications to find a key. (Internally, the kernel has something similar available for internal components that use keys.) It's giving main character energy. ๐Ÿ‘‘

The search algorithm goes like this:

  1. The process keyrings are searched in this order: the thread-keyring(7) if it exists, the process-keyring(7) if it exists, and then either the session-keyring(7) if it exists or the user-session-keyring(7) if that exists.
  2. If the caller was a process invoked by the request_key(2) upcall mechanism, then the keyrings of the original caller of request_key(2) get searched as well.
  3. The search of a keyring tree is in breadth-first order: each keyring is searched first for a match, then the keyrings referred to by that keyring are searched.
  4. If a matching key is found that is valid, the search terminates and that key is returned. Found it, periodt. โœจ
  5. If a matching key is found that has an error state attached, that error state is noted and the search continues.
  6. If no valid matching key is found, then the first noted error state is returned; otherwise, an ENOKEY error is returned.

You can also search a specific keyring, in which case only steps (3) to (6) apply.

See request_key(2) and keyctl_search(3) for more info.


๐Ÿงš On-demand key creation ๐ŸŽ€

If a key cannot be found, request_key(2) will โ€” if it was given a callout_info argument โ€” create a new key and then upcall to user space to instantiate it. Which means keys can be created on an as-needed basis. Built different, honestly. ๐Ÿ”ฅ

Typically this involves the kernel creating a new process that executes the request-key(8) program, which then executes the appropriate handler based on its configuration.

The handler gets passed a special authorization key that allows it โ€” and only it โ€” to instantiate the new key. That same thing is also used to permit searches performed by the handler program to also search the requester's keyrings.

See request_key(2), keyctl_assume_authority(3), keyctl_instantiate(3), keyctl_negate(3), keyctl_reject(3), request-key(8), and request-key.conf(5) for more info.


๐ŸŒˆ Users ๐Ÿ’œ

The Linux key-management facility has a number of users and usages, but it is absolutely not limited to the ones that already exist. The roster keeps growing, iykyk.

In-kernel users of this facility include:

Network filesystems - DNS : The kernel uses the upcall mechanism provided by the keys to upcall to user space to do DNS lookups and then to cache the results.

AF_RXRPC and kAFS - Authentication : The AF_RXRPC network protocol and the in-kernel AFS filesystem use keys to store the ticket needed to do secured or encrypted traffic. These are then looked up by network operations on AF_RXRPC and filesystem operations on kAFS.

NFS - User ID mapping : The NFS filesystem uses keys to store mappings of foreign user IDs to local user IDs.

CIFS - Password : The CIFS filesystem uses keys to store passwords for accessing remote shares.

Module verification : The kernel build process can be made to cryptographically sign modules. That signature is then checked when a module is loaded.

User-space users of this facility include:

Kerberos key storage : The MIT Kerberos 5 facility (libkrb5) can use keys to store authentication tokens which can be made to be automatically cleaned up a set time after the user last uses them, but until then permits them to hang around after the user has logged out so that cron(8) scripts can use them.

๐Ÿ“‚ FILES ๐Ÿ“‚

Okay so bestie, the kernel keeps a whole lineup of /proc files that either spill the tea about your keys or set the limits on how much key usage you're allowed. Let's meet them all, one by one, no skips. ๐Ÿ’…


๐Ÿ”‘ /proc/keys (since Linux 2.6.10)

This file exposes a list of the keys for which the reading thread has view permission, providing various information about each key. And here's the gag: the thread does not have to possess the key for it to be visible in this file. Just vibes. ๐Ÿ‘‘

The only keys included in the list are those that grant view permission to the reading process (regardless of whether or not it possesses them). LSM security checks are still performed, and may filter out further keys that the process is not authorized to view. So there's still a bouncer at the door, periodt.

Here's an example of the data you might see in this file (columns numbered for easy reference, you're welcome):

  (1)     (2)     (3)(4)    (5)     (6)   (7)   (8)        (9)
009a2028 I--Q---   1 perm 3f010000  1000  1000 user     krb_ccache:primary: 12
1806c4ba I--Q---   1 perm 3f010000  1000  1000 keyring  _pid: 2
25d3a08f I--Q---   1 perm 1f3f0000  1000 65534 keyring  _uid_ses.1000: 1
28576bd8 I--Q---   3 perm 3f010000  1000  1000 keyring  _krb: 1
2c546d21 I--Q--- 190 perm 3f030000  1000  1000 keyring  _ses: 2
30a4e0be I------   4   2d 1f030000  1000 65534 keyring  _persistent.1000: 1
32100fab I--Q---   4 perm 1f3f0000  1000 65534 keyring  _uid.1000: 2
32a387ea I--Q---   1 perm 3f010000  1000  1000 keyring  _pid: 2
3ce56aea I--Q---   5 perm 3f030000  1000  1000 keyring  _ses: 1

๐ŸŒธ the fields, decoded ๐ŸŒธ

The fields shown in each line of this file are as follows:

  • ID (1) โ€” the ID (serial number) of the key, expressed in hexadecimal.
  • Flags (2) โ€” a set of flags describing the state of the key:
    • I โ€” The key has been instantiated.
    • R โ€” The key has been revoked.
    • D โ€” The key is dead (i.e., the key type has been unregistered). (A key may be briefly in this state during garbage collection.)
    • Q โ€” The key contributes to the user's quota.
    • U โ€” The key is under construction via a callback to user space; see request-key(2).
    • N โ€” The key is negatively instantiated.
    • i โ€” The key has been invalidated.
  • Usage (3) โ€” this is a count of the number of kernel credential structures that are pinning the key (approximately: the number of threads and open file references that refer to this key).
  • Timeout (4) โ€” the amount of time until the key will expire, expressed in human-readable form (weeks, days, hours, minutes, and seconds). The string perm here means that the key is permanent (no timeout). The string expd means that the key has already expired, but has not yet been garbage collected. ๐Ÿ˜ญ
  • Permissions (5) โ€” the key permissions, expressed as four hexadecimal bytes containing, from left to right, the possessor, user, group, and other permissions. Within each byte, the permission bits are as follows:
    • 0x01 view
    • 0x02 read
    • 0x04 write
    • 0x08 search
    • 0x10 link
    • 0x20 setattr
  • UID (6) โ€” the user ID of the key owner.
  • GID (7) โ€” the group ID of the key. The value -1 here means that the key has no group ID; this can occur in certain circumstances for keys created by the kernel.
  • Type (8) โ€” the key type (user, keyring, etc.)
  • Description (9) โ€” the key description (name). This field contains descriptive information about the key. For most key types, it has the form
name[: extra-info]

The name subfield is the key's description (name). The optional extra-info field provides some further information about the key. The information that appears here depends on the key type, as follows:

  • "user", "logon" โ€” the size in bytes of the key payload (expressed in decimal).
  • "keyring" โ€” the number of keys linked to the keyring, or the string empty if there are no keys linked to the keyring.
  • "big_key" โ€” the payload size in bytes, followed either by the string [file], if the key payload exceeds the threshold that means that the payload is stored in a (swappable) tmpfs(5) filesystem, or otherwise the string [buff], indicating that the key is small enough to reside in kernel memory.

For the .request_key_auth key type (authorization key; see request_key(2)), the description field has the form shown in the following example:

key:c9a9b19 pid:28880 ci:10

The three subfields are as follows:

  • key โ€” the hexadecimal ID of the key being instantiated in the requesting program.
  • pid โ€” the PID of the requesting program.
  • ci โ€” the length of the callout data with which the requested key should be instantiated (i.e., the length of the payload associated with the authorization key).

๐Ÿ‘ฅ /proc/key-users (since Linux 2.6.10)

This file lists various information for each user ID that has at least one key on the system. Example data you might catch in here:

   0:    10 9/9 2/1000000 22/25000000
  42:     9 9/9 8/200 106/20000
1000:    11 11/11 10/200 271/20000

The fields shown in each line are as follows:

  • uid โ€” the user ID.
  • usage โ€” this is a kernel-internal usage count for the kernel structure used to record key users.
  • nkeys/nikeys โ€” the total number of keys owned by the user, and the number of those keys that have been instantiated.
  • qnkeys/maxkeys โ€” the number of keys owned by the user, and the maximum number of keys that the user may own.
  • qnbytes/maxbytes โ€” the number of bytes consumed in payloads of the keys owned by this user, and the upper limit on the number of bytes in key payloads for that user.

โณ /proc/sys/kernel/keys/gc_delay (since Linux 2.6.32)

The value in this file specifies the interval, in seconds, after which revoked and expired keys will be garbage collected. And why would you even want a delay, you ask? Because it gives you a whole window of time where user space can actually see an error โ€” respectively EKEYREVOKED and EKEYEXPIRED โ€” that tells you what happened to the key. Closure, basically. ๐Ÿซถ

The default value in this file is 300 (i.e., 5 minutes).


๐Ÿ’ซ /proc/sys/kernel/keys/persistent_keyring_expiry (since Linux 3.13)

This file defines an interval, in seconds, to which the persistent keyring's expiration timer is reset each time the keyring is accessed (via keyctl_get_persistent(3) or the keyctl(2) KEYCTL_GET_PERSISTENT operation.)

The default value in this file is 259200 (i.e., 3 days).


The following files (which are writable by privileged processes) are used to enforce quotas on the number of keys and number of bytes of data that can be stored in key payloads. Budget era. ๐Ÿ’ธ


๐Ÿ“ /proc/sys/kernel/keys/maxbytes (since Linux 2.6.26)

This is the maximum number of bytes of data that a nonroot user can hold in the payloads of the keys owned by the user.

The default value in this file is 20,000.


๐Ÿ“ /proc/sys/kernel/keys/maxkeys (since Linux 2.6.26)

This is the maximum number of keys that a nonroot user may own.

The default value in this file is 200.


๐ŸŽ€ /proc/sys/kernel/keys/root_maxbytes (since Linux 2.6.26)

This is the maximum number of bytes of data that the root user (UID 0 in the root user namespace) can hold in the payloads of the keys owned by root.

The default value in this file is 25,000,000 (20,000 before Linux 3.17).


๐ŸŽ€ /proc/sys/kernel/keys/root_maxkeys (since Linux 2.6.26)

This is the maximum number of keys that the root user (UID 0 in the root user namespace) may own.

The default value in this file is 1,000,000 (200 before Linux 3.17).


๐ŸŒˆ With respect to keyrings, note that each link in a keyring consumes 4 bytes of the keyring payload. Tiny but mighty, fr fr.

๐ŸŒŸ SEE ALSO ๐ŸŒŸ


And that's the whole thing bestie, you made it to the end!! ๐Ÿฅณ This one came from Linux man-pages 6.20, dated 2026-02-08. Go forth and keyctl responsibly, mwah ๐Ÿ’–โœจ

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: GPL-2.0-or-later
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms