summaryrefslogtreecommitdiffstats
path: root/security/keys/process_keys.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-01-08 01:02:47 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 20:13:53 -0800
commitb5f545c880a2a47947ba2118b2509644ab7a2969 (patch)
tree8720e02262b0ff6309ae79603f6c63965296d378 /security/keys/process_keys.c
parentcab8eb594e84b434d20412fc5a3985b0bee3ab9f (diff)
downloadblackbird-op-linux-b5f545c880a2a47947ba2118b2509644ab7a2969.tar.gz
blackbird-op-linux-b5f545c880a2a47947ba2118b2509644ab7a2969.zip
[PATCH] keys: Permit running process to instantiate keys
Make it possible for a running process (such as gssapid) to be able to instantiate a key, as was requested by Trond Myklebust for NFS4. The patch makes the following changes: (1) A new, optional key type method has been added. This permits a key type to intercept requests at the point /sbin/request-key is about to be spawned and do something else with them - passing them over the rpc_pipefs files or netlink sockets for instance. The uninstantiated key, the authorisation key and the intended operation name are passed to the method. (2) The callout_info is no longer passed as an argument to /sbin/request-key to prevent unauthorised viewing of this data using ps or by looking in /proc/pid/cmdline. This means that the old /sbin/request-key program will not work with the patched kernel as it will expect to see an extra argument that is no longer there. A revised keyutils package will be made available tomorrow. (3) The callout_info is now attached to the authorisation key. Reading this key will retrieve the information. (4) A new field has been added to the task_struct. This holds the authorisation key currently active for a thread. Searches now look here for the caller's set of keys rather than looking for an auth key in the lowest level of the session keyring. This permits a thread to be servicing multiple requests at once and to switch between them. Note that this is per-thread, not per-process, and so is usable in multithreaded programs. The setting of this field is inherited across fork and exec. (5) A new keyctl function (KEYCTL_ASSUME_AUTHORITY) has been added that permits a thread to assume the authority to deal with an uninstantiated key. Assumption is only permitted if the authorisation key associated with the uninstantiated key is somewhere in the thread's keyrings. This function can also clear the assumption. (6) A new magic key specifier has been added to refer to the currently assumed authorisation key (KEY_SPEC_REQKEY_AUTH_KEY). (7) Instantiation will only proceed if the appropriate authorisation key is assumed first. The assumed authorisation key is discarded if instantiation is successful. (8) key_validate() is moved from the file of request_key functions to the file of permissions functions. (9) The documentation is updated. From: <Valdis.Kletnieks@vt.edu> Build fix. Signed-off-by: David Howells <dhowells@redhat.com> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Cc: Alexander Zangerl <az@bond.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security/keys/process_keys.c')
-rw-r--r--security/keys/process_keys.c71
1 files changed, 38 insertions, 33 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 566b1cc0118a..74cb79eb917e 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -270,9 +270,14 @@ int copy_thread_group_keys(struct task_struct *tsk)
int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
{
key_check(tsk->thread_keyring);
+ key_check(tsk->request_key_auth);
/* no thread keyring yet */
tsk->thread_keyring = NULL;
+
+ /* copy the request_key() authorisation for this thread */
+ key_get(tsk->request_key_auth);
+
return 0;
} /* end copy_keys() */
@@ -290,11 +295,12 @@ void exit_thread_group_keys(struct signal_struct *tg)
/*****************************************************************************/
/*
- * dispose of keys upon thread exit
+ * dispose of per-thread keys upon thread exit
*/
void exit_keys(struct task_struct *tsk)
{
key_put(tsk->thread_keyring);
+ key_put(tsk->request_key_auth);
} /* end exit_keys() */
@@ -382,7 +388,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
struct task_struct *context)
{
struct request_key_auth *rka;
- key_ref_t key_ref, ret, err, instkey_ref;
+ key_ref_t key_ref, ret, err;
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
@@ -461,30 +467,12 @@ key_ref_t search_process_keyrings(struct key_type *type,
err = key_ref;
break;
}
-
- /* if this process has a session keyring and that has an
- * instantiation authorisation key in the bottom level, then we
- * also search the keyrings of the process mentioned there */
- if (context != current)
- goto no_key;
-
- rcu_read_lock();
- instkey_ref = __keyring_search_one(
- make_key_ref(rcu_dereference(
- context->signal->session_keyring),
- 1),
- &key_type_request_key_auth, NULL, 0);
- rcu_read_unlock();
-
- if (IS_ERR(instkey_ref))
- goto no_key;
-
- rka = key_ref_to_ptr(instkey_ref)->payload.data;
-
- key_ref = search_process_keyrings(type, description, match,
- rka->context);
- key_ref_put(instkey_ref);
-
+ }
+ /* or search the user-session keyring */
+ else {
+ key_ref = keyring_search_aux(
+ make_key_ref(context->user->session_keyring, 1),
+ context, type, description, match);
if (!IS_ERR(key_ref))
goto found;
@@ -500,11 +488,21 @@ key_ref_t search_process_keyrings(struct key_type *type,
break;
}
}
- /* or search the user-session keyring */
- else {
- key_ref = keyring_search_aux(
- make_key_ref(context->user->session_keyring, 1),
- context, type, description, match);
+
+ /* if this process has an instantiation authorisation key, then we also
+ * search the keyrings of the process mentioned there
+ * - we don't permit access to request_key auth keys via this method
+ */
+ if (context->request_key_auth &&
+ context == current &&
+ type != &key_type_request_key_auth &&
+ key_validate(context->request_key_auth) == 0
+ ) {
+ rka = context->request_key_auth->payload.data;
+
+ key_ref = search_process_keyrings(type, description, match,
+ rka->context);
+
if (!IS_ERR(key_ref))
goto found;
@@ -521,8 +519,6 @@ key_ref_t search_process_keyrings(struct key_type *type,
}
}
-
-no_key:
/* no key - decide on the error we're going to go for */
key_ref = ret ? ret : err;
@@ -628,6 +624,15 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
key = ERR_PTR(-EINVAL);
goto error;
+ case KEY_SPEC_REQKEY_AUTH_KEY:
+ key = context->request_key_auth;
+ if (!key)
+ goto error;
+
+ atomic_inc(&key->usage);
+ key_ref = make_key_ref(key, 1);
+ break;
+
default:
key_ref = ERR_PTR(-EINVAL);
if (id < 1)
OpenPOWER on IntegriCloud