1 #define _SYSTEM 1 2 3 #include <minix/type.h> 4 #include <minix/const.h> 5 #include <minix/com.h> 6 #include <minix/syslib.h> 7 #include <sys/param.h> 8 #include <sys/mman.h> 9 #include <assert.h> 10 #include <unistd.h> 11 #include <errno.h> 12 #include <libexec.h> 13 #include <string.h> 14 #include <machine/elf.h> 15 #include <machine/vmparam.h> 16 #include <machine/memory.h> 17 #include <minix/syslib.h> 18 19 /* For verbose logging */ 20 #define ELF_DEBUG 0 21 22 /* Support only 32-bit ELF objects */ 23 #define __ELF_WORD_SIZE 32 24 25 #define SECTOR_SIZE 512 26 27 static int check_header(Elf_Ehdr *hdr); 28 29 static int elf_sane(Elf_Ehdr *hdr) 30 { 31 if (check_header(hdr) != OK) { 32 return 0; 33 } 34 35 if((hdr->e_type != ET_EXEC) && (hdr->e_type != ET_DYN)) { 36 return 0; 37 } 38 39 if ((hdr->e_phoff > SECTOR_SIZE) || 40 (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > SECTOR_SIZE) { 41 #if ELF_DEBUG 42 printf("peculiar phoff\n"); 43 #endif 44 return 0; 45 } 46 47 return 1; 48 } 49 50 static int elf_ph_sane(Elf_Phdr *phdr) 51 { 52 if (rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr) { 53 return 0; 54 } 55 return 1; 56 } 57 58 static int elf_unpack(char *exec_hdr, 59 int hdr_len, Elf_Ehdr **hdr, Elf_Phdr **phdr) 60 { 61 assert(hdr_len >= sizeof(Elf_Ehdr)); 62 63 *hdr = (Elf_Ehdr *) exec_hdr; 64 if(!elf_sane(*hdr)) { 65 return ENOEXEC; 66 } 67 *phdr = (Elf_Phdr *)(exec_hdr + (*hdr)->e_phoff); 68 if(!elf_ph_sane(*phdr)) { 69 return ENOEXEC; 70 } 71 #if 0 72 if((int)((*phdr) + (*hdr)->e_phnum) >= hdr_len) return ENOEXEC; 73 #endif 74 return OK; 75 } 76 77 #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ 78 (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ 79 (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ 80 (ehdr).e_ident[EI_MAG3] == ELFMAG3) 81 82 static int check_header(Elf_Ehdr *hdr) 83 { 84 if (!IS_ELF(*hdr) || 85 hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 86 hdr->e_ident[EI_VERSION] != EV_CURRENT || 87 hdr->e_phentsize != sizeof(Elf_Phdr) || 88 hdr->e_version != ELF_TARG_VER) 89 return ENOEXEC; 90 91 return OK; 92 } 93 94 /* Return >0 if there is an ELF interpreter (i.e. it is a dynamically linked 95 * executable) and we could extract it successfully. 96 * Return 0 if there isn't one. 97 * Return <0 on error. 98 */ 99 int elf_has_interpreter(char *exec_hdr, /* executable header */ 100 int hdr_len, char *interp, int maxsz) 101 { 102 Elf_Ehdr *hdr = NULL; 103 Elf_Phdr *phdr = NULL; 104 int e, i; 105 106 if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return 0; 107 108 for (i = 0; i < hdr->e_phnum; i++) { 109 switch (phdr[i].p_type) { 110 case PT_INTERP: 111 if(!interp) return 1; 112 if(phdr[i].p_filesz >= maxsz) 113 return -1; 114 if(phdr[i].p_offset + phdr[i].p_filesz >= hdr_len) 115 return -1; 116 memcpy(interp, exec_hdr + phdr[i].p_offset, phdr[i].p_filesz); 117 interp[phdr[i].p_filesz] = '\0'; 118 return 1; 119 default: 120 continue; 121 } 122 } 123 return 0; 124 } 125 126 int libexec_load_elf(struct exec_info *execi) 127 { 128 Elf_Ehdr *hdr = NULL; 129 Elf_Phdr *phdr = NULL; 130 int e, i = 0; 131 int first = 1; 132 vir_bytes startv = 0, stacklow; 133 134 assert(execi != NULL); 135 assert(execi->hdr != NULL); 136 137 if((e=elf_unpack(execi->hdr, execi->hdr_len, &hdr, &phdr)) != OK) { 138 return e; 139 } 140 141 /* this function can load the dynamic linker, but that 142 * shouldn't require an interpreter itself. 143 */ 144 i = elf_has_interpreter(execi->hdr, execi->hdr_len, NULL, 0); 145 if(i > 0) { 146 return ENOEXEC; 147 } 148 149 execi->stack_size = roundup(execi->stack_size, PAGE_SIZE); 150 execi->stack_high = rounddown(execi->stack_high, PAGE_SIZE); 151 stacklow = execi->stack_high - execi->stack_size; 152 153 assert(execi->copymem); 154 assert(execi->clearmem); 155 assert(execi->allocmem_prealloc_cleared); 156 assert(execi->allocmem_prealloc_junk); 157 assert(execi->allocmem_ondemand); 158 159 for (i = 0; i < hdr->e_phnum; i++) { 160 Elf_Phdr *ph = &phdr[i]; 161 off_t file_limit = ph->p_offset + ph->p_filesz; 162 /* sanity check binary before wiping out the target process */ 163 if(execi->filesize < file_limit) { 164 return ENOEXEC; 165 } 166 } 167 168 if(execi->clearproc) execi->clearproc(execi); 169 170 for (i = 0; i < hdr->e_phnum; i++) { 171 vir_bytes seg_membytes, page_offset, p_vaddr, vaddr; 172 vir_bytes chunk, vfileend, vmemend; 173 off_t foffset, fbytes; 174 Elf_Phdr *ph = &phdr[i]; 175 int try_mmap = 1; 176 u16_t clearend = 0; 177 int pagechunk; 178 int mmap_prot = PROT_READ; 179 180 if(!(ph->p_flags & PF_R)) { 181 printf("libexec: warning: unreadable segment\n"); 182 } 183 184 if(ph->p_flags & PF_W) { 185 mmap_prot |= PROT_WRITE; 186 #if ELF_DEBUG 187 printf("libexec: adding PROT_WRITE\n"); 188 #endif 189 } else { 190 #if ELF_DEBUG 191 printf("libexec: not adding PROT_WRITE\n"); 192 #endif 193 } 194 195 if (ph->p_type != PT_LOAD || ph->p_memsz == 0) continue; 196 197 if((ph->p_vaddr % PAGE_SIZE) != (ph->p_offset % PAGE_SIZE)) { 198 printf("libexec: unaligned ELF program?\n"); 199 try_mmap = 0; 200 } 201 202 if(!execi->memmap) { 203 try_mmap = 0; 204 } 205 206 foffset = ph->p_offset; 207 fbytes = ph->p_filesz; 208 vaddr = p_vaddr = ph->p_vaddr + execi->load_offset; 209 seg_membytes = ph->p_memsz; 210 211 page_offset = vaddr % PAGE_SIZE; 212 vaddr -= page_offset; 213 foffset -= page_offset; 214 seg_membytes += page_offset; 215 fbytes += page_offset; 216 vfileend = p_vaddr + ph->p_filesz; 217 218 /* if there's usable memory after the file end, we have 219 * to tell VM to clear the memory part of the page when it's 220 * mapped in 221 */ 222 if((pagechunk = (vfileend % PAGE_SIZE)) 223 && ph->p_filesz < ph->p_memsz) { 224 clearend = PAGE_SIZE - pagechunk; 225 } 226 227 seg_membytes = roundup(seg_membytes, PAGE_SIZE); 228 fbytes = roundup(fbytes, PAGE_SIZE); 229 230 if(first || startv > vaddr) startv = vaddr; 231 first = 0; 232 233 if ((ph->p_flags & PF_X) != 0 && execi->text_size < seg_membytes) 234 execi->text_size = seg_membytes; 235 else 236 execi->data_size = seg_membytes; 237 238 if(try_mmap && execi->memmap(execi, vaddr, fbytes, foffset, clearend, mmap_prot) == OK) { 239 #if ELF_DEBUG 240 printf("libexec: mmap 0x%lx-0x%lx done, clearend 0x%x\n", 241 vaddr, vaddr+fbytes, clearend); 242 #endif 243 244 if(seg_membytes > fbytes) { 245 int rem_mem = seg_membytes - fbytes;; 246 vir_bytes remstart = vaddr + fbytes; 247 if(execi->allocmem_ondemand(execi, 248 remstart, rem_mem) != OK) { 249 printf("libexec: mmap extra mem failed\n"); 250 return ENOMEM; 251 } 252 #if ELF_DEBUG 253 else printf("libexec: allocated 0x%lx-0x%lx\n", 254 255 remstart, remstart+rem_mem); 256 #endif 257 } 258 } else { 259 /* make us some memory */ 260 if(execi->allocmem_prealloc_junk(execi, vaddr, seg_membytes) != OK) { 261 if(execi->clearproc) execi->clearproc(execi); 262 return ENOMEM; 263 } 264 265 #if ELF_DEBUG 266 printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes); 267 #endif 268 269 /* Copy executable section into it */ 270 if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) { 271 if(execi->clearproc) execi->clearproc(execi); 272 return ENOMEM; 273 } 274 275 #if ELF_DEBUG 276 printf("copied 0x%lx-0x%lx\n", p_vaddr, p_vaddr+ph->p_filesz); 277 #endif 278 279 /* Clear remaining bits */ 280 vmemend = vaddr + seg_membytes; 281 if((chunk = p_vaddr - vaddr) > 0) { 282 #if ELF_DEBUG 283 printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk); 284 #endif 285 execi->clearmem(execi, vaddr, chunk); 286 } 287 288 if((chunk = vmemend - vfileend) > 0) { 289 #if ELF_DEBUG 290 printf("end clearing 0x%lx-0x%lx\n", vfileend, vfileend+chunk); 291 #endif 292 execi->clearmem(execi, vfileend, chunk); 293 } 294 } 295 } 296 297 /* Make it a stack */ 298 if(execi->allocmem_ondemand(execi, stacklow, execi->stack_size) != OK) { 299 if(execi->clearproc) execi->clearproc(execi); 300 return ENOMEM; 301 } 302 303 #if ELF_DEBUG 304 printf("stack mmapped 0x%lx-0x%lx\n", stacklow, stacklow+execi->stack_size); 305 #endif 306 307 /* record entry point and lowest load vaddr for caller */ 308 execi->pc = hdr->e_entry + execi->load_offset; 309 execi->load_base = startv; 310 311 return OK; 312 } 313 314