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/bae3e0b0c48c
branches:  trunk
changeset: 826940:bae3e0b0c48c
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 1dc659a8a439 -r bae3e0b0c48c 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 1dc659a8a439 -r bae3e0b0c48c 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 1dc659a8a439 -r bae3e0b0c48c 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 1dc659a8a439 -r bae3e0b0c48c 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 1dc659a8a439 -r bae3e0b0c48c 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