elf64read.c (6503B)
1 #include <assert.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 #include <scc/mach.h> 6 #include <scc/elf64.h> 7 8 #include "../libmach.h" 9 #include "fun.h" 10 11 static int 12 unpack_hdr(int order, unsigned char *buf, Elf_Ehdr *hdr) 13 { 14 int n; 15 16 n = unpack(order, 17 buf, 18 "'16sslqqqlssssss", 19 hdr->e_ident, 20 &hdr->e_type, 21 &hdr->e_machine, 22 &hdr->e_version, 23 &hdr->e_entry, 24 &hdr->e_phoff, 25 &hdr->e_shoff, 26 &hdr->e_flags, 27 &hdr->e_ehsize, 28 &hdr->e_phentsize, 29 &hdr->e_phnum, 30 &hdr->e_shentsize, 31 &hdr->e_shnum, 32 &hdr->e_shstrndx); 33 34 assert(n == ELFHSZ); 35 36 return n; 37 } 38 39 static int 40 unpack_phdr(int order, unsigned char *buf, Elf_Phdr *phdr) 41 { 42 int n; 43 44 n = unpack(order, 45 buf, 46 "llqqqqqq", 47 &phdr->p_type, 48 &phdr->p_flags, 49 &phdr->p_offset, 50 &phdr->p_vaddr, 51 &phdr->p_paddr, 52 &phdr->p_filesz, 53 &phdr->p_memsz, 54 &phdr->p_align); 55 56 assert(n == ELFPSZ); 57 58 return n; 59 } 60 61 static int 62 unpack_shdr(int order, unsigned char *buf, Elf_Shdr *shdr) 63 { 64 int n; 65 66 n = unpack(order, 67 buf, 68 "llqqqqllqq", 69 &shdr->sh_name, 70 &shdr->sh_type, 71 &shdr->sh_flags, 72 &shdr->sh_addr, 73 &shdr->sh_offset, 74 &shdr->sh_size, 75 &shdr->sh_link, 76 &shdr->sh_info, 77 &shdr->sh_addralign, 78 &shdr->sh_entsize); 79 80 assert(n == ELFSSZ); 81 82 return n; 83 } 84 85 static int 86 unpack_sym(int order, unsigned char *buf, Elf_Sym *sym) 87 { 88 int n; 89 90 n = unpack(order, 91 buf, 92 "lccsqq", 93 &sym->st_name, 94 &sym->st_info, 95 &sym->st_other, 96 &sym->st_shndx, 97 &sym->st_value, 98 &sym->st_size); 99 assert(n == ELFESZ); 100 101 return n; 102 } 103 104 static int 105 readhdr(Obj *obj, FILE *fp) 106 { 107 Elf64 *elf; 108 Elf_Ehdr *hdr; 109 unsigned char buf[ELFHSZ]; 110 111 elf = obj->data; 112 hdr = &elf->hdr; 113 114 if (fread(buf, ELFHSZ, 1, fp) != 1) 115 return 0; 116 unpack_hdr(ORDER(obj->type), buf, hdr); 117 118 switch (hdr->e_type) { 119 case ET_REL: 120 case ET_EXEC: 121 case ET_DYN: 122 return 1; 123 default: 124 return 0; 125 } 126 } 127 128 static int 129 readphdr(Obj *obj, FILE *fp) 130 { 131 long long i; 132 Elf_Ehdr *hdr; 133 Elf_Phdr *phdr; 134 Elf64 *elf; 135 unsigned char buf[ELFPSZ]; 136 137 elf = obj->data; 138 hdr = &elf->hdr; 139 140 if (hdr->e_phoff == 0 || hdr->e_phnum == 0) 141 return 1; 142 143 phdr = calloc(hdr->e_phnum, sizeof(*phdr)); 144 if (!phdr) 145 return 0; 146 elf->phdr = phdr; 147 148 if (!objpos(obj, fp, hdr->e_phoff)) 149 return 0; 150 for (i = 0; i < hdr->e_phnum; i++) { 151 if (fread(buf, ELFPSZ, 1, fp) != 1) 152 return 0; 153 unpack_phdr(ORDER(obj->type), buf, &phdr[i]); 154 } 155 156 return 1; 157 } 158 159 static int 160 readshdr(Obj *obj, FILE *fp) 161 { 162 unsigned long long i, nsec; 163 Elf_Ehdr *hdr; 164 Elf_Shdr *shdr; 165 Elf64 *elf; 166 unsigned char buf[ELFSSZ + ELFHSZ]; 167 168 elf = obj->data; 169 hdr = &elf->hdr; 170 elf->nsec = 0; 171 elf->shdr = NULL; 172 173 if (hdr->e_shoff == 0) 174 return 1; 175 176 if (!objpos(obj, fp, hdr->e_shoff)) 177 return 0; 178 179 if (hdr->e_shnum != SHN_UNDEF) { 180 nsec = hdr->e_shnum; 181 } else { 182 Elf_Shdr sec0; 183 fpos_t pos; 184 185 fgetpos(fp, &pos); 186 fread(buf, ELFHSZ, 1, fp); 187 fsetpos(fp, &pos); 188 189 if (ferror(fp)) 190 return 0; 191 192 unpack_shdr(ORDER(obj->type), buf, &sec0); 193 nsec = sec0.sh_size; 194 } 195 196 if (nsec > SIZE_MAX) 197 return 0; 198 if (nsec == 0) 199 return 1; 200 201 shdr = calloc(nsec, sizeof(*shdr)); 202 if (!shdr) 203 return 0; 204 elf->shdr = shdr; 205 elf->nsec = nsec; 206 207 for (i = 0; i < nsec; i++) { 208 if (fread(buf, ELFSSZ, 1, fp) != 1) 209 return 0; 210 unpack_shdr(ORDER(obj->type), buf, &shdr[i]); 211 if (shdr[i].sh_type == SHT_SYMTAB) { 212 /* 213 * elf supports multiple symbol table, but we don't 214 * care and we only support one, and we reject elf 215 * files with more of one symbol table. 216 */ 217 if (elf->symtab) 218 return 0; 219 elf->symtab = &shdr[i]; 220 } 221 } 222 223 return 1; 224 } 225 226 static int 227 readsecstr(Obj *obj, FILE *fp) 228 { 229 long idx; 230 size_t siz; 231 char *str; 232 Elf_Shdr *shdr; 233 Elf64 *elf; 234 Elf_Ehdr *hdr; 235 236 elf = obj->data; 237 hdr = &elf->hdr; 238 idx = hdr->e_shstrndx; 239 if (idx == SHN_UNDEF) 240 return 0; 241 if (idx == SHN_XINDEX) { 242 if (hdr->e_shnum == 0) 243 return 0; 244 idx = elf->shdr[0].sh_link; 245 } 246 247 if (idx >= hdr->e_shnum) 248 return 0; 249 shdr = &elf->shdr[idx]; 250 251 if (shdr->sh_size > SIZE_MAX) 252 return 0; 253 254 siz = shdr->sh_size; 255 if (siz == 0) 256 return 1; 257 str = malloc(siz); 258 if (!str) 259 return 0; 260 261 elf->strtbl[SEC_STRTBL] = str; 262 elf->strsiz[SEC_STRTBL] = siz; 263 264 if (!objpos(obj, fp, shdr->sh_offset)) 265 return 0; 266 if (fread(str, siz, 1, fp) != 1) 267 return 0; 268 269 return 1; 270 } 271 272 static int 273 readsymstr(Obj *obj, FILE *fp) 274 { 275 long idx; 276 size_t siz; 277 char *str; 278 Elf64 *elf; 279 Elf_Shdr *shdr; 280 281 elf = obj->data; 282 if (!elf->symtab) 283 return 1; 284 285 idx = elf->symtab->sh_link; 286 if (idx >= elf->nsec) 287 return 0; 288 shdr = &elf->shdr[idx]; 289 290 if (shdr->sh_size > SIZE_MAX) 291 return 0; 292 293 siz = shdr->sh_size; 294 if (siz == 0) 295 return 1; 296 str = malloc(siz); 297 if (!str) 298 return 0; 299 300 elf->strtbl[SYM_STRTBL] = str; 301 elf->strsiz[SYM_STRTBL] = siz; 302 303 if (!objpos(obj, fp, shdr->sh_offset)) 304 return 0; 305 if (fread(str, siz, 1, fp) != 1) 306 return 0; 307 308 return 1; 309 } 310 311 static int 312 readsym(Obj *obj, FILE *fp) 313 { 314 long nsym, i; 315 int sec; 316 Elf64 *elf; 317 Elf_Sym *syms; 318 Elf_Shdr *shdr; 319 unsigned char buf[ELFSSZ]; 320 321 elf = obj->data; 322 if (!elf->symtab) 323 return 1; 324 shdr = elf->symtab; 325 326 assert(shdr->sh_type == SHT_SYMTAB); 327 328 nsym = shdr->sh_size / shdr->sh_entsize; 329 if (nsym >= SIZE_MAX) 330 return 0; 331 332 syms = calloc(nsym, sizeof(*syms)); 333 if (!syms) 334 return 0; 335 elf->syms = syms; 336 elf->nsym = nsym; 337 338 if (!objpos(obj, fp, shdr->sh_offset)) 339 return 0; 340 341 for (i = 0; i < nsym; i++) { 342 if (fread(buf, ELFESZ, 1, fp) != 1) 343 return 0; 344 unpack_sym(ORDER(obj->type), buf, &syms[i]); 345 346 sec = syms[i].st_shndx; 347 switch (sec) { 348 case SHN_XINDEX: 349 /* 350 * Elf supports an extension mechanism to allow 351 * indexes bigger than 4 bytes. We don't care 352 * and we reject elf files using this feature. 353 */ 354 return 0; 355 case SHN_UNDEF: 356 case SHN_ABS: 357 case SHN_COMMON: 358 break; 359 default: 360 if (sec >= elf->nsec) 361 return 0; 362 break; 363 } 364 } 365 366 return 1; 367 } 368 369 int 370 elf64read(Obj *obj, FILE *fp) 371 { 372 if (!readhdr(obj, fp)) 373 return -1; 374 if (!readphdr(obj, fp)) 375 return -1; 376 if (!readshdr(obj, fp)) 377 return -1; 378 if (!readsym(obj, fp)) 379 return -1; 380 if (!readsecstr(obj, fp)) 381 return -1; 382 if (!readsymstr(obj, fp)) 383 return -1; 384 385 return 0; 386 }