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