diff options
author | David Howells <dhowells@redhat.com> | 2006-01-08 01:02:47 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 20:13:53 -0800 |
commit | b5f545c880a2a47947ba2118b2509644ab7a2969 (patch) | |
tree | 8720e02262b0ff6309ae79603f6c63965296d378 /security/keys/keyctl.c | |
parent | cab8eb594e84b434d20412fc5a3985b0bee3ab9f (diff) |
[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/keyctl.c')
-rw-r--r-- | security/keys/keyctl.c | 107 |
1 files changed, 84 insertions, 23 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 299f0ae11cf..3d2ebae029c 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -834,6 +834,17 @@ long keyctl_instantiate_key(key_serial_t id, if (plen > 32767) goto error; + /* the appropriate instantiation authorisation key must have been + * assumed before calling this */ + ret = -EPERM; + instkey = current->request_key_auth; + if (!instkey) + goto error; + + rka = instkey->payload.data; + if (rka->target_key->serial != id) + goto error; + /* pull the payload in if one was supplied */ payload = NULL; @@ -848,15 +859,6 @@ long keyctl_instantiate_key(key_serial_t id, goto error2; } - /* find the instantiation authorisation key */ - instkey = key_get_instantiation_authkey(id); - if (IS_ERR(instkey)) { - ret = PTR_ERR(instkey); - goto error2; - } - - rka = instkey->payload.data; - /* find the destination keyring amongst those belonging to the * requesting task */ keyring_ref = NULL; @@ -865,7 +867,7 @@ long keyctl_instantiate_key(key_serial_t id, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); - goto error3; + goto error2; } } @@ -874,11 +876,17 @@ long keyctl_instantiate_key(key_serial_t id, key_ref_to_ptr(keyring_ref), instkey); key_ref_put(keyring_ref); - error3: - key_put(instkey); - error2: + + /* discard the assumed authority if it's just been disabled by + * instantiation of the key */ + if (ret == 0) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + } + +error2: kfree(payload); - error: +error: return ret; } /* end keyctl_instantiate_key() */ @@ -895,14 +903,16 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) key_ref_t keyring_ref; long ret; - /* find the instantiation authorisation key */ - instkey = key_get_instantiation_authkey(id); - if (IS_ERR(instkey)) { - ret = PTR_ERR(instkey); + /* the appropriate instantiation authorisation key must have been + * assumed before calling this */ + ret = -EPERM; + instkey = current->request_key_auth; + if (!instkey) goto error; - } rka = instkey->payload.data; + if (rka->target_key->serial != id) + goto error; /* find the destination keyring if present (which must also be * writable) */ @@ -911,7 +921,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); - goto error2; + goto error; } } @@ -920,9 +930,15 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) key_ref_to_ptr(keyring_ref), instkey); key_ref_put(keyring_ref); - error2: - key_put(instkey); - error: + + /* discard the assumed authority if it's just been disabled by + * instantiation of the key */ + if (ret == 0) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + } + +error: return ret; } /* end keyctl_negate_key() */ @@ -1007,6 +1023,48 @@ error: /*****************************************************************************/ /* + * assume the authority to instantiate the specified key + */ +long keyctl_assume_authority(key_serial_t id) +{ + struct key *authkey; + long ret; + + /* special key IDs aren't permitted */ + ret = -EINVAL; + if (id < 0) + goto error; + + /* we divest ourselves of authority if given an ID of 0 */ + if (id == 0) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + ret = 0; + goto error; + } + + /* attempt to assume the authority temporarily granted to us whilst we + * instantiate the specified key + * - the authorisation key must be in the current task's keyrings + * somewhere + */ + authkey = key_get_instantiation_authkey(id); + if (IS_ERR(authkey)) { + ret = PTR_ERR(authkey); + goto error; + } + + key_put(current->request_key_auth); + current->request_key_auth = authkey; + ret = authkey->serial; + +error: + return ret; + +} /* end keyctl_assume_authority() */ + +/*****************************************************************************/ +/* * the key control system call */ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, @@ -1082,6 +1140,9 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, return keyctl_set_timeout((key_serial_t) arg2, (unsigned) arg3); + case KEYCTL_ASSUME_AUTHORITY: + return keyctl_assume_authority((key_serial_t) arg2); + default: return -EOPNOTSUPP; } |