Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76181c13 authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

KEYS: Make request_key() and co fundamentally asynchronous



Make request_key() and co fundamentally asynchronous to make it easier for
NFS to make use of them.  There are now accessor functions that do
asynchronous constructions, a wait function to wait for construction to
complete, and a completion function for the key type to indicate completion
of construction.

Note that the construction queue is now gone.  Instead, keys under
construction are linked in to the appropriate keyring in advance, and that
anyone encountering one must wait for it to be complete before they can use
it.  This is done automatically for userspace.

The following auxiliary changes are also made:

 (1) Key type implementation stuff is split from linux/key.h into
     linux/key-type.h.

 (2) AF_RXRPC provides a way to allocate null rxrpc-type keys so that AFS does
     not need to call key_instantiate_and_link() directly.

 (3) Adjust the debugging macros so that they're -Wformat checked even if
     they are disabled, and make it so they can be enabled simply by defining
     __KDEBUG to be consistent with other code of mine.

 (3) Documentation.

[alan@lxorguk.ukuu.org.uk: keys: missing word in documentation]
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 398c95bd
Loading
Loading
Loading
Loading
+21 −4
Original line number Diff line number Diff line
@@ -20,6 +20,19 @@ or:
					     const char *callout_string,
					     void *aux);

or:

	struct key *request_key_async(const struct key_type *type,
				      const char *description,
				      const char *callout_string);

or:

	struct key *request_key_async_with_auxdata(const struct key_type *type,
						   const char *description,
						   const char *callout_string,
						   void *aux);

Or by userspace invoking the request_key system call:

	key_serial_t request_key(const char *type,
@@ -32,10 +45,14 @@ does not need to link the key to a keyring to prevent it from being immediately
destroyed.  The kernel interface returns a pointer directly to the key, and
it's up to the caller to destroy the key.

The request_key_with_auxdata() call is like the in-kernel request_key() call,
except that it permits auxiliary data to be passed to the upcaller (the default
is NULL).  This is only useful for those key types that define their own upcall
mechanism rather than using /sbin/request-key.
The request_key*_with_auxdata() calls are like the in-kernel request_key*()
calls, except that they permit auxiliary data to be passed to the upcaller (the
default is NULL).  This is only useful for those key types that define their
own upcall mechanism rather than using /sbin/request-key.

The two async in-kernel calls may return keys that are still in the process of
being constructed.  The two non-async ones will wait for construction to
complete first.

The userspace interface links the key to a keyring associated with the process
to prevent the key from going away, and returns the serial number of the key to
+79 −14
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@

This service allows cryptographic keys, authentication tokens, cross-domain
user mappings, and similar to be cached in the kernel for the use of
filesystems other kernel services.
filesystems and other kernel services.

Keyrings are permitted; these are a special type of key that can hold links to
other keys. Processes each have three standard keyring subscriptions that a
@@ -726,6 +726,15 @@ 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:

@@ -791,6 +800,36 @@ payload contents" for more information.
    passed to the key_type->request_key() op if it exists.


(*) A key can be requested asynchronously by calling one of:

	struct key *request_key_async(const struct key_type *type,
				      const char *description,
				      const char *callout_string);

    or:

	struct key *request_key_async_with_auxdata(const struct key_type *type,
						   const char *description,
						   const char *callout_string,
					     	   void *aux);

    which are asynchronous equivalents of request_key() and
    request_key_with_auxdata() respectively.

    These two functions return with the key potentially still under
    construction.  To wait for contruction completion, the following should be
    called:

	int wait_for_key_construction(struct key *key, bool intr);

    The function will wait for the key to finish being constructed and then
    invokes key_validate() to return an appropriate value to indicate the state
    of the key (0 indicates the key is usable).

    If intr is true, then the wait can be interrupted by a signal, in which
    case error ERESTARTSYS will be returned.


(*) When it is no longer required, the key should be released using:

	void key_put(struct key *key);
@@ -924,7 +963,11 @@ DEFINING A KEY TYPE

A kernel service may want to define its own key type. For instance, an AFS
filesystem might want to define a Kerberos 5 ticket key type. To do this, it
author fills in a struct key_type and registers it with the system.
author fills in a key_type struct and registers it with the system.

Source files that implement key types should include the following header file:

	<linux/key-type.h>

The structure has a number of fields, some of which are mandatory:

@@ -1053,22 +1096,44 @@ The structure has a number of fields, some of which are mandatory:
     as might happen when the userspace buffer is accessed.


 (*) int (*request_key)(struct key *key, struct key *authkey, const char *op,
 (*) int (*request_key)(struct key_construction *cons, const char *op,
			void *aux);

     This method is optional.  If provided, request_key() and
     request_key_with_auxdata() will invoke this function rather than
     upcalling to /sbin/request-key to operate upon a key of this type.
     This method is optional.  If provided, request_key() and friends will
     invoke this function rather than upcalling to /sbin/request-key to operate
     upon a key of this type.

     The aux parameter is as passed to request_key_async_with_auxdata() and
     similar or is NULL otherwise.  Also passed are the construction record for
     the key to be operated upon and the operation type (currently only
     "create").

     This method is permitted to return before the upcall is complete, but the
     following function must be called under all circumstances to complete the
     instantiation process, whether or not it succeeds, whether or not there's
     an error:

	void complete_request_key(struct key_construction *cons, int error);

     The error parameter should be 0 on success, -ve on error.  The
     construction record is destroyed by this action and the authorisation key
     will be revoked.  If an error is indicated, the key under construction
     will be negatively instantiated if it wasn't already instantiated.

     If this method returns an error, that error will be returned to the
     caller of request_key*().  complete_request_key() must be called prior to
     returning.

     The key under construction and the authorisation key can be found in the
     key_construction struct pointed to by cons:

     (*) struct key *key;

     	 The key under construction.

     The aux parameter is as passed to request_key_with_auxdata() or is NULL
     otherwise.  Also passed are the key to be operated upon, the
     authorisation key for this operation and the operation type (currently
     only "create").
     (*) struct key *authkey;

     This function should return only when the upcall is complete.  Upon return
     the authorisation key will be revoked, and the target key will be
     negatively instantiated if it is still uninstantiated.  The error will be
     returned to the caller of request_key*().
     	 The authorisation key.


============================
+7 −0
Original line number Diff line number Diff line
@@ -857,3 +857,10 @@ The kernel interface functions are as follows:

     This is used to extract the error number from a message indicating either
     a local error occurred or a network error occurred.

 (*) Allocate a null key for doing anonymous security.

	struct key *rxrpc_get_null_key(const char *keyname);

     This is used to allocate a null RxRPC key that can be used to indicate
     anonymous security for a particular domain.
+6 −11
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ static struct afs_cell *afs_cell_root;
static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
{
	struct afs_cell *cell;
	struct key *key;
	size_t namelen;
	char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
	int ret;
@@ -89,20 +90,14 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
	do {
		*dp++ = toupper(*cp);
	} while (*cp++);
	cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
					KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
	if (IS_ERR(cell->anonymous_key)) {
		_debug("no key");
		ret = PTR_ERR(cell->anonymous_key);
		goto error;
	}

	ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0,
				       NULL, NULL);
	if (ret < 0) {
		_debug("instantiate failed");
	key = rxrpc_get_null_key(keyname);
	if (IS_ERR(key)) {
		_debug("no key");
		ret = PTR_ERR(key);
		goto error;
	}
	cell->anonymous_key = key;

	_debug("anon key %p{%x}",
	       cell->anonymous_key, key_serial(cell->anonymous_key));
+2 −0
Original line number Diff line number Diff line
@@ -19,4 +19,6 @@
 */
extern struct key_type key_type_rxrpc;

extern struct key *rxrpc_get_null_key(const char *);

#endif /* _KEYS_USER_TYPE_H */
Loading