Commit e338d263a76af78fe8f38a72131188b58fceb591
Committed by
Linus Torvalds
1 parent
8f6936f4d2
Exists in
master
and in
4 other branches
Add 64-bit capability support to the kernel
The patch supports legacy (32-bit) capability userspace, and where possible translates 32-bit capabilities to/from userspace and the VFS to 64-bit kernel space capabilities. If a capability set cannot be compressed into 32-bits for consumption by user space, the system call fails, with -ERANGE. FWIW libcap-2.00 supports this change (and earlier capability formats) http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.6/ [akpm@linux-foundation.org: coding-syle fixes] [akpm@linux-foundation.org: use get_task_comm()] [ezk@cs.sunysb.edu: build fix] [akpm@linux-foundation.org: do not initialise statics to 0 or NULL] [akpm@linux-foundation.org: unused var] [serue@us.ibm.com: export __cap_ symbols] Signed-off-by: Andrew G. Morgan <morgan@kernel.org> Cc: Stephen Smalley <sds@tycho.nsa.gov> Acked-by: Serge Hallyn <serue@us.ibm.com> Cc: Chris Wright <chrisw@sous-sol.org> Cc: James Morris <jmorris@namei.org> Cc: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 7 changed files with 349 additions and 125 deletions Side-by-side Diff
fs/nfsd/auth.c
... | ... | @@ -11,8 +11,6 @@ |
11 | 11 | #include <linux/nfsd/nfsd.h> |
12 | 12 | #include <linux/nfsd/export.h> |
13 | 13 | |
14 | -#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) | |
15 | - | |
16 | 14 | int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) |
17 | 15 | { |
18 | 16 | struct exp_flavor_info *f; |
19 | 17 | |
... | ... | @@ -69,10 +67,12 @@ |
69 | 67 | ret = set_current_groups(cred.cr_group_info); |
70 | 68 | put_group_info(cred.cr_group_info); |
71 | 69 | if ((cred.cr_uid)) { |
72 | - cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; | |
70 | + current->cap_effective = | |
71 | + cap_drop_nfsd_set(current->cap_effective); | |
73 | 72 | } else { |
74 | - cap_t(current->cap_effective) |= (CAP_NFSD_MASK & | |
75 | - current->cap_permitted); | |
73 | + current->cap_effective = | |
74 | + cap_raise_nfsd_set(current->cap_effective, | |
75 | + current->cap_permitted); | |
76 | 76 | } |
77 | 77 | return ret; |
78 | 78 | } |
fs/proc/array.c
... | ... | @@ -281,14 +281,23 @@ |
281 | 281 | return buffer; |
282 | 282 | } |
283 | 283 | |
284 | +static char *render_cap_t(const char *header, kernel_cap_t *a, char *buffer) | |
285 | +{ | |
286 | + unsigned __capi; | |
287 | + | |
288 | + buffer += sprintf(buffer, "%s", header); | |
289 | + CAP_FOR_EACH_U32(__capi) { | |
290 | + buffer += sprintf(buffer, "%08x", | |
291 | + a->cap[(_LINUX_CAPABILITY_U32S-1) - __capi]); | |
292 | + } | |
293 | + return buffer + sprintf(buffer, "\n"); | |
294 | +} | |
295 | + | |
284 | 296 | static inline char *task_cap(struct task_struct *p, char *buffer) |
285 | 297 | { |
286 | - return buffer + sprintf(buffer, "CapInh:\t%016x\n" | |
287 | - "CapPrm:\t%016x\n" | |
288 | - "CapEff:\t%016x\n", | |
289 | - cap_t(p->cap_inheritable), | |
290 | - cap_t(p->cap_permitted), | |
291 | - cap_t(p->cap_effective)); | |
298 | + buffer = render_cap_t("CapInh:\t", &p->cap_inheritable, buffer); | |
299 | + buffer = render_cap_t("CapPrm:\t", &p->cap_permitted, buffer); | |
300 | + return render_cap_t("CapEff:\t", &p->cap_effective, buffer); | |
292 | 301 | } |
293 | 302 | |
294 | 303 | static inline char *task_context_switch_counts(struct task_struct *p, |
include/linux/capability.h
... | ... | @@ -23,14 +23,21 @@ |
23 | 23 | kernel might be somewhat backwards compatible, but don't bet on |
24 | 24 | it. */ |
25 | 25 | |
26 | -/* XXX - Note, cap_t, is defined by POSIX to be an "opaque" pointer to | |
26 | +/* Note, cap_t, is defined by POSIX (draft) to be an "opaque" pointer to | |
27 | 27 | a set of three capability sets. The transposition of 3*the |
28 | 28 | following structure to such a composite is better handled in a user |
29 | 29 | library since the draft standard requires the use of malloc/free |
30 | 30 | etc.. */ |
31 | 31 | |
32 | -#define _LINUX_CAPABILITY_VERSION 0x19980330 | |
32 | +#define _LINUX_CAPABILITY_VERSION_1 0x19980330 | |
33 | +#define _LINUX_CAPABILITY_U32S_1 1 | |
33 | 34 | |
35 | +#define _LINUX_CAPABILITY_VERSION_2 0x20071026 | |
36 | +#define _LINUX_CAPABILITY_U32S_2 2 | |
37 | + | |
38 | +#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2 | |
39 | +#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_2 | |
40 | + | |
34 | 41 | typedef struct __user_cap_header_struct { |
35 | 42 | __u32 version; |
36 | 43 | int pid; |
37 | 44 | |
38 | 45 | |
39 | 46 | |
40 | 47 | |
41 | 48 | |
42 | 49 | |
43 | 50 | |
44 | 51 | |
45 | 52 | |
46 | 53 | |
47 | 54 | |
... | ... | @@ -42,43 +49,42 @@ |
42 | 49 | __u32 inheritable; |
43 | 50 | } __user *cap_user_data_t; |
44 | 51 | |
52 | + | |
45 | 53 | #define XATTR_CAPS_SUFFIX "capability" |
46 | 54 | #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX |
47 | 55 | |
48 | -#define XATTR_CAPS_SZ (3*sizeof(__le32)) | |
49 | 56 | #define VFS_CAP_REVISION_MASK 0xFF000000 |
57 | +#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK | |
58 | +#define VFS_CAP_FLAGS_EFFECTIVE 0x000001 | |
59 | + | |
50 | 60 | #define VFS_CAP_REVISION_1 0x01000000 |
61 | +#define VFS_CAP_U32_1 1 | |
62 | +#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1)) | |
51 | 63 | |
52 | -#define VFS_CAP_REVISION VFS_CAP_REVISION_1 | |
64 | +#define VFS_CAP_REVISION_2 0x02000000 | |
65 | +#define VFS_CAP_U32_2 2 | |
66 | +#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2)) | |
53 | 67 | |
54 | -#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK | |
55 | -#define VFS_CAP_FLAGS_EFFECTIVE 0x000001 | |
68 | +#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2 | |
69 | +#define VFS_CAP_U32 VFS_CAP_U32_2 | |
70 | +#define VFS_CAP_REVISION VFS_CAP_REVISION_2 | |
56 | 71 | |
72 | + | |
57 | 73 | struct vfs_cap_data { |
58 | - __u32 magic_etc; /* Little endian */ | |
74 | + __le32 magic_etc; /* Little endian */ | |
59 | 75 | struct { |
60 | - __u32 permitted; /* Little endian */ | |
61 | - __u32 inheritable; /* Little endian */ | |
62 | - } data[1]; | |
76 | + __le32 permitted; /* Little endian */ | |
77 | + __le32 inheritable; /* Little endian */ | |
78 | + } data[VFS_CAP_U32]; | |
63 | 79 | }; |
64 | 80 | |
65 | 81 | #ifdef __KERNEL__ |
66 | 82 | |
67 | -/* #define STRICT_CAP_T_TYPECHECKS */ | |
68 | - | |
69 | -#ifdef STRICT_CAP_T_TYPECHECKS | |
70 | - | |
71 | 83 | typedef struct kernel_cap_struct { |
72 | - __u32 cap; | |
84 | + __u32 cap[_LINUX_CAPABILITY_U32S]; | |
73 | 85 | } kernel_cap_t; |
74 | 86 | |
75 | -#else | |
76 | - | |
77 | -typedef __u32 kernel_cap_t; | |
78 | - | |
79 | -#endif | |
80 | - | |
81 | -#define _USER_CAP_HEADER_SIZE (2*sizeof(__u32)) | |
87 | +#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct)) | |
82 | 88 | #define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) |
83 | 89 | |
84 | 90 | #endif |
... | ... | @@ -121,10 +127,6 @@ |
121 | 127 | |
122 | 128 | #define CAP_FSETID 4 |
123 | 129 | |
124 | -/* Used to decide between falling back on the old suser() or fsuser(). */ | |
125 | - | |
126 | -#define CAP_FS_MASK 0x1f | |
127 | - | |
128 | 130 | /* Overrides the restriction that the real or effective user ID of a |
129 | 131 | process sending a signal must match the real or effective user ID |
130 | 132 | of the process receiving the signal. */ |
... | ... | @@ -147,8 +149,12 @@ |
147 | 149 | ** Linux-specific capabilities |
148 | 150 | **/ |
149 | 151 | |
150 | -/* Transfer any capability in your permitted set to any pid, | |
151 | - remove any capability in your permitted set from any pid */ | |
152 | +/* Without VFS support for capabilities: | |
153 | + * Transfer any capability in your permitted set to any pid, | |
154 | + * remove any capability in your permitted set from any pid | |
155 | + * With VFS support for capabilities (neither of above, but) | |
156 | + * Add any capability to the current process' inheritable set | |
157 | + */ | |
152 | 158 | |
153 | 159 | #define CAP_SETPCAP 8 |
154 | 160 | |
155 | 161 | |
156 | 162 | |
157 | 163 | |
158 | 164 | |
159 | 165 | |
160 | 166 | |
161 | 167 | |
162 | 168 | |
163 | 169 | |
164 | 170 | |
165 | 171 | |
166 | 172 | |
167 | 173 | |
168 | 174 | |
169 | 175 | |
170 | 176 | |
171 | 177 | |
172 | 178 | |
... | ... | @@ -309,70 +315,153 @@ |
309 | 315 | |
310 | 316 | #define CAP_SETFCAP 31 |
311 | 317 | |
318 | +/* | |
319 | + * Bit location of each capability (used by user-space library and kernel) | |
320 | + */ | |
321 | + | |
322 | +#define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */ | |
323 | +#define CAP_TO_MASK(x) (1 << ((x) & 31)) /* mask for indexed __u32 */ | |
324 | + | |
312 | 325 | #ifdef __KERNEL__ |
313 | 326 | |
314 | 327 | /* |
315 | 328 | * Internal kernel functions only |
316 | 329 | */ |
317 | 330 | |
318 | -#ifdef STRICT_CAP_T_TYPECHECKS | |
331 | +#define CAP_FOR_EACH_U32(__capi) \ | |
332 | + for (__capi = 0; __capi < _LINUX_CAPABILITY_U32S; ++__capi) | |
319 | 333 | |
320 | -#define to_cap_t(x) { x } | |
321 | -#define cap_t(x) (x).cap | |
334 | +# define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \ | |
335 | + | CAP_TO_MASK(CAP_DAC_OVERRIDE) \ | |
336 | + | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \ | |
337 | + | CAP_TO_MASK(CAP_FOWNER) \ | |
338 | + | CAP_TO_MASK(CAP_FSETID)) | |
322 | 339 | |
323 | -#else | |
340 | +#if _LINUX_CAPABILITY_U32S != 2 | |
341 | +# error Fix up hand-coded capability macro initializers | |
342 | +#else /* HAND-CODED capability initializers */ | |
324 | 343 | |
325 | -#define to_cap_t(x) (x) | |
326 | -#define cap_t(x) (x) | |
344 | +# define CAP_EMPTY_SET {{ 0, 0 }} | |
345 | +# define CAP_FULL_SET {{ ~0, ~0 }} | |
346 | +# define CAP_INIT_EFF_SET {{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }} | |
347 | +# define CAP_FS_SET {{ CAP_FS_MASK_B0, 0 }} | |
348 | +# define CAP_NFSD_SET {{ CAP_FS_MASK_B0|CAP_TO_MASK(CAP_SYS_RESOURCE), 0 }} | |
327 | 349 | |
328 | -#endif | |
350 | +#endif /* _LINUX_CAPABILITY_U32S != 2 */ | |
329 | 351 | |
330 | -#define CAP_EMPTY_SET to_cap_t(0) | |
331 | -#define CAP_FULL_SET to_cap_t(~0) | |
332 | -#define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) | |
333 | -#define CAP_INIT_INH_SET to_cap_t(0) | |
352 | +#define CAP_INIT_INH_SET CAP_EMPTY_SET | |
334 | 353 | |
335 | -#define CAP_TO_MASK(x) (1 << (x)) | |
336 | -#define cap_raise(c, flag) (cap_t(c) |= CAP_TO_MASK(flag)) | |
337 | -#define cap_lower(c, flag) (cap_t(c) &= ~CAP_TO_MASK(flag)) | |
338 | -#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag)) | |
354 | +# define cap_clear(c) do { (c) = __cap_empty_set; } while (0) | |
355 | +# define cap_set_full(c) do { (c) = __cap_full_set; } while (0) | |
356 | +# define cap_set_init_eff(c) do { (c) = __cap_init_eff_set; } while (0) | |
339 | 357 | |
340 | -static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b) | |
358 | +#define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag)) | |
359 | +#define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag)) | |
360 | +#define cap_raised(c, flag) ((c).cap[CAP_TO_INDEX(flag)] & CAP_TO_MASK(flag)) | |
361 | + | |
362 | +#define CAP_BOP_ALL(c, a, b, OP) \ | |
363 | +do { \ | |
364 | + unsigned __capi; \ | |
365 | + CAP_FOR_EACH_U32(__capi) { \ | |
366 | + c.cap[__capi] = a.cap[__capi] OP b.cap[__capi]; \ | |
367 | + } \ | |
368 | +} while (0) | |
369 | + | |
370 | +#define CAP_UOP_ALL(c, a, OP) \ | |
371 | +do { \ | |
372 | + unsigned __capi; \ | |
373 | + CAP_FOR_EACH_U32(__capi) { \ | |
374 | + c.cap[__capi] = OP a.cap[__capi]; \ | |
375 | + } \ | |
376 | +} while (0) | |
377 | + | |
378 | +static inline kernel_cap_t cap_combine(const kernel_cap_t a, | |
379 | + const kernel_cap_t b) | |
341 | 380 | { |
342 | - kernel_cap_t dest; | |
343 | - cap_t(dest) = cap_t(a) | cap_t(b); | |
344 | - return dest; | |
381 | + kernel_cap_t dest; | |
382 | + CAP_BOP_ALL(dest, a, b, |); | |
383 | + return dest; | |
345 | 384 | } |
346 | 385 | |
347 | -static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b) | |
386 | +static inline kernel_cap_t cap_intersect(const kernel_cap_t a, | |
387 | + const kernel_cap_t b) | |
348 | 388 | { |
349 | - kernel_cap_t dest; | |
350 | - cap_t(dest) = cap_t(a) & cap_t(b); | |
351 | - return dest; | |
389 | + kernel_cap_t dest; | |
390 | + CAP_BOP_ALL(dest, a, b, &); | |
391 | + return dest; | |
352 | 392 | } |
353 | 393 | |
354 | -static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop) | |
394 | +static inline kernel_cap_t cap_drop(const kernel_cap_t a, | |
395 | + const kernel_cap_t drop) | |
355 | 396 | { |
356 | - kernel_cap_t dest; | |
357 | - cap_t(dest) = cap_t(a) & ~cap_t(drop); | |
358 | - return dest; | |
397 | + kernel_cap_t dest; | |
398 | + CAP_BOP_ALL(dest, a, drop, &~); | |
399 | + return dest; | |
359 | 400 | } |
360 | 401 | |
361 | -static inline kernel_cap_t cap_invert(kernel_cap_t c) | |
402 | +static inline kernel_cap_t cap_invert(const kernel_cap_t c) | |
362 | 403 | { |
363 | - kernel_cap_t dest; | |
364 | - cap_t(dest) = ~cap_t(c); | |
365 | - return dest; | |
404 | + kernel_cap_t dest; | |
405 | + CAP_UOP_ALL(dest, c, ~); | |
406 | + return dest; | |
366 | 407 | } |
367 | 408 | |
368 | -#define cap_isclear(c) (!cap_t(c)) | |
369 | -#define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set))) | |
409 | +static inline int cap_isclear(const kernel_cap_t a) | |
410 | +{ | |
411 | + unsigned __capi; | |
412 | + CAP_FOR_EACH_U32(__capi) { | |
413 | + if (a.cap[__capi] != 0) | |
414 | + return 0; | |
415 | + } | |
416 | + return 1; | |
417 | +} | |
370 | 418 | |
371 | -#define cap_clear(c) do { cap_t(c) = 0; } while(0) | |
372 | -#define cap_set_full(c) do { cap_t(c) = ~0; } while(0) | |
373 | -#define cap_mask(c,mask) do { cap_t(c) &= cap_t(mask); } while(0) | |
419 | +static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set) | |
420 | +{ | |
421 | + kernel_cap_t dest; | |
422 | + dest = cap_drop(a, set); | |
423 | + return cap_isclear(dest); | |
424 | +} | |
374 | 425 | |
375 | -#define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK) | |
426 | +/* Used to decide between falling back on the old suser() or fsuser(). */ | |
427 | + | |
428 | +static inline int cap_is_fs_cap(int cap) | |
429 | +{ | |
430 | + const kernel_cap_t __cap_fs_set = CAP_FS_SET; | |
431 | + return !!(CAP_TO_MASK(cap) & __cap_fs_set.cap[CAP_TO_INDEX(cap)]); | |
432 | +} | |
433 | + | |
434 | +static inline kernel_cap_t cap_drop_fs_set(const kernel_cap_t a) | |
435 | +{ | |
436 | + const kernel_cap_t __cap_fs_set = CAP_FS_SET; | |
437 | + return cap_drop(a, __cap_fs_set); | |
438 | +} | |
439 | + | |
440 | +static inline kernel_cap_t cap_raise_fs_set(const kernel_cap_t a, | |
441 | + const kernel_cap_t permitted) | |
442 | +{ | |
443 | + const kernel_cap_t __cap_fs_set = CAP_FS_SET; | |
444 | + return cap_combine(a, | |
445 | + cap_intersect(permitted, __cap_fs_set)); | |
446 | +} | |
447 | + | |
448 | +static inline kernel_cap_t cap_drop_nfsd_set(const kernel_cap_t a) | |
449 | +{ | |
450 | + const kernel_cap_t __cap_fs_set = CAP_NFSD_SET; | |
451 | + return cap_drop(a, __cap_fs_set); | |
452 | +} | |
453 | + | |
454 | +static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a, | |
455 | + const kernel_cap_t permitted) | |
456 | +{ | |
457 | + const kernel_cap_t __cap_nfsd_set = CAP_NFSD_SET; | |
458 | + return cap_combine(a, | |
459 | + cap_intersect(permitted, __cap_nfsd_set)); | |
460 | +} | |
461 | + | |
462 | +extern const kernel_cap_t __cap_empty_set; | |
463 | +extern const kernel_cap_t __cap_full_set; | |
464 | +extern const kernel_cap_t __cap_init_eff_set; | |
376 | 465 | |
377 | 466 | int capable(int cap); |
378 | 467 | int __capable(struct task_struct *t, int cap); |
kernel/capability.c
... | ... | @@ -22,6 +22,37 @@ |
22 | 22 | static DEFINE_SPINLOCK(task_capability_lock); |
23 | 23 | |
24 | 24 | /* |
25 | + * Leveraged for setting/resetting capabilities | |
26 | + */ | |
27 | + | |
28 | +const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET; | |
29 | +const kernel_cap_t __cap_full_set = CAP_FULL_SET; | |
30 | +const kernel_cap_t __cap_init_eff_set = CAP_INIT_EFF_SET; | |
31 | + | |
32 | +EXPORT_SYMBOL(__cap_empty_set); | |
33 | +EXPORT_SYMBOL(__cap_full_set); | |
34 | +EXPORT_SYMBOL(__cap_init_eff_set); | |
35 | + | |
36 | +/* | |
37 | + * More recent versions of libcap are available from: | |
38 | + * | |
39 | + * http://www.kernel.org/pub/linux/libs/security/linux-privs/ | |
40 | + */ | |
41 | + | |
42 | +static void warn_legacy_capability_use(void) | |
43 | +{ | |
44 | + static int warned; | |
45 | + if (!warned) { | |
46 | + char name[sizeof(current->comm)]; | |
47 | + | |
48 | + printk(KERN_INFO "warning: `%s' uses 32-bit capabilities" | |
49 | + " (legacy support in use)\n", | |
50 | + get_task_comm(name, current)); | |
51 | + warned = 1; | |
52 | + } | |
53 | +} | |
54 | + | |
55 | +/* | |
25 | 56 | * For sys_getproccap() and sys_setproccap(), any of the three |
26 | 57 | * capability set pointers may be NULL -- indicating that that set is |
27 | 58 | * uninteresting and/or not to be changed. |
28 | 59 | |
... | ... | @@ -42,12 +73,21 @@ |
42 | 73 | pid_t pid; |
43 | 74 | __u32 version; |
44 | 75 | struct task_struct *target; |
45 | - struct __user_cap_data_struct data; | |
76 | + unsigned tocopy; | |
77 | + kernel_cap_t pE, pI, pP; | |
46 | 78 | |
47 | 79 | if (get_user(version, &header->version)) |
48 | 80 | return -EFAULT; |
49 | 81 | |
50 | - if (version != _LINUX_CAPABILITY_VERSION) { | |
82 | + switch (version) { | |
83 | + case _LINUX_CAPABILITY_VERSION_1: | |
84 | + warn_legacy_capability_use(); | |
85 | + tocopy = _LINUX_CAPABILITY_U32S_1; | |
86 | + break; | |
87 | + case _LINUX_CAPABILITY_VERSION_2: | |
88 | + tocopy = _LINUX_CAPABILITY_U32S_2; | |
89 | + break; | |
90 | + default: | |
51 | 91 | if (put_user(_LINUX_CAPABILITY_VERSION, &header->version)) |
52 | 92 | return -EFAULT; |
53 | 93 | return -EINVAL; |
54 | 94 | |
55 | 95 | |
... | ... | @@ -71,15 +111,48 @@ |
71 | 111 | } else |
72 | 112 | target = current; |
73 | 113 | |
74 | - ret = security_capget(target, &data.effective, &data.inheritable, &data.permitted); | |
114 | + ret = security_capget(target, &pE, &pI, &pP); | |
75 | 115 | |
76 | 116 | out: |
77 | 117 | read_unlock(&tasklist_lock); |
78 | 118 | spin_unlock(&task_capability_lock); |
79 | 119 | |
80 | - if (!ret && copy_to_user(dataptr, &data, sizeof data)) | |
81 | - return -EFAULT; | |
120 | + if (!ret) { | |
121 | + struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S]; | |
122 | + unsigned i; | |
82 | 123 | |
124 | + for (i = 0; i < tocopy; i++) { | |
125 | + kdata[i].effective = pE.cap[i]; | |
126 | + kdata[i].permitted = pP.cap[i]; | |
127 | + kdata[i].inheritable = pI.cap[i]; | |
128 | + } | |
129 | + | |
130 | + /* | |
131 | + * Note, in the case, tocopy < _LINUX_CAPABILITY_U32S, | |
132 | + * we silently drop the upper capabilities here. This | |
133 | + * has the effect of making older libcap | |
134 | + * implementations implicitly drop upper capability | |
135 | + * bits when they perform a: capget/modify/capset | |
136 | + * sequence. | |
137 | + * | |
138 | + * This behavior is considered fail-safe | |
139 | + * behavior. Upgrading the application to a newer | |
140 | + * version of libcap will enable access to the newer | |
141 | + * capabilities. | |
142 | + * | |
143 | + * An alternative would be to return an error here | |
144 | + * (-ERANGE), but that causes legacy applications to | |
145 | + * unexpectidly fail; the capget/modify/capset aborts | |
146 | + * before modification is attempted and the application | |
147 | + * fails. | |
148 | + */ | |
149 | + | |
150 | + if (copy_to_user(dataptr, kdata, tocopy | |
151 | + * sizeof(struct __user_cap_data_struct))) { | |
152 | + return -EFAULT; | |
153 | + } | |
154 | + } | |
155 | + | |
83 | 156 | return ret; |
84 | 157 | } |
85 | 158 | |
... | ... | @@ -167,6 +240,8 @@ |
167 | 240 | */ |
168 | 241 | asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) |
169 | 242 | { |
243 | + struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S]; | |
244 | + unsigned i, tocopy; | |
170 | 245 | kernel_cap_t inheritable, permitted, effective; |
171 | 246 | __u32 version; |
172 | 247 | struct task_struct *target; |
... | ... | @@ -176,7 +251,15 @@ |
176 | 251 | if (get_user(version, &header->version)) |
177 | 252 | return -EFAULT; |
178 | 253 | |
179 | - if (version != _LINUX_CAPABILITY_VERSION) { | |
254 | + switch (version) { | |
255 | + case _LINUX_CAPABILITY_VERSION_1: | |
256 | + warn_legacy_capability_use(); | |
257 | + tocopy = _LINUX_CAPABILITY_U32S_1; | |
258 | + break; | |
259 | + case _LINUX_CAPABILITY_VERSION_2: | |
260 | + tocopy = _LINUX_CAPABILITY_U32S_2; | |
261 | + break; | |
262 | + default: | |
180 | 263 | if (put_user(_LINUX_CAPABILITY_VERSION, &header->version)) |
181 | 264 | return -EFAULT; |
182 | 265 | return -EINVAL; |
183 | 266 | |
... | ... | @@ -188,10 +271,22 @@ |
188 | 271 | if (pid && pid != task_pid_vnr(current) && !capable(CAP_SETPCAP)) |
189 | 272 | return -EPERM; |
190 | 273 | |
191 | - if (copy_from_user(&effective, &data->effective, sizeof(effective)) || | |
192 | - copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) || | |
193 | - copy_from_user(&permitted, &data->permitted, sizeof(permitted))) | |
274 | + if (copy_from_user(&kdata, data, tocopy | |
275 | + * sizeof(struct __user_cap_data_struct))) { | |
194 | 276 | return -EFAULT; |
277 | + } | |
278 | + | |
279 | + for (i = 0; i < tocopy; i++) { | |
280 | + effective.cap[i] = kdata[i].effective; | |
281 | + permitted.cap[i] = kdata[i].permitted; | |
282 | + inheritable.cap[i] = kdata[i].inheritable; | |
283 | + } | |
284 | + while (i < _LINUX_CAPABILITY_U32S) { | |
285 | + effective.cap[i] = 0; | |
286 | + permitted.cap[i] = 0; | |
287 | + inheritable.cap[i] = 0; | |
288 | + i++; | |
289 | + } | |
195 | 290 | |
196 | 291 | spin_lock(&task_capability_lock); |
197 | 292 | read_lock(&tasklist_lock); |
mm/oom_kill.c
... | ... | @@ -125,8 +125,7 @@ |
125 | 125 | * Superuser processes are usually more important, so we make it |
126 | 126 | * less likely that we kill those. |
127 | 127 | */ |
128 | - if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) || | |
129 | - p->uid == 0 || p->euid == 0) | |
128 | + if (__capable(p, CAP_SYS_ADMIN) || p->uid == 0 || p->euid == 0) | |
130 | 129 | points /= 4; |
131 | 130 | |
132 | 131 | /* |
... | ... | @@ -135,7 +134,7 @@ |
135 | 134 | * tend to only have this flag set on applications they think |
136 | 135 | * of as important. |
137 | 136 | */ |
138 | - if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO)) | |
137 | + if (__capable(p, CAP_SYS_RAWIO)) | |
139 | 138 | points /= 4; |
140 | 139 | |
141 | 140 | /* |
security/commoncap.c
1 | -/* Common capabilities, needed by capability.o and root_plug.o | |
1 | +/* Common capabilities, needed by capability.o and root_plug.o | |
2 | 2 | * |
3 | 3 | * This program is free software; you can redistribute it and/or modify |
4 | 4 | * it under the terms of the GNU General Public License as published by |
... | ... | @@ -93,9 +93,9 @@ |
93 | 93 | kernel_cap_t *inheritable, kernel_cap_t *permitted) |
94 | 94 | { |
95 | 95 | /* Derived from kernel/capability.c:sys_capget. */ |
96 | - *effective = cap_t (target->cap_effective); | |
97 | - *inheritable = cap_t (target->cap_inheritable); | |
98 | - *permitted = cap_t (target->cap_permitted); | |
96 | + *effective = target->cap_effective; | |
97 | + *inheritable = target->cap_inheritable; | |
98 | + *permitted = target->cap_permitted; | |
99 | 99 | return 0; |
100 | 100 | } |
101 | 101 | |
102 | 102 | |
103 | 103 | |
104 | 104 | |
105 | 105 | |
106 | 106 | |
... | ... | @@ -197,28 +197,51 @@ |
197 | 197 | return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS); |
198 | 198 | } |
199 | 199 | |
200 | -static inline int cap_from_disk(__le32 *caps, struct linux_binprm *bprm, | |
201 | - int size) | |
200 | +static inline int cap_from_disk(struct vfs_cap_data *caps, | |
201 | + struct linux_binprm *bprm, unsigned size) | |
202 | 202 | { |
203 | 203 | __u32 magic_etc; |
204 | + unsigned tocopy, i; | |
204 | 205 | |
205 | - if (size != XATTR_CAPS_SZ) | |
206 | + if (size < sizeof(magic_etc)) | |
206 | 207 | return -EINVAL; |
207 | 208 | |
208 | - magic_etc = le32_to_cpu(caps[0]); | |
209 | + magic_etc = le32_to_cpu(caps->magic_etc); | |
209 | 210 | |
210 | 211 | switch ((magic_etc & VFS_CAP_REVISION_MASK)) { |
211 | - case VFS_CAP_REVISION: | |
212 | - if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) | |
213 | - bprm->cap_effective = true; | |
214 | - else | |
215 | - bprm->cap_effective = false; | |
216 | - bprm->cap_permitted = to_cap_t(le32_to_cpu(caps[1])); | |
217 | - bprm->cap_inheritable = to_cap_t(le32_to_cpu(caps[2])); | |
218 | - return 0; | |
212 | + case VFS_CAP_REVISION_1: | |
213 | + if (size != XATTR_CAPS_SZ_1) | |
214 | + return -EINVAL; | |
215 | + tocopy = VFS_CAP_U32_1; | |
216 | + break; | |
217 | + case VFS_CAP_REVISION_2: | |
218 | + if (size != XATTR_CAPS_SZ_2) | |
219 | + return -EINVAL; | |
220 | + tocopy = VFS_CAP_U32_2; | |
221 | + break; | |
219 | 222 | default: |
220 | 223 | return -EINVAL; |
221 | 224 | } |
225 | + | |
226 | + if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) { | |
227 | + bprm->cap_effective = true; | |
228 | + } else { | |
229 | + bprm->cap_effective = false; | |
230 | + } | |
231 | + | |
232 | + for (i = 0; i < tocopy; ++i) { | |
233 | + bprm->cap_permitted.cap[i] = | |
234 | + le32_to_cpu(caps->data[i].permitted); | |
235 | + bprm->cap_inheritable.cap[i] = | |
236 | + le32_to_cpu(caps->data[i].inheritable); | |
237 | + } | |
238 | + while (i < VFS_CAP_U32) { | |
239 | + bprm->cap_permitted.cap[i] = 0; | |
240 | + bprm->cap_inheritable.cap[i] = 0; | |
241 | + i++; | |
242 | + } | |
243 | + | |
244 | + return 0; | |
222 | 245 | } |
223 | 246 | |
224 | 247 | /* Locate any VFS capabilities: */ |
... | ... | @@ -226,7 +249,7 @@ |
226 | 249 | { |
227 | 250 | struct dentry *dentry; |
228 | 251 | int rc = 0; |
229 | - __le32 v1caps[XATTR_CAPS_SZ]; | |
252 | + struct vfs_cap_data vcaps; | |
230 | 253 | struct inode *inode; |
231 | 254 | |
232 | 255 | if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) { |
... | ... | @@ -239,8 +262,8 @@ |
239 | 262 | if (!inode->i_op || !inode->i_op->getxattr) |
240 | 263 | goto out; |
241 | 264 | |
242 | - rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &v1caps, | |
243 | - XATTR_CAPS_SZ); | |
265 | + rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps, | |
266 | + XATTR_CAPS_SZ); | |
244 | 267 | if (rc == -ENODATA || rc == -EOPNOTSUPP) { |
245 | 268 | /* no data, that's ok */ |
246 | 269 | rc = 0; |
... | ... | @@ -249,7 +272,7 @@ |
249 | 272 | if (rc < 0) |
250 | 273 | goto out; |
251 | 274 | |
252 | - rc = cap_from_disk(v1caps, bprm, rc); | |
275 | + rc = cap_from_disk(&vcaps, bprm, rc); | |
253 | 276 | if (rc) |
254 | 277 | printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", |
255 | 278 | __FUNCTION__, rc, bprm->filename); |
... | ... | @@ -344,8 +367,10 @@ |
344 | 367 | * capability rules */ |
345 | 368 | if (!is_global_init(current)) { |
346 | 369 | current->cap_permitted = new_permitted; |
347 | - current->cap_effective = bprm->cap_effective ? | |
348 | - new_permitted : 0; | |
370 | + if (bprm->cap_effective) | |
371 | + current->cap_effective = new_permitted; | |
372 | + else | |
373 | + cap_clear(current->cap_effective); | |
349 | 374 | } |
350 | 375 | |
351 | 376 | /* AUD: Audit candidate if current->cap_effective is set */ |
352 | 377 | |
... | ... | @@ -467,13 +492,15 @@ |
467 | 492 | |
468 | 493 | if (!issecure (SECURE_NO_SETUID_FIXUP)) { |
469 | 494 | if (old_fsuid == 0 && current->fsuid != 0) { |
470 | - cap_t (current->cap_effective) &= | |
471 | - ~CAP_FS_MASK; | |
495 | + current->cap_effective = | |
496 | + cap_drop_fs_set( | |
497 | + current->cap_effective); | |
472 | 498 | } |
473 | 499 | if (old_fsuid != 0 && current->fsuid == 0) { |
474 | - cap_t (current->cap_effective) |= | |
475 | - (cap_t (current->cap_permitted) & | |
476 | - CAP_FS_MASK); | |
500 | + current->cap_effective = | |
501 | + cap_raise_fs_set( | |
502 | + current->cap_effective, | |
503 | + current->cap_permitted); | |
477 | 504 | } |
478 | 505 | } |
479 | 506 | break; |
... | ... | @@ -577,9 +604,9 @@ |
577 | 604 | |
578 | 605 | void cap_task_reparent_to_init (struct task_struct *p) |
579 | 606 | { |
580 | - p->cap_effective = CAP_INIT_EFF_SET; | |
581 | - p->cap_inheritable = CAP_INIT_INH_SET; | |
582 | - p->cap_permitted = CAP_FULL_SET; | |
607 | + cap_set_init_eff(p->cap_effective); | |
608 | + cap_clear(p->cap_inheritable); | |
609 | + cap_set_full(p->cap_permitted); | |
583 | 610 | p->keep_capabilities = 0; |
584 | 611 | return; |
585 | 612 | } |
security/dummy.c
... | ... | @@ -36,14 +36,19 @@ |
36 | 36 | static int dummy_capget (struct task_struct *target, kernel_cap_t * effective, |
37 | 37 | kernel_cap_t * inheritable, kernel_cap_t * permitted) |
38 | 38 | { |
39 | - *effective = *inheritable = *permitted = 0; | |
40 | 39 | if (target->euid == 0) { |
41 | - *permitted |= (~0 & ~CAP_FS_MASK); | |
42 | - *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK); | |
40 | + cap_set_full(*permitted); | |
41 | + cap_set_init_eff(*effective); | |
42 | + } else { | |
43 | + cap_clear(*permitted); | |
44 | + cap_clear(*effective); | |
43 | 45 | } |
44 | - if (target->fsuid == 0) { | |
45 | - *permitted |= CAP_FS_MASK; | |
46 | - *effective |= CAP_FS_MASK; | |
46 | + | |
47 | + cap_clear(*inheritable); | |
48 | + | |
49 | + if (target->fsuid != 0) { | |
50 | + *permitted = cap_drop_fs_set(*permitted); | |
51 | + *effective = cap_drop_fs_set(*effective); | |
47 | 52 | } |
48 | 53 | return 0; |
49 | 54 | } |