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 /include/linux/capability.h | |
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>
Diffstat (limited to 'include/linux/capability.h')
-rw-r--r-- | include/linux/capability.h | 221 |
1 files changed, 155 insertions, 66 deletions
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); |