aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/capability.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/capability.c')
-rw-r--r--kernel/capability.c78
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 */
23static 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 */
138static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, 132static 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 */
168kernel_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
182EXPORT_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 289error:
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