Source-Changes-HG archive

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

[src/netbsd-6]: src/sys/compat/linux/common Pull up following revision(s) (re...



details:   https://anonhg.NetBSD.org/src/rev/61e25d512f99
branches:  netbsd-6
changeset: 776612:61e25d512f99
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Mon Apr 21 21:03:38 2014 +0000

description:
Pull up following revision(s) (requested by maxv in ticket #1051):
        sys/compat/linux/common/linux_exec_elf32.c: revision 1.91 via patch
A specially-crafted binary could easily control a kernel array index.
Add some checks to ensure that nothing will be read outside the allocated
area. Rewrite the code so that we don't need to allocate the whole section.
Spotted by several developers, patch from chs@/enami@

diffstat:

 sys/compat/linux/common/linux_exec_elf32.c |  105 +++++++++++-----------------
 1 files changed, 43 insertions(+), 62 deletions(-)

diffs (193 lines):

diff -r 740772e915ea -r 61e25d512f99 sys/compat/linux/common/linux_exec_elf32.c
--- a/sys/compat/linux/common/linux_exec_elf32.c        Mon Apr 21 10:18:34 2014 +0000
+++ b/sys/compat/linux/common/linux_exec_elf32.c        Mon Apr 21 21:03:38 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_exec_elf32.c,v 1.86 2012/02/12 16:34:10 matt Exp $       */
+/*     $NetBSD: linux_exec_elf32.c,v 1.86.2.1 2014/04/21 21:03:38 bouyer Exp $ */
 
 /*-
  * Copyright (c) 1995, 1998, 2000, 2001 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.86 2012/02/12 16:34:10 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.86.2.1 2014/04/21 21:03:38 bouyer Exp $");
 
 #ifndef ELFSIZE
 /* XXX should die */
@@ -91,50 +91,43 @@
        struct exec_package *epp,
        Elf_Ehdr *eh)
 {
+       Elf_Shdr *sh;
        size_t shsize;
-       int strndx;
+       u_int shstrndx;
        size_t i;
        static const char signature[] = "__libc_atexit";
-       char *strtable = NULL;
-       Elf_Shdr *sh;
-
+       const size_t sigsz = sizeof(signature);
+       char tbuf[sizeof(signature)];
        int error;
 
-       /*
-        * load the section header table
-        */
+       /* Load the section header table. */
        shsize = eh->e_shnum * sizeof(Elf_Shdr);
        sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
        error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize);
        if (error)
                goto out;
 
-       /*
-        * Now let's find the string table. If it does not exists, give up.
-        */
-       strndx = (int)(eh->e_shstrndx);
-       if (strndx == SHN_UNDEF) {
+       /* Now let's find the string table. If it does not exist, give up. */
+       shstrndx = eh->e_shstrndx;
+       if (shstrndx == SHN_UNDEF || shstrndx >= eh->e_shnum) {
                error = ENOEXEC;
                goto out;
        }
 
-       /*
-        * strndx is the index in section header table of the string table
-        * section get the whole string table in strtable, and then we get access to the names
-        * s->sh_name is the offset of the section name in strtable.
-        */
-       strtable = malloc(sh[strndx].sh_size, M_TEMP, M_WAITOK);
-       error = exec_read_from(l, epp->ep_vp, sh[strndx].sh_offset, strtable,
-           sh[strndx].sh_size);
-       if (error)
-               goto out;
-
+       /* Check if any section has the name we're looking for. */
+       const off_t stroff = sh[shstrndx].sh_offset;
        for (i = 0; i < eh->e_shnum; i++) {
                Elf_Shdr *s = &sh[i];
-               if (!memcmp((void*)(&(strtable[s->sh_name])), signature,
-                               sizeof(signature))) {
-                       DPRINTF(("linux_atexit_sig=%s\n",
-                           &(strtable[s->sh_name])));
+
+               if (s->sh_name + sigsz > sh[shstrndx].sh_size)
+                       continue;
+
+               error = exec_read_from(l, epp->ep_vp, stroff + s->sh_name, tbuf,
+                   sigsz);
+               if (error)
+                       goto out;
+               if (!memcmp(tbuf, signature, sigsz)) {
+                       DPRINTF(("linux_atexit_sig=%s\n", tbuf));
                        error = 0;
                        goto out;
                }
@@ -143,8 +136,6 @@
 
 out:
        free(sh, M_TEMP);
-       if (strtable)
-               free(strtable, M_TEMP);
        return (error);
 }
 #endif
@@ -218,56 +209,48 @@
 
 #ifdef LINUX_DEBUGLINK_SIGNATURE
 /*
- * Look for a .gnu_debuglink, specific to x86_64 interpeter
+ * Look for a .gnu_debuglink, specific to x86_64 interpreter
  */
 int
 ELFNAME2(linux,debuglink_signature)(struct lwp *l, struct exec_package *epp, Elf_Ehdr *eh)
 {
+       Elf_Shdr *sh;
        size_t shsize;
-       int strndx;
+       u_int shstrndx;
        size_t i;
        static const char signature[] = ".gnu_debuglink";
-       char *strtable = NULL;
-       Elf_Shdr *sh;
-
+       const size_t sigsz = sizeof(signature);
+       char tbuf[sizeof(signature)];
        int error;
 
-       /*
-        * load the section header table
-        */
+       /* Load the section header table. */
        shsize = eh->e_shnum * sizeof(Elf_Shdr);
        sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
        error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize);
        if (error)
                goto out;
 
-       /*
-        * Now let's find the string table. If it does not exists, give up.
-        */
-       strndx = (int)(eh->e_shstrndx);
-       if (strndx == SHN_UNDEF) {
+       /* Now let's find the string table. If it does not exist, give up. */
+       shstrndx = eh->e_shstrndx;
+       if (shstrndx == SHN_UNDEF || shstrndx >= eh->e_shnum) {
                error = ENOEXEC;
                goto out;
        }
 
-       /*
-        * strndx is the index in section header table of the string table
-        * section get the whole string table in strtable, and then we get access to the names
-        * s->sh_name is the offset of the section name in strtable.
-        */
-       strtable = malloc(sh[strndx].sh_size, M_TEMP, M_WAITOK);
-       error = exec_read_from(l, epp->ep_vp, sh[strndx].sh_offset, strtable,
-           sh[strndx].sh_size);
-       if (error)
-               goto out;
-
+       /* Check if any section has the name we're looking for. */
+       const off_t stroff = sh[shstrndx].sh_offset;
        for (i = 0; i < eh->e_shnum; i++) {
                Elf_Shdr *s = &sh[i];
 
-               if (!memcmp((void*)(&(strtable[s->sh_name])), signature,
-                               sizeof(signature))) {
-                       DPRINTF(("linux_debuglink_sig=%s\n",
-                           &(strtable[s->sh_name])));
+               if (s->sh_name + sigsz > sh[shstrndx].sh_size)
+                       continue;
+
+               error = exec_read_from(l, epp->ep_vp, stroff + s->sh_name, tbuf,
+                   sigsz);
+               if (error)
+                       goto out;
+               if (!memcmp(tbuf, signature, sigsz)) {
+                       DPRINTF(("linux_debuglink_sig=%s\n", tbuf));
                        error = 0;
                        goto out;
                }
@@ -276,8 +259,6 @@
 
 out:
        free(sh, M_TEMP);
-       if (strtable)
-               free(strtable, M_TEMP);
        return (error);
 }
 #endif
@@ -339,7 +320,7 @@
                continue;
        }
 
-       /* Check for certain intepreter names. */
+       /* Check for certain interpreter names. */
        if (itp) {
                if (!strncmp(itp, "/lib/ld-linux", 13) ||
 #if (ELFSIZE == 64)



Home | Main Index | Thread Index | Old Index