Messages in this thread Patch in this message | | | Date | Sat, 1 May 1999 21:29:24 -0700 (PDT) | From | Y2K <> | Subject | capabilities patch that more "pure draft" |
| |
Moved controversial change of formula out of compute_creds and made it optional on a per-binary basis via ECF_MAKE_SOILED flag in elf header. SECURE_PURE_CAP now is SECURE_STRICT_FX and will only control default fI and fE values if vfs system can't or won't provide cap information. I think the system is very flexible and should help smooth out some of the points of contention. I hope to merge it with the fcaps/libcap stuff soon. Is this change acceptible to those of you who thought I deviated from the draft too much?
This patch is off of 2.2.7 .
diff -urP linux/Documentation/Configure.help linux-cap/Documentation/Configure.help --- linux/Documentation/Configure.help Sat May 1 14:39:55 1999 +++ linux-cap/Documentation/Configure.help Sat May 1 14:59:27 1999 @@ -1572,6 +1572,39 @@ you have use for it; the module is called binfmt_misc.o. If you don't know what to answer at this point, say Y. +Securebits no root ! +CONFIG_SECUREBITS_NOROOT + This is experimental tweak that will effect SECUREBITS_DEFAULT + 0 is insecure but not fixed + 1 is secure but not fixed + 2 is insecure and fixed + 3 is secure and fixed + Your userland probably doesn't understand capabilities well enough yet! + A secure setting will most likely cause your whole system to become unusable! + If you don't know what to answer at this point, say 2! + +Securebits no setuid fixup ! +CONFIG_SECUREBITS_NO_SETUID_FIXUP + This is experimental tweak that will effect SECUREBITS_DEFAULT + 0 is insecure but not fixed + 1 is secure but not fixed + 2 is insecure and fixed + 3 is secure and fixed + Your userland probably doesn't understand capabilities well enough yet! + A secure setting will most likely cause your whole system to become unusable! + If you don't know what to answer at this point, say 2! + +Securebits pure capabilites ! +CONFIG_SECUREBITS_STRICT_FX + This is experimental tweak that will effect SECUREBITS_DEFAULT + 0 is insecure but not fixed + 1 is secure but not fixed + 2 is insecure and fixed + 3 is secure and fixed + Your userland probably doesn't understand capabilities well enough yet! + A secure setting will most likely cause your whole system to become unusable! + If you don't know what to answer at this point, say 2! + Solaris binary emulation CONFIG_SOLARIS_EMUL This is experimental code which will enable you to run (many) diff -urP linux/arch/i386/config.in linux-cap/arch/i386/config.in --- linux/arch/i386/config.in Sat May 1 14:39:55 1999 +++ linux-cap/arch/i386/config.in Sat May 1 15:20:46 1999 @@ -112,6 +112,12 @@ bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + int 'Securebits NOROOT 0,1,2,3' CONFIG_SECUREBITS_NOROOT 2 + int 'Securebits NO_SETUID_FIXUP 0,1,2,3' CONFIG_SECUREBITS_NO_SETUID_FIXUP 2 + int 'Securebits STRICT_FX 0,1,2,3' CONFIG_SECUREBITS_STRICT_FX 2 +fi + endmenu source drivers/pnp/Config.in diff -urP linux/cap.ldo linux-cap/cap.ldo --- linux/cap.ldo Wed Dec 31 16:00:00 1969 +++ linux-cap/cap.ldo Sat May 1 17:41:26 1999 @@ -0,0 +1,26 @@ +/* sample fake cap ldo thingy */ +/* ld -i -T cap.lds cap.ldo */ + +SECTIONS { + .caps (NOLOAD) : { +LONG(4); /* name size */ +LONG(64); /* content size */ +LONG(7); /* content type */ +BYTE(67); /* C */ +BYTE(65); /* A */ +BYTE(80); /* P */ +BYTE(83); /* S */ +/* CAPS is name of note */ +LONG(0xca5ab1e); /* yet another signature */ +LONG(0x19990501); /* version */ +LONG(4); /* flags */ +LONG(1); /* xuid */ +LONG(-1); /* effective fE */ +LONG(0); /* permitted fP */ +LONG(-1); /* inheritable fI */ +LONG(0); /* required fR */ +LONG(0); /* known fK -- another source of version info? */ +LONG(0); /* disinherite fD aka fM */ +LONG(0); /* padding */ + } :pcaps +} diff -urP linux/cap.lds linux-cap/cap.lds --- linux/cap.lds Wed Dec 31 16:00:00 1969 +++ linux-cap/cap.lds Sat May 1 14:58:54 1999 @@ -0,0 +1,10 @@ +/* cap.lds cap ld script */ +/* ld -i -T cap.lds foo.ldo */ + +OUTPUT(cap.o) +PHDRS { +pcaps PT_NOTE /* PHDRS */ ; +} +SECTIONS { + .caps (NOLOAD) : { *(.caps) } : pcaps +} diff -urP linux/fs/attr.c linux-cap/fs/attr.c --- linux/fs/attr.c Fri Nov 13 10:07:26 1998 +++ linux-cap/fs/attr.c Sat May 1 14:58:54 1999 @@ -37,6 +37,9 @@ if (ia_valid & ATTR_MODE) { if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) goto error; + /* Also check the setuid bit! */ + if ( (inode->i_uid==0) && !capable(CAP_SETFCAP) ) + attr->ia_mode &= ~S_ISUID; /* Also check the setgid bit! */ if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : inode->i_gid) && !capable(CAP_FSETID)) @@ -74,6 +77,8 @@ inode->i_mode = attr->ia_mode; if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) inode->i_mode &= ~S_ISGID; + if ( (inode->i_uid==0) && !capable(CAP_SETFCAP) ) + attr->ia_mode &= ~S_ISUID; } mark_inode_dirty(inode); } diff -urP linux/fs/binfmt_elf.c linux-cap/fs/binfmt_elf.c --- linux/fs/binfmt_elf.c Wed Apr 28 17:39:29 1999 +++ linux-cap/fs/binfmt_elf.c Sat May 1 19:54:01 1999 @@ -396,6 +396,69 @@ #define INTERPRETER_AOUT 1 #define INTERPRETER_ELF 2 +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) + +/* Given a pointer to a set of notes, find the first with the given + name and type */ +static void *find_note(char *buf, int bufsz, const char *notename, int type) +{ + while(bufsz > sizeof(Elf32_Nhdr)) { + Elf32_Nhdr *nhdr = (Elf32_Nhdr *)buf; + char *name; + void *desc; + int sz; + + sz = sizeof(Elf32_Nhdr) + + roundup(nhdr->n_namesz, 4) + + roundup(nhdr->n_descsz, 4); + if (bufsz < sz) + break; + name = buf + sizeof(Elf32_Nhdr); + desc = name + roundup(nhdr->n_namesz, 4); + + if (strncmp(name, notename, nhdr->n_namesz) == 0 && + type == nhdr->n_type) + return desc; + + buf += sz; + bufsz -= sz; + } + + return NULL; +} + +/* restrict capabilities if we find a "CAPS" note */ +static inline int +do_elfcap_restrict(struct linux_binprm *bprm,struct elf_capabilities_note *note) +{ + /* check version */ + if (note->cap.signature!=0xca5ab1e || note->cap.version!=0x19990501) + return -ENOEXEC; + /* You may want to loose owner's uid */ + if (note->cap.flags & ECF_MAKE_EUID_UID) + bprm->e_uid = current->uid; + /* We only honour random uid changes for root */ + /* we also care about CAP_SETUID here */ + if (!bprm->e_uid&&(note->cap.flags&ECF_MAKE_EUID_XUID) ) { + if (capable(CAP_SETUID)||cap_raised(bprm->cap_permitted,CAP_SETUID)) + bprm->e_uid = note->cap.xuid; + else + return -EPERM; + } + /* standard restrictions */ + cap_mask( bprm->cap_effective, note->cap.effective ); + cap_mask( bprm->cap_permitted, note->cap.permitted ); + cap_mask( bprm->cap_inheritable, note->cap.inheritable ); + /* restrict even more if soiled */ + if (note->cap.flags & ECF_MAKE_SOILED ) + cap_mask( bprm->cap_inheritable, current->cap_permitted ); + /* make sure we have everything required */ + if (!cap_issubset(note->cap.required,bprm->cap_inheritable) ) + return -EPERM; + /* set things up so we can disinherite at compute_creds */ + bprm->cap_disinherite=note->cap.disinherite; + return 0; +} static inline int do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) @@ -425,8 +488,10 @@ retval = -ENOEXEC; /* First of all, some simple consistency checks */ - if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) + if (elf_ex.e_ident[0] != 0x7f ) + goto out; + if (strncmp(&elf_ex.e_ident[1], "ELF", 3) && + strncmp(&elf_ex.e_ident[1], "FLE", 3)) goto out; if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) @@ -473,7 +538,52 @@ end_data = 0; for (i = 0; i < elf_ex.e_phnum; i++) { - if (elf_ppnt->p_type == PT_INTERP) { + switch(elf_ppnt->p_type) { + case PT_NOTE: { + struct elf_capabilities_note *caps; + char *buf; + int subret = 0; + + retval = -ENOMEM; + buf = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); + + if (buf == NULL) + goto out_free_dentry; + + retval = read_exec(bprm->dentry, elf_ppnt->p_offset, + buf, elf_ppnt->p_filesz, 1); + + if (retval < 0) { + kfree(buf); + goto out_free_dentry; + } + + caps = (struct elf_capabilities_note *)find_note(buf, + elf_ppnt->p_filesz, "CAPS", NT_ELF_CAP); + + if (caps != NULL) { + /* what to do with multiple CAPS notes? + Find the most restrictive union? */ + + /* process caps here */ + subret=do_elfcap_restrict(bprm, caps); + if (subret==-ENOEXEC) { + printk("found bad CAPS note!\n"); + subret=0; + } + else + printk("found CAPS note!\n"); + } + + kfree(buf); + if (subret) { + retval=subret; + goto out_free_ph; + } + } + break; + + case PT_INTERP: { retval = -EINVAL; if (elf_interpreter) goto out_free_interp; @@ -533,6 +643,8 @@ interp_ex = *((struct exec *) bprm->buf); interp_elf_ex = *((struct elfhdr *) bprm->buf); } + break; + } elf_ppnt++; } @@ -777,7 +889,8 @@ /* error cleanup */ out_free_dentry: - dput(interpreter_dentry); + if (interpreter_dentry) + dput(interpreter_dentry); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); diff -urP linux/fs/exec.c linux-cap/fs/exec.c --- linux/fs/exec.c Mon Jan 18 13:47:38 1999 +++ linux-cap/fs/exec.c Sat May 1 18:54:49 1999 @@ -601,29 +601,57 @@ id_change = 1; } - /* We don't have VFS support for capabilities yet */ - cap_clear(bprm->cap_inheritable); - cap_clear(bprm->cap_permitted); - cap_clear(bprm->cap_effective); + cap_clear(bprm->cap_disinherite); + /* This patch doesn't have VFS support for capabilities yet */ + /* It might look something like this when it does */ + /* + * int subret; + * subret=vfs_cap_dentry(dentry,CAP_FS_GET, + * &bprm->cap_effective, + * &bprm->cap_inheritable, + * &bprm->cap_permitted); + * if (subret==-ENOSYS||subret==-ENODATA) + * USE_DEFAULTS_AS_BELOW + * else if (subret) + * return subret; + * else cap_mask(bprm->cap_inheritable,current->cap_inheritable); + */ + if (issecure(SECURE_STRICT_FX) ) { + cap_clear(bprm->cap_inheritable); + cap_clear(bprm->cap_permitted); + cap_clear(bprm->cap_effective); + } + else { + /* these are some useful defaults */ + cap_t(bprm->cap_inheritable)=cap_t(current->cap_permitted); + cap_mask(bprm->cap_inheritable,current->cap_inheritable); + cap_clear(bprm->cap_permitted); + cap_set_full(bprm->cap_effective); + } + /* FIXME: Better explanation needed here, especially after changes */ /* To support inheritance of root-permissions and suid-root * executables under compatibility mode, we raise the - * effective and inherited bitmasks of the executable file + * effective and permitted bitmasks of suid-root executable files * (translation: we set the executable "capability dumb" and - * set the allowed set to maximum). We don't set any forced - * bits. + * set the allowed set to maximum). * - * If only the real uid is 0, we only raise the inheritable - * bitmask of the executable file (translation: we set the - * allowed set to maximum and the application to "capability - * smart"). + * if root executes a non-root-suid file he will not raise + * any special privledges. He will however have his effective + * set cleared out for backwards compatibility. */ - if (!issecure(SECURE_NOROOT)) { - if (bprm->e_uid == 0 || current->uid == 0) - cap_set_full(bprm->cap_inheritable); - if (bprm->e_uid == 0) + if (!issecure(SECURE_NOROOT)&&(mode&S_ISUID)) { + if (inode->i_uid==0) { + cap_set_full(bprm->cap_permitted); cap_set_full(bprm->cap_effective); + } + else if (!current->uid) + cap_clear(bprm->cap_effective); + } + else if (!issecure(SECURE_NO_SETUID_FIXUP)&& + current->uid==0&¤t->euid) { + cap_clear(bprm->cap_effective); } /* Only if pP' is _not_ a subset of pP, do we consider there @@ -688,6 +716,7 @@ cap_t(current->cap_permitted) = new_permitted; cap_t(current->cap_effective) = new_permitted & cap_t(bprm->cap_effective); + cap_t(current->cap_inheritable) &= ~(cap_t(bprm->cap_disinherite)); } /* AUD: Audit candidate if current->cap_effective is set */ diff -urP linux/fs/open.c linux-cap/fs/open.c --- linux/fs/open.c Wed Apr 28 17:40:14 1999 +++ linux-cap/fs/open.c Sat May 1 14:58:54 1999 @@ -296,7 +296,7 @@ current->fsgid = current->gid; /* Clear the capabilities if we switch to a non-root user */ - if (current->uid) + if (current->uid||issecure(SECURE_NOROOT)) cap_clear(current->cap_effective); else current->cap_effective = current->cap_permitted; diff -urP linux/include/linux/binfmts.h linux-cap/include/linux/binfmts.h --- linux/include/linux/binfmts.h Mon Feb 22 14:50:25 1999 +++ linux-cap/include/linux/binfmts.h Sat May 1 14:58:55 1999 @@ -25,6 +25,7 @@ struct dentry * dentry; int e_uid, e_gid; kernel_cap_t cap_inheritable, cap_permitted, cap_effective; + kernel_cap_t cap_disinherite; int argc, envc; char * filename; /* Name of binary */ unsigned long loader, exec; diff -urP linux/include/linux/capability.h linux-cap/include/linux/capability.h --- linux/include/linux/capability.h Mon Feb 22 14:50:24 1999 +++ linux-cap/include/linux/capability.h Sat May 1 17:06:43 1999 @@ -264,6 +264,28 @@ #define CAP_SYS_TTY_CONFIG 26 +/* Allow changes to capability flags associated with files */ + +#define CAP_SETFCAP 27 + +/* These following caps can not really exist right now */ +/* for discussion only */ +/* they are greater than 31 */ + +/* Allow changing of securebits stuff */ + +#define CAP_LINUX_SECUREBITS 34 + +/* linux will ignore these. used by user-land only */ + +#define CAP_LINUX_USR_0 96 +#define CAP_LINUX_USR_15 111 + +/* reserved for new caps that may be made that normaly everyone has */ +#define CAP_LINUX_RESERVE_NORMAL_0 112 +#define CAP_LINUX_RESERVE_NORMAL_15 127 + + #ifdef __KERNEL__ /* diff -urP linux/include/linux/elf.h linux-cap/include/linux/elf.h --- linux/include/linux/elf.h Tue Jan 26 15:21:22 1999 +++ linux-cap/include/linux/elf.h Sat May 1 15:45:42 1999 @@ -476,6 +476,7 @@ #define NT_PRFPREG 2 #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 +#define NT_ELF_CAP 7 /* Note header in a PT_NOTE section */ typedef struct elf32_note { @@ -495,6 +496,32 @@ Elf32_Word n_descsz; /* Content size */ Elf32_Word n_type; /* Content type */ } Elf64_Nhdr; + +/* Capabilities support + */ +struct elf_capabilities { + Elf32_Word signature; /* 0xca5ab1e */ + Elf32_Word version; +/* Currently 0x19990501, this is so that you can append on the end painlessly */ + Elf32_Word flags; +#define ECF_MAKE_EUID_UID 1 +#define ECF_MAKE_EUID_XUID 2 +#define ECF_MAKE_SOILED 4 + Elf32_Word xuid; + Elf32_Word effective; /* fE */ + Elf32_Word permitted; /* fP */ + Elf32_Word inheritable; /* fI */ + Elf32_Word required; /* fR */ + Elf32_Word known; /* fK */ + Elf32_Word disinherite; /* fD aka fM */ + Elf32_Word pad; /* extra padding, pretty thin right now */ +}; + +struct elf_capabilities_note { + Elf32_Nhdr notehdr; + Elf32_Word note_signature; /* CAPS 0x43415053 */ + struct elf_capabilities cap; +}; #if ELF_CLASS == ELFCLASS32 diff -urP linux/include/linux/securebits.h linux-cap/include/linux/securebits.h --- linux/include/linux/securebits.h Wed Apr 1 16:26:34 1998 +++ linux-cap/include/linux/securebits.h Sat May 1 16:38:34 1999 @@ -1,7 +1,22 @@ #ifndef _LINUX_SECUREBITS_H #define _LINUX_SECUREBITS_H 1 -#define SECUREBITS_DEFAULT 0x00000000 +#ifndef CONFIG_SECUREBITS_NOROOT +#define CONFIG_SECUREBITS_NOROOT 0x00000002 +#endif + +#ifndef CONFIG_SECUREBITS_NO_SETUID_FIXUP +#define CONFIG_SECUREBITS_NO_SETUID_FIXUP 0x00000002 +#endif + +#ifndef CONFIG_SECUREBITS_STRICT_FX +#define CONFIG_SECUREBITS_STRICT_FX 0x00000002 +#endif + +#define SECUREBITS_DEFAULT ( CONFIG_SECUREBITS_NOROOT | \ + (CONFIG_SECUREBITS_NO_SETUID_FIXUP << 2) | \ + (CONFIG_SECUREBITS_STRICT_FX << 4) ) + extern unsigned securebits; @@ -11,12 +26,22 @@ *of the executable file* if the effective uid of the new process is 0. If the real uid is 0, we raise the inheritable bitmask of the executable file. */ +/* FIXME: the above description isn't quite accurate anymore */ +/* When set UID 0 has no special priviledges. When unset, we support + setuid root raising permitted bitmask upon exec, + and sys_access not clearing caps temporarily, + and fsuser and suser work differently, + and other stuff maybe */ #define SECURE_NOROOT 0 /* When set, setuid to/from uid 0 does not trigger capability-"fixes" to be compatible with old programs relying on set*uid to loose privileges. When unset, setuid doesn't change privileges. */ #define SECURE_NO_SETUID_FIXUP 2 + +/* When set, fI and fE are set to zero when vfs info is not availible */ +/* When unset fI=pP&pI and fE=~0 when vfs info is not availible */ +#define SECURE_STRICT_FX 4 /* Each securesetting is implemented using two bits. One bit specify whether the setting is on or off. The other bit specify whether the diff -urP linux/kernel/sys.c linux-cap/kernel/sys.c --- linux/kernel/sys.c Fri Nov 20 11:43:19 1998 +++ linux-cap/kernel/sys.c Sat May 1 14:58:55 1999 @@ -318,6 +318,7 @@ * * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective * capabilities are set to the permitted capabilities. + * The inheritible set is combined with the permitted. * * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should * never happen. @@ -337,6 +338,8 @@ } if (old_euid != 0 && current->euid == 0) { current->cap_effective = current->cap_permitted; + current->cap_inheritable=cap_combine(current->cap_inheritable, + current->cap_permitted); } }
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |