Blame view

kernel/capability.c 10.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   * linux/kernel/capability.c
   *
   * Copyright (C) 1997  Andrew Main <zefram@fysh.org>
   *
72c2d5823   Andrew Morgan   V3 file capabilit...
6
   * Integrated into 2.1.97+,  Andrew G. Morgan <morgan@kernel.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   * 30 May 2002:	Cleanup, Robert M. Love <rml@tech9.net>
314f70fd9   Daniel Walker   whitespace fixes:...
8
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9

e68b75a02   Eric Paris   When the capset s...
10
  #include <linux/audit.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
11
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/mm.h>
9984de1a5   Paul Gortmaker   kernel: Map most ...
13
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  #include <linux/security.h>
  #include <linux/syscalls.h>
b460cbc58   Serge E. Hallyn   pid namespaces: d...
16
  #include <linux/pid_namespace.h>
3486740a4   Serge E. Hallyn   userns: security:...
17
  #include <linux/user_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  
  /*
e338d263a   Andrew Morgan   Add 64-bit capabi...
21
22
23
24
   * Leveraged for setting/resetting capabilities
   */
  
  const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
e338d263a   Andrew Morgan   Add 64-bit capabi...
25
26
  
  EXPORT_SYMBOL(__cap_empty_set);
e338d263a   Andrew Morgan   Add 64-bit capabi...
27

1f29fae29   Serge E. Hallyn   file capabilities...
28
29
30
31
32
33
34
35
  int file_caps_enabled = 1;
  
  static int __init file_caps_disable(char *str)
  {
  	file_caps_enabled = 0;
  	return 1;
  }
  __setup("no_file_caps", file_caps_disable);
1f29fae29   Serge E. Hallyn   file capabilities...
36

e338d263a   Andrew Morgan   Add 64-bit capabi...
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  /*
   * More recent versions of libcap are available from:
   *
   *   http://www.kernel.org/pub/linux/libs/security/linux-privs/
   */
  
  static void warn_legacy_capability_use(void)
  {
  	static int warned;
  	if (!warned) {
  		char name[sizeof(current->comm)];
  
  		printk(KERN_INFO "warning: `%s' uses 32-bit capabilities"
  		       " (legacy support in use)
  ",
  		       get_task_comm(name, current));
  		warned = 1;
  	}
  }
  
  /*
ca05a99a5   Andrew G. Morgan   capabilities: rem...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
   * Version 2 capabilities worked fine, but the linux/capability.h file
   * that accompanied their introduction encouraged their use without
   * the necessary user-space source code changes. As such, we have
   * created a version 3 with equivalent functionality to version 2, but
   * with a header change to protect legacy source code from using
   * version 2 when it wanted to use version 1. If your system has code
   * that trips the following warning, it is using version 2 specific
   * capabilities and may be doing so insecurely.
   *
   * The remedy is to either upgrade your version of libcap (to 2.10+,
   * if the application is linked against it), or recompile your
   * application with modern kernel headers and this warning will go
   * away.
   */
  
  static void warn_deprecated_v2(void)
  {
  	static int warned;
  
  	if (!warned) {
  		char name[sizeof(current->comm)];
  
  		printk(KERN_INFO "warning: `%s' uses deprecated v2"
  		       " capabilities in a way that may be insecure.
  ",
  		       get_task_comm(name, current));
  		warned = 1;
  	}
  }
  
  /*
   * Version check. Return the number of u32s in each capability flag
   * array, or a negative value on error.
   */
  static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
  {
  	__u32 version;
  
  	if (get_user(version, &header->version))
  		return -EFAULT;
  
  	switch (version) {
  	case _LINUX_CAPABILITY_VERSION_1:
  		warn_legacy_capability_use();
  		*tocopy = _LINUX_CAPABILITY_U32S_1;
  		break;
  	case _LINUX_CAPABILITY_VERSION_2:
  		warn_deprecated_v2();
  		/*
  		 * fall through - v3 is otherwise equivalent to v2.
  		 */
  	case _LINUX_CAPABILITY_VERSION_3:
  		*tocopy = _LINUX_CAPABILITY_U32S_3;
  		break;
  	default:
  		if (put_user((u32)_KERNEL_CAPABILITY_VERSION, &header->version))
  			return -EFAULT;
  		return -EINVAL;
  	}
  
  	return 0;
  }
ab763c711   Andrew G. Morgan   security: filesys...
120
  /*
d84f4f992   David Howells   CRED: Inaugurate ...
121
122
123
124
125
   * The only thing that can change the capabilities of the current
   * process is the current process. As such, we can't be in this code
   * at the same time as we are in the process of setting capabilities
   * in this process. The net result is that we can limit our use of
   * locks to when we are reading the caps of another process.
ab763c711   Andrew G. Morgan   security: filesys...
126
127
128
129
130
131
132
133
   */
  static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
  				     kernel_cap_t *pIp, kernel_cap_t *pPp)
  {
  	int ret;
  
  	if (pid && (pid != task_pid_vnr(current))) {
  		struct task_struct *target;
86fc80f16   Thomas Gleixner   capabilities: Use...
134
  		rcu_read_lock();
ab763c711   Andrew G. Morgan   security: filesys...
135
136
137
138
139
140
  
  		target = find_task_by_vpid(pid);
  		if (!target)
  			ret = -ESRCH;
  		else
  			ret = security_capget(target, pEp, pIp, pPp);
86fc80f16   Thomas Gleixner   capabilities: Use...
141
  		rcu_read_unlock();
ab763c711   Andrew G. Morgan   security: filesys...
142
143
144
145
146
  	} else
  		ret = security_capget(current, pEp, pIp, pPp);
  
  	return ret;
  }
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
147
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
   * sys_capget - get the capabilities of a given process.
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
149
150
151
152
153
154
   * @header: pointer to struct that contains capability version and
   *	target pid data
   * @dataptr: pointer to struct that contains the effective, permitted,
   *	and inheritable capabilities that are returned
   *
   * Returns 0 on success and < 0 on error.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
   */
b290ebe2c   Heiko Carstens   [CVE-2009-0029] S...
156
  SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  {
314f70fd9   Daniel Walker   whitespace fixes:...
158
159
  	int ret = 0;
  	pid_t pid;
e338d263a   Andrew Morgan   Add 64-bit capabi...
160
161
  	unsigned tocopy;
  	kernel_cap_t pE, pI, pP;
314f70fd9   Daniel Walker   whitespace fixes:...
162

ca05a99a5   Andrew G. Morgan   capabilities: rem...
163
  	ret = cap_validate_magic(header, &tocopy);
c4a5af54c   Andrew G. Morgan   Silence the exist...
164
165
  	if ((dataptr == NULL) || (ret != 0))
  		return ((dataptr == NULL) && (ret == -EINVAL)) ? 0 : ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166

314f70fd9   Daniel Walker   whitespace fixes:...
167
168
  	if (get_user(pid, &header->pid))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169

314f70fd9   Daniel Walker   whitespace fixes:...
170
171
  	if (pid < 0)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172

ab763c711   Andrew G. Morgan   security: filesys...
173
  	ret = cap_get_target_pid(pid, &pE, &pI, &pP);
e338d263a   Andrew Morgan   Add 64-bit capabi...
174
  	if (!ret) {
ca05a99a5   Andrew G. Morgan   capabilities: rem...
175
  		struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
e338d263a   Andrew Morgan   Add 64-bit capabi...
176
177
178
179
180
181
182
183
184
  		unsigned i;
  
  		for (i = 0; i < tocopy; i++) {
  			kdata[i].effective = pE.cap[i];
  			kdata[i].permitted = pP.cap[i];
  			kdata[i].inheritable = pI.cap[i];
  		}
  
  		/*
ca05a99a5   Andrew G. Morgan   capabilities: rem...
185
  		 * Note, in the case, tocopy < _KERNEL_CAPABILITY_U32S,
e338d263a   Andrew Morgan   Add 64-bit capabi...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  		 * we silently drop the upper capabilities here. This
  		 * has the effect of making older libcap
  		 * implementations implicitly drop upper capability
  		 * bits when they perform a: capget/modify/capset
  		 * sequence.
  		 *
  		 * This behavior is considered fail-safe
  		 * behavior. Upgrading the application to a newer
  		 * version of libcap will enable access to the newer
  		 * capabilities.
  		 *
  		 * An alternative would be to return an error here
  		 * (-ERANGE), but that causes legacy applications to
  		 * unexpectidly fail; the capget/modify/capset aborts
  		 * before modification is attempted and the application
  		 * fails.
  		 */
e338d263a   Andrew Morgan   Add 64-bit capabi...
203
204
205
206
207
  		if (copy_to_user(dataptr, kdata, tocopy
  				 * sizeof(struct __user_cap_data_struct))) {
  			return -EFAULT;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208

314f70fd9   Daniel Walker   whitespace fixes:...
209
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  }
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
211
  /**
ab763c711   Andrew G. Morgan   security: filesys...
212
   * sys_capset - set capabilities for a process or (*) a group of processes
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
213
214
215
216
217
   * @header: pointer to struct that contains capability version and
   *	target pid data
   * @data: pointer to struct that contains the effective, permitted,
   *	and inheritable capabilities
   *
1cdcbec1a   David Howells   CRED: Neuter sys_...
218
219
   * Set capabilities for the current process only.  The ability to any other
   * process(es) has been deprecated and removed.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
   *
   * The restrictions on setting capabilities are specified as:
   *
1cdcbec1a   David Howells   CRED: Neuter sys_...
223
224
225
   * I: any raised capabilities must be a subset of the old permitted
   * P: any raised capabilities must be a subset of the old permitted
   * E: must be set to a subset of new permitted
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
226
227
   *
   * Returns 0 on success and < 0 on error.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
   */
b290ebe2c   Heiko Carstens   [CVE-2009-0029] S...
229
  SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  {
ca05a99a5   Andrew G. Morgan   capabilities: rem...
231
  	struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
825332e4f   Arjan van de Ven   capabilities: sim...
232
  	unsigned i, tocopy, copybytes;
314f70fd9   Daniel Walker   whitespace fixes:...
233
  	kernel_cap_t inheritable, permitted, effective;
d84f4f992   David Howells   CRED: Inaugurate ...
234
  	struct cred *new;
314f70fd9   Daniel Walker   whitespace fixes:...
235
236
  	int ret;
  	pid_t pid;
ca05a99a5   Andrew G. Morgan   capabilities: rem...
237
238
239
  	ret = cap_validate_magic(header, &tocopy);
  	if (ret != 0)
  		return ret;
314f70fd9   Daniel Walker   whitespace fixes:...
240
241
242
  
  	if (get_user(pid, &header->pid))
  		return -EFAULT;
1cdcbec1a   David Howells   CRED: Neuter sys_...
243
244
245
  	/* may only affect current now */
  	if (pid != 0 && pid != task_pid_vnr(current))
  		return -EPERM;
825332e4f   Arjan van de Ven   capabilities: sim...
246
247
248
249
250
  	copybytes = tocopy * sizeof(struct __user_cap_data_struct);
  	if (copybytes > sizeof(kdata))
  		return -EFAULT;
  
  	if (copy_from_user(&kdata, data, copybytes))
314f70fd9   Daniel Walker   whitespace fixes:...
251
  		return -EFAULT;
e338d263a   Andrew Morgan   Add 64-bit capabi...
252
253
254
255
256
257
  
  	for (i = 0; i < tocopy; i++) {
  		effective.cap[i] = kdata[i].effective;
  		permitted.cap[i] = kdata[i].permitted;
  		inheritable.cap[i] = kdata[i].inheritable;
  	}
ca05a99a5   Andrew G. Morgan   capabilities: rem...
258
  	while (i < _KERNEL_CAPABILITY_U32S) {
e338d263a   Andrew Morgan   Add 64-bit capabi...
259
260
261
262
263
  		effective.cap[i] = 0;
  		permitted.cap[i] = 0;
  		inheritable.cap[i] = 0;
  		i++;
  	}
314f70fd9   Daniel Walker   whitespace fixes:...
264

d84f4f992   David Howells   CRED: Inaugurate ...
265
266
267
268
269
270
271
272
  	new = prepare_creds();
  	if (!new)
  		return -ENOMEM;
  
  	ret = security_capset(new, current_cred(),
  			      &effective, &inheritable, &permitted);
  	if (ret < 0)
  		goto error;
57f71a0af   Al Viro   sanitize audit_lo...
273
  	audit_log_capset(pid, new, current_cred());
e68b75a02   Eric Paris   When the capset s...
274

d84f4f992   David Howells   CRED: Inaugurate ...
275
276
277
278
  	return commit_creds(new);
  
  error:
  	abort_creds(new);
314f70fd9   Daniel Walker   whitespace fixes:...
279
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  }
12b5989be   Chris Wright   [PATCH] refactor ...
281

5cd9c58fb   David Howells   security: Fix set...
282
  /**
3263245de   Serge E. Hallyn   userns: make has_...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
   * has_capability - Does a task have a capability in init_user_ns
   * @t: The task in question
   * @cap: The capability to be tested for
   *
   * Return true if the specified task has the given superior capability
   * currently in effect to the initial user namespace, false if not.
   *
   * Note that this does not set PF_SUPERPRIV on the task.
   */
  bool has_capability(struct task_struct *t, int cap)
  {
  	int ret = security_real_capable(t, &init_user_ns, cap);
  
  	return (ret == 0);
  }
  
  /**
   * has_capability - Does a task have a capability in a specific user ns
   * @t: The task in question
   * @ns: target user namespace
   * @cap: The capability to be tested for
   *
   * Return true if the specified task has the given superior capability
   * currently in effect to the specified user namespace, false if not.
   *
   * Note that this does not set PF_SUPERPRIV on the task.
   */
  bool has_ns_capability(struct task_struct *t,
  		       struct user_namespace *ns, int cap)
  {
  	int ret = security_real_capable(t, ns, cap);
  
  	return (ret == 0);
  }
  
  /**
   * has_capability_noaudit - Does a task have a capability (unaudited)
   * @t: The task in question
   * @cap: The capability to be tested for
   *
   * Return true if the specified task has the given superior capability
   * currently in effect to init_user_ns, false if not.  Don't write an
   * audit message for the check.
   *
   * Note that this does not set PF_SUPERPRIV on the task.
   */
  bool has_capability_noaudit(struct task_struct *t, int cap)
  {
  	int ret = security_real_capable_noaudit(t, &init_user_ns, cap);
  
  	return (ret == 0);
  }
  
  /**
5cd9c58fb   David Howells   security: Fix set...
337
338
339
340
341
342
343
344
345
   * capable - Determine if the current task has a superior capability in effect
   * @cap: The capability to be tested for
   *
   * Return true if the current task has the given superior capability currently
   * available for use, false if not.
   *
   * This sets PF_SUPERPRIV on the task if the capability is available on the
   * assumption that it's about to be used.
   */
3486740a4   Serge E. Hallyn   userns: security:...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  bool capable(int cap)
  {
  	return ns_capable(&init_user_ns, cap);
  }
  EXPORT_SYMBOL(capable);
  
  /**
   * ns_capable - Determine if the current task has a superior capability in effect
   * @ns:  The usernamespace we want the capability in
   * @cap: The capability to be tested for
   *
   * Return true if the current task has the given superior capability currently
   * available for use, false if not.
   *
   * This sets PF_SUPERPRIV on the task if the capability is available on the
   * assumption that it's about to be used.
   */
  bool ns_capable(struct user_namespace *ns, int cap)
12b5989be   Chris Wright   [PATCH] refactor ...
364
  {
637d32dc7   Eric Paris   Capabilities: BUG...
365
366
367
368
369
  	if (unlikely(!cap_valid(cap))) {
  		printk(KERN_CRIT "capable() called with invalid cap=%u
  ", cap);
  		BUG();
  	}
3486740a4   Serge E. Hallyn   userns: security:...
370
  	if (security_capable(ns, current_cred(), cap) == 0) {
5cd9c58fb   David Howells   security: Fix set...
371
  		current->flags |= PF_SUPERPRIV;
3486740a4   Serge E. Hallyn   userns: security:...
372
  		return true;
12b5989be   Chris Wright   [PATCH] refactor ...
373
  	}
3486740a4   Serge E. Hallyn   userns: security:...
374
  	return false;
12b5989be   Chris Wright   [PATCH] refactor ...
375
  }
3486740a4   Serge E. Hallyn   userns: security:...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  EXPORT_SYMBOL(ns_capable);
  
  /**
   * task_ns_capable - Determine whether current task has a superior
   * capability targeted at a specific task's user namespace.
   * @t: The task whose user namespace is targeted.
   * @cap: The capability in question.
   *
   *  Return true if it does, false otherwise.
   */
  bool task_ns_capable(struct task_struct *t, int cap)
  {
  	return ns_capable(task_cred_xxx(t, user)->user_ns, cap);
  }
  EXPORT_SYMBOL(task_ns_capable);
47a150edc   Serge E. Hallyn   Cache user_ns in ...
391
392
393
394
395
396
397
398
399
400
401
402
  
  /**
   * nsown_capable - Check superior capability to one's own user_ns
   * @cap: The capability in question
   *
   * Return true if the current task has the given superior capability
   * targeted at its own user namespace.
   */
  bool nsown_capable(int cap)
  {
  	return ns_capable(current_user_ns(), cap);
  }