Messages in this thread Patch in this message | | | From | Andy Lutomirski <> | Subject | [PATCH] scaled-back caps, take 4 (was Re: [PATCH] capabilites, take 2) | Date | Fri, 14 May 2004 15:48:04 -0700 |
| |
On Friday 14 May 2004 11:07, Chris Wright wrote: > * Andy Lutomirski (luto@stanford.edu) wrote: > > Stephen Smalley wrote: > > > On Fri, 2004-05-14 at 11:57, Andy Lutomirski wrote: > > > > Thanks -- turning brain back on, SELinux is obviously better than any > > > > fine-grained capability scheme I can imagine. > > > > > > > > So unless anyone convinces me you're wrong, I'll stick with just > > > > fixing up capabilities to work without making them finer-grained. > > > > > > Great, thanks. Fixing capabilities to work is definitely useful and > > > desirable. Significantly expanding them in any manner is a poor use of > > > limited resources, IMHO; I'd much rather see people work on applying > > > SELinux to the problem and solving it more effectively for the future. > > > > Does this mean I should trash my 'maximum' mask? > > > > (I like 'cap -c = sftp-server' so it can't try to run setuid/fP apps.) > > OTOH, since SELinux accomplishes this better, it may not be worth the > > effort. > > Let's just get back to the simplest task. Allow execve() to do smth. > reasonable with capabilities.
Sold.
This version throws out the inheritable mask. There is no change in behavior with newcaps=0.
All that's left in newcaps=1 mode is:
fP := permitted (app gains these) pP := permitted (app can make them effective) pE := effective
There is no inheritable mask :) So we can't argue about what it's supposed to / not supposed to.
It's not too well tested yet. Enjoy.
--Andy
cap_2.6.6-mm2_4.patch: New stripped-back capabilities.
fs/exec.c | 15 ++++- include/linux/binfmts.h | 9 ++- security/commoncap.c | 130 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 136 insertions(+), 18 deletions(-)
--- linux-2.6.6-mm2/fs/exec.c~caps 2004-05-13 11:42:26.000000000 -0700 +++ linux-2.6.6-mm2/fs/exec.c 2004-05-14 12:36:17.000000000 -0700 @@ -882,8 +882,10 @@ if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) { /* Set-uid? */ - if (mode & S_ISUID) + if (mode & S_ISUID) { bprm->e_uid = inode->i_uid; + bprm->secflags |= BINPRM_SEC_SETUID; + } /* Set-gid? */ /* @@ -891,10 +893,18 @@ * is a candidate for mandatory locking, not a setgid * executable. */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { bprm->e_gid = inode->i_gid; + bprm->secflags |= BINPRM_SEC_SETGID; + } } + /* Pretend we have VFS capabilities */ + if ((bprm->secflags & BINPRM_SEC_SETUID) && bprm->e_uid == 0) + cap_set_full(bprm->cap_permitted); + else + cap_clear(bprm->cap_permitted); + /* fill in binprm security blob */ retval = security_bprm_set(bprm); if (retval) @@ -1089,6 +1099,7 @@ bprm.loader = 0; bprm.exec = 0; bprm.security = NULL; + bprm.secflags = 0; bprm.mm = mm_alloc(); retval = -ENOMEM; if (!bprm.mm) --- linux-2.6.6-mm2/security/commoncap.c~caps 2004-05-13 11:42:26.000000000 -0700 +++ linux-2.6.6-mm2/security/commoncap.c 2004-05-14 13:24:45.000000000 -0700 @@ -24,6 +24,11 @@ #include <linux/xattr.h> #include <linux/hugetlb.h> +static int newcaps = 0; + +module_param(newcaps, int, 444); +MODULE_PARM_DESC(newcaps, "Set newcaps=1 to enable experimental capabilities"); + int cap_capable (struct task_struct *tsk, int cap) { /* Derived from include/linux/sched.h:capable. */ @@ -48,17 +53,19 @@ { /* Derived from kernel/capability.c:sys_capget. */ *effective = cap_t (target->cap_effective); - *inheritable = cap_t (target->cap_inheritable); *permitted = cap_t (target->cap_permitted); + if (newcaps) + *inheritable = CAP_EMPTY_SET; + else + *inheritable = cap_t (target->cap_inheritable); return 0; } int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - /* Derived from kernel/capability.c:sys_capset. */ /* verify restrictions on target's new Inheritable set */ - if (!cap_issubset (*inheritable, + if (!newcaps && !cap_issubset (*inheritable, cap_combine (target->cap_inheritable, current->cap_permitted))) { return -EPERM; @@ -83,12 +90,16 @@ kernel_cap_t *inheritable, kernel_cap_t *permitted) { target->cap_effective = *effective; - target->cap_inheritable = *inheritable; target->cap_permitted = *permitted; + if (!newcaps) + target->cap_inheritable = *inheritable; } int cap_bprm_set_security (struct linux_binprm *bprm) { + if (newcaps) + return 0; + /* Copied from fs/exec.c:prepare_binprm. */ /* We don't have VFS support for capabilities yet */ @@ -115,9 +126,9 @@ return 0; } -void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) +static void cap_bprm_apply_creds_compat (struct linux_binprm *bprm, int unsafe) { - /* Derived from fs/exec.c:compute_creds. */ + /* This function will hopefully die in 2.7. */ kernel_cap_t new_permitted, working; new_permitted = cap_intersect (bprm->cap_permitted, cap_bset); @@ -158,15 +169,88 @@ current->keep_capabilities = 0; } +/* + * The rules of Linux capabilities (not POSIX!) + * + * What the masks mean: + * pP = capabilities that this process has + * pE = capabilities that this process has and are enabled + * (so pE <= pP) + * + * The capability evolution rules are: + * + * pP' = ((fP & cap_bset) | pP) & Y + * pE' = (pE | fP) & pP' + * + * X = cap_bset + * Y is zero if uid!=0, euid==0, and setuid non-root + * + * Exception: if setuid-nonroot, then pE' is reset to 0. + * + * If file capabilities are introduced, programs that are granted + * fP > 0 need to be aware of how to deal with it. + * Because the effective set is left alone on non-setuid fP>0, + * such a program should drop capabilities that were not in its initial + * effective set before running untrusted code. + * + */ +void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) +{ + kernel_cap_t new_pP, new_pE, fP; + int is_setuid, is_setgid; + + if(!newcaps) { + cap_bprm_apply_creds_compat(bprm, unsafe); + return; + } + + fP = bprm->cap_permitted; + is_setuid = (bprm->secflags & BINPRM_SEC_SETUID); + is_setgid = (bprm->secflags & BINPRM_SEC_SETGID); + + /* Check that it's safe to elevate privileges */ + if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) + bprm->secflags |= BINPRM_SEC_NOELEVATE; + + if (bprm->secflags & BINPRM_SEC_NOELEVATE) { + is_setuid = is_setgid = 0; + cap_clear(fP); + } + + new_pP = cap_intersect(fP, cap_bset); + new_pP = cap_combine(new_pP, current->cap_permitted); + + /* setuid-nonroot is special. */ + if (is_setuid && bprm->e_uid != 0 && current->uid != 0 && + current->euid == 0) + cap_clear(new_pP); + + if (!cap_issubset(new_pP, current->cap_permitted)) + bprm->secflags |= BINPRM_SEC_SECUREEXEC; + + new_pE = cap_combine(current->cap_effective, fP); + cap_mask(new_pE, new_pP); + if (is_setuid && bprm->e_uid != 0) + cap_clear(new_pE); + + /* Apply new security state */ + if (is_setuid) { + current->suid = current->euid = current->fsuid = bprm->e_uid; + } + if (is_setgid) + current->sgid = current->egid = current->fsgid = bprm->e_gid; + + current->cap_permitted = new_pP; + current->cap_effective = new_pE; + + current->keep_capabilities = 0; +} + int cap_bprm_secureexec (struct linux_binprm *bprm) { - /* If/when this module is enhanced to incorporate capability - bits on files, the test below should be extended to also perform a - test between the old and new capability sets. For now, - it simply preserves the legacy decision algorithm used by - the old userland. */ return (current->euid != current->uid || - current->egid != current->gid); + current->egid != current->gid || + (bprm->secflags & BINPRM_SEC_SECUREEXEC)); } int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, @@ -280,9 +364,14 @@ void cap_task_reparent_to_init (struct task_struct *p) { - p->cap_effective = CAP_INIT_EFF_SET; - p->cap_inheritable = CAP_INIT_INH_SET; - p->cap_permitted = CAP_FULL_SET; + if (newcaps) { + cap_set_full(p->cap_permitted); + cap_set_full(p->cap_effective); + } else { + p->cap_effective = CAP_INIT_EFF_SET; + p->cap_inheritable = CAP_INIT_INH_SET; + p->cap_permitted = CAP_FULL_SET; + } p->keep_capabilities = 0; return; } @@ -367,6 +456,15 @@ return -ENOMEM; } +static int __init commoncap_init (void) +{ + if (newcaps) { + printk(KERN_NOTICE "Experimental capability support is on\n"); + } + + return 0; +} + EXPORT_SYMBOL(cap_capable); EXPORT_SYMBOL(cap_ptrace); EXPORT_SYMBOL(cap_capget); @@ -382,5 +480,7 @@ EXPORT_SYMBOL(cap_syslog); EXPORT_SYMBOL(cap_vm_enough_memory); +module_init(commoncap_init); + MODULE_DESCRIPTION("Standard Linux Common Capabilities Security Module"); MODULE_LICENSE("GPL"); --- linux-2.6.6-mm2/include/linux/binfmts.h~caps 2004-05-13 11:42:26.000000000 -0700 +++ linux-2.6.6-mm2/include/linux/binfmts.h 2004-05-14 10:28:05.000000000 -0700 @@ -20,6 +20,10 @@ /* * This structure is used to hold the arguments that are used when loading binaries. */ +#define BINPRM_SEC_SETUID 1 +#define BINPRM_SEC_SETGID 2 +#define BINPRM_SEC_SECUREEXEC 4 +#define BINPRM_SEC_NOELEVATE 8 struct linux_binprm{ char buf[BINPRM_BUF_SIZE]; struct page *page[MAX_ARG_PAGES]; @@ -28,7 +32,10 @@ int sh_bang; struct file * file; int e_uid, e_gid; - kernel_cap_t cap_inheritable, cap_permitted, cap_effective; + int secflags; + kernel_cap_t cap_permitted; + /* old caps -- do NOT use in new code */ + kernel_cap_t cap_inheritable, cap_effective; void *security; int argc, envc; char * filename; /* Name of binary as seen by procps */ - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |