$RodHat_
Syscall reference · Security

keyctl(2)

Manipulate the kernel key retention service: read, revoke, time out and link keys and keyrings.

Since
Linux 2.6.10check your kernel →
glibc
none (use syscall(2))
System
Linux
Man page
keyctl(2)

Synopsis

#include <linux/keyctl.h>  /* Definition of KEY* constants */
#include <sys/syscall.h>   /* Definition of SYS_* constants */
#include <unistd.h>

long syscall(SYS_keyctl, int op, ...);

Rod's take

Environment variables are where secrets go to die: /proc/PID/environ, core dumps, every child you ever fork. The kernel keyring has been doing this properly since 2.6.10: typed keys, per-key permissions, timeouts the kernel enforces itself, and revocation that doesn't mean killing the process. Process keyring if the secret should die with the process, session keyring if children need it. Set a timeout, read it with keyctl_read_alloc, revoke it when you're done. The API is ugly, the permission bitmask is hostile and the quotas are stingy. Still beats DB_PASSWORD in the environment by a mile.

Flags and arguments that matter

NameWhat it does
KEYCTL_READLinux 2.6.10Read a key's payload; returns the full payload size so you can detect a short buffer.
KEYCTL_REVOKELinux 2.6.10Revoke a key; further operations on it fail with EKEYREVOKED.
KEYCTL_SET_TIMEOUTLinux 2.6.16Expire the key t seconds from now (realtime clock); 0 clears the timeout.
KEYCTL_SETPERMLinux 2.6.10Set the possessor/user/group/other permission mask on a key.
KEYCTL_SEARCHLinux 2.6.10Search a keyring tree for a key of a given type and description.
KEYCTL_INVALIDATELinux 3.5Mark a key invalid immediately and schedule it for garbage collection.
KEYCTL_GET_KEYRING_IDLinux 2.6.10Resolve a special ID (KEY_SPEC_PROCESS_KEYRING etc.) to a real keyring serial.
KEY_SPEC_PROCESS_KEYRINGProcess keyring: shared by threads, absent in a fork() child, cleared on execve.
KEY_SPEC_SESSION_KEYRINGSession keyring: inherited across fork and preserved across execve.

Errors you will actually hit

errnoMeaning
ENOKEYNo matching key was found, or an invalid key was specified.
EACCESThe requested operation wasn't permitted by the key's permissions.
EKEYEXPIREDAn expired key was found or specified.
EKEYREVOKEDA revoked key was found or specified.
EDQUOTCreating or linking the key would exceed the caller's key quota.

Example

#include <keyutils.h>   /* -lkeyutils */

key_serial_t key = add_key("user", "myapp:db:password",
                           pw, pwlen, KEY_SPEC_PROCESS_KEYRING);
if (key == -1) err(1, "add_key");
if (keyctl(KEYCTL_SET_TIMEOUT, key, 600) < 0)
    perror("KEYCTL_SET_TIMEOUT");

void *payload = NULL;
long len = keyctl_read_alloc(key, &payload);
if (len < 0) err(1, "keyctl_read_alloc");
connect_db(payload, (size_t)len);
explicit_bzero(payload, (size_t)len);
free(payload);
keyctl(KEYCTL_REVOKE, key);

Trimmed from the full walkthrough in The kernel keyring has been in Linux since 2.6.10 and you have never used it.

BSD equivalent

FreeBSD and OpenBSD: no kernel keyring equivalent.

The long version, from the console

Sources

  1. keyctl(2), man7.org
  2. KEYCTL_READ(2const), man7.org
  3. KEYCTL_SET_TIMEOUT(2const), man7.org
  4. KEYCTL_INVALIDATE(2const), man7.org
  5. KEYCTL_REVOKE(2const), man7.org
  6. process-keyring(7), man7.org
  7. session-keyring(7), man7.org

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.