aboutsummaryrefslogtreecommitdiffstats
path: root/security/commoncap.c
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2015-09-04 18:42:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-04 19:54:41 -0400
commit58319057b7847667f0c9585b9de0e8932b0fdb08 (patch)
tree65117825e10dbe63b0daa4b1268c5305f6bb978b /security/commoncap.c
parente9f069868d60550c4b46f084ac9276a57c1b4711 (diff)
capabilities: ambient capabilities
Credit where credit is due: this idea comes from Christoph Lameter with a lot of valuable input from Serge Hallyn. This patch is heavily based on Christoph's patch. ===== The status quo ===== On Linux, there are a number of capabilities defined by the kernel. To perform various privileged tasks, processes can wield capabilities that they hold. Each task has four capability masks: effective (pE), permitted (pP), inheritable (pI), and a bounding set (X). When the kernel checks for a capability, it checks pE. The other capability masks serve to modify what capabilities can be in pE. Any task can remove capabilities from pE, pP, or pI at any time. If a task has a capability in pP, it can add that capability to pE and/or pI. If a task has CAP_SETPCAP, then it can add any capability to pI, and it can remove capabilities from X. Tasks are not the only things that can have capabilities; files can also have capabilities. A file can have no capabilty information at all [1]. If a file has capability information, then it has a permitted mask (fP) and an inheritable mask (fI) as well as a single effective bit (fE) [2]. File capabilities modify the capabilities of tasks that execve(2) them. A task that successfully calls execve has its capabilities modified for the file ultimately being excecuted (i.e. the binary itself if that binary is ELF or for the interpreter if the binary is a script.) [3] In the capability evolution rules, for each mask Z, pZ represents the old value and pZ' represents the new value. The rules are: pP' = (X & fP) | (pI & fI) pI' = pI pE' = (fE ? pP' : 0) X is unchanged For setuid binaries, fP, fI, and fE are modified by a moderately complicated set of rules that emulate POSIX behavior. Similarly, if euid == 0 or ruid == 0, then fP, fI, and fE are modified differently (primary, fP and fI usually end up being the full set). For nonroot users executing binaries with neither setuid nor file caps, fI and fP are empty and fE is false. As an extra complication, if you execute a process as nonroot and fE is set, then the "secure exec" rules are in effect: AT_SECURE gets set, LD_PRELOAD doesn't work, etc. This is rather messy. We've learned that making any changes is dangerous, though: if a new kernel version allows an unprivileged program to change its security state in a way that persists cross execution of a setuid program or a program with file caps, this persistent state is surprisingly likely to allow setuid or file-capped programs to be exploited for privilege escalation. ===== The problem ===== Capability inheritance is basically useless. If you aren't root and you execute an ordinary binary, fI is zero, so your capabilities have no effect whatsoever on pP'. This means that you can't usefully execute a helper process or a shell command with elevated capabilities if you aren't root. On current kernels, you can sort of work around this by setting fI to the full set for most or all non-setuid executable files. This causes pP' = pI for nonroot, and inheritance works. No one does this because it's a PITA and it isn't even supported on most filesystems. If you try this, you'll discover that every nonroot program ends up with secure exec rules, breaking many things. This is a problem that has bitten many people who have tried to use capabilities for anything useful. ===== The proposed change ===== This patch adds a fifth capability mask called the ambient mask (pA). pA does what most people expect pI to do. pA obeys the invariant that no bit can ever be set in pA if it is not set in both pP and pI. Dropping a bit from pP or pI drops that bit from pA. This ensures that existing programs that try to drop capabilities still do so, with a complication. Because capability inheritance is so broken, setting KEEPCAPS, using setresuid to switch to nonroot uids, and then calling execve effectively drops capabilities. Therefore, setresuid from root to nonroot conditionally clears pA unless SECBIT_NO_SETUID_FIXUP is set. Processes that don't like this can re-add bits to pA afterwards. The capability evolution rules are changed: pA' = (file caps or setuid or setgid ? 0 : pA) pP' = (X & fP) | (pI & fI) | pA' pI' = pI pE' = (fE ? pP' : pA') X is unchanged If you are nonroot but you have a capability, you can add it to pA. If you do so, your children get that capability in pA, pP, and pE. For example, you can set pA = CAP_NET_BIND_SERVICE, and your children can automatically bind low-numbered ports. Hallelujah! Unprivileged users can create user namespaces, map themselves to a nonzero uid, and create both privileged (relative to their namespace) and unprivileged process trees. This is currently more or less impossible. Hallelujah! You cannot use pA to try to subvert a setuid, setgid, or file-capped program: if you execute any such program, pA gets cleared and the resulting evolution rules are unchanged by this patch. Users with nonzero pA are unlikely to unintentionally leak that capability. If they run programs that try to drop privileges, dropping privileges will still work. It's worth noting that the degree of paranoia in this patch could possibly be reduced without causing serious problems. Specifically, if we allowed pA to persist across executing non-pA-aware setuid binaries and across setresuid, then, naively, the only capabilities that could leak as a result would be the capabilities in pA, and any attacker *already* has those capabilities. This would make me nervous, though -- setuid binaries that tried to privilege-separate might fail to do so, and putting CAP_DAC_READ_SEARCH or CAP_DAC_OVERRIDE into pA could have unexpected side effects. (Whether these unexpected side effects would be exploitable is an open question.) I've therefore taken the more paranoid route. We can revisit this later. An alternative would be to require PR_SET_NO_NEW_PRIVS before setting ambient capabilities. I think that this would be annoying and would make granting otherwise unprivileged users minor ambient capabilities (CAP_NET_BIND_SERVICE or CAP_NET_RAW for example) much less useful than it is with this patch. ===== Footnotes ===== [1] Files that are missing the "security.capability" xattr or that have unrecognized values for that xattr end up with has_cap set to false. The code that does that appears to be complicated for no good reason. [2] The libcap capability mask parsers and formatters are dangerously misleading and the documentation is flat-out wrong. fE is *not* a mask; it's a single bit. This has probably confused every single person who has tried to use file capabilities. [3] Linux very confusingly processes both the script and the interpreter if applicable, for reasons that elude me. The results from thinking about a script's file capabilities and/or setuid bits are mostly discarded. Preliminary userspace code is here, but it needs updating: https://git.kernel.org/cgit/linux/kernel/git/luto/util-linux-playground.git/commit/?h=cap_ambient&id=7f5afbd175d2 Here is a test program that can be used to verify the functionality (from Christoph): /* * Test program for the ambient capabilities. This program spawns a shell * that allows running processes with a defined set of capabilities. * * (C) 2015 Christoph Lameter <cl@linux.com> * Released under: GPL v3 or later. * * * Compile using: * * gcc -o ambient_test ambient_test.o -lcap-ng * * This program must have the following capabilities to run properly: * Permissions for CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_NICE * * A command to equip the binary with the right caps is: * * setcap cap_net_raw,cap_net_admin,cap_sys_nice+p ambient_test * * * To get a shell with additional caps that can be inherited by other processes: * * ./ambient_test /bin/bash * * * Verifying that it works: * * From the bash spawed by ambient_test run * * cat /proc/$$/status * * and have a look at the capabilities. */ #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <cap-ng.h> #include <sys/prctl.h> #include <linux/capability.h> /* * Definitions from the kernel header files. These are going to be removed * when the /usr/include files have these defined. */ #define PR_CAP_AMBIENT 47 #define PR_CAP_AMBIENT_IS_SET 1 #define PR_CAP_AMBIENT_RAISE 2 #define PR_CAP_AMBIENT_LOWER 3 #define PR_CAP_AMBIENT_CLEAR_ALL 4 static void set_ambient_cap(int cap) { int rc; capng_get_caps_process(); rc = capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap); if (rc) { printf("Cannot add inheritable cap\n"); exit(2); } capng_apply(CAPNG_SELECT_CAPS); /* Note the two 0s at the end. Kernel checks for these */ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) { perror("Cannot set cap"); exit(1); } } int main(int argc, char **argv) { int rc; set_ambient_cap(CAP_NET_RAW); set_ambient_cap(CAP_NET_ADMIN); set_ambient_cap(CAP_SYS_NICE); printf("Ambient_test forking shell\n"); if (execv(argv[1], argv + 1)) perror("Cannot exec"); return 0; } Signed-off-by: Christoph Lameter <cl@linux.com> # Original author Signed-off-by: Andy Lutomirski <luto@kernel.org> Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com> Acked-by: Kees Cook <keescook@chromium.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Aaron Jones <aaronmdjones@gmail.com> Cc: Ted Ts'o <tytso@mit.edu> Cc: Andrew G. Morgan <morgan@kernel.org> Cc: Mimi Zohar <zohar@linux.vnet.ibm.com> Cc: Austin S Hemmelgarn <ahferroin7@gmail.com> Cc: Markku Savela <msa@moth.iki.fi> Cc: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: James Morris <james.l.morris@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c102
1 files changed, 92 insertions, 10 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index d103f5a4043d..1f74dde1063e 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -267,6 +267,16 @@ int cap_capset(struct cred *new,
267 new->cap_effective = *effective; 267 new->cap_effective = *effective;
268 new->cap_inheritable = *inheritable; 268 new->cap_inheritable = *inheritable;
269 new->cap_permitted = *permitted; 269 new->cap_permitted = *permitted;
270
271 /*
272 * Mask off ambient bits that are no longer both permitted and
273 * inheritable.
274 */
275 new->cap_ambient = cap_intersect(new->cap_ambient,
276 cap_intersect(*permitted,
277 *inheritable));
278 if (WARN_ON(!cap_ambient_invariant_ok(new)))
279 return -EINVAL;
270 return 0; 280 return 0;
271} 281}
272 282
@@ -347,6 +357,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
347 357
348 /* 358 /*
349 * pP' = (X & fP) | (pI & fI) 359 * pP' = (X & fP) | (pI & fI)
360 * The addition of pA' is handled later.
350 */ 361 */
351 new->cap_permitted.cap[i] = 362 new->cap_permitted.cap[i] =
352 (new->cap_bset.cap[i] & permitted) | 363 (new->cap_bset.cap[i] & permitted) |
@@ -474,10 +485,13 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
474{ 485{
475 const struct cred *old = current_cred(); 486 const struct cred *old = current_cred();
476 struct cred *new = bprm->cred; 487 struct cred *new = bprm->cred;
477 bool effective, has_cap = false; 488 bool effective, has_cap = false, is_setid;
478 int ret; 489 int ret;
479 kuid_t root_uid; 490 kuid_t root_uid;
480 491
492 if (WARN_ON(!cap_ambient_invariant_ok(old)))
493 return -EPERM;
494
481 effective = false; 495 effective = false;
482 ret = get_file_caps(bprm, &effective, &has_cap); 496 ret = get_file_caps(bprm, &effective, &has_cap);
483 if (ret < 0) 497 if (ret < 0)
@@ -522,8 +536,9 @@ skip:
522 * 536 *
523 * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. 537 * In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
524 */ 538 */
525 if ((!uid_eq(new->euid, old->uid) || 539 is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid);
526 !gid_eq(new->egid, old->gid) || 540
541 if ((is_setid ||
527 !cap_issubset(new->cap_permitted, old->cap_permitted)) && 542 !cap_issubset(new->cap_permitted, old->cap_permitted)) &&
528 bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { 543 bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
529 /* downgrade; they get no more than they had, and maybe less */ 544 /* downgrade; they get no more than they had, and maybe less */
@@ -539,10 +554,28 @@ skip:
539 new->suid = new->fsuid = new->euid; 554 new->suid = new->fsuid = new->euid;
540 new->sgid = new->fsgid = new->egid; 555 new->sgid = new->fsgid = new->egid;
541 556
557 /* File caps or setid cancels ambient. */
558 if (has_cap || is_setid)
559 cap_clear(new->cap_ambient);
560
561 /*
562 * Now that we've computed pA', update pP' to give:
563 * pP' = (X & fP) | (pI & fI) | pA'
564 */
565 new->cap_permitted = cap_combine(new->cap_permitted, new->cap_ambient);
566
567 /*
568 * Set pE' = (fE ? pP' : pA'). Because pA' is zero if fE is set,
569 * this is the same as pE' = (fE ? pP' : 0) | pA'.
570 */
542 if (effective) 571 if (effective)
543 new->cap_effective = new->cap_permitted; 572 new->cap_effective = new->cap_permitted;
544 else 573 else
545 cap_clear(new->cap_effective); 574 new->cap_effective = new->cap_ambient;
575
576 if (WARN_ON(!cap_ambient_invariant_ok(new)))
577 return -EPERM;
578
546 bprm->cap_effective = effective; 579 bprm->cap_effective = effective;
547 580
548 /* 581 /*
@@ -557,7 +590,7 @@ skip:
557 * Number 1 above might fail if you don't have a full bset, but I think 590 * Number 1 above might fail if you don't have a full bset, but I think
558 * that is interesting information to audit. 591 * that is interesting information to audit.
559 */ 592 */
560 if (!cap_isclear(new->cap_effective)) { 593 if (!cap_issubset(new->cap_effective, new->cap_ambient)) {
561 if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || 594 if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
562 !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) || 595 !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
563 issecure(SECURE_NOROOT)) { 596 issecure(SECURE_NOROOT)) {
@@ -568,6 +601,10 @@ skip:
568 } 601 }
569 602
570 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); 603 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
604
605 if (WARN_ON(!cap_ambient_invariant_ok(new)))
606 return -EPERM;
607
571 return 0; 608 return 0;
572} 609}
573 610
@@ -589,7 +626,7 @@ int cap_bprm_secureexec(struct linux_binprm *bprm)
589 if (!uid_eq(cred->uid, root_uid)) { 626 if (!uid_eq(cred->uid, root_uid)) {
590 if (bprm->cap_effective) 627 if (bprm->cap_effective)
591 return 1; 628 return 1;
592 if (!cap_isclear(cred->cap_permitted)) 629 if (!cap_issubset(cred->cap_permitted, cred->cap_ambient))
593 return 1; 630 return 1;
594 } 631 }
595 632
@@ -691,10 +728,18 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
691 uid_eq(old->suid, root_uid)) && 728 uid_eq(old->suid, root_uid)) &&
692 (!uid_eq(new->uid, root_uid) && 729 (!uid_eq(new->uid, root_uid) &&
693 !uid_eq(new->euid, root_uid) && 730 !uid_eq(new->euid, root_uid) &&
694 !uid_eq(new->suid, root_uid)) && 731 !uid_eq(new->suid, root_uid))) {
695 !issecure(SECURE_KEEP_CAPS)) { 732 if (!issecure(SECURE_KEEP_CAPS)) {
696 cap_clear(new->cap_permitted); 733 cap_clear(new->cap_permitted);
697 cap_clear(new->cap_effective); 734 cap_clear(new->cap_effective);
735 }
736
737 /*
738 * Pre-ambient programs expect setresuid to nonroot followed
739 * by exec to drop capabilities. We should make sure that
740 * this remains the case.
741 */
742 cap_clear(new->cap_ambient);
698 } 743 }
699 if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid)) 744 if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid))
700 cap_clear(new->cap_effective); 745 cap_clear(new->cap_effective);
@@ -924,6 +969,43 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
924 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); 969 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
925 return commit_creds(new); 970 return commit_creds(new);
926 971
972 case PR_CAP_AMBIENT:
973 if (arg2 == PR_CAP_AMBIENT_CLEAR_ALL) {
974 if (arg3 | arg4 | arg5)
975 return -EINVAL;
976
977 new = prepare_creds();
978 if (!new)
979 return -ENOMEM;
980 cap_clear(new->cap_ambient);
981 return commit_creds(new);
982 }
983
984 if (((!cap_valid(arg3)) | arg4 | arg5))
985 return -EINVAL;
986
987 if (arg2 == PR_CAP_AMBIENT_IS_SET) {
988 return !!cap_raised(current_cred()->cap_ambient, arg3);
989 } else if (arg2 != PR_CAP_AMBIENT_RAISE &&
990 arg2 != PR_CAP_AMBIENT_LOWER) {
991 return -EINVAL;
992 } else {
993 if (arg2 == PR_CAP_AMBIENT_RAISE &&
994 (!cap_raised(current_cred()->cap_permitted, arg3) ||
995 !cap_raised(current_cred()->cap_inheritable,
996 arg3)))
997 return -EPERM;
998
999 new = prepare_creds();
1000 if (!new)
1001 return -ENOMEM;
1002 if (arg2 == PR_CAP_AMBIENT_RAISE)
1003 cap_raise(new->cap_ambient, arg3);
1004 else
1005 cap_lower(new->cap_ambient, arg3);
1006 return commit_creds(new);
1007 }
1008
927 default: 1009 default:
928 /* No functionality available - continue with default */ 1010 /* No functionality available - continue with default */
929 return -ENOSYS; 1011 return -ENOSYS;