linux/security/keys/permission.c
David Howells b5f545c880 [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>
2006-01-08 20:13:53 -08:00

107 lines
2.5 KiB
C

/* permission.c: key permission determination
*
* Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/security.h>
#include "internal.h"
/*****************************************************************************/
/*
* check to see whether permission is granted to use a key in the desired way,
* but permit the security modules to override
*/
int key_task_permission(const key_ref_t key_ref,
struct task_struct *context,
key_perm_t perm)
{
struct key *key;
key_perm_t kperm;
int ret;
key = key_ref_to_ptr(key_ref);
/* use the second 8-bits of permissions for keys the caller owns */
if (key->uid == context->fsuid) {
kperm = key->perm >> 16;
goto use_these_perms;
}
/* use the third 8-bits of permissions for keys the caller has a group
* membership in common with */
if (key->gid != -1 && key->perm & KEY_GRP_ALL) {
if (key->gid == context->fsgid) {
kperm = key->perm >> 8;
goto use_these_perms;
}
task_lock(context);
ret = groups_search(context->group_info, key->gid);
task_unlock(context);
if (ret) {
kperm = key->perm >> 8;
goto use_these_perms;
}
}
/* otherwise use the least-significant 8-bits */
kperm = key->perm;
use_these_perms:
/* use the top 8-bits of permissions for keys the caller possesses
* - possessor permissions are additive with other permissions
*/
if (is_key_possessed(key_ref))
kperm |= key->perm >> 24;
kperm = kperm & perm & KEY_ALL;
if (kperm != perm)
return -EACCES;
/* let LSM be the final arbiter */
return security_key_permission(key_ref, context, perm);
} /* end key_task_permission() */
EXPORT_SYMBOL(key_task_permission);
/*****************************************************************************/
/*
* validate a key
*/
int key_validate(struct key *key)
{
struct timespec now;
int ret = 0;
if (key) {
/* check it's still accessible */
ret = -EKEYREVOKED;
if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
test_bit(KEY_FLAG_DEAD, &key->flags))
goto error;
/* check it hasn't expired */
ret = 0;
if (key->expiry) {
now = current_kernel_time();
if (now.tv_sec >= key->expiry)
ret = -EKEYEXPIRED;
}
}
error:
return ret;
} /* end key_validate() */
EXPORT_SYMBOL(key_validate);