Source-Changes-HG archive

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

[src/trunk]: src/sys When loading a module from VFS and from the bootloader, ...



details:   https://anonhg.NetBSD.org/src/rev/fdda6d5ef1c5
branches:  trunk
changeset: 816490:fdda6d5ef1c5
user:      maxv <maxv%NetBSD.org@localhost>
date:      Sat Jul 09 07:25:00 2016 +0000

description:
When loading a module from VFS and from the bootloader, the kernel packs
up the module segments into one big RWX chunk. Split this chunk into two
different text and data+bss+rodata chunks. The latter is made non-
executable. This also provides some kind of ASLR, since the chunks are
not necessarily contiguous.

diffstat:

 sys/kern/subr_kobj.c     |  134 +++++++++++++++++++++++++++++++---------------
 sys/kern/subr_kobj_vfs.c |   20 +++++-
 sys/sys/kobj_impl.h      |    8 +-
 3 files changed, 109 insertions(+), 53 deletions(-)

diffs (288 lines):

diff -r 445e42b6c135 -r fdda6d5ef1c5 sys/kern/subr_kobj.c
--- a/sys/kern/subr_kobj.c      Sat Jul 09 06:58:06 2016 +0000
+++ b/sys/kern/subr_kobj.c      Sat Jul 09 07:25:00 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: subr_kobj.c,v 1.54 2016/07/08 08:55:48 maxv Exp $      */
+/*     $NetBSD: subr_kobj.c,v 1.55 2016/07/09 07:25:00 maxv Exp $      */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -63,7 +63,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_kobj.c,v 1.54 2016/07/08 08:55:48 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_kobj.c,v 1.55 2016/07/09 07:25:00 maxv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_modular.h"
@@ -160,8 +160,10 @@
        Elf_Ehdr *hdr;
        Elf_Shdr *shdr;
        Elf_Sym *es;
-       vaddr_t mapbase;
-       size_t mapsize;
+       vaddr_t map_text_base;
+       vaddr_t map_data_base;
+       size_t map_text_size;
+       size_t map_data_size;
        int error;
        int symtabindex;
        int symstrindex;
@@ -392,40 +394,54 @@
         * Size up code/data(progbits) and bss(nobits).
         */
        alignmask = 0;
-       mapsize = 0;
+       map_text_size = 0;
+       map_data_size = 0;
        for (i = 0; i < hdr->e_shnum; i++) {
-               switch (shdr[i].sh_type) {
-               case SHT_PROGBITS:
-               case SHT_NOBITS:
-                       alignmask = shdr[i].sh_addralign - 1;
-                       mapsize += alignmask;
-                       mapsize &= ~alignmask;
-                       mapsize += shdr[i].sh_size;
-                       break;
+               if (shdr[i].sh_type != SHT_PROGBITS &&
+                   shdr[i].sh_type != SHT_NOBITS)
+                       continue;
+               alignmask = shdr[i].sh_addralign - 1;
+               if ((shdr[i].sh_flags & SHF_EXECINSTR)) {
+                       map_text_size += alignmask;
+                       map_text_size &= ~alignmask;
+                       map_text_size += shdr[i].sh_size;
+               } else {
+                       map_data_size += alignmask;
+                       map_data_size &= ~alignmask;
+                       map_data_size += shdr[i].sh_size;
                }
        }
 
-       /*
-        * We know how much space we need for the text/data/bss/etc.
-        * This stuff needs to be in a single chunk so that profiling etc
-        * can get the bounds and gdb can associate offsets with modules.
-        */
-       if (mapsize == 0) {
-               kobj_error(ko, "no text/data/bss");
+       if (map_text_size == 0) {
+               kobj_error(ko, "no text");
+               error = ENOEXEC;
+               goto out;
+       }
+       if (map_data_size == 0) {
+               kobj_error(ko, "no data/bss");
                error = ENOEXEC;
                goto out;
        }
 
-       mapbase = uvm_km_alloc(module_map, round_page(mapsize),
+       map_text_base = uvm_km_alloc(module_map, round_page(map_text_size),
            0, UVM_KMF_WIRED | UVM_KMF_EXEC);
-       if (mapbase == 0) {
+       if (map_text_base == 0) {
                kobj_error(ko, "out of memory");
                error = ENOMEM;
                goto out;
        }
+       ko->ko_text_address = map_text_base;
+       ko->ko_text_size = map_text_size;
 
-       ko->ko_address = mapbase;
-       ko->ko_size = mapsize;
+       map_data_base = uvm_km_alloc(module_map, round_page(map_data_size),
+           0, UVM_KMF_WIRED);
+       if (map_data_base == 0) {
+               kobj_error(ko, "out of memory");
+               error = ENOMEM;
+               goto out;
+       }
+       ko->ko_data_address = map_data_base;
+       ko->ko_data_size = map_data_size;
 
        /*
         * Now load code/data(progbits), zero bss(nobits), allocate space
@@ -440,10 +456,17 @@
                case SHT_PROGBITS:
                case SHT_NOBITS:
                        alignmask = shdr[i].sh_addralign - 1;
-                       mapbase += alignmask;
-                       mapbase &= ~alignmask;
-                       addr = (void *)mapbase;
-                       mapbase += shdr[i].sh_size;
+                       if ((shdr[i].sh_flags & SHF_EXECINSTR)) {
+                               map_text_base += alignmask;
+                               map_text_base &= ~alignmask;
+                               addr = (void *)map_text_base;
+                               map_text_base += shdr[i].sh_size;
+                       } else {
+                               map_data_base += alignmask;
+                               map_data_base &= ~alignmask;
+                               addr = (void *)map_data_base;
+                               map_data_base += shdr[i].sh_size;
+                       }
 
                        ko->ko_progtab[pb].addr = addr;
                        if (shdr[i].sh_type == SHT_PROGBITS) {
@@ -535,12 +558,19 @@
                panic("%s:%d: %s: lost rela", __func__, __LINE__,
                   ko->ko_name);
        }
-       if (mapbase != ko->ko_address + mapsize) {
-               panic("%s:%d: %s: "
-                   "mapbase 0x%lx != address %lx + mapsize %ld (0x%lx)\n",
-                   __func__, __LINE__, ko->ko_name,
-                   (long)mapbase, (long)ko->ko_address, (long)mapsize,
-                   (long)ko->ko_address + mapsize);
+       if (map_text_base != ko->ko_text_address + map_text_size) {
+               panic("%s:%d: %s: map_text_base 0x%lx != address %lx "
+                   "+ map_text_size %ld (0x%lx)\n",
+                   __func__, __LINE__, ko->ko_name, (long)map_text_base,
+                   (long)ko->ko_text_address, (long)map_text_size,
+                   (long)ko->ko_text_address + map_text_size);
+       }
+       if (map_data_base != ko->ko_data_address + map_data_size) {
+               panic("%s:%d: %s: map_data_base 0x%lx != address %lx "
+                   "+ map_data_size %ld (0x%lx)\n",
+                   __func__, __LINE__, ko->ko_name, (long)map_data_base,
+                   (long)ko->ko_data_address, (long)map_data_size,
+                   (long)ko->ko_data_address + map_data_size);
        }
 
        /*
@@ -580,16 +610,25 @@
         * Notify MD code that a module has been unloaded.
         */
        if (ko->ko_loaded) {
-               error = kobj_machdep(ko, (void *)ko->ko_address, ko->ko_size,
-                   false);
+               error = kobj_machdep(ko, (void *)ko->ko_text_address,
+                   ko->ko_text_size, false);
                if (error != 0)
-                       kobj_error(ko, "machine dependent deinit failed %d",
+                       kobj_error(ko, "machine dependent deinit failed (text) %d",
                            error);
+               error = kobj_machdep(ko, (void *)ko->ko_data_address,
+                   ko->ko_data_size, false);
+               if (error != 0)
+                       kobj_error(ko, "machine dependent deinit failed (data) %d",
+                           error);
        }
-       if (ko->ko_address != 0) {
-               uvm_km_free(module_map, ko->ko_address, round_page(ko->ko_size),
-                   UVM_KMF_WIRED);
+       if (ko->ko_text_address != 0) {
+               uvm_km_free(module_map, ko->ko_text_address,
+                   round_page(ko->ko_text_size), UVM_KMF_WIRED);
        }
+       if (ko->ko_data_address != 0) {
+               uvm_km_free(module_map, ko->ko_data_address,
+                   round_page(ko->ko_data_size), UVM_KMF_WIRED);
+       }
        if (ko->ko_ksyms == true) {
                ksyms_modunload(ko->ko_name);
        }
@@ -622,10 +661,10 @@
 {
 
        if (address != NULL) {
-               *address = ko->ko_address;
+               *address = ko->ko_text_address;
        }
        if (size != NULL) {
-               *size = ko->ko_size;
+               *size = ko->ko_text_size;
        }
        return 0;
 }
@@ -673,10 +712,15 @@
         * Most architectures use this opportunity to flush their caches.
         */
        if (error == 0) {
-               error = kobj_machdep(ko, (void *)ko->ko_address, ko->ko_size,
-                   true);
+               error = kobj_machdep(ko, (void *)ko->ko_text_address,
+                   ko->ko_text_size, true);
                if (error != 0)
-                       kobj_error(ko, "machine dependent init failed %d",
+                       kobj_error(ko, "machine dependent init failed (text) %d",
+                           error);
+               error = kobj_machdep(ko, (void *)ko->ko_data_address,
+                   ko->ko_data_size, true);
+               if (error != 0)
+                       kobj_error(ko, "machine dependent init failed (data) %d",
                            error);
                ko->ko_loaded = true;
        }
diff -r 445e42b6c135 -r fdda6d5ef1c5 sys/kern/subr_kobj_vfs.c
--- a/sys/kern/subr_kobj_vfs.c  Sat Jul 09 06:58:06 2016 +0000
+++ b/sys/kern/subr_kobj_vfs.c  Sat Jul 09 07:25:00 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: subr_kobj_vfs.c,v 1.8 2015/08/24 22:50:32 pooka Exp $  */
+/*     $NetBSD: subr_kobj_vfs.c,v 1.9 2016/07/09 07:25:00 maxv Exp $   */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -75,7 +75,7 @@
 #include <sys/vnode.h>
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_kobj_vfs.c,v 1.8 2015/08/24 22:50:32 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_kobj_vfs.c,v 1.9 2016/07/09 07:25:00 maxv Exp $");
 
 static void
 kobj_close_vfs(kobj_t ko)
@@ -104,9 +104,19 @@
                base = kmem_alloc(size, KM_SLEEP);
        } else {
                base = *basep;
-               KASSERT((uintptr_t)base >= (uintptr_t)ko->ko_address);
-               KASSERT((uintptr_t)base + size <=
-                   (uintptr_t)ko->ko_address + ko->ko_size);
+#ifdef DIAGNOSTIC
+               bool ok = false;
+               if ((uintptr_t)base >= (uintptr_t)ko->ko_text_address &&
+                   (uintptr_t)base + size <=
+                   (uintptr_t)ko->ko_text_address + ko->ko_text_size)
+                       ok = true;
+               if ((uintptr_t)base >= (uintptr_t)ko->ko_data_address &&
+                   (uintptr_t)base + size <=
+                   (uintptr_t)ko->ko_data_address + ko->ko_data_size)
+                       ok = true;
+               if (!ok)
+                       panic("kobj_read_vfs: not in a dedicated segment");
+#endif
        }
 
        error = vn_rdwr(UIO_READ, ko->ko_source, base, size, off,
diff -r 445e42b6c135 -r fdda6d5ef1c5 sys/sys/kobj_impl.h
--- a/sys/sys/kobj_impl.h       Sat Jul 09 06:58:06 2016 +0000
+++ b/sys/sys/kobj_impl.h       Sat Jul 09 07:25:00 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kobj_impl.h,v 1.3 2011/08/13 21:04:07 christos Exp $   */
+/*     $NetBSD: kobj_impl.h,v 1.4 2016/07/09 07:25:00 maxv Exp $       */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -107,7 +107,8 @@
        kobjtype_t      ko_type;
        void            *ko_source;
        ssize_t         ko_memsize;
-       vaddr_t         ko_address;     /* Relocation address */
+       vaddr_t         ko_text_address;        /* Address of text segment */
+       vaddr_t         ko_data_address;        /* Address of data segment */
        Elf_Shdr        *ko_shdr;
        progent_t       *ko_progtab;
        relaent_t       *ko_relatab;
@@ -115,7 +116,8 @@
        Elf_Sym         *ko_symtab;     /* Symbol table */
        char            *ko_strtab;     /* String table */
        char            *ko_shstrtab;   /* Section name string table */
-       size_t          ko_size;        /* Size of text/data/bss */
+       size_t          ko_text_size;   /* Size of text segment */
+       size_t          ko_data_size;   /* Size of data/bss/rodata segment */
        size_t          ko_symcnt;      /* Number of symbols */
        size_t          ko_strtabsz;    /* Number of bytes in string table */
        size_t          ko_shstrtabsz;  /* Number of bytes in scn str table */



Home | Main Index | Thread Index | Old Index