Module Name: src
Committed By: maxv
Date: Sat Oct 7 10:26:39 UTC 2017
Modified Files:
src/sys/arch/i386/stand/boot: boot2.c
src/sys/arch/i386/stand/lib: exec.c
src/sys/arch/x86/include: bootinfo.h
src/sys/lib/libsa: loadfile.h loadfile_elf32.c
Log Message:
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@.)
To generate a diff of this commit:
cvs rdiff -u -r1.66 -r1.67 src/sys/arch/i386/stand/boot/boot2.c
cvs rdiff -u -r1.68 -r1.69 src/sys/arch/i386/stand/lib/exec.c
cvs rdiff -u -r1.26 -r1.27 src/sys/arch/x86/include/bootinfo.h
cvs rdiff -u -r1.13 -r1.14 src/sys/lib/libsa/loadfile.h
cvs rdiff -u -r1.43 -r1.44 src/sys/lib/libsa/loadfile_elf32.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/i386/stand/boot/boot2.c
diff -u src/sys/arch/i386/stand/boot/boot2.c:1.66 src/sys/arch/i386/stand/boot/boot2.c:1.67
--- src/sys/arch/i386/stand/boot/boot2.c:1.66 Wed Feb 3 05:27:53 2016
+++ src/sys/arch/i386/stand/boot/boot2.c Sat Oct 7 10:26:38 2017
@@ -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 @@ void command_ls(char *);
#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 @@ const struct bootblk_command commands[]
#endif
{ "quit", command_quit },
{ "boot", command_boot },
+ { "pkboot", command_pkboot },
{ "dev", command_dev },
{ "consdev", command_consdev },
#ifndef SMALL
@@ -470,6 +472,14 @@ command_boot(char *arg)
}
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];
Index: src/sys/arch/i386/stand/lib/exec.c
diff -u src/sys/arch/i386/stand/lib/exec.c:1.68 src/sys/arch/i386/stand/lib/exec.c:1.69
--- src/sys/arch/i386/stand/lib/exec.c:1.68 Fri Mar 24 08:50:17 2017
+++ src/sys/arch/i386/stand/lib/exec.c Sat Oct 7 10:26:38 2017
@@ -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 @@ userconf_add(char *cmd)
}
}
+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 @@ exec_netbsd(const char *file, physaddr_t
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;
Index: src/sys/arch/x86/include/bootinfo.h
diff -u src/sys/arch/x86/include/bootinfo.h:1.26 src/sys/arch/x86/include/bootinfo.h:1.27
--- src/sys/arch/x86/include/bootinfo.h:1.26 Tue Feb 14 13:25:22 2017
+++ src/sys/arch/x86/include/bootinfo.h Sat Oct 7 10:26:38 2017
@@ -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 @@ struct btinfo_efi {
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 */
Index: src/sys/lib/libsa/loadfile.h
diff -u src/sys/lib/libsa/loadfile.h:1.13 src/sys/lib/libsa/loadfile.h:1.14
--- src/sys/lib/libsa/loadfile.h:1.13 Sat Dec 3 09:20:55 2016
+++ src/sys/lib/libsa/loadfile.h Sat Oct 7 10:26:39 2017
@@ -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
Index: src/sys/lib/libsa/loadfile_elf32.c
diff -u src/sys/lib/libsa/loadfile_elf32.c:1.43 src/sys/lib/libsa/loadfile_elf32.c:1.44
--- src/sys/lib/libsa/loadfile_elf32.c:1.43 Thu Oct 5 02:59:21 2017
+++ src/sys/lib/libsa/loadfile_elf32.c Sat Oct 7 10:26:39 2017
@@ -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 @@ externalize_shdr(Elf_Byte bo, Elf_Shdr *
/* -------------------------------------------------------------------------- */
+#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:
+ loaded = 0;
+ break;
+ }
+
+ if (loaded) {
+ shdr[i].sh_offset = maxp - elfp;
+ maxp = roundup(maxp + size, KERNALIGN);
+ }
+ }
+
+ /*
+ * Load the SYMBOL SECTIONS.
+ */
+ maxp = roundup(maxp, ELFROUND);
+ for (i = 0; i < elf->e_shnum; i++) {
+ addr = maxp;
+ size = (size_t)shdr[i].sh_size;
+
+ switch (shdr[i].sh_type) {
+ case SHT_STRTAB:
+ for (j = 0; j < elf->e_shnum; j++)
+ if (shdr[j].sh_type == SHT_SYMTAB &&
+ shdr[j].sh_link == (unsigned int)i)
+ goto havesym;
+ if (elf->e_shstrndx == i)
+ goto havesym;
+ /*
+ * Don't bother with any string table that isn't
+ * referenced by a symbol table.
+ */
+ shdr[i].sh_offset = 0;
+ break;
+ havesym:
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_SYMTAB:
+ if (lseek(fd, shdr[i].sh_offset, SEEK_SET) == -1) {
+ WARN(("lseek symbols"));
+ goto out;
+ }
+ nr = READ(fd, addr, size);
+ if (nr == -1) {
+ WARN(("read symbols"));
+ goto out;
+ }
+ if (nr != (ssize_t)size) {
+ errno = EIO;
+ WARN(("read symbols"));
+ goto out;
+ }
+
+ shdr[i].sh_offset = maxp - elfp;
+ maxp += roundup(size, ELFROUND);
+ break;
+ }
+ }
+ maxp = roundup(maxp, KERNALIGN);
+
+ /*
+ * Finally, load the SECTION HEADERS.
+ */
+#ifndef _STANDALONE
+ for (i = 0; i < elf->e_shnum; i++)
+ externalize_shdr(elf->e_ident[EI_DATA], &shdr[i]);
+#endif
+ BCOPY(shdr, shpp, sz);
+
+ DEALLOC(shdr, sz);
+
+ /*
+ * Just update MARK_SYM and MARK_END without touching the rest.
+ */
+ marks[MARK_SYM] = LOADADDR(elfp);
+ marks[MARK_END] = LOADADDR(maxp);
+ return 0;
+
+out:
+ DEALLOC(shdr, sz);
+ return 1;
+}
+
+/* -------------------------------------------------------------------------- */
+
/*
* See comment below. This function is in charge of loading the SECTION HEADERS.
*/
@@ -485,8 +675,8 @@ out:
* We just give the kernel a pointer to the ELF HEADER, which is enough for it
* to find the location and number of symbols by itself later.
*/
-int
-ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
+static int
+ELFNAMEEND(loadfile_static)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
{
Elf_Phdr *phdr;
int i, first;
@@ -631,4 +821,16 @@ freephdr:
return 1;
}
+/* -------------------------------------------------------------------------- */
+
+int
+ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
+{
+ if (flags & LOAD_DYN) {
+ return ELFNAMEEND(loadfile_dynamic)(fd, elf, marks, flags);
+ } else {
+ return ELFNAMEEND(loadfile_static)(fd, elf, marks, flags);
+ }
+}
+
#endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */