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

[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
...@@ -3,16 +3,23 @@ ...@@ -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: ...@@ -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: ...@@ -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
...@@ -62,7 +79,7 @@ A request proceeds in the following manner: ...@@ -62,7 +79,7 @@ A request proceeds in the following manner:
instantiation. instantiation.
(7) The program may want to access another key from A's context (say a (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. 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 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: ...@@ -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
...@@ -118,17 +136,17 @@ A search of any particular keyring proceeds in the following fashion: ...@@ -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 (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 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 not, the search continues, and the error code is retained if of higher
priority than the one currently set. priority than the one currently set.
(3) It then considers all the keyring-type keys in the keyring it's currently (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 grants permission, it recurses, executing steps (2) and (3) on that
keyring. keyring.
The process stops immediately a valid key is found with permission granted to 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. returned.
When search_process_keyrings() is invoked, it performs the following searches 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 ...@@ -153,7 +171,7 @@ The moment one succeeds, all pending errors are discarded and the found key is
returned. returned.
Only if all these fail does the whole thing fail with the highest priority 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: The error priority is:
......
...@@ -780,6 +780,17 @@ payload contents" for more information. ...@@ -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: ...@@ -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
============================ ============================
......
...@@ -177,7 +177,8 @@ struct key { ...@@ -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, ...@@ -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,
......
...@@ -99,6 +99,7 @@ extern int install_process_keyring(struct task_struct *tsk); ...@@ -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);
......
...@@ -183,7 +183,7 @@ asmlinkage long sys_request_key(const char __user *_type, ...@@ -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)) {
......
/* request_key.c: request a key from userspace /* 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) * Written by David Howells (dhowells@redhat.com)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -33,7 +33,8 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); ...@@ -33,7 +33,8 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
*/ */
static int call_sbin_request_key(struct key *key, static int call_sbin_request_key(struct key *key,
struct key *authkey, struct key *authkey,
const char *op) const char *op,
void *aux)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
key_serial_t prkey, sskey; key_serial_t prkey, sskey;
...@@ -127,6 +128,7 @@ static int call_sbin_request_key(struct key *key, ...@@ -127,6 +128,7 @@ static int call_sbin_request_key(struct key *key,
static struct key *__request_key_construction(struct key_type *type, static struct key *__request_key_construction(struct key_type *type,
const char *description, const char *description,
const char *callout_info, const char *callout_info,
void *aux,
unsigned long flags) unsigned long flags)
{ {
request_key_actor_t actor; request_key_actor_t actor;
...@@ -164,7 +166,7 @@ static struct key *__request_key_construction(struct key_type *type, ...@@ -164,7 +166,7 @@ static struct key *__request_key_construction(struct key_type *type,
actor = call_sbin_request_key; actor = call_sbin_request_key;
if (type->request_key) if (type->request_key)
actor = type->request_key; actor = type->request_key;
ret = actor(key, authkey, "create"); ret = actor(key, authkey, "create", aux);
if (ret < 0) if (ret < 0)
goto request_failed; goto request_failed;
...@@ -258,8 +260,9 @@ static struct key *__request_key_construction(struct key_type *type, ...@@ -258,8 +260,9 @@ static struct key *__request_key_construction(struct key_type *type,
*/ */
static struct key *request_key_construction(struct key_type *type, static struct key *request_key_construction(struct key_type *type,
const char *description, const char *description,
struct key_user *user,
const char *callout_info, const char *callout_info,
void *aux,
struct key_user *user,
unsigned long flags) unsigned long flags)
{ {
struct key_construction *pcons; struct key_construction *pcons;
...@@ -284,7 +287,7 @@ static struct key *request_key_construction(struct key_type *type, ...@@ -284,7 +287,7 @@ static struct key *request_key_construction(struct key_type *type,
} }
/* see about getting userspace to construct the key */ /* 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); flags);
error: error:
kleave(" = %p", key); kleave(" = %p", key);
...@@ -392,6 +395,7 @@ static void request_key_link(struct key *key, struct key *dest_keyring) ...@@ -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, 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)
{ {
...@@ -399,8 +403,9 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -399,8 +403,9 @@ struct key *request_key_and_link(struct key_type *type,
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
kenter("%s,%s,%s,%p,%lx", kenter("%s,%s,%s,%p,%p,%lx",
type->name, description, callout_info, dest_keyring, flags); type->name, description, callout_info, aux,
dest_keyring, flags);
/* search all the process keyrings for a key */ /* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match, key_ref = search_process_keyrings(type, description, type->match,
...@@ -433,8 +438,8 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -433,8 +438,8 @@ struct key *request_key_and_link(struct key_type *type,
/* ask userspace (returns NULL if it waited on a key /* ask userspace (returns NULL if it waited on a key
* being constructed) */ * being constructed) */
key = request_key_construction(type, description, key = request_key_construction(type, description,
user, callout_info, callout_info, aux,
flags); user, flags);
if (key) if (key)
break; break;
...@@ -491,8 +496,27 @@ struct key *request_key(struct key_type *type, ...@@ -491,8 +496,27 @@ struct key *request_key(struct key_type *type,
const char *callout_info) const char *callout_info)
{ {
return request_key_and_link(type, description, callout_info, NULL, return request_key_and_link(type, description, callout_info, NULL,
KEY_ALLOC_IN_QUOTA); NULL, KEY_ALLOC_IN_QUOTA);
} /* end request_key() */ } /* end request_key() */
EXPORT_SYMBOL(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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment