Again more work on binfmt_elf.c

Y2K (y2k@y2ker.com)
Mon, 26 Apr 1999 17:07:44 -0700 (PDT)


In responce to Jeremy's earlier patch.
Mostly just added function do_elfcap_restrict() .
Patch is off of standard clean 2.2.6 but needs other patches such as
earlier ones to work right.

--- binfmt_elf.c.old Mon Apr 26 16:51:10 1999
+++ binfmt_elf.c Mon Apr 26 16:48:32 1999
@@ -396,6 +396,68 @@
#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;
+}
+
+static inline int
+do_elfcap_restrict(struct linux_binprm *bprm, struct elf_capability_note *note)
+{
+ /* check version */
+ if (note.cap.signature!=0xca5ab1e || note.cap.version)
+ return 0;
+ /* 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)&&
+ (capable(CAP_SETUID)|| cap_raised(bprm->permitted,CAP_SETUID)) )
+ 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 );
+
+ /* required needs more work */
+ if (!cap_issubset(note.cap.required,bprm->cap_inheritable) )
+ return -EPERM;
+
+ if (note.cap.securebits&&capable(CAP_LINUX_SECUREBITS) )
+ SECUREBITS_SET(bprm->securebits, note.cap.securebits);
+ else if (note.cap.securebits)
+ return -EPERM;
+
+ return 0;
+
+}

static inline int
do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
@@ -425,8 +487,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 +537,48 @@
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);
+
+ 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 +638,8 @@
interp_ex = *((struct exec *) bprm->buf);
interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
+ break;
+ }
elf_ppnt++;
}

@@ -777,7 +884,8 @@

/* error cleanup */
out_free_dentry:
- dput(interpreter_dentry);
+ if (interpreter_dentry)
+ dput(interpreter_dentry);
out_free_interp:
if (elf_interpreter)
kfree(elf_interpreter);

--
Warning:
When I mention capabilites I mean "soiled" capabilities not "pure draft".
Any caps I mention are *derived* from a withdrawn draft posix document.

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