diff options
Diffstat (limited to 'kernel/capability.c')
-rw-r--r-- | kernel/capability.c | 78 |
1 files changed, 24 insertions, 54 deletions
diff --git a/kernel/capability.c b/kernel/capability.c index a404b980b1bd..36b4b4daebec 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -15,12 +15,7 @@ | |||
15 | #include <linux/syscalls.h> | 15 | #include <linux/syscalls.h> |
16 | #include <linux/pid_namespace.h> | 16 | #include <linux/pid_namespace.h> |
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | 18 | #include "cred-internals.h" | |
19 | /* | ||
20 | * This lock protects task->cap_* for all tasks including current. | ||
21 | * Locking rule: acquire this prior to tasklist_lock. | ||
22 | */ | ||
23 | static DEFINE_SPINLOCK(task_capability_lock); | ||
24 | 19 | ||
25 | /* | 20 | /* |
26 | * Leveraged for setting/resetting capabilities | 21 | * Leveraged for setting/resetting capabilities |
@@ -128,12 +123,11 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy) | |||
128 | } | 123 | } |
129 | 124 | ||
130 | /* | 125 | /* |
131 | * If we have configured with filesystem capability support, then the | 126 | * The only thing that can change the capabilities of the current |
132 | * only thing that can change the capabilities of the current process | 127 | * process is the current process. As such, we can't be in this code |
133 | * is the current process. As such, we can't be in this code at the | 128 | * at the same time as we are in the process of setting capabilities |
134 | * same time as we are in the process of setting capabilities in this | 129 | * in this process. The net result is that we can limit our use of |
135 | * process. The net result is that we can limit our use of locks to | 130 | * locks to when we are reading the caps of another process. |
136 | * when we are reading the caps of another process. | ||
137 | */ | 131 | */ |
138 | static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | 132 | static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, |
139 | kernel_cap_t *pIp, kernel_cap_t *pPp) | 133 | kernel_cap_t *pIp, kernel_cap_t *pPp) |
@@ -143,7 +137,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | |||
143 | if (pid && (pid != task_pid_vnr(current))) { | 137 | if (pid && (pid != task_pid_vnr(current))) { |
144 | struct task_struct *target; | 138 | struct task_struct *target; |
145 | 139 | ||
146 | spin_lock(&task_capability_lock); | ||
147 | read_lock(&tasklist_lock); | 140 | read_lock(&tasklist_lock); |
148 | 141 | ||
149 | target = find_task_by_vpid(pid); | 142 | target = find_task_by_vpid(pid); |
@@ -153,34 +146,12 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | |||
153 | ret = security_capget(target, pEp, pIp, pPp); | 146 | ret = security_capget(target, pEp, pIp, pPp); |
154 | 147 | ||
155 | read_unlock(&tasklist_lock); | 148 | read_unlock(&tasklist_lock); |
156 | spin_unlock(&task_capability_lock); | ||
157 | } else | 149 | } else |
158 | ret = security_capget(current, pEp, pIp, pPp); | 150 | ret = security_capget(current, pEp, pIp, pPp); |
159 | 151 | ||
160 | return ret; | 152 | return ret; |
161 | } | 153 | } |
162 | 154 | ||
163 | /* | ||
164 | * Atomically modify the effective capabilities returning the original | ||
165 | * value. No permission check is performed here - it is assumed that the | ||
166 | * caller is permitted to set the desired effective capabilities. | ||
167 | */ | ||
168 | kernel_cap_t cap_set_effective(const kernel_cap_t pE_new) | ||
169 | { | ||
170 | kernel_cap_t pE_old; | ||
171 | |||
172 | spin_lock(&task_capability_lock); | ||
173 | |||
174 | pE_old = current->cred->cap_effective; | ||
175 | current->cred->cap_effective = pE_new; | ||
176 | |||
177 | spin_unlock(&task_capability_lock); | ||
178 | |||
179 | return pE_old; | ||
180 | } | ||
181 | |||
182 | EXPORT_SYMBOL(cap_set_effective); | ||
183 | |||
184 | /** | 155 | /** |
185 | * sys_capget - get the capabilities of a given process. | 156 | * sys_capget - get the capabilities of a given process. |
186 | * @header: pointer to struct that contains capability version and | 157 | * @header: pointer to struct that contains capability version and |
@@ -208,7 +179,6 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) | |||
208 | return -EINVAL; | 179 | return -EINVAL; |
209 | 180 | ||
210 | ret = cap_get_target_pid(pid, &pE, &pI, &pP); | 181 | ret = cap_get_target_pid(pid, &pE, &pI, &pP); |
211 | |||
212 | if (!ret) { | 182 | if (!ret) { |
213 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; | 183 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; |
214 | unsigned i; | 184 | unsigned i; |
@@ -270,6 +240,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
270 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; | 240 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; |
271 | unsigned i, tocopy; | 241 | unsigned i, tocopy; |
272 | kernel_cap_t inheritable, permitted, effective; | 242 | kernel_cap_t inheritable, permitted, effective; |
243 | struct cred *new; | ||
273 | int ret; | 244 | int ret; |
274 | pid_t pid; | 245 | pid_t pid; |
275 | 246 | ||
@@ -284,8 +255,8 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
284 | if (pid != 0 && pid != task_pid_vnr(current)) | 255 | if (pid != 0 && pid != task_pid_vnr(current)) |
285 | return -EPERM; | 256 | return -EPERM; |
286 | 257 | ||
287 | if (copy_from_user(&kdata, data, tocopy | 258 | if (copy_from_user(&kdata, data, |
288 | * sizeof(struct __user_cap_data_struct))) | 259 | tocopy * sizeof(struct __user_cap_data_struct))) |
289 | return -EFAULT; | 260 | return -EFAULT; |
290 | 261 | ||
291 | for (i = 0; i < tocopy; i++) { | 262 | for (i = 0; i < tocopy; i++) { |
@@ -300,24 +271,23 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
300 | i++; | 271 | i++; |
301 | } | 272 | } |
302 | 273 | ||
303 | ret = audit_log_capset(pid, &effective, &inheritable, &permitted); | 274 | new = prepare_creds(); |
304 | if (ret) | 275 | if (!new) |
276 | return -ENOMEM; | ||
277 | |||
278 | ret = security_capset(new, current_cred(), | ||
279 | &effective, &inheritable, &permitted); | ||
280 | if (ret < 0) | ||
281 | goto error; | ||
282 | |||
283 | ret = audit_log_capset(pid, new, current_cred()); | ||
284 | if (ret < 0) | ||
305 | return ret; | 285 | return ret; |
306 | 286 | ||
307 | /* This lock is required even when filesystem capability support is | 287 | return commit_creds(new); |
308 | * configured - it protects the sys_capget() call from returning | 288 | |
309 | * incorrect data in the case that the targeted process is not the | 289 | error: |
310 | * current one. | 290 | abort_creds(new); |
311 | */ | ||
312 | spin_lock(&task_capability_lock); | ||
313 | |||
314 | ret = security_capset_check(&effective, &inheritable, &permitted); | ||
315 | /* Having verified that the proposed changes are legal, we now put them | ||
316 | * into effect. | ||
317 | */ | ||
318 | if (!ret) | ||
319 | security_capset_set(&effective, &inheritable, &permitted); | ||
320 | spin_unlock(&task_capability_lock); | ||
321 | return ret; | 291 | return ret; |
322 | } | 292 | } |
323 | 293 | ||