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/88ef1b8e00ec
branches: trunk
changeset: 346348:88ef1b8e00ec
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 cdbddb26d76c -r 88ef1b8e00ec 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 cdbddb26d76c -r 88ef1b8e00ec 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 cdbddb26d76c -r 88ef1b8e00ec 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