diff options
author | Andrew Morgan <morgan@kernel.org> | 2008-02-05 01:29:42 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 12:44:20 -0500 |
commit | e338d263a76af78fe8f38a72131188b58fceb591 (patch) | |
tree | f3f046fc6fd66de43de7191830f0daf3bc4ec8eb | |
parent | 8f6936f4d29aa14e54a2470b954a2e1f96322988 (diff) |
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>
-rw-r--r-- | fs/nfsd/auth.c | 10 | ||||
-rw-r--r-- | fs/proc/array.c | 21 | ||||
-rw-r--r-- | include/linux/capability.h | 221 | ||||
-rw-r--r-- | kernel/capability.c | 113 | ||||
-rw-r--r-- | mm/oom_kill.c | 5 | ||||
-rw-r--r-- | security/commoncap.c | 87 | ||||
-rw-r--r-- | security/dummy.c | 17 |
7 files changed, 349 insertions, 125 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 21928056e35e..d13403e33622 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
@@ -11,8 +11,6 @@ | |||
11 | #include <linux/nfsd/nfsd.h> | 11 | #include <linux/nfsd/nfsd.h> |
12 | #include <linux/nfsd/export.h> | 12 | #include <linux/nfsd/export.h> |
13 | 13 | ||
14 | #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) | ||
15 | |||
16 | int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | 14 | int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) |
17 | { | 15 | { |
18 | struct exp_flavor_info *f; | 16 | struct exp_flavor_info *f; |
@@ -69,10 +67,12 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
69 | ret = set_current_groups(cred.cr_group_info); | 67 | ret = set_current_groups(cred.cr_group_info); |
70 | put_group_info(cred.cr_group_info); | 68 | put_group_info(cred.cr_group_info); |
71 | if ((cred.cr_uid)) { | 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 | } else { | 72 | } else { |
74 | cap_t(current->cap_effective) |= (CAP_NFSD_MASK & | 73 | current->cap_effective = |
75 | current->cap_permitted); | 74 | cap_raise_nfsd_set(current->cap_effective, |
75 | current->cap_permitted); | ||
76 | } | 76 | } |
77 | return ret; | 77 | return ret; |
78 | } | 78 | } |
diff --git a/fs/proc/array.c b/fs/proc/array.c index b380313092bd..6ba2746e4517 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -281,14 +281,23 @@ static inline char *task_sig(struct task_struct *p, char *buffer) | |||
281 | return buffer; | 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 | static inline char *task_cap(struct task_struct *p, char *buffer) | 296 | static inline char *task_cap(struct task_struct *p, char *buffer) |
285 | { | 297 | { |
286 | return buffer + sprintf(buffer, "CapInh:\t%016x\n" | 298 | buffer = render_cap_t("CapInh:\t", &p->cap_inheritable, buffer); |
287 | "CapPrm:\t%016x\n" | 299 | buffer = render_cap_t("CapPrm:\t", &p->cap_permitted, buffer); |
288 | "CapEff:\t%016x\n", | 300 | return render_cap_t("CapEff:\t", &p->cap_effective, buffer); |
289 | cap_t(p->cap_inheritable), | ||
290 | cap_t(p->cap_permitted), | ||
291 | cap_t(p->cap_effective)); | ||
292 | } | 301 | } |
293 | 302 | ||
294 | static inline char *task_context_switch_counts(struct task_struct *p, | 303 | static inline char *task_context_switch_counts(struct task_struct *p, |
diff --git a/include/linux/capability.h b/include/linux/capability.h index 7a8d7ade28a0..a934dac672dd 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -23,13 +23,20 @@ struct task_struct; | |||
23 | kernel might be somewhat backwards compatible, but don't bet on | 23 | kernel might be somewhat backwards compatible, but don't bet on |
24 | it. */ | 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 | a set of three capability sets. The transposition of 3*the | 27 | a set of three capability sets. The transposition of 3*the |
28 | following structure to such a composite is better handled in a user | 28 | following structure to such a composite is better handled in a user |
29 | library since the draft standard requires the use of malloc/free | 29 | library since the draft standard requires the use of malloc/free |
30 | etc.. */ | 30 | etc.. */ |
31 | 31 | ||
32 | #define _LINUX_CAPABILITY_VERSION 0x19980330 | 32 | #define _LINUX_CAPABILITY_VERSION_1 0x19980330 |
33 | #define _LINUX_CAPABILITY_U32S_1 1 | ||
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 | ||
33 | 40 | ||
34 | typedef struct __user_cap_header_struct { | 41 | typedef struct __user_cap_header_struct { |
35 | __u32 version; | 42 | __u32 version; |
@@ -42,43 +49,42 @@ typedef struct __user_cap_data_struct { | |||
42 | __u32 inheritable; | 49 | __u32 inheritable; |
43 | } __user *cap_user_data_t; | 50 | } __user *cap_user_data_t; |
44 | 51 | ||
52 | |||
45 | #define XATTR_CAPS_SUFFIX "capability" | 53 | #define XATTR_CAPS_SUFFIX "capability" |
46 | #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX | 54 | #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX |
47 | 55 | ||
48 | #define XATTR_CAPS_SZ (3*sizeof(__le32)) | ||
49 | #define VFS_CAP_REVISION_MASK 0xFF000000 | 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 | #define VFS_CAP_REVISION_1 0x01000000 | 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)) | ||
67 | |||
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 | ||
53 | 71 | ||
54 | #define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK | ||
55 | #define VFS_CAP_FLAGS_EFFECTIVE 0x000001 | ||
56 | 72 | ||
57 | struct vfs_cap_data { | 73 | struct vfs_cap_data { |
58 | __u32 magic_etc; /* Little endian */ | 74 | __le32 magic_etc; /* Little endian */ |
59 | struct { | 75 | struct { |
60 | __u32 permitted; /* Little endian */ | 76 | __le32 permitted; /* Little endian */ |
61 | __u32 inheritable; /* Little endian */ | 77 | __le32 inheritable; /* Little endian */ |
62 | } data[1]; | 78 | } data[VFS_CAP_U32]; |
63 | }; | 79 | }; |
64 | 80 | ||
65 | #ifdef __KERNEL__ | 81 | #ifdef __KERNEL__ |
66 | 82 | ||
67 | /* #define STRICT_CAP_T_TYPECHECKS */ | ||
68 | |||
69 | #ifdef STRICT_CAP_T_TYPECHECKS | ||
70 | |||
71 | typedef struct kernel_cap_struct { | 83 | typedef struct kernel_cap_struct { |
72 | __u32 cap; | 84 | __u32 cap[_LINUX_CAPABILITY_U32S]; |
73 | } kernel_cap_t; | 85 | } kernel_cap_t; |
74 | 86 | ||
75 | #else | 87 | #define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct)) |
76 | |||
77 | typedef __u32 kernel_cap_t; | ||
78 | |||
79 | #endif | ||
80 | |||
81 | #define _USER_CAP_HEADER_SIZE (2*sizeof(__u32)) | ||
82 | #define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) | 88 | #define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) |
83 | 89 | ||
84 | #endif | 90 | #endif |
@@ -121,10 +127,6 @@ typedef __u32 kernel_cap_t; | |||
121 | 127 | ||
122 | #define CAP_FSETID 4 | 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 | /* Overrides the restriction that the real or effective user ID of a | 130 | /* Overrides the restriction that the real or effective user ID of a |
129 | process sending a signal must match the real or effective user ID | 131 | process sending a signal must match the real or effective user ID |
130 | of the process receiving the signal. */ | 132 | of the process receiving the signal. */ |
@@ -147,8 +149,12 @@ typedef __u32 kernel_cap_t; | |||
147 | ** Linux-specific capabilities | 149 | ** Linux-specific capabilities |
148 | **/ | 150 | **/ |
149 | 151 | ||
150 | /* Transfer any capability in your permitted set to any pid, | 152 | /* Without VFS support for capabilities: |
151 | remove any capability in your permitted set from any pid */ | 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 | #define CAP_SETPCAP 8 | 159 | #define CAP_SETPCAP 8 |
154 | 160 | ||
@@ -309,70 +315,153 @@ typedef __u32 kernel_cap_t; | |||
309 | 315 | ||
310 | #define CAP_SETFCAP 31 | 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 | #ifdef __KERNEL__ | 325 | #ifdef __KERNEL__ |
313 | 326 | ||
314 | /* | 327 | /* |
315 | * Internal kernel functions only | 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) | ||
333 | |||
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)) | ||
339 | |||
340 | #if _LINUX_CAPABILITY_U32S != 2 | ||
341 | # error Fix up hand-coded capability macro initializers | ||
342 | #else /* HAND-CODED capability initializers */ | ||
343 | |||
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 }} | ||
349 | |||
350 | #endif /* _LINUX_CAPABILITY_U32S != 2 */ | ||
351 | |||
352 | #define CAP_INIT_INH_SET CAP_EMPTY_SET | ||
353 | |||
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) | ||
357 | |||
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) | ||
380 | { | ||
381 | kernel_cap_t dest; | ||
382 | CAP_BOP_ALL(dest, a, b, |); | ||
383 | return dest; | ||
384 | } | ||
319 | 385 | ||
320 | #define to_cap_t(x) { x } | 386 | static inline kernel_cap_t cap_intersect(const kernel_cap_t a, |
321 | #define cap_t(x) (x).cap | 387 | const kernel_cap_t b) |
388 | { | ||
389 | kernel_cap_t dest; | ||
390 | CAP_BOP_ALL(dest, a, b, &); | ||
391 | return dest; | ||
392 | } | ||
322 | 393 | ||
323 | #else | 394 | static inline kernel_cap_t cap_drop(const kernel_cap_t a, |
395 | const kernel_cap_t drop) | ||
396 | { | ||
397 | kernel_cap_t dest; | ||
398 | CAP_BOP_ALL(dest, a, drop, &~); | ||
399 | return dest; | ||
400 | } | ||
324 | 401 | ||
325 | #define to_cap_t(x) (x) | 402 | static inline kernel_cap_t cap_invert(const kernel_cap_t c) |
326 | #define cap_t(x) (x) | 403 | { |
404 | kernel_cap_t dest; | ||
405 | CAP_UOP_ALL(dest, c, ~); | ||
406 | return dest; | ||
407 | } | ||
327 | 408 | ||
328 | #endif | 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 | } | ||
329 | 418 | ||
330 | #define CAP_EMPTY_SET to_cap_t(0) | 419 | static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set) |
331 | #define CAP_FULL_SET to_cap_t(~0) | 420 | { |
332 | #define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) | 421 | kernel_cap_t dest; |
333 | #define CAP_INIT_INH_SET to_cap_t(0) | 422 | dest = cap_drop(a, set); |
423 | return cap_isclear(dest); | ||
424 | } | ||
334 | 425 | ||
335 | #define CAP_TO_MASK(x) (1 << (x)) | 426 | /* Used to decide between falling back on the old suser() or fsuser(). */ |
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)) | ||
339 | 427 | ||
340 | static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b) | 428 | static inline int cap_is_fs_cap(int cap) |
341 | { | 429 | { |
342 | kernel_cap_t dest; | 430 | const kernel_cap_t __cap_fs_set = CAP_FS_SET; |
343 | cap_t(dest) = cap_t(a) | cap_t(b); | 431 | return !!(CAP_TO_MASK(cap) & __cap_fs_set.cap[CAP_TO_INDEX(cap)]); |
344 | return dest; | ||
345 | } | 432 | } |
346 | 433 | ||
347 | static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b) | 434 | static inline kernel_cap_t cap_drop_fs_set(const kernel_cap_t a) |
348 | { | 435 | { |
349 | kernel_cap_t dest; | 436 | const kernel_cap_t __cap_fs_set = CAP_FS_SET; |
350 | cap_t(dest) = cap_t(a) & cap_t(b); | 437 | return cap_drop(a, __cap_fs_set); |
351 | return dest; | ||
352 | } | 438 | } |
353 | 439 | ||
354 | static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop) | 440 | static inline kernel_cap_t cap_raise_fs_set(const kernel_cap_t a, |
441 | const kernel_cap_t permitted) | ||
355 | { | 442 | { |
356 | kernel_cap_t dest; | 443 | const kernel_cap_t __cap_fs_set = CAP_FS_SET; |
357 | cap_t(dest) = cap_t(a) & ~cap_t(drop); | 444 | return cap_combine(a, |
358 | return dest; | 445 | cap_intersect(permitted, __cap_fs_set)); |
359 | } | 446 | } |
360 | 447 | ||
361 | static inline kernel_cap_t cap_invert(kernel_cap_t c) | 448 | static inline kernel_cap_t cap_drop_nfsd_set(const kernel_cap_t a) |
362 | { | 449 | { |
363 | kernel_cap_t dest; | 450 | const kernel_cap_t __cap_fs_set = CAP_NFSD_SET; |
364 | cap_t(dest) = ~cap_t(c); | 451 | return cap_drop(a, __cap_fs_set); |
365 | return dest; | ||
366 | } | 452 | } |
367 | 453 | ||
368 | #define cap_isclear(c) (!cap_t(c)) | 454 | static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a, |
369 | #define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set))) | 455 | const kernel_cap_t permitted) |
370 | 456 | { | |
371 | #define cap_clear(c) do { cap_t(c) = 0; } while(0) | 457 | const kernel_cap_t __cap_nfsd_set = CAP_NFSD_SET; |
372 | #define cap_set_full(c) do { cap_t(c) = ~0; } while(0) | 458 | return cap_combine(a, |
373 | #define cap_mask(c,mask) do { cap_t(c) &= cap_t(mask); } while(0) | 459 | cap_intersect(permitted, __cap_nfsd_set)); |
460 | } | ||
374 | 461 | ||
375 | #define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK) | 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 | int capable(int cap); | 466 | int capable(int cap); |
378 | int __capable(struct task_struct *t, int cap); | 467 | int __capable(struct task_struct *t, int cap); |
diff --git a/kernel/capability.c b/kernel/capability.c index efbd9cdce132..39e8193b41ea 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -22,6 +22,37 @@ | |||
22 | static DEFINE_SPINLOCK(task_capability_lock); | 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 | * For sys_getproccap() and sys_setproccap(), any of the three | 56 | * For sys_getproccap() and sys_setproccap(), any of the three |
26 | * capability set pointers may be NULL -- indicating that that set is | 57 | * capability set pointers may be NULL -- indicating that that set is |
27 | * uninteresting and/or not to be changed. | 58 | * uninteresting and/or not to be changed. |
@@ -42,12 +73,21 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) | |||
42 | pid_t pid; | 73 | pid_t pid; |
43 | __u32 version; | 74 | __u32 version; |
44 | struct task_struct *target; | 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 | if (get_user(version, &header->version)) | 79 | if (get_user(version, &header->version)) |
48 | return -EFAULT; | 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 | if (put_user(_LINUX_CAPABILITY_VERSION, &header->version)) | 91 | if (put_user(_LINUX_CAPABILITY_VERSION, &header->version)) |
52 | return -EFAULT; | 92 | return -EFAULT; |
53 | return -EINVAL; | 93 | return -EINVAL; |
@@ -71,14 +111,47 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) | |||
71 | } else | 111 | } else |
72 | target = current; | 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 | out: | 116 | out: |
77 | read_unlock(&tasklist_lock); | 117 | read_unlock(&tasklist_lock); |
78 | spin_unlock(&task_capability_lock); | 118 | spin_unlock(&task_capability_lock); |
79 | 119 | ||
80 | if (!ret && copy_to_user(dataptr, &data, sizeof data)) | 120 | if (!ret) { |
81 | return -EFAULT; | 121 | struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S]; |
122 | unsigned i; | ||
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 | } | ||
82 | 155 | ||
83 | return ret; | 156 | return ret; |
84 | } | 157 | } |
@@ -167,6 +240,8 @@ static inline int cap_set_all(kernel_cap_t *effective, | |||
167 | */ | 240 | */ |
168 | asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | 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 | kernel_cap_t inheritable, permitted, effective; | 245 | kernel_cap_t inheritable, permitted, effective; |
171 | __u32 version; | 246 | __u32 version; |
172 | struct task_struct *target; | 247 | struct task_struct *target; |
@@ -176,7 +251,15 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
176 | if (get_user(version, &header->version)) | 251 | if (get_user(version, &header->version)) |
177 | return -EFAULT; | 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 | if (put_user(_LINUX_CAPABILITY_VERSION, &header->version)) | 263 | if (put_user(_LINUX_CAPABILITY_VERSION, &header->version)) |
181 | return -EFAULT; | 264 | return -EFAULT; |
182 | return -EINVAL; | 265 | return -EINVAL; |
@@ -188,10 +271,22 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
188 | if (pid && pid != task_pid_vnr(current) && !capable(CAP_SETPCAP)) | 271 | if (pid && pid != task_pid_vnr(current) && !capable(CAP_SETPCAP)) |
189 | return -EPERM; | 272 | return -EPERM; |
190 | 273 | ||
191 | if (copy_from_user(&effective, &data->effective, sizeof(effective)) || | 274 | if (copy_from_user(&kdata, data, tocopy |
192 | copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) || | 275 | * sizeof(struct __user_cap_data_struct))) { |
193 | copy_from_user(&permitted, &data->permitted, sizeof(permitted))) | ||
194 | return -EFAULT; | 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 | spin_lock(&task_capability_lock); | 291 | spin_lock(&task_capability_lock); |
197 | read_lock(&tasklist_lock); | 292 | read_lock(&tasklist_lock); |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 96473b482099..320d74e707af 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -125,8 +125,7 @@ unsigned long badness(struct task_struct *p, unsigned long uptime) | |||
125 | * Superuser processes are usually more important, so we make it | 125 | * Superuser processes are usually more important, so we make it |
126 | * less likely that we kill those. | 126 | * less likely that we kill those. |
127 | */ | 127 | */ |
128 | if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) || | 128 | if (__capable(p, CAP_SYS_ADMIN) || p->uid == 0 || p->euid == 0) |
129 | p->uid == 0 || p->euid == 0) | ||
130 | points /= 4; | 129 | points /= 4; |
131 | 130 | ||
132 | /* | 131 | /* |
@@ -135,7 +134,7 @@ unsigned long badness(struct task_struct *p, unsigned long uptime) | |||
135 | * tend to only have this flag set on applications they think | 134 | * tend to only have this flag set on applications they think |
136 | * of as important. | 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 | points /= 4; | 138 | points /= 4; |
140 | 139 | ||
141 | /* | 140 | /* |
diff --git a/security/commoncap.c b/security/commoncap.c index b06617b35b93..01ab47845dcf 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -1,4 +1,4 @@ | |||
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 | * This program is free software; you can redistribute it and/or modify | 3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
@@ -93,9 +93,9 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective, | |||
93 | kernel_cap_t *inheritable, kernel_cap_t *permitted) | 93 | kernel_cap_t *inheritable, kernel_cap_t *permitted) |
94 | { | 94 | { |
95 | /* Derived from kernel/capability.c:sys_capget. */ | 95 | /* Derived from kernel/capability.c:sys_capget. */ |
96 | *effective = cap_t (target->cap_effective); | 96 | *effective = target->cap_effective; |
97 | *inheritable = cap_t (target->cap_inheritable); | 97 | *inheritable = target->cap_inheritable; |
98 | *permitted = cap_t (target->cap_permitted); | 98 | *permitted = target->cap_permitted; |
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | 101 | ||
@@ -197,28 +197,51 @@ int cap_inode_killpriv(struct dentry *dentry) | |||
197 | return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS); | 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, | 200 | static inline int cap_from_disk(struct vfs_cap_data *caps, |
201 | int size) | 201 | struct linux_binprm *bprm, unsigned size) |
202 | { | 202 | { |
203 | __u32 magic_etc; | 203 | __u32 magic_etc; |
204 | unsigned tocopy, i; | ||
204 | 205 | ||
205 | if (size != XATTR_CAPS_SZ) | 206 | if (size < sizeof(magic_etc)) |
206 | return -EINVAL; | 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 | switch ((magic_etc & VFS_CAP_REVISION_MASK)) { | 211 | switch ((magic_etc & VFS_CAP_REVISION_MASK)) { |
211 | case VFS_CAP_REVISION: | 212 | case VFS_CAP_REVISION_1: |
212 | if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) | 213 | if (size != XATTR_CAPS_SZ_1) |
213 | bprm->cap_effective = true; | 214 | return -EINVAL; |
214 | else | 215 | tocopy = VFS_CAP_U32_1; |
215 | bprm->cap_effective = false; | 216 | break; |
216 | bprm->cap_permitted = to_cap_t(le32_to_cpu(caps[1])); | 217 | case VFS_CAP_REVISION_2: |
217 | bprm->cap_inheritable = to_cap_t(le32_to_cpu(caps[2])); | 218 | if (size != XATTR_CAPS_SZ_2) |
218 | return 0; | 219 | return -EINVAL; |
220 | tocopy = VFS_CAP_U32_2; | ||
221 | break; | ||
219 | default: | 222 | default: |
220 | return -EINVAL; | 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 | /* Locate any VFS capabilities: */ | 247 | /* Locate any VFS capabilities: */ |
@@ -226,7 +249,7 @@ static int get_file_caps(struct linux_binprm *bprm) | |||
226 | { | 249 | { |
227 | struct dentry *dentry; | 250 | struct dentry *dentry; |
228 | int rc = 0; | 251 | int rc = 0; |
229 | __le32 v1caps[XATTR_CAPS_SZ]; | 252 | struct vfs_cap_data vcaps; |
230 | struct inode *inode; | 253 | struct inode *inode; |
231 | 254 | ||
232 | if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) { | 255 | if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) { |
@@ -239,8 +262,8 @@ static int get_file_caps(struct linux_binprm *bprm) | |||
239 | if (!inode->i_op || !inode->i_op->getxattr) | 262 | if (!inode->i_op || !inode->i_op->getxattr) |
240 | goto out; | 263 | goto out; |
241 | 264 | ||
242 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &v1caps, | 265 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps, |
243 | XATTR_CAPS_SZ); | 266 | XATTR_CAPS_SZ); |
244 | if (rc == -ENODATA || rc == -EOPNOTSUPP) { | 267 | if (rc == -ENODATA || rc == -EOPNOTSUPP) { |
245 | /* no data, that's ok */ | 268 | /* no data, that's ok */ |
246 | rc = 0; | 269 | rc = 0; |
@@ -249,7 +272,7 @@ static int get_file_caps(struct linux_binprm *bprm) | |||
249 | if (rc < 0) | 272 | if (rc < 0) |
250 | goto out; | 273 | goto out; |
251 | 274 | ||
252 | rc = cap_from_disk(v1caps, bprm, rc); | 275 | rc = cap_from_disk(&vcaps, bprm, rc); |
253 | if (rc) | 276 | if (rc) |
254 | printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", | 277 | printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", |
255 | __FUNCTION__, rc, bprm->filename); | 278 | __FUNCTION__, rc, bprm->filename); |
@@ -344,8 +367,10 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
344 | * capability rules */ | 367 | * capability rules */ |
345 | if (!is_global_init(current)) { | 368 | if (!is_global_init(current)) { |
346 | current->cap_permitted = new_permitted; | 369 | current->cap_permitted = new_permitted; |
347 | current->cap_effective = bprm->cap_effective ? | 370 | if (bprm->cap_effective) |
348 | new_permitted : 0; | 371 | current->cap_effective = new_permitted; |
372 | else | ||
373 | cap_clear(current->cap_effective); | ||
349 | } | 374 | } |
350 | 375 | ||
351 | /* AUD: Audit candidate if current->cap_effective is set */ | 376 | /* AUD: Audit candidate if current->cap_effective is set */ |
@@ -467,13 +492,15 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, | |||
467 | 492 | ||
468 | if (!issecure (SECURE_NO_SETUID_FIXUP)) { | 493 | if (!issecure (SECURE_NO_SETUID_FIXUP)) { |
469 | if (old_fsuid == 0 && current->fsuid != 0) { | 494 | if (old_fsuid == 0 && current->fsuid != 0) { |
470 | cap_t (current->cap_effective) &= | 495 | current->cap_effective = |
471 | ~CAP_FS_MASK; | 496 | cap_drop_fs_set( |
497 | current->cap_effective); | ||
472 | } | 498 | } |
473 | if (old_fsuid != 0 && current->fsuid == 0) { | 499 | if (old_fsuid != 0 && current->fsuid == 0) { |
474 | cap_t (current->cap_effective) |= | 500 | current->cap_effective = |
475 | (cap_t (current->cap_permitted) & | 501 | cap_raise_fs_set( |
476 | CAP_FS_MASK); | 502 | current->cap_effective, |
503 | current->cap_permitted); | ||
477 | } | 504 | } |
478 | } | 505 | } |
479 | break; | 506 | break; |
@@ -577,9 +604,9 @@ int cap_task_kill(struct task_struct *p, struct siginfo *info, | |||
577 | 604 | ||
578 | void cap_task_reparent_to_init (struct task_struct *p) | 605 | void cap_task_reparent_to_init (struct task_struct *p) |
579 | { | 606 | { |
580 | p->cap_effective = CAP_INIT_EFF_SET; | 607 | cap_set_init_eff(p->cap_effective); |
581 | p->cap_inheritable = CAP_INIT_INH_SET; | 608 | cap_clear(p->cap_inheritable); |
582 | p->cap_permitted = CAP_FULL_SET; | 609 | cap_set_full(p->cap_permitted); |
583 | p->keep_capabilities = 0; | 610 | p->keep_capabilities = 0; |
584 | return; | 611 | return; |
585 | } | 612 | } |
diff --git a/security/dummy.c b/security/dummy.c index c505122e22db..649326bf64ea 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -36,14 +36,19 @@ static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) | |||
36 | static int dummy_capget (struct task_struct *target, kernel_cap_t * effective, | 36 | static int dummy_capget (struct task_struct *target, kernel_cap_t * effective, |
37 | kernel_cap_t * inheritable, kernel_cap_t * permitted) | 37 | kernel_cap_t * inheritable, kernel_cap_t * permitted) |
38 | { | 38 | { |
39 | *effective = *inheritable = *permitted = 0; | ||
40 | if (target->euid == 0) { | 39 | if (target->euid == 0) { |
41 | *permitted |= (~0 & ~CAP_FS_MASK); | 40 | cap_set_full(*permitted); |
42 | *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK); | 41 | cap_set_init_eff(*effective); |
42 | } else { | ||
43 | cap_clear(*permitted); | ||
44 | cap_clear(*effective); | ||
43 | } | 45 | } |
44 | if (target->fsuid == 0) { | 46 | |
45 | *permitted |= CAP_FS_MASK; | 47 | cap_clear(*inheritable); |
46 | *effective |= CAP_FS_MASK; | 48 | |
49 | if (target->fsuid != 0) { | ||
50 | *permitted = cap_drop_fs_set(*permitted); | ||
51 | *effective = cap_drop_fs_set(*effective); | ||
47 | } | 52 | } |
48 | return 0; | 53 | return 0; |
49 | } | 54 | } |