diff options
author | David Howells <dhowells@redhat.com> | 2008-11-13 18:39:17 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-11-13 18:39:17 -0500 |
commit | f1752eec6145c97163dbce62d17cf5d928e28a27 (patch) | |
tree | 16bc51166d38815092de36a461b845b0b4b522f9 /kernel | |
parent | b6dff3ec5e116e3af6f537d4caedcad6b9e5082a (diff) |
CRED: Detach the credentials from task_struct
Detach the credentials from task_struct, duplicating them in copy_process()
and releasing them in __put_task_struct().
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: James Morris <jmorris@namei.org>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 2 | ||||
-rw-r--r-- | kernel/cred.c | 96 | ||||
-rw-r--r-- | kernel/fork.c | 24 |
3 files changed, 103 insertions, 19 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index 9a3ec66a9d84..5a6a612c302d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
@@ -9,7 +9,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ | |||
9 | rcupdate.o extable.o params.o posix-timers.o \ | 9 | rcupdate.o extable.o params.o posix-timers.o \ |
10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ | 10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ |
11 | hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ | 11 | hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ |
12 | notifier.o ksysfs.o pm_qos_params.o sched_clock.o | 12 | notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o |
13 | 13 | ||
14 | CFLAGS_REMOVE_sched.o = -mno-spe | 14 | CFLAGS_REMOVE_sched.o = -mno-spe |
15 | 15 | ||
diff --git a/kernel/cred.c b/kernel/cred.c new file mode 100644 index 000000000000..833244a7cb05 --- /dev/null +++ b/kernel/cred.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* Task credentials management | ||
2 | * | ||
3 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/cred.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/key.h> | ||
15 | #include <linux/keyctl.h> | ||
16 | #include <linux/init_task.h> | ||
17 | #include <linux/security.h> | ||
18 | |||
19 | /* | ||
20 | * The initial credentials for the initial task | ||
21 | */ | ||
22 | struct cred init_cred = { | ||
23 | .usage = ATOMIC_INIT(3), | ||
24 | .securebits = SECUREBITS_DEFAULT, | ||
25 | .cap_inheritable = CAP_INIT_INH_SET, | ||
26 | .cap_permitted = CAP_FULL_SET, | ||
27 | .cap_effective = CAP_INIT_EFF_SET, | ||
28 | .cap_bset = CAP_INIT_BSET, | ||
29 | .user = INIT_USER, | ||
30 | .group_info = &init_groups, | ||
31 | }; | ||
32 | |||
33 | /* | ||
34 | * The RCU callback to actually dispose of a set of credentials | ||
35 | */ | ||
36 | static void put_cred_rcu(struct rcu_head *rcu) | ||
37 | { | ||
38 | struct cred *cred = container_of(rcu, struct cred, rcu); | ||
39 | |||
40 | BUG_ON(atomic_read(&cred->usage) != 0); | ||
41 | |||
42 | key_put(cred->thread_keyring); | ||
43 | key_put(cred->request_key_auth); | ||
44 | put_group_info(cred->group_info); | ||
45 | free_uid(cred->user); | ||
46 | security_cred_free(cred); | ||
47 | kfree(cred); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * __put_cred - Destroy a set of credentials | ||
52 | * @sec: The record to release | ||
53 | * | ||
54 | * Destroy a set of credentials on which no references remain. | ||
55 | */ | ||
56 | void __put_cred(struct cred *cred) | ||
57 | { | ||
58 | call_rcu(&cred->rcu, put_cred_rcu); | ||
59 | } | ||
60 | EXPORT_SYMBOL(__put_cred); | ||
61 | |||
62 | /* | ||
63 | * Copy credentials for the new process created by fork() | ||
64 | */ | ||
65 | int copy_creds(struct task_struct *p, unsigned long clone_flags) | ||
66 | { | ||
67 | struct cred *pcred; | ||
68 | int ret; | ||
69 | |||
70 | pcred = kmemdup(p->cred, sizeof(*p->cred), GFP_KERNEL); | ||
71 | if (!pcred) | ||
72 | return -ENOMEM; | ||
73 | |||
74 | #ifdef CONFIG_SECURITY | ||
75 | pcred->security = NULL; | ||
76 | #endif | ||
77 | |||
78 | ret = security_cred_alloc(pcred); | ||
79 | if (ret < 0) { | ||
80 | kfree(pcred); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | atomic_set(&pcred->usage, 1); | ||
85 | get_group_info(pcred->group_info); | ||
86 | get_uid(pcred->user); | ||
87 | key_get(pcred->thread_keyring); | ||
88 | key_get(pcred->request_key_auth); | ||
89 | |||
90 | atomic_inc(&pcred->user->processes); | ||
91 | |||
92 | /* RCU assignment is unneeded here as no-one can have accessed this | ||
93 | * pointer yet, barring us */ | ||
94 | p->cred = pcred; | ||
95 | return 0; | ||
96 | } | ||
diff --git a/kernel/fork.c b/kernel/fork.c index 81fdc7733908..c932e283ddfc 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -146,9 +146,7 @@ void __put_task_struct(struct task_struct *tsk) | |||
146 | WARN_ON(atomic_read(&tsk->usage)); | 146 | WARN_ON(atomic_read(&tsk->usage)); |
147 | WARN_ON(tsk == current); | 147 | WARN_ON(tsk == current); |
148 | 148 | ||
149 | security_task_free(tsk); | 149 | put_cred(tsk->cred); |
150 | free_uid(tsk->__temp_cred.user); | ||
151 | put_group_info(tsk->__temp_cred.group_info); | ||
152 | delayacct_tsk_free(tsk); | 150 | delayacct_tsk_free(tsk); |
153 | 151 | ||
154 | if (!profile_handoff_task(tsk)) | 152 | if (!profile_handoff_task(tsk)) |
@@ -969,7 +967,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
969 | DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); | 967 | DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); |
970 | DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); | 968 | DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); |
971 | #endif | 969 | #endif |
972 | p->cred = &p->__temp_cred; | ||
973 | retval = -EAGAIN; | 970 | retval = -EAGAIN; |
974 | if (atomic_read(&p->cred->user->processes) >= | 971 | if (atomic_read(&p->cred->user->processes) >= |
975 | p->signal->rlim[RLIMIT_NPROC].rlim_cur) { | 972 | p->signal->rlim[RLIMIT_NPROC].rlim_cur) { |
@@ -978,9 +975,9 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
978 | goto bad_fork_free; | 975 | goto bad_fork_free; |
979 | } | 976 | } |
980 | 977 | ||
981 | atomic_inc(&p->cred->user->__count); | 978 | retval = copy_creds(p, clone_flags); |
982 | atomic_inc(&p->cred->user->processes); | 979 | if (retval < 0) |
983 | get_group_info(p->cred->group_info); | 980 | goto bad_fork_free; |
984 | 981 | ||
985 | /* | 982 | /* |
986 | * If multiple threads are within copy_process(), then this check | 983 | * If multiple threads are within copy_process(), then this check |
@@ -1035,9 +1032,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1035 | do_posix_clock_monotonic_gettime(&p->start_time); | 1032 | do_posix_clock_monotonic_gettime(&p->start_time); |
1036 | p->real_start_time = p->start_time; | 1033 | p->real_start_time = p->start_time; |
1037 | monotonic_to_bootbased(&p->real_start_time); | 1034 | monotonic_to_bootbased(&p->real_start_time); |
1038 | #ifdef CONFIG_SECURITY | ||
1039 | p->cred->security = NULL; | ||
1040 | #endif | ||
1041 | p->io_context = NULL; | 1035 | p->io_context = NULL; |
1042 | p->audit_context = NULL; | 1036 | p->audit_context = NULL; |
1043 | cgroup_fork(p); | 1037 | cgroup_fork(p); |
@@ -1082,10 +1076,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1082 | /* Perform scheduler related setup. Assign this task to a CPU. */ | 1076 | /* Perform scheduler related setup. Assign this task to a CPU. */ |
1083 | sched_fork(p, clone_flags); | 1077 | sched_fork(p, clone_flags); |
1084 | 1078 | ||
1085 | if ((retval = security_task_alloc(p))) | ||
1086 | goto bad_fork_cleanup_policy; | ||
1087 | if ((retval = audit_alloc(p))) | 1079 | if ((retval = audit_alloc(p))) |
1088 | goto bad_fork_cleanup_security; | 1080 | goto bad_fork_cleanup_policy; |
1089 | /* copy all the process information */ | 1081 | /* copy all the process information */ |
1090 | if ((retval = copy_semundo(clone_flags, p))) | 1082 | if ((retval = copy_semundo(clone_flags, p))) |
1091 | goto bad_fork_cleanup_audit; | 1083 | goto bad_fork_cleanup_audit; |
@@ -1284,8 +1276,6 @@ bad_fork_cleanup_semundo: | |||
1284 | exit_sem(p); | 1276 | exit_sem(p); |
1285 | bad_fork_cleanup_audit: | 1277 | bad_fork_cleanup_audit: |
1286 | audit_free(p); | 1278 | audit_free(p); |
1287 | bad_fork_cleanup_security: | ||
1288 | security_task_free(p); | ||
1289 | bad_fork_cleanup_policy: | 1279 | bad_fork_cleanup_policy: |
1290 | #ifdef CONFIG_NUMA | 1280 | #ifdef CONFIG_NUMA |
1291 | mpol_put(p->mempolicy); | 1281 | mpol_put(p->mempolicy); |
@@ -1298,9 +1288,7 @@ bad_fork_cleanup_cgroup: | |||
1298 | bad_fork_cleanup_put_domain: | 1288 | bad_fork_cleanup_put_domain: |
1299 | module_put(task_thread_info(p)->exec_domain->module); | 1289 | module_put(task_thread_info(p)->exec_domain->module); |
1300 | bad_fork_cleanup_count: | 1290 | bad_fork_cleanup_count: |
1301 | put_group_info(p->cred->group_info); | 1291 | put_cred(p->cred); |
1302 | atomic_dec(&p->cred->user->processes); | ||
1303 | free_uid(p->cred->user); | ||
1304 | bad_fork_free: | 1292 | bad_fork_free: |
1305 | free_task(p); | 1293 | free_task(p); |
1306 | fork_out: | 1294 | fork_out: |