1 /* 2 * Copyright (c) 2018-2021 Maxime Villard, m00nbsd.net 3 * All rights reserved. 4 * 5 * This code is part of the NVMM hypervisor. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 32 #include <err.h> 33 #include <fcntl.h> 34 #include <stdint.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 39 #include "common.h" 40 41 #ifdef __NetBSD__ 42 #define ELFSIZE 64 43 #include <sys/exec_elf.h> 44 #else /* DragonFly */ 45 #include <sys/elf64.h> 46 #define Elf_Ehdr Elf64_Ehdr 47 #define Elf_Phdr Elf64_Phdr 48 #endif /* __NetBSD__ */ 49 50 #define ELF_MAXPHNUM 128 51 #define ELF_MAXSHNUM 32768 52 53 static int 54 elf_check_header(Elf_Ehdr *eh) 55 { 56 if (eh->e_shnum > ELF_MAXSHNUM || eh->e_phnum > ELF_MAXPHNUM) 57 return -1; 58 return 0; 59 } 60 61 static uint64_t 62 elf_parse(struct nvmm_machine *mach, char *base) 63 { 64 Elf_Ehdr *ehdr = (Elf_Ehdr *)base; 65 Elf_Phdr *phdr; 66 uintptr_t hva; 67 gpaddr_t lastgpa; 68 size_t i; 69 70 if (elf_check_header(ehdr) == -1) 71 errx(EXIT_FAILURE, "wrong ELF header"); 72 phdr = (Elf_Phdr *)((char *)ehdr + ehdr->e_phoff); 73 74 for (i = 0; i < ehdr->e_phnum; i++) { 75 if (phdr[i].p_type != PT_LOAD) { 76 if (phdr[i].p_filesz == 0) { 77 /* Ignore zero-sized GNU_STACK segment 78 * (found on DragonFly) */ 79 continue; 80 } else { 81 errx(EXIT_FAILURE, "unsupported ELF"); 82 } 83 } 84 85 hva = toyvirt_mem_add(mach, phdr[i].p_vaddr, 86 roundup(phdr[i].p_filesz, PAGE_SIZE)); 87 memcpy((void *)hva, base + phdr[i].p_offset, phdr[i].p_filesz); 88 89 lastgpa = phdr[i].p_vaddr + 90 roundup(phdr[i].p_filesz, PAGE_SIZE); 91 } 92 93 /* Add 128 pages after the kernel image. */ 94 toyvirt_mem_add(mach, lastgpa, 128 * PAGE_SIZE); 95 96 return ehdr->e_entry; 97 } 98 99 int 100 elf_map(struct nvmm_machine *mach, const char *path, uint64_t *rip) 101 { 102 struct stat st; 103 char *base = NULL; 104 int fd, ret = -1; 105 106 fd = open(path, O_RDONLY); 107 if (fstat(fd, &st) == -1) 108 goto out; 109 if ((size_t)st.st_size < sizeof(Elf_Ehdr)) 110 goto out; 111 base = malloc(st.st_size); 112 pread(fd, base, st.st_size, 0); 113 114 *rip = elf_parse(mach, base); 115 ret = 0; 116 117 out: 118 close(fd); 119 free(base); 120 return ret; 121 } 122