--- exec_elf.c.~1.37.2.2.~ 2014-02-27 02:17:53.000000000 +0400 +++ exec_elf.c 2017-01-21 15:36:25.193986485 +0300 @@ -94,6 +94,7 @@ #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) @@ -104,6 +105,8 @@ const Elf_Phdr *, Elf_Addr *, u_long *, int *, 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 *); @@ -860,39 +863,86 @@ Elf_Ehdr *eh) { size_t i; - Elf_Shdr *sh; - Elf_Nhdr *np; - size_t shsize; + Elf_Phdr *ph; + size_t phsize; + char *nbuf; int error; int isnetbsd = 0; - char *ndata; epp->ep_pax_flags = 0; - if (eh->e_shnum > MAXSHNUM || eh->e_shnum == 0) + + if (eh->e_phnum > 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(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 > MAXNOTESIZE || - shp->sh_size < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ) + nbuf = kmem_alloc(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 > 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; - ndata = (char *)(np + 1); - switch (np->n_type) { + 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); + + /* 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; + } + } + kmem_free(nbuf, 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) { case ELF_NOTE_TYPE_NETBSD_TAG: if (np->n_namesz != ELF_NOTE_NETBSD_NAMESZ || np->n_descsz != ELF_NOTE_NETBSD_DESCSZ || @@ -945,14 +995,9 @@ np->n_type); #endif break; - } } - kmem_free(np, MAXNOTESIZE); - error = isnetbsd ? 0 : ENOEXEC; -out: - kmem_free(sh, shsize); - return error; + return isnetbsd; } int