1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021-2023 John Baldwin <jhb@FreeBSD.org> 5 * 6 * This software was developed by SRI International and the University 7 * of Cambridge Computer Laboratory (Department of Computer Science 8 * and Technology) under Defense Advanced Research Projects Agency 9 * (DARPA) contract HR0011-18-C-0016 ("ECATS"), as part of the DARPA 10 * SSITH research programme and under DARPA Contract No. HR001123C0031 11 * ("MTSS"). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/endian.h> 37 38 #include <err.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <gelf.h> 42 #include <libelf.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "ef.h" 48 49 SET_DECLARE(elf_reloc, struct elf_reloc_data); 50 51 static elf_reloc_t * 52 elf_find_reloc(const GElf_Ehdr *hdr) 53 { 54 struct elf_reloc_data **erd; 55 56 SET_FOREACH(erd, elf_reloc) { 57 if (hdr->e_ident[EI_CLASS] == (*erd)->class && 58 hdr->e_ident[EI_DATA] == (*erd)->data && 59 hdr->e_machine == (*erd)->machine) 60 return ((*erd)->reloc); 61 } 62 return (NULL); 63 } 64 65 int 66 elf_open_file(struct elf_file *efile, const char *filename, int verbose) 67 { 68 int error; 69 70 memset(efile, 0, sizeof(*efile)); 71 efile->ef_filename = filename; 72 efile->ef_fd = open(filename, O_RDONLY); 73 if (efile->ef_fd == -1) { 74 if (verbose) 75 warn("open(%s)", filename); 76 return (errno); 77 } 78 79 efile->ef_elf = elf_begin(efile->ef_fd, ELF_C_READ, NULL); 80 if (efile->ef_elf == NULL) { 81 if (verbose) 82 warnx("elf_begin(%s): %s", filename, elf_errmsg(0)); 83 elf_close_file(efile); 84 return (EINVAL); 85 } 86 87 if (elf_kind(efile->ef_elf) != ELF_K_ELF) { 88 if (verbose) 89 warnx("%s: not an ELF file", filename); 90 elf_close_file(efile); 91 return (EINVAL); 92 } 93 94 if (gelf_getehdr(efile->ef_elf, &efile->ef_hdr) == NULL) { 95 if (verbose) 96 warnx("gelf_getehdr(%s): %s", filename, elf_errmsg(0)); 97 elf_close_file(efile); 98 return (EINVAL); 99 } 100 101 efile->ef_reloc = elf_find_reloc(&efile->ef_hdr); 102 if (efile->ef_reloc == NULL) { 103 if (verbose) 104 warnx("%s: unsupported architecture", filename); 105 elf_close_file(efile); 106 return (EFTYPE); 107 } 108 109 error = ef_open(efile, verbose); 110 if (error != 0) { 111 error = ef_obj_open(efile, verbose); 112 if (error != 0) { 113 if (verbose) 114 warnc(error, "%s: not a valid DSO or object file", 115 filename); 116 elf_close_file(efile); 117 return (error); 118 } 119 } 120 121 efile->ef_pointer_size = elf_object_size(efile, ELF_T_ADDR); 122 123 return (0); 124 } 125 126 void 127 elf_close_file(struct elf_file *efile) 128 { 129 if (efile->ef_ops != NULL) { 130 EF_CLOSE(efile); 131 } 132 if (efile->ef_elf != NULL) { 133 elf_end(efile->ef_elf); 134 efile->ef_elf = NULL; 135 } 136 if (efile->ef_fd > 0) { 137 close(efile->ef_fd); 138 efile->ef_fd = -1; 139 } 140 } 141 142 bool 143 elf_compatible(struct elf_file *efile, const GElf_Ehdr *hdr) 144 { 145 if (efile->ef_hdr.e_ident[EI_CLASS] != hdr->e_ident[EI_CLASS] || 146 efile->ef_hdr.e_ident[EI_DATA] != hdr->e_ident[EI_DATA] || 147 efile->ef_hdr.e_machine != hdr->e_machine) 148 return (false); 149 return (true); 150 } 151 152 size_t 153 elf_object_size(struct elf_file *efile, Elf_Type type) 154 { 155 return (gelf_fsize(efile->ef_elf, type, 1, efile->ef_hdr.e_version)); 156 } 157 158 /* 159 * The number of objects of 'type' in region of the file of size 160 * 'file_size'. 161 */ 162 static size_t 163 elf_object_count(struct elf_file *efile, Elf_Type type, size_t file_size) 164 { 165 return (file_size / elf_object_size(efile, type)); 166 } 167 168 int 169 elf_read_raw_data(struct elf_file *efile, off_t offset, void *dst, size_t len) 170 { 171 ssize_t nread; 172 173 nread = pread(efile->ef_fd, dst, len, offset); 174 if (nread == -1) 175 return (errno); 176 if (nread != len) 177 return (EIO); 178 return (0); 179 } 180 181 int 182 elf_read_raw_data_alloc(struct elf_file *efile, off_t offset, size_t len, 183 void **out) 184 { 185 void *buf; 186 int error; 187 188 buf = malloc(len); 189 if (buf == NULL) 190 return (ENOMEM); 191 error = elf_read_raw_data(efile, offset, buf, len); 192 if (error != 0) { 193 free(buf); 194 return (error); 195 } 196 *out = buf; 197 return (0); 198 } 199 200 int 201 elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len, 202 void **out) 203 { 204 Elf_Data dst, src; 205 void *buf; 206 int error; 207 208 buf = malloc(len); 209 if (buf == NULL) 210 return (ENOMEM); 211 212 error = elf_read_raw_data(efile, offset, buf, len); 213 if (error != 0) { 214 free(buf); 215 return (error); 216 } 217 218 memset(&dst, 0, sizeof(dst)); 219 memset(&src, 0, sizeof(src)); 220 221 src.d_buf = buf; 222 src.d_size = len; 223 src.d_type = type; 224 src.d_version = efile->ef_hdr.e_version; 225 226 dst.d_buf = buf; 227 dst.d_size = len; 228 dst.d_version = EV_CURRENT; 229 230 if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) == 231 NULL) { 232 free(buf); 233 return (ENXIO); 234 } 235 236 if (dst.d_size != len) 237 warnx("elf_read_data: translation of type %u size mismatch", 238 type); 239 240 *out = buf; 241 return (0); 242 } 243 244 int 245 elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len, 246 void **buf) 247 { 248 int error; 249 void *p; 250 251 p = malloc(len); 252 if (p == NULL) 253 return (ENOMEM); 254 error = EF_SEG_READ_REL(efile, address, len, p); 255 if (error != 0) { 256 free(p); 257 return (error); 258 } 259 *buf = p; 260 return (0); 261 } 262 263 int 264 elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp) 265 { 266 GElf_Phdr *phdr; 267 size_t nphdr, i; 268 int error; 269 270 if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1) 271 return (EFTYPE); 272 273 phdr = calloc(nphdr, sizeof(*phdr)); 274 if (phdr == NULL) 275 return (ENOMEM); 276 277 for (i = 0; i < nphdr; i++) { 278 if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) { 279 error = EFTYPE; 280 goto out; 281 } 282 } 283 284 *nphdrp = nphdr; 285 *phdrp = phdr; 286 return (0); 287 out: 288 free(phdr); 289 return (error); 290 } 291 292 int 293 elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp) 294 { 295 GElf_Shdr *shdr; 296 Elf_Scn *scn; 297 size_t nshdr, i; 298 int error; 299 300 if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1) 301 return (EFTYPE); 302 303 shdr = calloc(nshdr, sizeof(*shdr)); 304 if (shdr == NULL) 305 return (ENOMEM); 306 307 for (i = 0; i < nshdr; i++) { 308 scn = elf_getscn(efile->ef_elf, i); 309 if (scn == NULL) { 310 error = EFTYPE; 311 goto out; 312 } 313 if (gelf_getshdr(scn, &shdr[i]) == NULL) { 314 error = EFTYPE; 315 goto out; 316 } 317 } 318 319 *nshdrp = nshdr; 320 *shdrp = shdr; 321 return (0); 322 out: 323 free(shdr); 324 return (error); 325 } 326 327 int 328 elf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp, 329 GElf_Dyn **dynp) 330 { 331 GElf_Shdr shdr; 332 Elf_Scn *scn; 333 Elf_Data *data; 334 GElf_Dyn *dyn; 335 long i, ndyn; 336 337 scn = elf_getscn(efile->ef_elf, section_index); 338 if (scn == NULL) 339 return (EINVAL); 340 if (gelf_getshdr(scn, &shdr) == NULL) 341 return (EINVAL); 342 data = elf_getdata(scn, NULL); 343 if (data == NULL) 344 return (EINVAL); 345 346 ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size); 347 dyn = calloc(ndyn, sizeof(*dyn)); 348 if (dyn == NULL) 349 return (ENOMEM); 350 351 for (i = 0; i < ndyn; i++) { 352 if (gelf_getdyn(data, i, &dyn[i]) == NULL) { 353 free(dyn); 354 return (EINVAL); 355 } 356 } 357 358 *ndynp = ndyn; 359 *dynp = dyn; 360 return (0); 361 } 362 363 int 364 elf_read_symbols(struct elf_file *efile, int section_index, size_t *nsymp, 365 GElf_Sym **symp) 366 { 367 GElf_Shdr shdr; 368 Elf_Scn *scn; 369 Elf_Data *data; 370 GElf_Sym *sym; 371 size_t i, nsym; 372 373 scn = elf_getscn(efile->ef_elf, section_index); 374 if (scn == NULL) 375 return (EINVAL); 376 if (gelf_getshdr(scn, &shdr) == NULL) 377 return (EINVAL); 378 data = elf_getdata(scn, NULL); 379 if (data == NULL) 380 return (EINVAL); 381 382 nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size); 383 sym = calloc(nsym, sizeof(*sym)); 384 if (sym == NULL) 385 return (ENOMEM); 386 387 for (i = 0; i < nsym; i++) { 388 if (gelf_getsym(data, i, &sym[i]) == NULL) { 389 free(sym); 390 return (EINVAL); 391 } 392 } 393 394 *nsymp = nsym; 395 *symp = sym; 396 return (0); 397 } 398 399 int 400 elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr, 401 long *strcnt, char **strtab) 402 { 403 int error; 404 405 if (shdr->sh_type != SHT_STRTAB) 406 return (EINVAL); 407 error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size, 408 (void **)strtab); 409 if (error != 0) 410 return (error); 411 *strcnt = shdr->sh_size; 412 return (0); 413 } 414 415 int 416 elf_read_rel(struct elf_file *efile, int section_index, long *nrelp, 417 GElf_Rel **relp) 418 { 419 GElf_Shdr shdr; 420 Elf_Scn *scn; 421 Elf_Data *data; 422 GElf_Rel *rel; 423 long i, nrel; 424 425 scn = elf_getscn(efile->ef_elf, section_index); 426 if (scn == NULL) 427 return (EINVAL); 428 if (gelf_getshdr(scn, &shdr) == NULL) 429 return (EINVAL); 430 data = elf_getdata(scn, NULL); 431 if (data == NULL) 432 return (EINVAL); 433 434 nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size); 435 rel = calloc(nrel, sizeof(*rel)); 436 if (rel == NULL) 437 return (ENOMEM); 438 439 for (i = 0; i < nrel; i++) { 440 if (gelf_getrel(data, i, &rel[i]) == NULL) { 441 free(rel); 442 return (EINVAL); 443 } 444 } 445 446 *nrelp = nrel; 447 *relp = rel; 448 return (0); 449 } 450 451 int 452 elf_read_rela(struct elf_file *efile, int section_index, long *nrelap, 453 GElf_Rela **relap) 454 { 455 GElf_Shdr shdr; 456 Elf_Scn *scn; 457 Elf_Data *data; 458 GElf_Rela *rela; 459 long i, nrela; 460 461 scn = elf_getscn(efile->ef_elf, section_index); 462 if (scn == NULL) 463 return (EINVAL); 464 if (gelf_getshdr(scn, &shdr) == NULL) 465 return (EINVAL); 466 data = elf_getdata(scn, NULL); 467 if (data == NULL) 468 return (EINVAL); 469 470 nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size); 471 rela = calloc(nrela, sizeof(*rela)); 472 if (rela == NULL) 473 return (ENOMEM); 474 475 for (i = 0; i < nrela; i++) { 476 if (gelf_getrela(data, i, &rela[i]) == NULL) { 477 free(rela); 478 return (EINVAL); 479 } 480 } 481 482 *nrelap = nrela; 483 *relap = rela; 484 return (0); 485 } 486 487 size_t 488 elf_pointer_size(struct elf_file *efile) 489 { 490 return (efile->ef_pointer_size); 491 } 492 493 int 494 elf_int(struct elf_file *efile, const void *p) 495 { 496 if (elf_encoding(efile) == ELFDATA2LSB) 497 return (le32dec(p)); 498 else 499 return (be32dec(p)); 500 } 501 502 GElf_Addr 503 elf_address_from_pointer(struct elf_file *efile, const void *p) 504 { 505 switch (elf_class(efile)) { 506 case ELFCLASS32: 507 if (elf_encoding(efile) == ELFDATA2LSB) 508 return (le32dec(p)); 509 else 510 return (be32dec(p)); 511 case ELFCLASS64: 512 if (elf_encoding(efile) == ELFDATA2LSB) 513 return (le64dec(p)); 514 else 515 return (be64dec(p)); 516 default: 517 __builtin_unreachable(); 518 } 519 } 520 521 int 522 elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst, 523 size_t len) 524 { 525 return (EF_SEG_READ_STRING(efile, address, len, dst)); 526 } 527 528 int 529 elf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp, 530 long *countp) 531 { 532 GElf_Addr *buf, start, stop; 533 char *p; 534 void *raw; 535 long i, count; 536 int error; 537 538 error = EF_LOOKUP_SET(efile, name, &start, &stop, &count); 539 if (error != 0) 540 return (error); 541 542 error = elf_read_relocated_data(efile, start, 543 count * elf_pointer_size(efile), &raw); 544 if (error != 0) 545 return (error); 546 547 buf = calloc(count, sizeof(*buf)); 548 if (buf == NULL) { 549 free(raw); 550 return (ENOMEM); 551 } 552 553 p = raw; 554 for (i = 0; i < count; i++) { 555 buf[i] = elf_address_from_pointer(efile, p); 556 p += elf_pointer_size(efile); 557 } 558 free(raw); 559 560 *bufp = buf; 561 *countp = count; 562 return (0); 563 } 564 565 int 566 elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr, 567 struct Gmod_depend *mdp) 568 { 569 int *p; 570 int error; 571 572 error = elf_read_relocated_data(efile, addr, sizeof(int) * 3, 573 (void **)&p); 574 if (error != 0) 575 return (error); 576 577 memset(mdp, 0, sizeof(*mdp)); 578 mdp->md_ver_minimum = elf_int(efile, p); 579 mdp->md_ver_preferred = elf_int(efile, p + 1); 580 mdp->md_ver_maximum = elf_int(efile, p + 2); 581 free(p); 582 return (0); 583 } 584 585 int 586 elf_read_mod_version(struct elf_file *efile, GElf_Addr addr, 587 struct Gmod_version *mdv) 588 { 589 int error, value; 590 591 error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value); 592 if (error != 0) 593 return (error); 594 595 memset(mdv, 0, sizeof(*mdv)); 596 mdv->mv_version = elf_int(efile, &value); 597 return (0); 598 } 599 600 int 601 elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr, 602 struct Gmod_metadata *md) 603 { 604 char *p; 605 size_t len, offset, pointer_size; 606 int error; 607 608 pointer_size = elf_pointer_size(efile); 609 len = 2 * sizeof(int); 610 len = roundup(len, pointer_size); 611 len += 2 * pointer_size; 612 613 error = elf_read_relocated_data(efile, addr, len, (void **)&p); 614 if (error != 0) 615 return (error); 616 617 memset(md, 0, sizeof(*md)); 618 offset = 0; 619 md->md_version = elf_int(efile, p + offset); 620 offset += sizeof(int); 621 md->md_type = elf_int(efile, p + offset); 622 offset += sizeof(int); 623 offset = roundup(offset, pointer_size); 624 md->md_data = elf_address_from_pointer(efile, p + offset); 625 offset += pointer_size; 626 md->md_cval = elf_address_from_pointer(efile, p + offset); 627 free(p); 628 return (0); 629 } 630 631 int 632 elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr, 633 struct Gmod_pnp_match_info *pnp) 634 { 635 char *p; 636 size_t len, offset, pointer_size; 637 int error; 638 639 pointer_size = elf_pointer_size(efile); 640 len = 3 * pointer_size; 641 len = roundup(len, pointer_size); 642 len += 2 * sizeof(int); 643 644 error = elf_read_relocated_data(efile, addr, len, (void **)&p); 645 if (error != 0) 646 return (error); 647 648 memset(pnp, 0, sizeof(*pnp)); 649 offset = 0; 650 pnp->descr = elf_address_from_pointer(efile, p + offset); 651 offset += pointer_size; 652 pnp->bus = elf_address_from_pointer(efile, p + offset); 653 offset += pointer_size; 654 pnp->table = elf_address_from_pointer(efile, p + offset); 655 offset += pointer_size; 656 offset = roundup(offset, pointer_size); 657 pnp->entry_len = elf_int(efile, p + offset); 658 offset += sizeof(int); 659 pnp->num_entry = elf_int(efile, p + offset); 660 free(p); 661 return (0); 662 } 663 664 int 665 elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype, 666 GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest) 667 { 668 return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len, 669 dest)); 670 } 671