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 Original line Diff line number Diff line
@@ -3,16 +3,23 @@
			      ===================
			      ===================


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


The process starts by either the kernel requesting a service by calling
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,
	struct key *request_key(const struct key_type *type,
				const char *description,
				const char *description,
				const char *callout_string);
				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:
Or by userspace invoking the request_key system call:


	key_serial_t request_key(const char *type,
	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,
				 const char *callout_info,
				 key_serial_t dest_keyring);
				 key_serial_t dest_keyring);


The main difference between the two access points is that the in-kernel
The main difference between the access points is that the in-kernel interface
interface does not need to link the key to a keyring to prevent it from being
does not need to link the key to a keyring to prevent it from being immediately
immediately destroyed. The kernel interface returns a pointer directly to the
destroyed.  The kernel interface returns a pointer directly to the key, and
key, and it's up to the caller to destroy the key.
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
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
to prevent the key from going away, and returns the serial number of the key to
the caller.
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
THE PROCESS
===========
===========
@@ -40,8 +57,8 @@ A request proceeds in the following manner:
     interface].
     interface].


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


 (3) request_key() sees that A doesn't have the desired key yet, so it creates
 (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
(10) The program then exits 0 and request_key() deletes key V and returns key
     U to the caller.
     U to the caller.


This also extends further. If key W (step 7 above) didn't exist, key W would be
This also extends further.  If key W (step 7 above) didn't exist, key W would
created uninstantiated, another auth key (X) would be created (as per step 3)
be created uninstantiated, another auth key (X) would be created (as per step
and another copy of /sbin/request-key spawned (as per step 4); but the context
3) and another copy of /sbin/request-key spawned (as per step 4); but the
specified by auth key X will still be process A, as it was in auth key V.
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
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
/sbin/request-key at the appropriate places because (a) execve will discard two
+29 −0
Original line number Original line Diff line number Diff line
@@ -780,6 +780,17 @@ payload contents" for more information.
    See also Documentation/keys-request-key.txt.
    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:
(*) When it is no longer required, the key should be released using:


	void key_put(struct key *key);
	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.
     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
REQUEST-KEY CALLBACK SERVICE
============================
============================
+7 −1
Original line number Original line Diff line number Diff line
@@ -177,7 +177,8 @@ struct key {
/*
/*
 * kernel managed key type definition
 * 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 {
struct key_type {
	/* name of the type */
	/* name of the type */
@@ -285,6 +286,11 @@ extern struct key *request_key(struct key_type *type,
			       const char *description,
			       const char *description,
			       const char *callout_info);
			       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 int key_validate(struct key *key);


extern key_ref_t key_create_or_update(key_ref_t keyring,
extern key_ref_t key_create_or_update(key_ref_t keyring,
+1 −0
Original line number Original line 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,
extern struct key *request_key_and_link(struct key_type *type,
					const char *description,
					const char *description,
					const char *callout_info,
					const char *callout_info,
					void *aux,
					struct key *dest_keyring,
					struct key *dest_keyring,
					unsigned long flags);
					unsigned long flags);


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


	/* do the search */
	/* 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_ref_to_ptr(dest_ref),
				   KEY_ALLOC_IN_QUOTA);
				   KEY_ALLOC_IN_QUOTA);
	if (IS_ERR(key)) {
	if (IS_ERR(key)) {
Loading