Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern - Make maximum memory limits for various things #de...



details:   https://anonhg.NetBSD.org/src/rev/58bceebd67be
branches:  trunk
changeset: 753191:58bceebd67be
user:      christos <christos%NetBSD.org@localhost>
date:      Fri Mar 19 22:08:13 2010 +0000

description:
- 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.

diffstat:

 sys/kern/exec_elf.c |  124 +++++++++++++++++++++++++++++++--------------------
 1 files changed, 74 insertions(+), 50 deletions(-)

diffs (211 lines):

diff -r 8ce9e09051bc -r 58bceebd67be sys/kern/exec_elf.c
--- a/sys/kern/exec_elf.c       Fri Mar 19 20:53:50 2010 +0000
+++ b/sys/kern/exec_elf.c       Fri Mar 19 22:08:13 2010 +0000
@@ -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;
+       np = kmem_alloc(MAXNOTESIZE, KM_SLEEP);
+       for (i = 0; i < eh->e_shnum; i++) {
+               Elf_Shdr *shp = &sh[i];
 
-               if (ephp->p_type != PT_NOTE ||
-                   ephp->p_filesz > 1024 ||
-                   ephp->p_filesz < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ)
+               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;
 }
 



Home | Main Index | Thread Index | Old Index