Index: exec_elf.c =================================================================== RCS file: /cvsroot/src/sys/kern/exec_elf.c,v retrieving revision 1.69.2.4 diff -u -p -u -r1.69.2.4 exec_elf.c --- exec_elf.c 26 Jan 2016 01:18:37 -0000 1.69.2.4 +++ exec_elf.c 21 Jan 2017 12:06:40 -0000 @@ -95,6 +95,7 @@ extern struct emul emul_netbsd; #define elf_load_psection ELFNAME(load_psection) #define exec_elf_makecmds ELFNAME2(exec,makecmds) #define netbsd_elf_signature ELFNAME2(netbsd,signature) +#define netbsd_elf_note ELFNAME2(netbsd,note) #define netbsd_elf_probe ELFNAME2(netbsd,probe) #define coredump ELFNAMEEND(coredump) #define elf_free_emul_arg ELFNAME(free_emul_arg) @@ -107,6 +108,8 @@ elf_load_psection(struct exec_vmcmd_set Elf_Addr *, u_long *, int); int netbsd_elf_signature(struct lwp *, struct exec_package *, Elf_Ehdr *); +int netbsd_elf_note(struct exec_package *, const Elf_Nhdr *, const char *, + const char *); int netbsd_elf_probe(struct lwp *, struct exec_package *, void *, char *, vaddr_t *); @@ -885,73 +888,93 @@ netbsd_elf_signature(struct lwp *l, stru Elf_Ehdr *eh) { size_t i; - Elf_Shdr *sh; - Elf_Nhdr *np; - size_t shsize, nsize; + Elf_Phdr *ph; + size_t phsize; + char *nbuf; int error; int isnetbsd = 0; - char *ndata, *ndesc; - -#ifdef DIAGNOSTIC - const char *badnote; -#define BADNOTE(n) badnote = (n) -#else -#define BADNOTE(n) -#endif epp->ep_pax_flags = 0; - if (eh->e_shnum > ELF_MAXSHNUM || eh->e_shnum == 0) + + if (eh->e_phnum > ELF_MAXPHNUM || eh->e_phnum == 0) return ENOEXEC; - shsize = eh->e_shnum * sizeof(Elf_Shdr); - sh = kmem_alloc(shsize, KM_SLEEP); - error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize); + phsize = eh->e_phnum * sizeof(Elf_Phdr); + ph = kmem_alloc(phsize, KM_SLEEP); + error = exec_read_from(l, epp->ep_vp, eh->e_phoff, ph, phsize); if (error) goto out; - np = kmem_alloc(ELF_MAXNOTESIZE, KM_SLEEP); - for (i = 0; i < eh->e_shnum; i++) { - Elf_Shdr *shp = &sh[i]; - - if (shp->sh_type != SHT_NOTE || - shp->sh_size > ELF_MAXNOTESIZE || - shp->sh_size < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ) + nbuf = kmem_alloc(ELF_MAXNOTESIZE, KM_SLEEP); + for (i = 0; i < eh->e_phnum; i++) { + const char *nptr; + size_t nlen; + + if (ph[i].p_type != PT_NOTE || + ph[i].p_filesz > ELF_MAXNOTESIZE) continue; - error = exec_read_from(l, epp->ep_vp, shp->sh_offset, np, - shp->sh_size); + nlen = ph[i].p_filesz; + error = exec_read_from(l, epp->ep_vp, ph[i].p_offset, + nbuf, nlen); if (error) continue; - /* Point to the note, skip the header */ - ndata = (char *)(np + 1); + nptr = nbuf; + while (nlen > 0) { + const Elf_Nhdr *np; + const char *ndata, *ndesc; + + /* note header */ + np = (const Elf_Nhdr *)nptr; + if (nlen < sizeof(*np)) { + break; + } + nptr += sizeof(*np); + nlen -= sizeof(*np); - /* - * Padding is present if necessary to ensure 4-byte alignment. - * The actual section size is therefore: - * header size + 4-byte aligned name + 4-byte aligned desc - * Ensure this size is consistent with what is indicated - * in sh_size. The first check avoids integer overflows. - * - * Binaries from before NetBSD 1.6 have two notes in the same - * note section. The second note was never used, so as long as - * the section is at least as big as it should be, it's ok. - * These binaries also have a second note section with a note of - * type ELF_NOTE_TYPE_NETBSD_TAG, which can be ignored as well. - */ - if (np->n_namesz > shp->sh_size || np->n_descsz > shp->sh_size) { - BADNOTE("note size limit"); - goto bad; - } - nsize = sizeof(*np) + roundup(np->n_namesz, 4) + - roundup(np->n_descsz, 4); - if (nsize > shp->sh_size) { - BADNOTE("note size"); - goto bad; + /* note name */ + ndata = nptr; + if (nlen < roundup(np->n_namesz, 4)) { + break; + } + nptr += roundup(np->n_namesz, 4); + nlen -= roundup(np->n_namesz, 4); + + /* note description */ + ndesc = nptr; + if (nlen < roundup(np->n_descsz, 4)) { + break; + } + nptr += roundup(np->n_descsz, 4); + nlen -= roundup(np->n_descsz, 4); + + isnetbsd = netbsd_elf_note(epp, np, ndata, ndesc) + || isnetbsd; } - ndesc = ndata + roundup(np->n_namesz, 4); + } + kmem_free(nbuf, ELF_MAXNOTESIZE); + + error = isnetbsd ? 0 : ENOEXEC; +out: + kmem_free(ph, phsize); + return error; +} + +int +netbsd_elf_note(struct exec_package *epp, + const Elf_Nhdr *np, const char *ndata, const char *ndesc) +{ + int isnetbsd = 0; - switch (np->n_type) { +#ifdef DIAGNOSTIC + const char *badnote; +#define BADNOTE(n) badnote = (n) +#else +#define BADNOTE(n) +#endif + + switch (np->n_type) { case ELF_NOTE_TYPE_NETBSD_TAG: /* It is us */ if (np->n_namesz == ELF_NOTE_NETBSD_NAMESZ && @@ -1050,21 +1073,16 @@ bad: ELF_NOTE_GNU_NAMESZ) == 0) break; - int ns = MIN(np->n_namesz, shp->sh_size - sizeof(*np)); + int ns = (int)np->n_namesz; printf("%s: Unknown elf note type %d (%s): " "[namesz=%d, descsz=%d name=%-*.*s]\n", epp->ep_kname, np->n_type, badnote, np->n_namesz, np->n_descsz, ns, ns, ndata); #endif break; - } } - kmem_free(np, ELF_MAXNOTESIZE); - error = isnetbsd ? 0 : ENOEXEC; -out: - kmem_free(sh, shsize); - return error; + return isnetbsd; } int