Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/kernel/capability.c
Parent Directory | Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 5918 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 5918 byte(s)
Tag kernel26-2.6.12-alx-r9
1 | /* |
2 | * linux/kernel/capability.c |
3 | * |
4 | * Copyright (C) 1997 Andrew Main <zefram@fysh.org> |
5 | * |
6 | * Integrated into 2.1.97+, Andrew G. Morgan <morgan@transmeta.com> |
7 | * 30 May 2002: Cleanup, Robert M. Love <rml@tech9.net> |
8 | */ |
9 | |
10 | #include <linux/mm.h> |
11 | #include <linux/module.h> |
12 | #include <linux/security.h> |
13 | #include <linux/syscalls.h> |
14 | #include <asm/uaccess.h> |
15 | |
16 | unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ |
17 | kernel_cap_t cap_bset = CAP_INIT_EFF_SET; |
18 | |
19 | EXPORT_SYMBOL(securebits); |
20 | EXPORT_SYMBOL(cap_bset); |
21 | |
22 | /* |
23 | * This lock protects task->cap_* for all tasks including current. |
24 | * Locking rule: acquire this prior to tasklist_lock. |
25 | */ |
26 | static DEFINE_SPINLOCK(task_capability_lock); |
27 | |
28 | /* |
29 | * For sys_getproccap() and sys_setproccap(), any of the three |
30 | * capability set pointers may be NULL -- indicating that that set is |
31 | * uninteresting and/or not to be changed. |
32 | */ |
33 | |
34 | /* |
35 | * sys_capget - get the capabilities of a given process. |
36 | */ |
37 | asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) |
38 | { |
39 | int ret = 0; |
40 | pid_t pid; |
41 | __u32 version; |
42 | task_t *target; |
43 | struct __user_cap_data_struct data; |
44 | |
45 | if (get_user(version, &header->version)) |
46 | return -EFAULT; |
47 | |
48 | if (version != _LINUX_CAPABILITY_VERSION) { |
49 | if (put_user(_LINUX_CAPABILITY_VERSION, &header->version)) |
50 | return -EFAULT; |
51 | return -EINVAL; |
52 | } |
53 | |
54 | if (get_user(pid, &header->pid)) |
55 | return -EFAULT; |
56 | |
57 | if (pid < 0) |
58 | return -EINVAL; |
59 | |
60 | spin_lock(&task_capability_lock); |
61 | read_lock(&tasklist_lock); |
62 | |
63 | if (pid && pid != current->pid) { |
64 | target = find_task_by_pid(pid); |
65 | if (!target) { |
66 | ret = -ESRCH; |
67 | goto out; |
68 | } |
69 | } else |
70 | target = current; |
71 | |
72 | ret = security_capget(target, &data.effective, &data.inheritable, &data.permitted); |
73 | |
74 | out: |
75 | read_unlock(&tasklist_lock); |
76 | spin_unlock(&task_capability_lock); |
77 | |
78 | if (!ret && copy_to_user(dataptr, &data, sizeof data)) |
79 | return -EFAULT; |
80 | |
81 | return ret; |
82 | } |
83 | |
84 | /* |
85 | * cap_set_pg - set capabilities for all processes in a given process |
86 | * group. We call this holding task_capability_lock and tasklist_lock. |
87 | */ |
88 | static inline int cap_set_pg(int pgrp, kernel_cap_t *effective, |
89 | kernel_cap_t *inheritable, |
90 | kernel_cap_t *permitted) |
91 | { |
92 | task_t *g, *target; |
93 | int ret = -EPERM; |
94 | int found = 0; |
95 | |
96 | do_each_task_pid(pgrp, PIDTYPE_PGID, g) { |
97 | target = g; |
98 | while_each_thread(g, target) { |
99 | if (!security_capset_check(target, effective, |
100 | inheritable, |
101 | permitted)) { |
102 | security_capset_set(target, effective, |
103 | inheritable, |
104 | permitted); |
105 | ret = 0; |
106 | } |
107 | found = 1; |
108 | } |
109 | } while_each_task_pid(pgrp, PIDTYPE_PGID, g); |
110 | |
111 | if (!found) |
112 | ret = 0; |
113 | return ret; |
114 | } |
115 | |
116 | /* |
117 | * cap_set_all - set capabilities for all processes other than init |
118 | * and self. We call this holding task_capability_lock and tasklist_lock. |
119 | */ |
120 | static inline int cap_set_all(kernel_cap_t *effective, |
121 | kernel_cap_t *inheritable, |
122 | kernel_cap_t *permitted) |
123 | { |
124 | task_t *g, *target; |
125 | int ret = -EPERM; |
126 | int found = 0; |
127 | |
128 | do_each_thread(g, target) { |
129 | if (target == current || target->pid == 1) |
130 | continue; |
131 | found = 1; |
132 | if (security_capset_check(target, effective, inheritable, |
133 | permitted)) |
134 | continue; |
135 | ret = 0; |
136 | security_capset_set(target, effective, inheritable, permitted); |
137 | } while_each_thread(g, target); |
138 | |
139 | if (!found) |
140 | ret = 0; |
141 | return ret; |
142 | } |
143 | |
144 | /* |
145 | * sys_capset - set capabilities for a given process, all processes, or all |
146 | * processes in a given process group. |
147 | * |
148 | * The restrictions on setting capabilities are specified as: |
149 | * |
150 | * [pid is for the 'target' task. 'current' is the calling task.] |
151 | * |
152 | * I: any raised capabilities must be a subset of the (old current) permitted |
153 | * P: any raised capabilities must be a subset of the (old current) permitted |
154 | * E: must be set to a subset of (new target) permitted |
155 | */ |
156 | asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) |
157 | { |
158 | kernel_cap_t inheritable, permitted, effective; |
159 | __u32 version; |
160 | task_t *target; |
161 | int ret; |
162 | pid_t pid; |
163 | |
164 | if (get_user(version, &header->version)) |
165 | return -EFAULT; |
166 | |
167 | if (version != _LINUX_CAPABILITY_VERSION) { |
168 | if (put_user(_LINUX_CAPABILITY_VERSION, &header->version)) |
169 | return -EFAULT; |
170 | return -EINVAL; |
171 | } |
172 | |
173 | if (get_user(pid, &header->pid)) |
174 | return -EFAULT; |
175 | |
176 | if (pid && pid != current->pid && !capable(CAP_SETPCAP)) |
177 | return -EPERM; |
178 | |
179 | if (copy_from_user(&effective, &data->effective, sizeof(effective)) || |
180 | copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) || |
181 | copy_from_user(&permitted, &data->permitted, sizeof(permitted))) |
182 | return -EFAULT; |
183 | |
184 | spin_lock(&task_capability_lock); |
185 | read_lock(&tasklist_lock); |
186 | |
187 | if (pid > 0 && pid != current->pid) { |
188 | target = find_task_by_pid(pid); |
189 | if (!target) { |
190 | ret = -ESRCH; |
191 | goto out; |
192 | } |
193 | } else |
194 | target = current; |
195 | |
196 | ret = 0; |
197 | |
198 | /* having verified that the proposed changes are legal, |
199 | we now put them into effect. */ |
200 | if (pid < 0) { |
201 | if (pid == -1) /* all procs other than current and init */ |
202 | ret = cap_set_all(&effective, &inheritable, &permitted); |
203 | |
204 | else /* all procs in process group */ |
205 | ret = cap_set_pg(-pid, &effective, &inheritable, |
206 | &permitted); |
207 | } else { |
208 | ret = security_capset_check(target, &effective, &inheritable, |
209 | &permitted); |
210 | if (!ret) |
211 | security_capset_set(target, &effective, &inheritable, |
212 | &permitted); |
213 | } |
214 | |
215 | out: |
216 | read_unlock(&tasklist_lock); |
217 | spin_unlock(&task_capability_lock); |
218 | |
219 | return ret; |
220 | } |