Caps in elf: discussion stopper [was Re: caps in elf headers: use the sticky bit!]

Pavel Machek (pavel@bug.ucw.cz)
Tue, 20 Apr 1999 12:35:23 +0200


Hi!

Ok, I'll try to stop the discussion.

It may seem to you like this I'm fighting sticky vs. suid bit war.

I'm not. I'm adding possibility for executable to drop some of its
privileges. This is obviously safe. Loosing priviledges should be safe
modulo broken programs which do not do proper error handling.

I've added possibility to drop priviledges. This needs complementary
mechanism for _raising_ priviledges. One of such mechanism is existing
suid 0 mechanism. It is not ideal mechanism, but it is already there.

You are right that suid 0 mechanism could be replaced by some other
mechanism to grant additional priviledges. Like sticky bit. Notice
that adding additional mechanism for _raising_ priviledges is _not_
obviously safe. It may or may not be good idea to add sticky bit
solution. Adding 'trusted' ext2 flag is clearly good idea, and it
should be done. [Everybody note: sticky + ext2 flag is not _bad_ idea,
it is just quite hard to implement -- because anything is hard
compared to 100 lines of my current patch.]

Anyway, even if you have 'trusted' ext2 flag, you still need
capability headers in elf, and I think my implementation will work for
you.
Pavel

PS: Ted, you are right that elf+sticky solution is more flexible than
elf+suid0. But even current approach is very usefull: it allows you to
limit priviledges of existing suid 0 applications. Your approach adds
you possiblity to add some small priviledges to currently untrusted
executables (which is also possible with suid 0 approach but in VERY
UGLY way - so call it impossible). As sticky approach still needs
headers in executables, I think it is reasonable to put elf support in
ASAP. It will magically work with suid 0 just now, and you can add
sticky support when _you_ see convient.

PPS: Here is the diff I'm talking about. Consider printk's and "FLE"
uglinness not there :-). Only think that keeps me from Cc:-ing linus
is inavailability of header adder for dynamic binaries, but Jeremy
Fitzhardinge <jeremy@goop.org> is working on it.

-- 
I'm really pavel@atrey.karlin.mff.cuni.cz. 	   Pavel
Look at http://atrey.karlin.mff.cuni.cz/~pavel/ ;-).

--- clean/include/linux/elf.h Thu Jun 25 17:38:14 1998 +++ linux/include/linux/elf.h Mon Apr 19 22:11:31 1999 @@ -496,6 +496,39 @@ Elf32_Word n_type; /* Content type */ } Elf64_Nhdr; +/* Capabilities support + */ +struct elf_capabilities { + Elf32_Word signature; + Elf32_Word version; /* Currently 0, 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 + Elf32_Word xuid; + Elf32_Word effective; + Elf32_Word effective1; + Elf32_Word effective2; + Elf32_Word effective3; + Elf32_Word permitted; + Elf32_Word permitted1; + Elf32_Word permitted2; + Elf32_Word permitted3; + Elf32_Word inheritable; + Elf32_Word inheritable1; + Elf32_Word inheritable2; + Elf32_Word inheritable3; + Elf32_Word known; + Elf32_Word known1; + Elf32_Word known2; + Elf32_Word known3; +}; + +struct elf_capabilities_note { + Elf32_Nhdr notehdr; + __u32 note_signature; /* == "CAPS" */ + struct elf_capabilities cap; +}; + #if ELF_CLASS == ELFCLASS32 extern Elf32_Dyn _DYNAMIC []; --- clean/fs/binfmt_elf.c Fri Mar 26 17:46:23 1999 +++ linux/fs/binfmt_elf.c Mon Apr 19 21:27:38 1999 @@ -425,8 +425,11 @@ 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,6 +476,41 @@ end_data = 0; for (i = 0; i < elf_ex.e_phnum; i++) { + if (elf_ppnt->p_type == PT_NOTE) { + struct elf_capabilities_note note; + + printk( "Before: " ); + retval = read_exec(bprm->dentry, elf_ppnt->p_offset, + (void *) &note, + sizeof (struct elf_capabilities_note), 1); + if (retval<0) + goto out_free_ph; + + printk( "(s) " ); + + if (note.note_signature != be32_to_cpu(0x43415053)) /* "CAPS" */ + continue; + + printk( "uid = %d, effective = %x, permitted = %x, inheritable = %x\n", bprm->e_uid, bprm->cap_effective, bprm->cap_permitted, bprm->cap_inheritable ); + + retval = -ENOEXEC; + if (note.cap.signature != 0xca5ab1e) { + printk( "signature = %x, version = %x, header @ %x\n", note.cap.signature, note.cap.version, elf_ppnt->p_offset ); + goto out_free_ph; + } + if (note.cap.flags & ECF_MAKE_EUID_UID) /* You may want to loose owner's uid */ + bprm->e_uid = current->uid; + if (!bprm->e_uid) { /* We only honour random uid changes for root */ + if (note.cap.flags & ECF_MAKE_EUID_XUID) + bprm->e_uid = note.cap.xuid; + } + cap_mask( bprm->cap_effective, note.cap.effective ); + cap_mask( bprm->cap_permitted, note.cap.permitted ); + cap_mask( bprm->cap_inheritable, note.cap.inheritable ); + + printk( "Now: uid = %d, effective = %x, permitted = %x, inheritable = %x\n", bprm->e_uid, bprm->cap_effective, bprm->cap_permitted, bprm->cap_inheritable ); + + } if (elf_ppnt->p_type == PT_INTERP) { retval = -EINVAL; if (elf_interpreter)

- 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/