Re: Revised request_key(2) man page for review

From: Michael Kerrisk (man-pages)
Date: Wed Dec 14 2016 - 09:24:17 EST

Hi David,

Might you also have a chance to take a look at this page?



On 4 November 2016 at 16:45, Michael Kerrisk (man-pages)
<mtk.manpages@xxxxxxxxx> wrote:
> Hi David (and anyone else with an interest to review)
> Triggered by Eugene Syromyatnikov's recent input for the keyctl(2)
> man page, I've been doing a fair bit of work on improving the key
> management syscall man pages, and wonder if I could ask you for
> some review assistance?
> First off, below, I've pasted the current draft of the request_key(2)
> page, which has seen quite a a lot of changes (increasing from around
> 100 rendered lines to nearly 300). Could you take a look (and also take
> a look at the outstanding FIXME)? (The page source file is attached,
> in case you want to see all the formatting.)
> Thanks,
> Michael
> ====
> request_key - request a key from the kernel's key management
> facility
> #include <sys/types.h>
> #include <keyutils.h>
> key_serial_t request_key(const char *type, const char *description,
> const char *callout_info,
> key_serial_t dest_keyring);
> No glibc wrapper is provided for this system call; see NOTES.
> request_key() attempts to find a key of the given type with a
> description (name) that matches the specified description. If
> such a key could not be found, then the key is optionally creâ
> ated. If the key is found or created, request_key() attaches
> it to the keyring whose ID is specified in dest_keyring and
> returns the key's serial number.
> âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
> âFIXME â
> âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
> âIs 'keyring' allowed to be 0? Reading the source, it â
> âappears so. In this case, by default, the key is â
> âassigned to the session keyring. But, the â
> âKEYCTL_SET_REQKEY_KEYRING also seems to have an â
> âinfluence here. What are the details here? â
> â â
> âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
> request_key() first recursively searches for a matching key in
> all of the keyrings attached to the calling process. The
> keyrings are searched in the order: thread-specific keyring,
> process-specific keyring, and then session keyring.
> If request_key() is called from a program invoked by
> request_key() on behalf of some other process to generate a
> key, then the keyrings of that other process will be searched
> next, using that other process's user ID, group ID, supplemenâ
> tary group IDs, and security context to determine access.
> The search of the keyring tree is breadth-first: the keys in
> each keyring searched are checked for a match before any child
> keyrings are recursed into. Only keys for which the caller has
> search permission be found, and only keyrings for which the
> caller has search permission may be searched.
> If the key is not found and callout is NULL, then the call
> fails with the error ENOKEY.
> If the key is not found and callout is not NULL, then the kerâ
> nel attempts to invoke a user-space program to instantiate the
> key. The details are given below.
> The dest_keyring serial number may be that of a valid keyring
> for which the caller has write permission, or it may be one of
> the following special keyring IDs:
> This specifies the caller's thread-specific keyring
> (thread-keyring(7)).
> This specifies the caller's process-specific keyring
> (process-keyring(7)).
> This specifies the caller's session-specific keyring
> (session-keyring(7)).
> This specifies the caller's UID-specific keyring (user-
> keyring(7)).
> This specifies the caller's UID-session keyring (user-
> session-keyring(7)).
> Requesting user-space instantiation of a key
> If the kernel cannot find a key matching type and description,
> and callout is not NULL, then the kernel attempts to invoke a
> user-space program to instantiate a key with the given type and
> description. In this case, the following steps are performed:
> a) The kernel creates an uninstantiated key, U, with the
> requested type and description.
> b) The kernel creates an authorization key, V, that refers to
> the key U and records the facts that the caller of
> request_key(2) is:
> (1) the context in which the key U should be instantiated
> and secured, and
> (2) the context from which associated key requests may be
> satisfied.
> The authorization key is constructed as follows:
> * The key type is ".request_key_auth".
> * The key's UID and GID are the same as the corresponding
> filesystem IDs of the requesting process.
> * The key grants view, read, and search permissions to the
> key possessor as well as view permission for the key
> user.
> * The description (name) of the key is the hexadecimal
> string representing the ID of the key that is to be
> instantiated in the requesting program.
> * The payload of the key is taken from the data specified
> in callout_info.
> * Internally, the kernel also records a record of the PID
> of the process that called request_key(2).
> c) The kernel creates a process that executes a user-space
> service such as request-key(8) with a new session keyring
> that contains a link to the authorization key, V.
> This program is supplied with the following command-line
> arguments:
> [0] The string "/sbin/request-key".
> [1] The string "create" (indicating that a key is to be
> created).
> [2] The ID of the key that is to be instantiated.
> [3] The filesystem UID of the caller of request_key().
> [4] The filesystem GID of the caller of request_key().
> [5] The ID of the thread keyring of the caller of
> request_key(). This may be zero if that keyring hasn't
> been created.
> [6] The ID of the process keyring of the caller of
> request_key(). This may be zero if that keyring hasn't
> been created.
> [7] The ID of the session keyring of the caller of
> request_key().
> Note: each of the command-line arguments that is a key ID
> is encoded in decimal (unlike the key IDs shown in
> /proc/keys, which are shown as hexadecimal values).
> d) The program spawned in the previous step:
> * Assumes the authority to instantiate the key U using the
> keyctl(2) KEYCTL_ASSUME_AUTHORITY operation (typically
> via the keyctl_assume_authority(3) function).
> * Obtains the callout data from the payload of the authoâ
> rization key V (using the keyctl(2) KEYCTL_READ operaâ
> tion (or, more commonly, the keyctl_read(3) function)
> with a key ID value of KEY_SPEC_REQKEY_AUTH_KEY).
> * Instantiates the key (or execs another program that perâ
> forms that task), specifying the payload and destination
> keyring. (The destination keyring that the requestor
> specified when calling request_key() can be accessed
> using the special key ID KEY_SPEC_REQUESTOR_KEYRING.)
> Instantiation is performed using the keyctl(2)
> KEYCTL_INSTANTIATE operation (or, more commonly, the
> keyctl_instantiate(3) function). At this point, the
> request_key(2) call completes, and the requesting proâ
> gram can continue execution.
> If these steps are unsuccessful, then an ENOKEY error will be
> returned to the caller of request_key() and a temporary negaâ
> tive key will be installed in the keyring specified by
> dest_keyring. This will expire after a few seconds, but will
> cause subsequent calls to request_key() to fail until it does.
> The purpose of this negatively instantiated key is to prevent
> (possibly different) processes making repeated requests (that
> require expensive request-key(8) upcalls) for a key that can't
> (at the moment) be positively instantiated.
> Once the key has been instantiated, the authorization key
> (KEY_SPEC_REQKEY_AUTH_KEY) is revoked, and the destination
> keyring (KEY_SPEC_REQUESTOR_KEYRING) is no longer accessible
> from the request-key(8) program.
> If a key is created, thenâregardless of whether it is a valid
> key or a negative keyâit will displace any other key with the
> same type and description from the keyring specified in
> dest_keyring.
> On success, request_key() returns the serial number of the key
> it found or caused to be created. On error, -1 is returned and
> errno is set to indicate the cause of the error.
> EACCES The keyring wasn't available for modification by the
> user.
> EDQUOT The key quota for this user would be exceeded by creatâ
> ing this key or linking it to the keyring.
> EINTR The request was interrupted by a signal; see signal(7).
> EINVAL The size of the string (including the terminating null
> byte) specified in type or description exceeded the
> limit (32 bytes and 4096 bytes respectively).
> EINVAL The size of the string (including the terminating null
> byte) specified in callout_info exceeded the system page
> size.
> An expired key was found, but no replacement could be
> obtained.
> The attempt to generate a new key was rejected.
> A revoked key was found, but no replacement could be
> obtained.
> ENOKEY No matching key was found.
> ENOMEM Insufficient memory to create a key.
> This system call first appeared in Linux 2.6.10.
> This system call is a nonstandard Linux extension.
> No wrapper for this system call is provided in glibc. A wrapâ
> per is provided in the libkeyutils package. When employing the
> wrapper in that library, link with -lkeyutils.
> The program below demonstrates the use of request_key(). The
> type, description, and callout_info arguments for the system
> call are taken from the values supplied in the command line
> arguments. The call specifies the session keyring as the tarâ
> get keyring.
> In order to demonstrate this program, we first create a suitâ
> able entry in the file /etc/request-key.conf.
> $ sudo sh
> # echo 'create user mtk:* * /bin/keyctl instantiate %k %c %S' \
> > /etc/request-keys.conf
> # exit
> This entry specifies that when a new "user" key with the prefix
> "mtk:" must be instantiated, that task should be performed via
> the keyctl(1) command's instantiate operation. (The program
> could The arguments supplied to the instantiate operation are:
> the ID of the uninstantiated key (%k); the callout data supâ
> plied to the request_key() call (%c); and the session keyring
> (%S) of the requestor (i.e., the caller of request)key()).
> i(See request-key.conf(5) for details of these % specifiers.)
> Then we run the program and check the contents of /proc/keys to
> verify that the requested kay has been instantiated:
> $ ./a.out user mtk:key1 "Payload data"
> $ grep '2dddaf50' /proc/keys
> 2dddaf50 I--Q--- 1 perm 3f010000 1000 1000 user mtk:key1: 12
> Program source
> The program below
> #include <sys/types.h>
> #include <keyutils.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
> } while (0)
> int
> main(int argc, char *argv[])
> {
> key_serial_t key;
> if (argc != 4) {
> fprintf(stderr, "Usage: %s type description callout-data\n",
> argv[0]);
> }
> key = request_key(argv[1], argv[2], argv[3],
> if (key == -1)
> errExit("request_key");
> printf("Key ID is %lx\n", (long) key);
> }
> keyctl(1), add_key(2), keyctl(2), keyctl(3), keyrings(7),
> keyutils(7), capabilities(7), persistent-keyring(7),
> process-keyring(7), session-keyring(7), thread-keyring(7),
> user-keyring(7), user-session-keyring(7), request-key(8)
> The kernel source files Documentation/security/keys.txt and
> Documentation/security/keys-request-key.txt.
> Linux 2016-10-08 REQUEST_KEY(2)
> --
> Michael Kerrisk
> Linux man-pages maintainer;
> Linux/UNIX System Programming Training:

Michael Kerrisk
Linux man-pages maintainer;
Linux/UNIX System Programming Training: