==== //depot/linux/local/fs/binfmt_elf.c#2 - /home/jeremy/perforce/work/linux/local/fs/binfmt_elf.c ==== @@ -396,12 +396,42 @@ #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_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct file * file; - struct dentry *interpreter_dentry = NULL; /* to shut gcc up */ + struct dentry *interpreter_dentry = NULL; unsigned long load_addr = 0, load_bias; int load_addr_set = 0; char * elf_interpreter = NULL; @@ -473,7 +503,42 @@ 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; + + 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", 1); + + if (caps != NULL) { + /* what to do with multiple CAPS notes? + Find the most restrictive union? */ + + /* process caps here */ + + printk("found CAPS note!\n"); + } + + kfree(buf); + } + break; + + case PT_INTERP: { retval = -EINVAL; if (elf_interpreter) goto out_free_interp; @@ -533,6 +598,8 @@ interp_ex = *((struct exec *) bprm->buf); interp_elf_ex = *((struct elfhdr *) bprm->buf); } + break; + } elf_ppnt++; } @@ -777,7 +844,8 @@ /* error cleanup */ out_free_dentry: - dput(interpreter_dentry); + if (interpreter_dentry) + dput(interpreter_dentry); out_free_interp: if (elf_interpreter) kfree(elf_interpreter);