Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Add a new option in libsa, to load dynamic binaries. A s...
details: https://anonhg.NetBSD.org/src/rev/24ad200865a8
branches: trunk
changeset: 356639:24ad200865a8
user: maxv <maxv%NetBSD.org@localhost>
date: Sat Oct 07 10:26:38 2017 +0000
description:
Add a new option in libsa, to load dynamic binaries. A separate function
is used, and it does not break in any way the generic static loader. Then,
add a new "pkboot" command in the x86 bootloader, which boots a
GENERIC_KASLR kernel via the prekern. (See thread on tech-kern@.)
diffstat:
sys/arch/i386/stand/boot/boot2.c | 12 ++-
sys/arch/i386/stand/lib/exec.c | 72 ++++++++++++-
sys/arch/x86/include/bootinfo.h | 9 +-
sys/lib/libsa/loadfile.h | 3 +-
sys/lib/libsa/loadfile_elf32.c | 208 ++++++++++++++++++++++++++++++++++++++-
5 files changed, 295 insertions(+), 9 deletions(-)
diffs (truncated from 414 to 300 lines):
diff -r d4b10bbaa624 -r 24ad200865a8 sys/arch/i386/stand/boot/boot2.c
--- a/sys/arch/i386/stand/boot/boot2.c Sat Oct 07 10:16:47 2017 +0000
+++ b/sys/arch/i386/stand/boot/boot2.c Sat Oct 07 10:26:38 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: boot2.c,v 1.66 2016/02/03 05:27:53 christos Exp $ */
+/* $NetBSD: boot2.c,v 1.67 2017/10/07 10:26:38 maxv Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -121,6 +121,7 @@
#endif
void command_quit(char *);
void command_boot(char *);
+void command_pkboot(char *);
void command_dev(char *);
void command_consdev(char *);
#ifndef SMALL
@@ -137,6 +138,7 @@
#endif
{ "quit", command_quit },
{ "boot", command_boot },
+ { "pkboot", command_pkboot },
{ "dev", command_dev },
{ "consdev", command_consdev },
#ifndef SMALL
@@ -470,6 +472,14 @@
}
void
+command_pkboot(char *arg)
+{
+ extern int has_prekern;
+ has_prekern = 1;
+ command_boot(arg);
+}
+
+void
command_dev(char *arg)
{
static char savedevname[MAXDEVNAME + 1];
diff -r d4b10bbaa624 -r 24ad200865a8 sys/arch/i386/stand/lib/exec.c
--- a/sys/arch/i386/stand/lib/exec.c Sat Oct 07 10:16:47 2017 +0000
+++ b/sys/arch/i386/stand/lib/exec.c Sat Oct 07 10:26:38 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: exec.c,v 1.68 2017/03/24 08:50:17 nonaka Exp $ */
+/* $NetBSD: exec.c,v 1.69 2017/10/07 10:26:38 maxv Exp $ */
/*
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -266,6 +266,67 @@
}
}
+struct btinfo_prekern bi_prekern;
+int has_prekern = 0;
+
+static int
+common_load_prekern(const char *file, u_long *basemem, u_long *extmem,
+ physaddr_t loadaddr, int floppy, u_long marks[MARK_MAX])
+{
+ paddr_t kernpa_start, kernpa_end;
+ char prekernpath[] = "/prekern";
+ int fd, flags;
+
+ *extmem = getextmem();
+ *basemem = getbasemem();
+
+ marks[MARK_START] = loadaddr;
+
+ /* Load the prekern (static) */
+ flags = LOAD_KERNEL & ~(LOAD_HDR|COUNT_HDR|LOAD_SYM|COUNT_SYM);
+ if ((fd = loadfile(prekernpath, marks, flags)) == -1)
+ return EIO;
+ close(fd);
+
+ marks[MARK_END] = (1UL << 21); /* the kernel starts at 2MB XXX */
+ kernpa_start = marks[MARK_END];
+
+ /* Load the kernel (dynamic) */
+ flags = (LOAD_KERNEL | LOAD_DYN) & ~(floppy ? LOAD_BACKWARDS : 0);
+ if ((fd = loadfile(file, marks, flags)) == -1)
+ return EIO;
+ close(fd);
+
+ kernpa_end = marks[MARK_END];
+
+ /* If the root fs type is unusual, load its module. */
+ if (fsmod != NULL)
+ module_add_common(fsmod, BM_TYPE_KMOD);
+
+ bi_prekern.kernpa_start = kernpa_start;
+ bi_prekern.kernpa_end = kernpa_end;
+ BI_ADD(&bi_prekern, BTINFO_PREKERN, sizeof(struct btinfo_prekern));
+
+ /*
+ * Gather some information for the kernel. Do this after the
+ * "point of no return" to avoid memory leaks.
+ * (but before DOS might be trashed in the XMS case)
+ */
+#ifdef PASS_BIOSGEOM
+ bi_getbiosgeom();
+#endif
+#ifdef PASS_MEMMAP
+ bi_getmemmap();
+#endif
+
+ marks[MARK_END] = (((u_long)marks[MARK_END] + sizeof(int) - 1)) &
+ (-sizeof(int));
+ image_end = marks[MARK_END];
+ kernel_loaded = true;
+
+ return 0;
+}
+
static int
common_load_kernel(const char *file, u_long *basemem, u_long *extmem,
physaddr_t loadaddr, int floppy, u_long marks[MARK_MAX])
@@ -380,8 +441,13 @@
memset(marks, 0, sizeof(marks));
- error = common_load_kernel(file, &basemem, &extmem, loadaddr, floppy,
- marks);
+ if (has_prekern) {
+ error = common_load_prekern(file, &basemem, &extmem, loadaddr,
+ floppy, marks);
+ } else {
+ error = common_load_kernel(file, &basemem, &extmem, loadaddr,
+ floppy, marks);
+ }
if (error) {
errno = error;
goto out;
diff -r d4b10bbaa624 -r 24ad200865a8 sys/arch/x86/include/bootinfo.h
--- a/sys/arch/x86/include/bootinfo.h Sat Oct 07 10:16:47 2017 +0000
+++ b/sys/arch/x86/include/bootinfo.h Sat Oct 07 10:26:38 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bootinfo.h,v 1.26 2017/02/14 13:25:22 nonaka Exp $ */
+/* $NetBSD: bootinfo.h,v 1.27 2017/10/07 10:26:38 maxv Exp $ */
/*
* Copyright (c) 1997
@@ -40,6 +40,7 @@
#define BTINFO_USERCONFCOMMANDS 13
#define BTINFO_EFI 14
#define BTINFO_EFIMEMMAP 15
+#define BTINFO_PREKERN 16
#define BTINFO_STR "bootpath", "rootdevice", "bootdisk", "netif", \
"console", "biosgeom", "symtab", "memmap", "bootwedge", "modulelist", \
@@ -232,6 +233,12 @@
uint8_t reserved[12];
};
+struct btinfo_prekern {
+ struct btinfo_common common;
+ uint32_t kernpa_start;
+ uint32_t kernpa_end;
+};
+
struct btinfo_efimemmap {
struct btinfo_common common;
uint32_t num; /* number of memory descriptor */
diff -r d4b10bbaa624 -r 24ad200865a8 sys/lib/libsa/loadfile.h
--- a/sys/lib/libsa/loadfile.h Sat Oct 07 10:16:47 2017 +0000
+++ b/sys/lib/libsa/loadfile.h Sat Oct 07 10:26:38 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: loadfile.h,v 1.13 2016/12/03 09:20:55 maxv Exp $ */
+/* $NetBSD: loadfile.h,v 1.14 2017/10/07 10:26:39 maxv Exp $ */
/*-
* Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -53,6 +53,7 @@
#define LOAD_ALL 0x007f
#define LOAD_MINIMAL 0x002f
#define LOAD_BACKWARDS 0x0050
+#define LOAD_DYN 0x4000
#define COUNT_TEXT 0x0100
#define COUNT_TEXTA 0x0200
diff -r d4b10bbaa624 -r 24ad200865a8 sys/lib/libsa/loadfile_elf32.c
--- a/sys/lib/libsa/loadfile_elf32.c Sat Oct 07 10:16:47 2017 +0000
+++ b/sys/lib/libsa/loadfile_elf32.c Sat Oct 07 10:26:38 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: loadfile_elf32.c,v 1.43 2017/10/05 02:59:21 christos Exp $ */
+/* $NetBSD: loadfile_elf32.c,v 1.44 2017/10/07 10:26:39 maxv Exp $ */
/*
* Copyright (c) 1997, 2008, 2017 The NetBSD Foundation, Inc.
@@ -265,6 +265,196 @@
/* -------------------------------------------------------------------------- */
+#define KERNALIGN 4096
+
+/*
+ * Load a dynamic ELF binary into memory. Layout of the memory:
+ * +------------+-----------------+-----------------+-----------------+
+ * | ELF HEADER | SECTION HEADERS | KERNEL SECTIONS | SYMBOL SECTIONS |
+ * +------------+-----------------+-----------------+-----------------+
+ * The ELF HEADER start address is marks[MARK_END]. We then map the rest
+ * by increasing maxp. An alignment is enforced between the code sections.
+ *
+ * The offsets of the SYMBOL SECTIONS are relative to the start address of the
+ * ELF HEADER. We just give the kernel a pointer to the ELF HEADER, and we let
+ * the kernel find the location and number of symbols by itself.
+ */
+static int
+ELFNAMEEND(loadfile_dynamic)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
+{
+ Elf_Shdr *shdr;
+ Elf_Addr shpp, addr;
+ int i, j, loaded;
+ size_t size;
+ ssize_t sz, nr;
+ Elf_Addr maxp, elfp = 0;
+ u_long offset = 0;
+
+ /* some ports dont use the offset */
+ (void)&offset;
+
+ maxp = marks[MARK_END];
+
+ internalize_ehdr(elf->e_ident[EI_DATA], elf);
+
+ /* Create a local copy of the SECTION HEADERS. */
+ sz = elf->e_shnum * sizeof(Elf_Shdr);
+ shdr = ALLOC(sz);
+ if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) {
+ WARN(("lseek section headers"));
+ goto out;
+ }
+ nr = read(fd, shdr, sz);
+ if (nr == -1) {
+ WARN(("read section headers"));
+ goto out;
+ }
+ if (nr != sz) {
+ errno = EIO;
+ WARN(("read section headers"));
+ goto out;
+ }
+
+ /*
+ * Load the ELF HEADER. Update the section offset, to be relative to
+ * elfp.
+ */
+ elf->e_phoff = 0;
+ elf->e_shoff = sizeof(Elf_Ehdr);
+ elf->e_phentsize = 0;
+ elf->e_phnum = 0;
+ elfp = maxp;
+ externalize_ehdr(elf->e_ident[EI_DATA], elf);
+ BCOPY(elf, elfp, sizeof(*elf));
+ internalize_ehdr(elf->e_ident[EI_DATA], elf);
+ maxp += sizeof(Elf_Ehdr);
+
+#ifndef _STANDALONE
+ for (i = 0; i < elf->e_shnum; i++)
+ internalize_shdr(elf->e_ident[EI_DATA], &shdr[i]);
+#endif
+
+ /* Save location of the SECTION HEADERS. */
+ shpp = maxp;
+ maxp += roundup(sz, ELFROUND);
+
+ /*
+ * Load the KERNEL SECTIONS.
+ */
+ maxp = roundup(maxp, KERNALIGN);
+ for (i = 0; i < elf->e_shnum; i++) {
+ addr = maxp;
+ size = (size_t)shdr[i].sh_size;
+
+ loaded = 0;
+ switch (shdr[i].sh_type) {
+ case SHT_NOBITS:
+ /* Zero out bss. */
+ BZERO(addr, size);
+ loaded = 1;
+ break;
+ case SHT_PROGBITS:
+ if (lseek(fd, shdr[i].sh_offset, SEEK_SET) == -1) {
+ WARN(("lseek section"));
+ goto out;
+ }
+ nr = READ(fd, addr, size);
+ if (nr == -1) {
+ WARN(("read section"));
+ goto out;
+ }
+ if (nr != (ssize_t)size) {
+ errno = EIO;
+ WARN(("read section"));
+ goto out;
+ }
+
+ loaded = 1;
+ break;
+ default:
Home |
Main Index |
Thread Index |
Old Index