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 |
