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 "kldelf.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_raw_string(struct elf_file *efile, off_t offset, char *dst, size_t len) 202 { 203 ssize_t nread; 204 205 nread = pread(efile->ef_fd, dst, len, offset); 206 if (nread == -1) 207 return (errno); 208 if (nread == 0) 209 return (EIO); 210 211 /* A short read is ok so long as the data contains a terminator. */ 212 if (strnlen(dst, nread) == nread) 213 return (EFAULT); 214 215 return (0); 216 } 217 218 int 219 elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len, 220 void **out) 221 { 222 Elf_Data dst, src; 223 void *buf; 224 int error; 225 226 buf = malloc(len); 227 if (buf == NULL) 228 return (ENOMEM); 229 230 error = elf_read_raw_data(efile, offset, buf, len); 231 if (error != 0) { 232 free(buf); 233 return (error); 234 } 235 236 memset(&dst, 0, sizeof(dst)); 237 memset(&src, 0, sizeof(src)); 238 239 src.d_buf = buf; 240 src.d_size = len; 241 src.d_type = type; 242 src.d_version = efile->ef_hdr.e_version; 243 244 dst.d_buf = buf; 245 dst.d_size = len; 246 dst.d_version = EV_CURRENT; 247 248 if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) == 249 NULL) { 250 free(buf); 251 return (ENXIO); 252 } 253 254 if (dst.d_size != len) 255 warnx("elf_read_data: translation of type %u size mismatch", 256 type); 257 258 *out = buf; 259 return (0); 260 } 261 262 int 263 elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len, 264 void **buf) 265 { 266 int error; 267 void *p; 268 269 p = malloc(len); 270 if (p == NULL) 271 return (ENOMEM); 272 error = EF_SEG_READ_REL(efile, address, len, p); 273 if (error != 0) { 274 free(p); 275 return (error); 276 } 277 *buf = p; 278 return (0); 279 } 280 281 int 282 elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp) 283 { 284 GElf_Phdr *phdr; 285 size_t nphdr, i; 286 int error; 287 288 if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1) 289 return (EFTYPE); 290 291 phdr = calloc(nphdr, sizeof(*phdr)); 292 if (phdr == NULL) 293 return (ENOMEM); 294 295 for (i = 0; i < nphdr; i++) { 296 if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) { 297 error = EFTYPE; 298 goto out; 299 } 300 } 301 302 *nphdrp = nphdr; 303 *phdrp = phdr; 304 return (0); 305 out: 306 free(phdr); 307 return (error); 308 } 309 310 int 311 elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp) 312 { 313 GElf_Shdr *shdr; 314 Elf_Scn *scn; 315 size_t nshdr, i; 316 int error; 317 318 if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1) 319 return (EFTYPE); 320 321 shdr = calloc(nshdr, sizeof(*shdr)); 322 if (shdr == NULL) 323 return (ENOMEM); 324 325 for (i = 0; i < nshdr; i++) { 326 scn = elf_getscn(efile->ef_elf, i); 327 if (scn == NULL) { 328 error = EFTYPE; 329 goto out; 330 } 331 if (gelf_getshdr(scn, &shdr[i]) == NULL) { 332 error = EFTYPE; 333 goto out; 334 } 335 } 336 337 *nshdrp = nshdr; 338 *shdrp = shdr; 339 return (0); 340 out: 341 free(shdr); 342 return (error); 343 } 344 345 int 346 elf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp, 347 GElf_Dyn **dynp) 348 { 349 GElf_Shdr shdr; 350 Elf_Scn *scn; 351 Elf_Data *data; 352 GElf_Dyn *dyn; 353 long i, ndyn; 354 355 scn = elf_getscn(efile->ef_elf, section_index); 356 if (scn == NULL) 357 return (EINVAL); 358 if (gelf_getshdr(scn, &shdr) == NULL) 359 return (EINVAL); 360 data = elf_getdata(scn, NULL); 361 if (data == NULL) 362 return (EINVAL); 363 364 ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size); 365 dyn = calloc(ndyn, sizeof(*dyn)); 366 if (dyn == NULL) 367 return (ENOMEM); 368 369 for (i = 0; i < ndyn; i++) { 370 if (gelf_getdyn(data, i, &dyn[i]) == NULL) { 371 free(dyn); 372 return (EINVAL); 373 } 374 } 375 376 *ndynp = ndyn; 377 *dynp = dyn; 378 return (0); 379 } 380 381 int 382 elf_read_symbols(struct elf_file *efile, int section_index, size_t *nsymp, 383 GElf_Sym **symp) 384 { 385 GElf_Shdr shdr; 386 Elf_Scn *scn; 387 Elf_Data *data; 388 GElf_Sym *sym; 389 size_t i, nsym; 390 391 scn = elf_getscn(efile->ef_elf, section_index); 392 if (scn == NULL) 393 return (EINVAL); 394 if (gelf_getshdr(scn, &shdr) == NULL) 395 return (EINVAL); 396 data = elf_getdata(scn, NULL); 397 if (data == NULL) 398 return (EINVAL); 399 400 nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size); 401 sym = calloc(nsym, sizeof(*sym)); 402 if (sym == NULL) 403 return (ENOMEM); 404 405 for (i = 0; i < nsym; i++) { 406 if (gelf_getsym(data, i, &sym[i]) == NULL) { 407 free(sym); 408 return (EINVAL); 409 } 410 } 411 412 *nsymp = nsym; 413 *symp = sym; 414 return (0); 415 } 416 417 int 418 elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr, 419 long *strcnt, char **strtab) 420 { 421 int error; 422 423 if (shdr->sh_type != SHT_STRTAB) 424 return (EINVAL); 425 error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size, 426 (void **)strtab); 427 if (error != 0) 428 return (error); 429 *strcnt = shdr->sh_size; 430 return (0); 431 } 432 433 int 434 elf_read_rel(struct elf_file *efile, int section_index, long *nrelp, 435 GElf_Rel **relp) 436 { 437 GElf_Shdr shdr; 438 Elf_Scn *scn; 439 Elf_Data *data; 440 GElf_Rel *rel; 441 long i, nrel; 442 443 scn = elf_getscn(efile->ef_elf, section_index); 444 if (scn == NULL) 445 return (EINVAL); 446 if (gelf_getshdr(scn, &shdr) == NULL) 447 return (EINVAL); 448 data = elf_getdata(scn, NULL); 449 if (data == NULL) 450 return (EINVAL); 451 452 nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size); 453 rel = calloc(nrel, sizeof(*rel)); 454 if (rel == NULL) 455 return (ENOMEM); 456 457 for (i = 0; i < nrel; i++) { 458 if (gelf_getrel(data, i, &rel[i]) == NULL) { 459 free(rel); 460 return (EINVAL); 461 } 462 } 463 464 *nrelp = nrel; 465 *relp = rel; 466 return (0); 467 } 468 469 int 470 elf_read_rela(struct elf_file *efile, int section_index, long *nrelap, 471 GElf_Rela **relap) 472 { 473 GElf_Shdr shdr; 474 Elf_Scn *scn; 475 Elf_Data *data; 476 GElf_Rela *rela; 477 long i, nrela; 478 479 scn = elf_getscn(efile->ef_elf, section_index); 480 if (scn == NULL) 481 return (EINVAL); 482 if (gelf_getshdr(scn, &shdr) == NULL) 483 return (EINVAL); 484 data = elf_getdata(scn, NULL); 485 if (data == NULL) 486 return (EINVAL); 487 488 nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size); 489 rela = calloc(nrela, sizeof(*rela)); 490 if (rela == NULL) 491 return (ENOMEM); 492 493 for (i = 0; i < nrela; i++) { 494 if (gelf_getrela(data, i, &rela[i]) == NULL) { 495 free(rela); 496 return (EINVAL); 497 } 498 } 499 500 *nrelap = nrela; 501 *relap = rela; 502 return (0); 503 } 504 505 size_t 506 elf_pointer_size(struct elf_file *efile) 507 { 508 return (efile->ef_pointer_size); 509 } 510 511 int 512 elf_int(struct elf_file *efile, const void *p) 513 { 514 if (elf_encoding(efile) == ELFDATA2LSB) 515 return (le32dec(p)); 516 else 517 return (be32dec(p)); 518 } 519 520 GElf_Addr 521 elf_address_from_pointer(struct elf_file *efile, const void *p) 522 { 523 switch (elf_class(efile)) { 524 case ELFCLASS32: 525 if (elf_encoding(efile) == ELFDATA2LSB) 526 return (le32dec(p)); 527 else 528 return (be32dec(p)); 529 case ELFCLASS64: 530 if (elf_encoding(efile) == ELFDATA2LSB) 531 return (le64dec(p)); 532 else 533 return (be64dec(p)); 534 default: 535 __unreachable(); 536 } 537 } 538 539 int 540 elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst, 541 size_t len) 542 { 543 return (EF_SEG_READ_STRING(efile, address, len, dst)); 544 } 545 546 int 547 elf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp, 548 long *countp) 549 { 550 GElf_Addr *buf, start, stop; 551 char *p; 552 void *raw; 553 long i, count; 554 int error; 555 556 error = EF_LOOKUP_SET(efile, name, &start, &stop, &count); 557 if (error != 0) 558 return (error); 559 560 error = elf_read_relocated_data(efile, start, 561 count * elf_pointer_size(efile), &raw); 562 if (error != 0) 563 return (error); 564 565 buf = calloc(count, sizeof(*buf)); 566 if (buf == NULL) { 567 free(raw); 568 return (ENOMEM); 569 } 570 571 p = raw; 572 for (i = 0; i < count; i++) { 573 buf[i] = elf_address_from_pointer(efile, p); 574 p += elf_pointer_size(efile); 575 } 576 free(raw); 577 578 *bufp = buf; 579 *countp = count; 580 return (0); 581 } 582 583 int 584 elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr, 585 struct Gmod_depend *mdp) 586 { 587 int *p; 588 int error; 589 590 error = elf_read_relocated_data(efile, addr, sizeof(int) * 3, 591 (void **)&p); 592 if (error != 0) 593 return (error); 594 595 memset(mdp, 0, sizeof(*mdp)); 596 mdp->md_ver_minimum = elf_int(efile, p); 597 mdp->md_ver_preferred = elf_int(efile, p + 1); 598 mdp->md_ver_maximum = elf_int(efile, p + 2); 599 free(p); 600 return (0); 601 } 602 603 int 604 elf_read_mod_version(struct elf_file *efile, GElf_Addr addr, 605 struct Gmod_version *mdv) 606 { 607 int error, value; 608 609 error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value); 610 if (error != 0) 611 return (error); 612 613 memset(mdv, 0, sizeof(*mdv)); 614 mdv->mv_version = elf_int(efile, &value); 615 return (0); 616 } 617 618 int 619 elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr, 620 struct Gmod_metadata *md) 621 { 622 char *p; 623 size_t len, offset, pointer_size; 624 int error; 625 626 pointer_size = elf_pointer_size(efile); 627 len = 2 * sizeof(int); 628 len = roundup(len, pointer_size); 629 len += 2 * pointer_size; 630 631 error = elf_read_relocated_data(efile, addr, len, (void **)&p); 632 if (error != 0) 633 return (error); 634 635 memset(md, 0, sizeof(*md)); 636 offset = 0; 637 md->md_version = elf_int(efile, p + offset); 638 offset += sizeof(int); 639 md->md_type = elf_int(efile, p + offset); 640 offset += sizeof(int); 641 offset = roundup(offset, pointer_size); 642 md->md_data = elf_address_from_pointer(efile, p + offset); 643 offset += pointer_size; 644 md->md_cval = elf_address_from_pointer(efile, p + offset); 645 free(p); 646 return (0); 647 } 648 649 int 650 elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr, 651 struct Gmod_pnp_match_info *pnp) 652 { 653 char *p; 654 size_t len, offset, pointer_size; 655 int error; 656 657 pointer_size = elf_pointer_size(efile); 658 len = 3 * pointer_size; 659 len = roundup(len, pointer_size); 660 len += 2 * sizeof(int); 661 662 error = elf_read_relocated_data(efile, addr, len, (void **)&p); 663 if (error != 0) 664 return (error); 665 666 memset(pnp, 0, sizeof(*pnp)); 667 offset = 0; 668 pnp->descr = elf_address_from_pointer(efile, p + offset); 669 offset += pointer_size; 670 pnp->bus = elf_address_from_pointer(efile, p + offset); 671 offset += pointer_size; 672 pnp->table = elf_address_from_pointer(efile, p + offset); 673 offset += pointer_size; 674 offset = roundup(offset, pointer_size); 675 pnp->entry_len = elf_int(efile, p + offset); 676 offset += sizeof(int); 677 pnp->num_entry = elf_int(efile, p + offset); 678 free(p); 679 return (0); 680 } 681 682 int 683 elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype, 684 GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest) 685 { 686 return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len, 687 dest)); 688 } 689 690 int 691 elf_lookup_symbol(struct elf_file *efile, const char *name, GElf_Sym **sym, 692 bool see_local) 693 { 694 return (EF_LOOKUP_SYMBOL(efile, name, sym, see_local)); 695 } 696