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

Commit 4e54f085 authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

[PATCH] Keys: Allow in-kernel key requestor to pass auxiliary data to upcaller



The proposed NFS key type uses its own method of passing key requests to
userspace (upcalling) rather than invoking /sbin/request-key.  This is
because the responsible userspace daemon should already be running and will
be contacted through rpc_pipefs.

This patch permits the NFS filesystem to pass auxiliary data to the upcall
operation (struct key_type::request_key) so that the upcaller can use a
pre-existing communications channel more easily.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Acked-By: default avatarKevin Coffman <kwc@citi.umich.edu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 94583779
Loading
Loading
Loading
Loading
+36 −18
Original line number Diff line number Diff line
@@ -3,16 +3,23 @@
			      ===================

The key request service is part of the key retention service (refer to
Documentation/keys.txt). This document explains more fully how that the
requesting algorithm works.
Documentation/keys.txt).  This document explains more fully how the requesting
algorithm works.

The process starts by either the kernel requesting a service by calling
request_key():
request_key*():

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

or:

	struct key *request_key_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,
@@ -20,16 +27,26 @@ Or by userspace invoking the request_key system call:
				 const char *callout_info,
				 key_serial_t dest_keyring);

The main difference between the two access points is that the in-kernel
interface 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 main difference between the access points is that the in-kernel interface
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 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
the caller.


The following example assumes that the key types involved don't define their
own upcall mechanisms.  If they do, then those should be substituted for the
forking and execution of /sbin/request-key.


===========
THE PROCESS
===========
@@ -40,8 +57,8 @@ A request proceeds in the following manner:
     interface].

 (2) request_key() searches the process's subscribed keyrings to see if there's
     a suitable key there. If there is, it returns the key. If there isn't, and
     callout_info is not set, an error is returned. Otherwise the process
     a suitable key there.  If there is, it returns the key.  If there isn't,
     and callout_info is not set, an error is returned.  Otherwise the process
     proceeds to the next step.

 (3) request_key() sees that A doesn't have the desired key yet, so it creates
@@ -79,10 +96,11 @@ A request proceeds in the following manner:
(10) The program then exits 0 and request_key() deletes key V and returns key
     U to the caller.

This also extends further. If key W (step 7 above) didn't exist, key W would be
created uninstantiated, another auth key (X) would be created (as per step 3)
and another copy of /sbin/request-key spawned (as per step 4); but the context
specified by auth key X will still be process A, as it was in auth key V.
This also extends further.  If key W (step 7 above) didn't exist, key W would
be created uninstantiated, another auth key (X) would be created (as per step
3) and another copy of /sbin/request-key spawned (as per step 4); but the
context specified by auth key X will still be process A, as it was in auth key
V.

This is because process A's keyrings can't simply be attached to
/sbin/request-key at the appropriate places because (a) execve will discard two
+29 −0
Original line number Diff line number Diff line
@@ -780,6 +780,17 @@ payload contents" for more information.
    See also Documentation/keys-request-key.txt.


(*) 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,
					     const char *callout_string,
					     void *aux);

    This is identical to request_key(), except that the auxiliary data is
    passed to the key_type->request_key() op if it exists.


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

	void key_put(struct key *key);
@@ -1031,6 +1042,24 @@ 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,
			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.

     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").

     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*().


============================
REQUEST-KEY CALLBACK SERVICE
============================
+7 −1
Original line number Diff line number Diff line
@@ -177,7 +177,8 @@ struct key {
/*
 * kernel managed key type definition
 */
typedef int (*request_key_actor_t)(struct key *key, struct key *authkey, const char *op);
typedef int (*request_key_actor_t)(struct key *key, struct key *authkey,
				   const char *op, void *aux);

struct key_type {
	/* name of the type */
@@ -285,6 +286,11 @@ extern struct key *request_key(struct key_type *type,
			       const char *description,
			       const char *callout_info);

extern struct key *request_key_with_auxdata(struct key_type *type,
					    const char *description,
					    const char *callout_info,
					    void *aux);

extern int key_validate(struct key *key);

extern key_ref_t key_create_or_update(key_ref_t keyring,
+1 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ extern int install_process_keyring(struct task_struct *tsk);
extern struct key *request_key_and_link(struct key_type *type,
					const char *description,
					const char *callout_info,
					void *aux,
					struct key *dest_keyring,
					unsigned long flags);

+1 −1
Original line number Diff line number Diff line
@@ -183,7 +183,7 @@ asmlinkage long sys_request_key(const char __user *_type,
	}

	/* do the search */
	key = request_key_and_link(ktype, description, callout_info,
	key = request_key_and_link(ktype, description, callout_info, NULL,
				   key_ref_to_ptr(dest_ref),
				   KEY_ALLOC_IN_QUOTA);
	if (IS_ERR(key)) {
Loading