summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2004-10-18 17:58:51 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-10-18 17:58:51 -0700
commite4262f594a9e36cf93a8789fc7e02e9ff0d1f564 (patch)
treef5265fb6090dc67eb231c3554b88320e9bfeeb26 /kernel
parent322f317d1f560b90d8fe79d77fb248c98af92305 (diff)
[PATCH] implement in-kernel keys & keyring management
The feature set the patch includes: - Key attributes: - Key type - Description (by which a key of a particular type can be selected) - Payload - UID, GID and permissions mask - Expiry time - Keyrings (just a type of key that holds links to other keys) - User-defined keys - Key revokation - Access controls - Per user key-count and key-memory consumption quota - Three std keyrings per task: per-thread, per-process, session - Two std keyrings per user: per-user and default-user-session - prctl() functions for key and keyring creation and management - Kernel interfaces for filesystem, blockdev, net stack access - JIT key creation by usermode helper There are also two utility programs available: (*) http://people.redhat.com/~dhowells/keys/keyctl.c A comprehensive key management tool, permitting all the interfaces available to userspace to be exercised. (*) http://people.redhat.com/~dhowells/keys/request-key An example shell script (to be installed in /sbin) for instantiating a key. Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c13
-rw-r--r--kernel/sys.c20
-rw-r--r--kernel/user.c16
4 files changed, 47 insertions, 4 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 55d853392524..e242c22dee36 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -14,6 +14,7 @@
#include <linux/personality.h>
#include <linux/tty.h>
#include <linux/namespace.h>
+#include <linux/key.h>
#include <linux/security.h>
#include <linux/cpu.h>
#include <linux/acct.h>
@@ -816,6 +817,7 @@ asmlinkage NORET_TYPE void do_exit(long code)
__exit_fs(tsk);
exit_namespace(tsk);
exit_thread();
+ exit_keys(tsk);
if (tsk->signal->leader)
disassociate_ctty(1);
diff --git a/kernel/fork.c b/kernel/fork.c
index 3020dccc548f..2502791f0ba4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -24,6 +24,7 @@
#include <linux/mempolicy.h>
#include <linux/sem.h>
#include <linux/file.h>
+#include <linux/key.h>
#include <linux/binfmts.h>
#include <linux/mman.h>
#include <linux/fs.h>
@@ -1019,6 +1020,10 @@ static task_t *copy_process(unsigned long clone_flags,
}
#endif
+ p->tgid = p->pid;
+ if (clone_flags & CLONE_THREAD)
+ p->tgid = current->tgid;
+
if ((retval = security_task_alloc(p)))
goto bad_fork_cleanup_policy;
if ((retval = audit_alloc(p)))
@@ -1036,8 +1041,10 @@ static task_t *copy_process(unsigned long clone_flags,
goto bad_fork_cleanup_sighand;
if ((retval = copy_mm(clone_flags, p)))
goto bad_fork_cleanup_signal;
- if ((retval = copy_namespace(clone_flags, p)))
+ if ((retval = copy_keys(clone_flags, p)))
goto bad_fork_cleanup_mm;
+ if ((retval = copy_namespace(clone_flags, p)))
+ goto bad_fork_cleanup_keys;
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
if (retval)
goto bad_fork_cleanup_namespace;
@@ -1071,7 +1078,6 @@ static task_t *copy_process(unsigned long clone_flags,
* Ok, make it visible to the rest of the system.
* We dont wake it up yet.
*/
- p->tgid = p->pid;
p->group_leader = p;
INIT_LIST_HEAD(&p->ptrace_children);
INIT_LIST_HEAD(&p->ptrace_list);
@@ -1119,7 +1125,6 @@ static task_t *copy_process(unsigned long clone_flags,
retval = -EAGAIN;
goto bad_fork_cleanup_namespace;
}
- p->tgid = current->tgid;
p->group_leader = current->group_leader;
if (current->signal->group_stop_count > 0) {
@@ -1159,6 +1164,8 @@ fork_out:
bad_fork_cleanup_namespace:
exit_namespace(p);
+bad_fork_cleanup_keys:
+ exit_keys(p);
bad_fork_cleanup_mm:
if (p->mm)
mmput(p->mm);
diff --git a/kernel/sys.c b/kernel/sys.c
index a95e3900dc1e..e6dbc2940751 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -19,6 +19,7 @@
#include <linux/fs.h>
#include <linux/workqueue.h>
#include <linux/device.h>
+#include <linux/key.h>
#include <linux/times.h>
#include <linux/security.h>
#include <linux/dcookies.h>
@@ -282,6 +283,9 @@ cond_syscall(sys_set_mempolicy)
cond_syscall(compat_mbind)
cond_syscall(compat_get_mempolicy)
cond_syscall(compat_set_mempolicy)
+cond_syscall(sys_add_key)
+cond_syscall(sys_request_key)
+cond_syscall(sys_keyctl)
/* arch-specific weak syscall entries */
cond_syscall(sys_pciconfig_read)
@@ -605,6 +609,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
current->fsgid = new_egid;
current->egid = new_egid;
current->gid = new_rgid;
+ key_fsgid_changed(current);
return 0;
}
@@ -642,6 +647,8 @@ asmlinkage long sys_setgid(gid_t gid)
}
else
return -EPERM;
+
+ key_fsgid_changed(current);
return 0;
}
@@ -730,6 +737,8 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
current->suid = current->euid;
current->fsuid = current->euid;
+ key_fsuid_changed(current);
+
return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
}
@@ -775,6 +784,8 @@ asmlinkage long sys_setuid(uid_t uid)
current->fsuid = current->euid = uid;
current->suid = new_suid;
+ key_fsuid_changed(current);
+
return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
}
@@ -821,6 +832,8 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
if (suid != (uid_t) -1)
current->suid = suid;
+ key_fsuid_changed(current);
+
return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
}
@@ -870,6 +883,8 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
current->gid = rgid;
if (sgid != (gid_t) -1)
current->sgid = sgid;
+
+ key_fsgid_changed(current);
return 0;
}
@@ -911,6 +926,8 @@ asmlinkage long sys_setfsuid(uid_t uid)
current->fsuid = uid;
}
+ key_fsuid_changed(current);
+
security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
return old_fsuid;
@@ -937,6 +954,7 @@ asmlinkage long sys_setfsgid(gid_t gid)
wmb();
}
current->fsgid = gid;
+ key_fsgid_changed(current);
}
return old_fsgid;
}
@@ -1669,7 +1687,7 @@ asmlinkage long sys_umask(int mask)
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
- int error;
+ long error;
int sig;
error = security_task_prctl(option, arg2, arg3, arg4, arg5);
diff --git a/kernel/user.c b/kernel/user.c
index 523175afeecd..693487dc940e 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -12,6 +12,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/bitops.h>
+#include <linux/key.h>
/*
* UID task count cache, to get fast user lookup in "alloc_uid"
@@ -34,6 +35,10 @@ struct user_struct root_user = {
.sigpending = ATOMIC_INIT(0),
.mq_bytes = 0,
.locked_shm = 0,
+#ifdef CONFIG_KEYS
+ .uid_keyring = &root_user_keyring,
+ .session_keyring = &root_session_keyring,
+#endif
};
/*
@@ -87,6 +92,8 @@ void free_uid(struct user_struct *up)
{
if (up && atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
uid_hash_remove(up);
+ key_put(up->uid_keyring);
+ key_put(up->session_keyring);
kmem_cache_free(uid_cachep, up);
spin_unlock(&uidhash_lock);
}
@@ -116,6 +123,11 @@ struct user_struct * alloc_uid(uid_t uid)
new->mq_bytes = 0;
new->locked_shm = 0;
+ if (alloc_uid_keyring(new) < 0) {
+ kmem_cache_free(uid_cachep, new);
+ return NULL;
+ }
+
/*
* Before adding this, check whether we raced
* on adding the same user already..
@@ -123,6 +135,8 @@ struct user_struct * alloc_uid(uid_t uid)
spin_lock(&uidhash_lock);
up = uid_hash_find(uid, hashent);
if (up) {
+ key_put(new->uid_keyring);
+ key_put(new->session_keyring);
kmem_cache_free(uid_cachep, new);
} else {
uid_hash_insert(new, hashent);
@@ -146,8 +160,10 @@ void switch_uid(struct user_struct *new_user)
old_user = current->user;
atomic_inc(&new_user->processes);
atomic_dec(&old_user->processes);
+ switch_uid_keyring(new_user);
current->user = new_user;
free_uid(old_user);
+ suid_keys(current);
}