Module Name: src Committed By: christos Date: Fri Mar 19 22:08:13 UTC 2010
Modified Files: src/sys/kern: exec_elf.c Log Message: - Make maximum memory limits for various things #define constants and use the consistently across the code. - Re-do note parsing code to read the section headers instead of the program headers because the new binutils merge all the note sections in one program header. This fixes all the pax note parsing which has been broken for all binaries built with the new binutils. - Add diagnostics to the note parsing code to detect malformed binaries. - Allocate and free note scratch space only once, not once per note. To generate a diff of this commit: cvs rdiff -u -r1.14 -r1.15 src/sys/kern/exec_elf.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/exec_elf.c diff -u src/sys/kern/exec_elf.c:1.14 src/sys/kern/exec_elf.c:1.15 --- src/sys/kern/exec_elf.c:1.14 Mon Mar 15 16:35:20 2010 +++ src/sys/kern/exec_elf.c Fri Mar 19 18:08:13 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: exec_elf.c,v 1.14 2010/03/15 20:35:20 christos Exp $ */ +/* $NetBSD: exec_elf.c,v 1.15 2010/03/19 22:08:13 christos Exp $ */ /*- * Copyright (c) 1994, 2000, 2005 The NetBSD Foundation, Inc. @@ -57,7 +57,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.14 2010/03/15 20:35:20 christos Exp $"); +__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.15 2010/03/19 22:08:13 christos Exp $"); #ifdef _KERNEL_OPT #include "opt_pax.h" @@ -109,7 +109,12 @@ #define ELF_ROUND(a, b) (((a) + (b) - 1) & ~((b) - 1)) #define ELF_TRUNC(a, b) ((a) & ~((b) - 1)) -#define MAXPHNUM 50 +/* + * Arbitrary limits to avoid DoS for excessive memory allocation. + */ +#define MAXPHNUM 128 +#define MAXSHNUM 32768 +#define MAXNOTESIZE 1024 #ifdef PAX_ASLR /* @@ -119,33 +124,35 @@ pax_aslr_elf(struct lwp *l, struct exec_package *epp, Elf_Ehdr *eh, Elf_Phdr *ph) { - size_t pax_align = 0, pax_offset, i; - uint32_t r; + size_t pax_offset, i; - if (!pax_aslr_active(l)) - return; + if (pax_aslr_active(l)) { + size_t pax_align, l2, delta; + uint32_t r; - /* - * find align XXX: not all sections might have the same - * alignment - */ - for (i = 0; i < eh->e_phnum; i++) - if (ph[i].p_type == PT_LOAD) { - pax_align = ph[i].p_align; - break; - } + /* + * find align XXX: not all sections might have the same + * alignment + */ + for (pax_align = i = 0; i < eh->e_phnum; i++) + if (ph[i].p_type == PT_LOAD) { + pax_align = ph[i].p_align; + break; + } - r = arc4random(); + r = arc4random(); - if (pax_align == 0) - pax_align = PGSHIFT; + if (pax_align == 0) + pax_align = PGSHIFT; + l2 = ilog2(pax_align); + delta = PAX_ASLR_DELTA(r, l2, PAX_ASLR_DELTA_EXEC_LEN); #ifdef PAX_ASLR_DEBUG - uprintf("r=0x%x a=0x%x p=0x%x Delta=0x%lx\n", r, - ilog2(pax_align), PGSHIFT, PAX_ASLR_DELTA(r, - ilog2(pax_align), PAX_ASLR_DELTA_EXEC_LEN)); + uprintf("r=0x%x a=0x%x p=0x%x Delta=0x%lx\n", r, l2, PGSHIFT, + delta); #endif - pax_offset = ELF_TRUNC(PAX_ASLR_DELTA(r, - ilog2(pax_align), PAX_ASLR_DELTA_EXEC_LEN), pax_align) + PAGE_SIZE; + pax_offset = ELF_TRUNC(delta, pax_align) + PAGE_SIZE; + } else + pax_offset = PAGE_SIZE; for (i = 0; i < eh->e_phnum; i++) ph[i].p_vaddr += pax_offset; @@ -303,7 +310,7 @@ if (eh->e_type != type) return ENOEXEC; - if (eh->e_shnum > 32768 || eh->e_phnum > 128) + if (eh->e_shnum > MAXSHNUM || eh->e_phnum > MAXPHNUM) return ENOEXEC; return 0; @@ -845,36 +852,36 @@ Elf_Ehdr *eh) { size_t i; - Elf_Phdr *ph; - size_t phsize; + Elf_Shdr *sh; + Elf_Nhdr *np; + size_t shsize; int error; int isnetbsd = 0; char *ndata; epp->ep_pax_flags = 0; - if (eh->e_phnum > MAXPHNUM || eh->e_phnum == 0) + if (eh->e_shnum > MAXSHNUM || eh->e_shnum == 0) return ENOEXEC; - 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); + 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); if (error) goto out; - for (i = 0; i < eh->e_phnum; i++) { - Elf_Phdr *ephp = &ph[i]; - Elf_Nhdr *np; - - if (ephp->p_type != PT_NOTE || - ephp->p_filesz > 1024 || - ephp->p_filesz < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ) + 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) continue; - np = kmem_alloc(ephp->p_filesz, KM_SLEEP); - error = exec_read_from(l, epp->ep_vp, ephp->p_offset, np, - ephp->p_filesz); + error = exec_read_from(l, epp->ep_vp, shp->sh_offset, np, + shp->sh_size); if (error) - goto next; + continue; ndata = (char *)(np + 1); switch (np->n_type) { @@ -883,7 +890,7 @@ np->n_descsz != ELF_NOTE_NETBSD_DESCSZ || memcmp(ndata, ELF_NOTE_NETBSD_NAME, ELF_NOTE_NETBSD_NAMESZ)) - goto next; + goto bad; isnetbsd = 1; break; @@ -891,25 +898,42 @@ if (np->n_namesz != ELF_NOTE_PAX_NAMESZ || np->n_descsz != ELF_NOTE_PAX_DESCSZ || memcmp(ndata, ELF_NOTE_PAX_NAME, - ELF_NOTE_PAX_NAMESZ)) - goto next; + ELF_NOTE_PAX_NAMESZ)) { +bad: +#ifdef DIAGNOSTIC + printf("%s: bad tag %d: " + "[%d %d, %d %d, %*.*s %*.*s]\n", + epp->ep_name, + np->n_type + np->n_namesz, ELF_NOTE_PAX_NAMESZ, + np->n_descsz, ELF_NOTE_PAX_DESCSZ, + ELF_NOTE_PAX_NAMESZ, + ELF_NOTE_PAX_NAMESZ, + ndata, + ELF_NOTE_PAX_NAMESZ, + ELF_NOTE_PAX_NAMESZ, + ELF_NOTE_PAX_NAME); +#endif + continue; + } (void)memcpy(&epp->ep_pax_flags, ndata + ELF_NOTE_PAX_NAMESZ, sizeof(epp->ep_pax_flags)); break; default: +#ifdef DIAGNOSTIC + printf("%s: unknown note type %d\n", epp->ep_name, + np->n_type); +#endif break; } - -next: - kmem_free(np, ephp->p_filesz); - continue; } + kmem_free(np, MAXNOTESIZE); error = isnetbsd ? 0 : ENOEXEC; out: - kmem_free(ph, phsize); + kmem_free(sh, shsize); return error; }