diff options
-rw-r--r-- | fs/open.c | 37 | ||||
-rw-r--r-- | include/linux/capability.h | 2 | ||||
-rw-r--r-- | include/linux/securebits.h | 15 | ||||
-rw-r--r-- | kernel/capability.c | 21 |
4 files changed, 53 insertions, 22 deletions
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/namei.h> | 16 | #include <linux/namei.h> |
17 | #include <linux/backing-dev.h> | 17 | #include <linux/backing-dev.h> |
18 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
19 | #include <linux/securebits.h> | ||
19 | #include <linux/security.h> | 20 | #include <linux/security.h> |
20 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
21 | #include <linux/vfs.h> | 22 | #include <linux/vfs.h> |
@@ -425,7 +426,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | |||
425 | { | 426 | { |
426 | struct nameidata nd; | 427 | struct nameidata nd; |
427 | int old_fsuid, old_fsgid; | 428 | int old_fsuid, old_fsgid; |
428 | kernel_cap_t old_cap; | 429 | kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */ |
429 | int res; | 430 | int res; |
430 | 431 | ||
431 | if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ | 432 | if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ |
@@ -433,23 +434,27 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | |||
433 | 434 | ||
434 | old_fsuid = current->fsuid; | 435 | old_fsuid = current->fsuid; |
435 | old_fsgid = current->fsgid; | 436 | old_fsgid = current->fsgid; |
436 | old_cap = current->cap_effective; | ||
437 | 437 | ||
438 | current->fsuid = current->uid; | 438 | current->fsuid = current->uid; |
439 | current->fsgid = current->gid; | 439 | current->fsgid = current->gid; |
440 | 440 | ||
441 | /* | 441 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { |
442 | * Clear the capabilities if we switch to a non-root user | 442 | /* |
443 | * | 443 | * Clear the capabilities if we switch to a non-root user |
444 | * FIXME: There is a race here against sys_capset. The | 444 | */ |
445 | * capabilities can change yet we will restore the old | 445 | #ifndef CONFIG_SECURITY_FILE_CAPABILITIES |
446 | * value below. We should hold task_capabilities_lock, | 446 | /* |
447 | * but we cannot because user_path_walk can sleep. | 447 | * FIXME: There is a race here against sys_capset. The |
448 | */ | 448 | * capabilities can change yet we will restore the old |
449 | if (current->uid) | 449 | * value below. We should hold task_capabilities_lock, |
450 | cap_clear(current->cap_effective); | 450 | * but we cannot because user_path_walk can sleep. |
451 | else | 451 | */ |
452 | current->cap_effective = current->cap_permitted; | 452 | #endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */ |
453 | if (current->uid) | ||
454 | old_cap = cap_set_effective(__cap_empty_set); | ||
455 | else | ||
456 | old_cap = cap_set_effective(current->cap_permitted); | ||
457 | } | ||
453 | 458 | ||
454 | res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); | 459 | res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); |
455 | if (res) | 460 | if (res) |
@@ -478,7 +483,9 @@ out_path_release: | |||
478 | out: | 483 | out: |
479 | current->fsuid = old_fsuid; | 484 | current->fsuid = old_fsuid; |
480 | current->fsgid = old_fsgid; | 485 | current->fsgid = old_fsgid; |
481 | current->cap_effective = old_cap; | 486 | |
487 | if (!issecure(SECURE_NO_SETUID_FIXUP)) | ||
488 | cap_set_effective(old_cap); | ||
482 | 489 | ||
483 | return res; | 490 | return res; |
484 | } | 491 | } |
diff --git a/include/linux/capability.h b/include/linux/capability.h index fa830f8de032..02673846d205 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -501,6 +501,8 @@ extern const kernel_cap_t __cap_empty_set; | |||
501 | extern const kernel_cap_t __cap_full_set; | 501 | extern const kernel_cap_t __cap_full_set; |
502 | extern const kernel_cap_t __cap_init_eff_set; | 502 | extern const kernel_cap_t __cap_init_eff_set; |
503 | 503 | ||
504 | kernel_cap_t cap_set_effective(const kernel_cap_t pE_new); | ||
505 | |||
504 | int capable(int cap); | 506 | int capable(int cap); |
505 | int __capable(struct task_struct *t, int cap); | 507 | int __capable(struct task_struct *t, int cap); |
506 | 508 | ||
diff --git a/include/linux/securebits.h b/include/linux/securebits.h index c1f19dbceb05..92f09bdf1175 100644 --- a/include/linux/securebits.h +++ b/include/linux/securebits.h | |||
@@ -7,14 +7,15 @@ | |||
7 | inheritance of root-permissions and suid-root executable under | 7 | inheritance of root-permissions and suid-root executable under |
8 | compatibility mode. We raise the effective and inheritable bitmasks | 8 | compatibility mode. We raise the effective and inheritable bitmasks |
9 | *of the executable file* if the effective uid of the new process is | 9 | *of the executable file* if the effective uid of the new process is |
10 | 0. If the real uid is 0, we raise the inheritable bitmask of the | 10 | 0. If the real uid is 0, we raise the effective (legacy) bit of the |
11 | executable file. */ | 11 | executable file. */ |
12 | #define SECURE_NOROOT 0 | 12 | #define SECURE_NOROOT 0 |
13 | #define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */ | 13 | #define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */ |
14 | 14 | ||
15 | /* When set, setuid to/from uid 0 does not trigger capability-"fixes" | 15 | /* When set, setuid to/from uid 0 does not trigger capability-"fixup". |
16 | to be compatible with old programs relying on set*uid to loose | 16 | When unset, to provide compatiblility with old programs relying on |
17 | privileges. When unset, setuid doesn't change privileges. */ | 17 | set*uid to gain/lose privilege, transitions to/from uid 0 cause |
18 | capabilities to be gained/lost. */ | ||
18 | #define SECURE_NO_SETUID_FIXUP 2 | 19 | #define SECURE_NO_SETUID_FIXUP 2 |
19 | #define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */ | 20 | #define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */ |
20 | 21 | ||
@@ -26,10 +27,10 @@ | |||
26 | #define SECURE_KEEP_CAPS 4 | 27 | #define SECURE_KEEP_CAPS 4 |
27 | #define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */ | 28 | #define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */ |
28 | 29 | ||
29 | /* Each securesetting is implemented using two bits. One bit specify | 30 | /* Each securesetting is implemented using two bits. One bit specifies |
30 | whether the setting is on or off. The other bit specify whether the | 31 | whether the setting is on or off. The other bit specify whether the |
31 | setting is fixed or not. A setting which is fixed cannot be changed | 32 | setting is locked or not. A setting which is locked cannot be |
32 | from user-level. */ | 33 | changed from user-level. */ |
33 | #define issecure_mask(X) (1 << (X)) | 34 | #define issecure_mask(X) (1 << (X)) |
34 | #define issecure(X) (issecure_mask(X) & current->securebits) | 35 | #define issecure(X) (issecure_mask(X) & current->securebits) |
35 | 36 | ||
diff --git a/kernel/capability.c b/kernel/capability.c index cfbe44299488..901e0fdc3fff 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -121,6 +121,27 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy) | |||
121 | * uninteresting and/or not to be changed. | 121 | * uninteresting and/or not to be changed. |
122 | */ | 122 | */ |
123 | 123 | ||
124 | /* | ||
125 | * Atomically modify the effective capabilities returning the original | ||
126 | * value. No permission check is performed here - it is assumed that the | ||
127 | * caller is permitted to set the desired effective capabilities. | ||
128 | */ | ||
129 | kernel_cap_t cap_set_effective(const kernel_cap_t pE_new) | ||
130 | { | ||
131 | kernel_cap_t pE_old; | ||
132 | |||
133 | spin_lock(&task_capability_lock); | ||
134 | |||
135 | pE_old = current->cap_effective; | ||
136 | current->cap_effective = pE_new; | ||
137 | |||
138 | spin_unlock(&task_capability_lock); | ||
139 | |||
140 | return pE_old; | ||
141 | } | ||
142 | |||
143 | EXPORT_SYMBOL(cap_set_effective); | ||
144 | |||
124 | /** | 145 | /** |
125 | * sys_capget - get the capabilities of a given process. | 146 | * sys_capget - get the capabilities of a given process. |
126 | * @header: pointer to struct that contains capability version and | 147 | * @header: pointer to struct that contains capability version and |