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