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) */

Reply via email to