services

file: /proc/sys/kernel/services
variable: kernel.services
Official reference

The kernel services for key management are fairly simple to deal with. They can be broken down into two areas: keys and key types.

Dealing with keys is fairly straightforward. Firstly, the kernel service registers its type, then it searches for a key of that type. It should retain the key as long as it has need of it, and then it should release it. For a filesystem or device file, a search would probably be performed during the open call, and the key released upon close. How to deal with conflicting keys due to two different users opening the same file is left to the filesystem author to solve.

To access the key manager, the following header must be #included::

<linux/key.h>

Specific key types should have a header file under include/keys/ that should be used to access that type. For keys of type “user”, for example, that would be::

<keys/user-type.h>

Note that there are two different types of pointers to keys that may be encountered:

  • struct key *

    This simply points to the key structure itself. Key structures will be at least four-byte aligned.

  • key_ref_t

    This is equivalent to a struct key *, but the least significant bit is set if the caller “possesses” the key. By “possession” it is meant that the calling processes has a searchable link to the key from one of its keyrings. There are three functions for dealing with these::

key_ref_t make_key_ref(const struct key *key, bool possession);

struct key *key_ref_to_ptr(const key_ref_t key_ref);

bool is_key_possessed(const key_ref_t key_ref);

 The first function constructs a key reference from a key pointer and
 possession information (which must be true or false).

 The second function retrieves the key pointer from a reference and the
 third retrieves the possession flag.

When accessing a key’s payload contents, certain precautions must be taken to prevent access vs modification races. See the section “Notes on accessing payload contents” for more information.

  • To search for a key, call::

    struct key *request_key(const struct key_type *type, const char *description, const char *callout_info);

    This is used to request a key or keyring with a description that matches the description specified according to the key type’s match_preparse() method. This permits approximate matching to occur. If callout_string is not NULL, then /sbin/request-key will be invoked in an attempt to obtain the key from userspace. In that case, callout_string will be passed as an argument to the program.

    Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be returned.

    If successful, the key will have been attached to the default keyring for implicitly obtained request-key keys, as set by KEYCTL_SET_REQKEY_KEYRING.

    See also Documentation/security/keys/request-key.rst.

  • To search for a key in a specific domain, call::

    struct key *request_key_tag(const struct key_type *type, const char *description, struct key_tag *domain_tag, const char *callout_info);

    This is identical to request_key(), except that a domain tag may be specifies that causes search algorithm to only match keys matching that tag. The domain_tag may be NULL, specifying a global domain that is separate from any nominated domain.

  • To search for a key, passing auxiliary data to the upcaller, call::

    struct key *request_key_with_auxdata(const struct key_type *type, const char *description, struct key_tag *domain_tag, const void *callout_info, size_t callout_len, void *aux);

    This is identical to request_key_tag(), except that the auxiliary data is passed to the key_type->request_key() op if it exists, and the callout_info is a blob of length callout_len, if given (the length may be 0).

  • To search for a key under RCU conditions, call::

    struct key *request_key_rcu(const struct key_type *type, const char *description, struct key_tag *domain_tag);

    which is similar to request_key_tag() except that it does not check for keys that are under construction and it will not call out to userspace to construct a key if it can’t find a match.

  • When it is no longer required, the key should be released using::

    void key_put(struct key *key);

    Or::

    void key_ref_put(key_ref_t key_ref);

    These can be called from interrupt context. If CONFIG_KEYS is not set then the argument will not be parsed.

  • Extra references can be made to a key by calling one of the following functions::

    struct key *__key_get(struct key *key); struct key *key_get(struct key *key);

    Keys so references will need to be disposed of by calling key_put() when they’ve been finished with. The key pointer passed in will be returned.

    In the case of key_get(), if the pointer is NULL or CONFIG_KEYS is not set then the key will not be dereferenced and no increment will take place.

  • A key’s serial number can be obtained by calling::

    key_serial_t key_serial(struct key *key);

    If key is NULL or if CONFIG_KEYS is not set then 0 will be returned (in the latter case without parsing the argument).

  • If a keyring was found in the search, this can be further searched by::

    key_ref_t keyring_search(key_ref_t keyring_ref, const struct key_type *type, const char *description, bool recurse)

    This searches the specified keyring only (recurse == false) or keyring tree (recurse == true) specified for a matching key. Error ENOKEY is returned upon failure (use IS_ERR/PTR_ERR to determine). If successful, the returned key will need to be released.

    The possession attribute from the keyring reference is used to control access through the permissions mask and is propagated to the returned key reference pointer if successful.

  • A keyring can be created by::

    struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, const struct cred *cred, key_perm_t perm, struct key_restriction *restrict_link, unsigned long flags, struct key *dest);

    This creates a keyring with the given attributes and returns it. If dest is not NULL, the new keyring will be linked into the keyring to which it points. No permission checks are made upon the destination keyring.

    Error EDQUOT can be returned if the keyring would overload the quota (pass KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn’t be accounted towards the user’s quota). Error ENOMEM can also be returned.

    If restrict_link is not NULL, it should point to a structure that contains the function that will be called each time an attempt is made to link a key into the new keyring. The structure may also contain a key pointer and an associated key type. The function is called to check whether a key may be added into the keyring or not. The key type is used by the garbage collector to clean up function or data pointers in this structure if the given key type is unregistered. Callers of key_create_or_update() within the kernel can pass KEY_ALLOC_BYPASS_RESTRICTION to suppress the check. An example of using this is to manage rings of cryptographic keys that are set up when the kernel boots where userspace is also permitted to add keys

    • provided they can be verified by a key the kernel already has.

    When called, the restriction function will be passed the keyring being added to, the key type, the payload of the key being added, and data to be used in the restriction check. Note that when a new key is being created, this is called between payload preparsing and actual key creation. The function should return 0 to allow the link or an error to reject it.

    A convenience function, restrict_link_reject, exists to always return -EPERM to in this case.

  • To check the validity of a key, this function can be called::

    int validate_key(struct key *key);

    This checks that the key in question hasn’t expired or and hasn’t been revoked. Should the key be invalid, error EKEYEXPIRED or EKEYREVOKED will be returned. If the key is NULL or if CONFIG_KEYS is not set then 0 will be returned (in the latter case without parsing the argument).

  • To register a key type, the following function should be called::

    int register_key_type(struct key_type *type);

    This will return error EEXIST if a type of the same name is already present.

  • To unregister a key type, call::

    void unregister_key_type(struct key_type *type);

Under some circumstances, it may be desirable to deal with a bundle of keys. The facility provides access to the keyring type for managing such a bundle::

struct key_type key_type_keyring;

This can be used with a function such as request_key() to find a specific keyring in a process’s keyrings. A keyring thus found can then be searched with keyring_search(). Note that it is not possible to use request_key() to search a specific keyring, so using keyrings in this way is of limited utility.