forked from Minki/linux
[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: David Howells <dhowells@redhat.com> Acked-By: Kevin Coffman <kwc@citi.umich.edu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
94583779e6
commit
4e54f08543
@ -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
|
||||
@ -62,7 +79,7 @@ A request proceeds in the following manner:
|
||||
instantiation.
|
||||
|
||||
(7) The program may want to access another key from A's context (say a
|
||||
Kerberos TGT key). It just requests the appropriate key, and the keyring
|
||||
Kerberos TGT key). It just requests the appropriate key, and the keyring
|
||||
search notes that the session keyring has auth key V in its bottom level.
|
||||
|
||||
This will permit it to then search the keyrings of process A with the
|
||||
@ -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
|
||||
@ -118,17 +136,17 @@ A search of any particular keyring proceeds in the following fashion:
|
||||
|
||||
(2) It considers all the non-keyring keys within that keyring and, if any key
|
||||
matches the criteria specified, calls key_permission(SEARCH) on it to see
|
||||
if the key is allowed to be found. If it is, that key is returned; if
|
||||
if the key is allowed to be found. If it is, that key is returned; if
|
||||
not, the search continues, and the error code is retained if of higher
|
||||
priority than the one currently set.
|
||||
|
||||
(3) It then considers all the keyring-type keys in the keyring it's currently
|
||||
searching. It calls key_permission(SEARCH) on each keyring, and if this
|
||||
searching. It calls key_permission(SEARCH) on each keyring, and if this
|
||||
grants permission, it recurses, executing steps (2) and (3) on that
|
||||
keyring.
|
||||
|
||||
The process stops immediately a valid key is found with permission granted to
|
||||
use it. Any error from a previous match attempt is discarded and the key is
|
||||
use it. Any error from a previous match attempt is discarded and the key is
|
||||
returned.
|
||||
|
||||
When search_process_keyrings() is invoked, it performs the following searches
|
||||
@ -153,7 +171,7 @@ The moment one succeeds, all pending errors are discarded and the found key is
|
||||
returned.
|
||||
|
||||
Only if all these fail does the whole thing fail with the highest priority
|
||||
error. Note that several errors may have come from LSM.
|
||||
error. Note that several errors may have come from LSM.
|
||||
|
||||
The error priority is:
|
||||
|
||||
|
@ -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
|
||||
============================
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* request_key.c: request a key from userspace
|
||||
*
|
||||
* Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -33,7 +33,8 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
|
||||
*/
|
||||
static int call_sbin_request_key(struct key *key,
|
||||
struct key *authkey,
|
||||
const char *op)
|
||||
const char *op,
|
||||
void *aux)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
key_serial_t prkey, sskey;
|
||||
@ -127,6 +128,7 @@ error_alloc:
|
||||
static struct key *__request_key_construction(struct key_type *type,
|
||||
const char *description,
|
||||
const char *callout_info,
|
||||
void *aux,
|
||||
unsigned long flags)
|
||||
{
|
||||
request_key_actor_t actor;
|
||||
@ -164,7 +166,7 @@ static struct key *__request_key_construction(struct key_type *type,
|
||||
actor = call_sbin_request_key;
|
||||
if (type->request_key)
|
||||
actor = type->request_key;
|
||||
ret = actor(key, authkey, "create");
|
||||
ret = actor(key, authkey, "create", aux);
|
||||
if (ret < 0)
|
||||
goto request_failed;
|
||||
|
||||
@ -258,8 +260,9 @@ alloc_failed:
|
||||
*/
|
||||
static struct key *request_key_construction(struct key_type *type,
|
||||
const char *description,
|
||||
struct key_user *user,
|
||||
const char *callout_info,
|
||||
void *aux,
|
||||
struct key_user *user,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct key_construction *pcons;
|
||||
@ -284,7 +287,7 @@ static struct key *request_key_construction(struct key_type *type,
|
||||
}
|
||||
|
||||
/* see about getting userspace to construct the key */
|
||||
key = __request_key_construction(type, description, callout_info,
|
||||
key = __request_key_construction(type, description, callout_info, aux,
|
||||
flags);
|
||||
error:
|
||||
kleave(" = %p", key);
|
||||
@ -392,6 +395,7 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
|
||||
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)
|
||||
{
|
||||
@ -399,8 +403,9 @@ struct key *request_key_and_link(struct key_type *type,
|
||||
struct key *key;
|
||||
key_ref_t key_ref;
|
||||
|
||||
kenter("%s,%s,%s,%p,%lx",
|
||||
type->name, description, callout_info, dest_keyring, flags);
|
||||
kenter("%s,%s,%s,%p,%p,%lx",
|
||||
type->name, description, callout_info, aux,
|
||||
dest_keyring, flags);
|
||||
|
||||
/* search all the process keyrings for a key */
|
||||
key_ref = search_process_keyrings(type, description, type->match,
|
||||
@ -433,8 +438,8 @@ struct key *request_key_and_link(struct key_type *type,
|
||||
/* ask userspace (returns NULL if it waited on a key
|
||||
* being constructed) */
|
||||
key = request_key_construction(type, description,
|
||||
user, callout_info,
|
||||
flags);
|
||||
callout_info, aux,
|
||||
user, flags);
|
||||
if (key)
|
||||
break;
|
||||
|
||||
@ -491,8 +496,27 @@ struct key *request_key(struct key_type *type,
|
||||
const char *callout_info)
|
||||
{
|
||||
return request_key_and_link(type, description, callout_info, NULL,
|
||||
KEY_ALLOC_IN_QUOTA);
|
||||
NULL, KEY_ALLOC_IN_QUOTA);
|
||||
|
||||
} /* end request_key() */
|
||||
|
||||
EXPORT_SYMBOL(request_key);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* request a key with auxiliary data for the upcaller
|
||||
* - search the process's keyrings
|
||||
* - check the list of keys being created or updated
|
||||
* - call out to userspace for a key if supplementary info was provided
|
||||
*/
|
||||
struct key *request_key_with_auxdata(struct key_type *type,
|
||||
const char *description,
|
||||
const char *callout_info,
|
||||
void *aux)
|
||||
{
|
||||
return request_key_and_link(type, description, callout_info, aux,
|
||||
NULL, KEY_ALLOC_IN_QUOTA);
|
||||
|
||||
} /* end request_key_with_auxdata() */
|
||||
|
||||
EXPORT_SYMBOL(request_key_with_auxdata);
|
||||
|
Loading…
Reference in New Issue
Block a user