Source-Changes-HG archive

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

[src/trunk]: src/sys/compat/linux/common A specially-crafted binary could eas...



details:   https://anonhg.NetBSD.org/src/rev/73cab581b750
branches:  trunk
changeset: 795493:73cab581b750
user:      maxv <maxv%NetBSD.org@localhost>
date:      Tue Apr 15 17:29:00 2014 +0000

description:
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 51cdde8a78a7 -r 73cab581b750 sys/compat/linux/common/linux_exec_elf32.c
--- a/sys/compat/linux/common/linux_exec_elf32.c        Tue Apr 15 17:06:21 2014 +0000
+++ b/sys/compat/linux/common/linux_exec_elf32.c        Tue Apr 15 17:29:00 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_exec_elf32.c,v 1.90 2014/02/23 11:09:42 njoly Exp $      */
+/*     $NetBSD: linux_exec_elf32.c,v 1.91 2014/04/15 17:29:00 maxv 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.90 2014/02/23 11:09:42 njoly Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.91 2014/04/15 17:29:00 maxv Exp $");
 
 #ifndef ELFSIZE
 /* XXX should die */
@@ -92,50 +92,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;
                }
@@ -144,8 +137,6 @@
 
 out:
        free(sh, M_TEMP);
-       if (strtable)
-               free(strtable, M_TEMP);
        return (error);
 }
 #endif
@@ -219,56 +210,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;
                }
@@ -277,8 +260,6 @@
 
 out:
        free(sh, M_TEMP);
-       if (strtable)
-               free(strtable, M_TEMP);
        return (error);
 }
 #endif
@@ -340,7 +321,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