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