1 /* 2 * libkmod - interface to kernel module operations 3 * 4 * Copyright (C) 2011-2013 ProFUSION embedded systems 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <assert.h> 21 #include <elf.h> 22 #include <errno.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include <shared/util.h> 27 28 #include "libkmod.h" 29 #include "libkmod-internal.h" 30 31 enum kmod_elf_class { 32 KMOD_ELF_32 = (1 << 1), 33 KMOD_ELF_64 = (1 << 2), 34 KMOD_ELF_LSB = (1 << 3), 35 KMOD_ELF_MSB = (1 << 4) 36 }; 37 38 /* as defined in module-init-tools */ 39 struct kmod_modversion32 { 40 uint32_t crc; 41 char name[64 - sizeof(uint32_t)]; 42 }; 43 44 struct kmod_modversion64 { 45 uint64_t crc; 46 char name[64 - sizeof(uint64_t)]; 47 }; 48 49 struct kmod_elf { 50 const uint8_t *memory; 51 uint8_t *changed; 52 uint64_t size; 53 enum kmod_elf_class class; 54 struct kmod_elf_header { 55 struct { 56 uint64_t offset; 57 uint16_t count; 58 uint16_t entry_size; 59 } section; 60 struct { 61 uint16_t section; /* index of the strings section */ 62 uint64_t size; 63 uint64_t offset; 64 uint32_t nameoff; /* offset in strings itself */ 65 } strings; 66 uint16_t machine; 67 } header; 68 }; 69 70 //#define ENABLE_ELFDBG 1 71 72 #if defined(ENABLE_LOGGING) && defined(ENABLE_ELFDBG) 73 #define ELFDBG(elf, ...) \ 74 _elf_dbg(elf, __FILE__, __LINE__, __func__, __VA_ARGS__); 75 76 static inline void _elf_dbg(const struct kmod_elf *elf, const char *fname, unsigned line, const char *func, const char *fmt, ...) 77 { 78 va_list args; 79 80 fprintf(stderr, "ELFDBG-%d%c: %s:%u %s() ", 81 (elf->class & KMOD_ELF_32) ? 32 : 64, 82 (elf->class & KMOD_ELF_MSB) ? 'M' : 'L', 83 fname, line, func); 84 va_start(args, fmt); 85 vfprintf(stderr, fmt, args); 86 va_end(args); 87 } 88 #else 89 #define ELFDBG(elf, ...) 90 #endif 91 92 93 static int elf_identify(const void *memory, uint64_t size) 94 { 95 const uint8_t *p = memory; 96 int class = 0; 97 98 if (size <= EI_NIDENT || memcmp(p, ELFMAG, SELFMAG) != 0) 99 return -ENOEXEC; 100 101 switch (p[EI_CLASS]) { 102 case ELFCLASS32: 103 if (size <= sizeof(Elf32_Ehdr)) 104 return -EINVAL; 105 class |= KMOD_ELF_32; 106 break; 107 case ELFCLASS64: 108 if (size <= sizeof(Elf64_Ehdr)) 109 return -EINVAL; 110 class |= KMOD_ELF_64; 111 break; 112 default: 113 return -EINVAL; 114 } 115 116 switch (p[EI_DATA]) { 117 case ELFDATA2LSB: 118 class |= KMOD_ELF_LSB; 119 break; 120 case ELFDATA2MSB: 121 class |= KMOD_ELF_MSB; 122 break; 123 default: 124 return -EINVAL; 125 } 126 127 return class; 128 } 129 130 static inline uint64_t elf_get_uint(const struct kmod_elf *elf, uint64_t offset, uint16_t size) 131 { 132 const uint8_t *p; 133 uint64_t ret = 0; 134 size_t i; 135 136 assert(size <= sizeof(uint64_t)); 137 assert(offset + size <= elf->size); 138 if (offset + size > elf->size) { 139 ELFDBG(elf, "out of bounds: %"PRIu64" + %"PRIu16" = %"PRIu64"> %"PRIu64" (ELF size)\n", 140 offset, size, offset + size, elf->size); 141 return (uint64_t)-1; 142 } 143 144 p = elf->memory + offset; 145 if (elf->class & KMOD_ELF_MSB) { 146 for (i = 0; i < size; i++) 147 ret = (ret << 8) | p[i]; 148 } else { 149 for (i = 1; i <= size; i++) 150 ret = (ret << 8) | p[size - i]; 151 } 152 153 ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64"\n", 154 size, offset, ret); 155 156 return ret; 157 } 158 159 static inline int elf_set_uint(struct kmod_elf *elf, uint64_t offset, uint64_t size, uint64_t value) 160 { 161 uint8_t *p; 162 size_t i; 163 164 ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64" write memory=%p\n", 165 size, offset, value, elf->changed); 166 167 assert(size <= sizeof(uint64_t)); 168 assert(offset + size <= elf->size); 169 if (offset + size > elf->size) { 170 ELFDBG(elf, "out of bounds: %"PRIu64" + %"PRIu16" = %"PRIu64"> %"PRIu64" (ELF size)\n", 171 offset, size, offset + size, elf->size); 172 return -1; 173 } 174 175 if (elf->changed == NULL) { 176 elf->changed = malloc(elf->size); 177 if (elf->changed == NULL) 178 return -errno; 179 memcpy(elf->changed, elf->memory, elf->size); 180 elf->memory = elf->changed; 181 ELFDBG(elf, "copied memory to allow writing.\n"); 182 } 183 184 p = elf->changed + offset; 185 if (elf->class & KMOD_ELF_MSB) { 186 for (i = 1; i <= size; i++) { 187 p[size - i] = value & 0xff; 188 value = (value & 0xffffffffffffff00) >> 8; 189 } 190 } else { 191 for (i = 0; i < size; i++) { 192 p[i] = value & 0xff; 193 value = (value & 0xffffffffffffff00) >> 8; 194 } 195 } 196 197 return 0; 198 } 199 200 static inline const void *elf_get_mem(const struct kmod_elf *elf, uint64_t offset) 201 { 202 assert(offset < elf->size); 203 if (offset >= elf->size) { 204 ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n", 205 offset, elf->size); 206 return NULL; 207 } 208 return elf->memory + offset; 209 } 210 211 static inline const void *elf_get_section_header(const struct kmod_elf *elf, uint16_t idx) 212 { 213 assert(idx != SHN_UNDEF); 214 assert(idx < elf->header.section.count); 215 if (idx == SHN_UNDEF || idx >= elf->header.section.count) { 216 ELFDBG(elf, "invalid section number: %"PRIu16", last=%"PRIu16"\n", 217 idx, elf->header.section.count); 218 return NULL; 219 } 220 return elf_get_mem(elf, elf->header.section.offset + 221 (uint64_t)(idx * elf->header.section.entry_size)); 222 } 223 224 static inline int elf_get_section_info(const struct kmod_elf *elf, uint16_t idx, uint64_t *offset, uint64_t *size, uint32_t *nameoff) 225 { 226 const uint8_t *p = elf_get_section_header(elf, idx); 227 uint64_t min_size, off = p - elf->memory; 228 229 if (p == NULL) { 230 ELFDBG(elf, "no section at %"PRIu16"\n", idx); 231 *offset = 0; 232 *size = 0; 233 *nameoff = 0; 234 return -EINVAL; 235 } 236 237 #define READV(field) \ 238 elf_get_uint(elf, off + offsetof(typeof(*hdr), field), sizeof(hdr->field)) 239 240 if (elf->class & KMOD_ELF_32) { 241 const Elf32_Shdr *hdr _unused_ = (const Elf32_Shdr *)p; 242 *size = READV(sh_size); 243 *offset = READV(sh_offset); 244 *nameoff = READV(sh_name); 245 } else { 246 const Elf64_Shdr *hdr _unused_ = (const Elf64_Shdr *)p; 247 *size = READV(sh_size); 248 *offset = READV(sh_offset); 249 *nameoff = READV(sh_name); 250 } 251 #undef READV 252 253 if (addu64_overflow(*offset, *size, &min_size) 254 || min_size > elf->size) { 255 ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n", 256 min_size, elf->size); 257 return -EINVAL; 258 } 259 260 ELFDBG(elf, "section=%"PRIu16" is: offset=%"PRIu64" size=%"PRIu64" nameoff=%"PRIu32"\n", 261 idx, *offset, *size, *nameoff); 262 263 return 0; 264 } 265 266 static const char *elf_get_strings_section(const struct kmod_elf *elf, uint64_t *size) 267 { 268 *size = elf->header.strings.size; 269 return elf_get_mem(elf, elf->header.strings.offset); 270 } 271 272 struct kmod_elf *kmod_elf_new(const void *memory, off_t size) 273 { 274 struct kmod_elf *elf; 275 uint64_t min_size; 276 size_t shdrs_size, shdr_size; 277 int class; 278 279 assert_cc(sizeof(uint16_t) == sizeof(Elf32_Half)); 280 assert_cc(sizeof(uint16_t) == sizeof(Elf64_Half)); 281 assert_cc(sizeof(uint32_t) == sizeof(Elf32_Word)); 282 assert_cc(sizeof(uint32_t) == sizeof(Elf64_Word)); 283 284 class = elf_identify(memory, size); 285 if (class < 0) { 286 errno = -class; 287 return NULL; 288 } 289 290 elf = malloc(sizeof(struct kmod_elf)); 291 if (elf == NULL) { 292 return NULL; 293 } 294 295 elf->memory = memory; 296 elf->changed = NULL; 297 elf->size = size; 298 elf->class = class; 299 300 #define READV(field) \ 301 elf_get_uint(elf, offsetof(typeof(*hdr), field), sizeof(hdr->field)) 302 303 #define LOAD_HEADER \ 304 elf->header.section.offset = READV(e_shoff); \ 305 elf->header.section.count = READV(e_shnum); \ 306 elf->header.section.entry_size = READV(e_shentsize); \ 307 elf->header.strings.section = READV(e_shstrndx); \ 308 elf->header.machine = READV(e_machine) 309 if (elf->class & KMOD_ELF_32) { 310 const Elf32_Ehdr *hdr _unused_ = elf_get_mem(elf, 0); 311 LOAD_HEADER; 312 shdr_size = sizeof(Elf32_Shdr); 313 } else { 314 const Elf64_Ehdr *hdr _unused_ = elf_get_mem(elf, 0); 315 LOAD_HEADER; 316 shdr_size = sizeof(Elf64_Shdr); 317 } 318 #undef LOAD_HEADER 319 #undef READV 320 321 ELFDBG(elf, "section: offset=%"PRIu64" count=%"PRIu16" entry_size=%"PRIu16" strings index=%"PRIu16"\n", 322 elf->header.section.offset, 323 elf->header.section.count, 324 elf->header.section.entry_size, 325 elf->header.strings.section); 326 327 if (elf->header.section.entry_size != shdr_size) { 328 ELFDBG(elf, "unexpected section entry size: %"PRIu16", expected %"PRIu16"\n", 329 elf->header.section.entry_size, shdr_size); 330 goto invalid; 331 } 332 shdrs_size = shdr_size * elf->header.section.count; 333 if (addu64_overflow(shdrs_size, elf->header.section.offset, &min_size) 334 || min_size > elf->size) { 335 ELFDBG(elf, "file is too short to hold sections\n"); 336 goto invalid; 337 } 338 339 if (elf_get_section_info(elf, elf->header.strings.section, 340 &elf->header.strings.offset, 341 &elf->header.strings.size, 342 &elf->header.strings.nameoff) < 0) { 343 ELFDBG(elf, "could not get strings section\n"); 344 goto invalid; 345 } else { 346 uint64_t slen; 347 const char *s = elf_get_strings_section(elf, &slen); 348 if (slen == 0 || s[slen - 1] != '\0') { 349 ELFDBG(elf, "strings section does not ends with \\0\n"); 350 goto invalid; 351 } 352 } 353 354 return elf; 355 356 invalid: 357 free(elf); 358 errno = EINVAL; 359 return NULL; 360 } 361 362 void kmod_elf_unref(struct kmod_elf *elf) 363 { 364 free(elf->changed); 365 free(elf); 366 } 367 368 const void *kmod_elf_get_memory(const struct kmod_elf *elf) 369 { 370 return elf->memory; 371 } 372 373 static int elf_find_section(const struct kmod_elf *elf, const char *section) 374 { 375 uint64_t nameslen; 376 const char *names = elf_get_strings_section(elf, &nameslen); 377 uint16_t i; 378 379 for (i = 1; i < elf->header.section.count; i++) { 380 uint64_t off, size; 381 uint32_t nameoff; 382 const char *n; 383 int err = elf_get_section_info(elf, i, &off, &size, &nameoff); 384 if (err < 0) 385 continue; 386 if (nameoff >= nameslen) 387 continue; 388 n = names + nameoff; 389 if (!streq(section, n)) 390 continue; 391 392 return i; 393 } 394 395 return -ENOENT; 396 } 397 398 int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, const void **buf, uint64_t *buf_size) 399 { 400 uint64_t nameslen; 401 const char *names = elf_get_strings_section(elf, &nameslen); 402 uint16_t i; 403 404 *buf = NULL; 405 *buf_size = 0; 406 407 for (i = 1; i < elf->header.section.count; i++) { 408 uint64_t off, size; 409 uint32_t nameoff; 410 const char *n; 411 int err = elf_get_section_info(elf, i, &off, &size, &nameoff); 412 if (err < 0) 413 continue; 414 if (nameoff >= nameslen) 415 continue; 416 n = names + nameoff; 417 if (!streq(section, n)) 418 continue; 419 420 *buf = elf_get_mem(elf, off); 421 *buf_size = size; 422 return 0; 423 } 424 425 return -ENOENT; 426 } 427 428 /* array will be allocated with strings in a single malloc, just free *array */ 429 int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array) 430 { 431 size_t i, j, count; 432 uint64_t size; 433 const void *buf; 434 const char *strings; 435 char *s, **a; 436 int err; 437 438 *array = NULL; 439 440 err = kmod_elf_get_section(elf, section, &buf, &size); 441 if (err < 0) 442 return err; 443 444 strings = buf; 445 if (strings == NULL || size == 0) 446 return 0; 447 448 /* skip zero padding */ 449 while (strings[0] == '\0' && size > 1) { 450 strings++; 451 size--; 452 } 453 454 if (size <= 1) 455 return 0; 456 457 for (i = 0, count = 0; i < size; ) { 458 if (strings[i] != '\0') { 459 i++; 460 continue; 461 } 462 463 while (strings[i] == '\0' && i < size) 464 i++; 465 466 count++; 467 } 468 469 if (strings[i - 1] != '\0') 470 count++; 471 472 *array = a = malloc(size + 1 + sizeof(char *) * (count + 1)); 473 if (*array == NULL) 474 return -errno; 475 476 s = (char *)(a + count + 1); 477 memcpy(s, strings, size); 478 479 /* make sure the last string is NULL-terminated */ 480 s[size] = '\0'; 481 a[count] = NULL; 482 a[0] = s; 483 484 for (i = 0, j = 1; j < count && i < size; ) { 485 if (s[i] != '\0') { 486 i++; 487 continue; 488 } 489 490 while (strings[i] == '\0' && i < size) 491 i++; 492 493 a[j] = &s[i]; 494 j++; 495 } 496 497 return count; 498 } 499 500 /* array will be allocated with strings in a single malloc, just free *array */ 501 int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array) 502 { 503 size_t off, offcrc, slen; 504 uint64_t size; 505 struct kmod_modversion *a; 506 const void *buf; 507 char *itr; 508 int i, count, err; 509 #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64)) 510 511 assert_cc(sizeof(struct kmod_modversion64) == 512 sizeof(struct kmod_modversion32)); 513 514 if (elf->class & KMOD_ELF_32) 515 offcrc = sizeof(uint32_t); 516 else 517 offcrc = sizeof(uint64_t); 518 519 *array = NULL; 520 521 err = kmod_elf_get_section(elf, "__versions", &buf, &size); 522 if (err < 0) 523 return err; 524 525 if (buf == NULL || size == 0) 526 return 0; 527 528 if (size % MODVERSION_SEC_SIZE != 0) 529 return -EINVAL; 530 531 count = size / MODVERSION_SEC_SIZE; 532 533 off = (const uint8_t *)buf - elf->memory; 534 slen = 0; 535 536 for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) { 537 const char *symbol = elf_get_mem(elf, off + offcrc); 538 539 if (symbol[0] == '.') 540 symbol++; 541 542 slen += strlen(symbol) + 1; 543 } 544 545 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen); 546 if (*array == NULL) 547 return -errno; 548 549 itr = (char *)(a + count); 550 off = (const uint8_t *)buf - elf->memory; 551 552 for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) { 553 uint64_t crc = elf_get_uint(elf, off, offcrc); 554 const char *symbol = elf_get_mem(elf, off + offcrc); 555 size_t symbollen; 556 557 if (symbol[0] == '.') 558 symbol++; 559 560 a[i].crc = crc; 561 a[i].bind = KMOD_SYMBOL_UNDEF; 562 a[i].symbol = itr; 563 symbollen = strlen(symbol) + 1; 564 memcpy(itr, symbol, symbollen); 565 itr += symbollen; 566 } 567 568 return count; 569 } 570 571 int kmod_elf_strip_section(struct kmod_elf *elf, const char *section) 572 { 573 uint64_t off, size; 574 const void *buf; 575 int idx = elf_find_section(elf, section); 576 uint64_t val; 577 578 if (idx < 0) 579 return idx; 580 581 buf = elf_get_section_header(elf, idx); 582 off = (const uint8_t *)buf - elf->memory; 583 584 if (elf->class & KMOD_ELF_32) { 585 off += offsetof(Elf32_Shdr, sh_flags); 586 size = sizeof(((Elf32_Shdr *)buf)->sh_flags); 587 } else { 588 off += offsetof(Elf64_Shdr, sh_flags); 589 size = sizeof(((Elf64_Shdr *)buf)->sh_flags); 590 } 591 592 val = elf_get_uint(elf, off, size); 593 val &= ~(uint64_t)SHF_ALLOC; 594 595 return elf_set_uint(elf, off, size, val); 596 } 597 598 int kmod_elf_strip_vermagic(struct kmod_elf *elf) 599 { 600 uint64_t i, size; 601 const void *buf; 602 const char *strings; 603 int err; 604 605 err = kmod_elf_get_section(elf, ".modinfo", &buf, &size); 606 if (err < 0) 607 return err; 608 strings = buf; 609 if (strings == NULL || size == 0) 610 return 0; 611 612 /* skip zero padding */ 613 while (strings[0] == '\0' && size > 1) { 614 strings++; 615 size--; 616 } 617 if (size <= 1) 618 return 0; 619 620 for (i = 0; i < size; i++) { 621 const char *s; 622 size_t off, len; 623 624 if (strings[i] == '\0') 625 continue; 626 if (i + 1 >= size) 627 continue; 628 629 s = strings + i; 630 len = sizeof("vermagic=") - 1; 631 if (i + len >= size) 632 continue; 633 if (strncmp(s, "vermagic=", len) != 0) { 634 i += strlen(s); 635 continue; 636 } 637 off = (const uint8_t *)s - elf->memory; 638 639 if (elf->changed == NULL) { 640 elf->changed = malloc(elf->size); 641 if (elf->changed == NULL) 642 return -errno; 643 memcpy(elf->changed, elf->memory, elf->size); 644 elf->memory = elf->changed; 645 ELFDBG(elf, "copied memory to allow writing.\n"); 646 } 647 648 len = strlen(s); 649 ELFDBG(elf, "clear .modinfo vermagic \"%s\" (%zd bytes)\n", 650 s, len); 651 memset(elf->changed + off, '\0', len); 652 return 0; 653 } 654 655 ELFDBG(elf, "no vermagic found in .modinfo\n"); 656 return -ENOENT; 657 } 658 659 660 static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_modversion **array) 661 { 662 uint64_t i, last, size; 663 const void *buf; 664 const char *strings; 665 char *itr; 666 struct kmod_modversion *a; 667 int count, err; 668 669 *array = NULL; 670 671 err = kmod_elf_get_section(elf, "__ksymtab_strings", &buf, &size); 672 if (err < 0) 673 return err; 674 strings = buf; 675 if (strings == NULL || size == 0) 676 return 0; 677 678 /* skip zero padding */ 679 while (strings[0] == '\0' && size > 1) { 680 strings++; 681 size--; 682 } 683 if (size <= 1) 684 return 0; 685 686 last = 0; 687 for (i = 0, count = 0; i < size; i++) { 688 if (strings[i] == '\0') { 689 if (last == i) { 690 last = i + 1; 691 continue; 692 } 693 count++; 694 last = i + 1; 695 } 696 } 697 if (strings[i - 1] != '\0') 698 count++; 699 700 *array = a = malloc(size + 1 + sizeof(struct kmod_modversion) * count); 701 if (*array == NULL) 702 return -errno; 703 704 itr = (char *)(a + count); 705 last = 0; 706 for (i = 0, count = 0; i < size; i++) { 707 if (strings[i] == '\0') { 708 size_t slen = i - last; 709 if (last == i) { 710 last = i + 1; 711 continue; 712 } 713 a[count].crc = 0; 714 a[count].bind = KMOD_SYMBOL_GLOBAL; 715 a[count].symbol = itr; 716 memcpy(itr, strings + last, slen); 717 itr[slen] = '\0'; 718 itr += slen + 1; 719 count++; 720 last = i + 1; 721 } 722 } 723 if (strings[i - 1] != '\0') { 724 size_t slen = i - last; 725 a[count].crc = 0; 726 a[count].bind = KMOD_SYMBOL_GLOBAL; 727 a[count].symbol = itr; 728 memcpy(itr, strings + last, slen); 729 itr[slen] = '\0'; 730 count++; 731 } 732 733 return count; 734 } 735 736 static inline uint8_t kmod_symbol_bind_from_elf(uint8_t elf_value) 737 { 738 switch (elf_value) { 739 case STB_LOCAL: 740 return KMOD_SYMBOL_LOCAL; 741 case STB_GLOBAL: 742 return KMOD_SYMBOL_GLOBAL; 743 case STB_WEAK: 744 return KMOD_SYMBOL_WEAK; 745 default: 746 return KMOD_SYMBOL_NONE; 747 } 748 } 749 750 /* array will be allocated with strings in a single malloc, just free *array */ 751 int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array) 752 { 753 static const char crc_str[] = "__crc_"; 754 static const size_t crc_strlen = sizeof(crc_str) - 1; 755 uint64_t strtablen, symtablen, str_off, sym_off; 756 const void *strtab, *symtab; 757 struct kmod_modversion *a; 758 char *itr; 759 size_t slen, symlen; 760 int i, count, symcount, err; 761 762 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen); 763 if (err < 0) { 764 ELFDBG(elf, "no .strtab found.\n"); 765 goto fallback; 766 } 767 768 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen); 769 if (err < 0) { 770 ELFDBG(elf, "no .symtab found.\n"); 771 goto fallback; 772 } 773 774 if (elf->class & KMOD_ELF_32) 775 symlen = sizeof(Elf32_Sym); 776 else 777 symlen = sizeof(Elf64_Sym); 778 779 if (symtablen % symlen != 0) { 780 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen); 781 goto fallback; 782 } 783 784 symcount = symtablen / symlen; 785 count = 0; 786 slen = 0; 787 str_off = (const uint8_t *)strtab - elf->memory; 788 sym_off = (const uint8_t *)symtab - elf->memory + symlen; 789 for (i = 1; i < symcount; i++, sym_off += symlen) { 790 const char *name; 791 uint32_t name_off; 792 793 #define READV(field) \ 794 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\ 795 sizeof(s->field)) 796 if (elf->class & KMOD_ELF_32) { 797 Elf32_Sym *s; 798 name_off = READV(st_name); 799 } else { 800 Elf64_Sym *s; 801 name_off = READV(st_name); 802 } 803 #undef READV 804 if (name_off >= strtablen) { 805 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off); 806 goto fallback; 807 } 808 809 name = elf_get_mem(elf, str_off + name_off); 810 811 if (strncmp(name, crc_str, crc_strlen) != 0) 812 continue; 813 slen += strlen(name + crc_strlen) + 1; 814 count++; 815 } 816 817 if (count == 0) 818 goto fallback; 819 820 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen); 821 if (*array == NULL) 822 return -errno; 823 824 itr = (char *)(a + count); 825 count = 0; 826 str_off = (const uint8_t *)strtab - elf->memory; 827 sym_off = (const uint8_t *)symtab - elf->memory + symlen; 828 for (i = 1; i < symcount; i++, sym_off += symlen) { 829 const char *name; 830 uint32_t name_off; 831 uint64_t crc; 832 uint8_t info, bind; 833 834 #define READV(field) \ 835 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\ 836 sizeof(s->field)) 837 if (elf->class & KMOD_ELF_32) { 838 Elf32_Sym *s; 839 name_off = READV(st_name); 840 crc = READV(st_value); 841 info = READV(st_info); 842 } else { 843 Elf64_Sym *s; 844 name_off = READV(st_name); 845 crc = READV(st_value); 846 info = READV(st_info); 847 } 848 #undef READV 849 name = elf_get_mem(elf, str_off + name_off); 850 if (strncmp(name, crc_str, crc_strlen) != 0) 851 continue; 852 name += crc_strlen; 853 854 if (elf->class & KMOD_ELF_32) 855 bind = ELF32_ST_BIND(info); 856 else 857 bind = ELF64_ST_BIND(info); 858 859 a[count].crc = crc; 860 a[count].bind = kmod_symbol_bind_from_elf(bind); 861 a[count].symbol = itr; 862 slen = strlen(name); 863 memcpy(itr, name, slen); 864 itr[slen] = '\0'; 865 itr += slen + 1; 866 count++; 867 } 868 return count; 869 870 fallback: 871 ELFDBG(elf, "Falling back to __ksymtab_strings!\n"); 872 return kmod_elf_get_symbols_symtab(elf, array); 873 } 874 875 static int kmod_elf_crc_find(const struct kmod_elf *elf, const void *versions, uint64_t versionslen, const char *name, uint64_t *crc) 876 { 877 size_t verlen, crclen, off; 878 uint64_t i; 879 880 if (elf->class & KMOD_ELF_32) { 881 struct kmod_modversion32 *mv; 882 verlen = sizeof(*mv); 883 crclen = sizeof(mv->crc); 884 } else { 885 struct kmod_modversion64 *mv; 886 verlen = sizeof(*mv); 887 crclen = sizeof(mv->crc); 888 } 889 890 off = (const uint8_t *)versions - elf->memory; 891 for (i = 0; i < versionslen; i += verlen) { 892 const char *symbol = elf_get_mem(elf, off + i + crclen); 893 if (!streq(name, symbol)) 894 continue; 895 *crc = elf_get_uint(elf, off + i, crclen); 896 return i / verlen; 897 } 898 899 ELFDBG(elf, "could not find crc for symbol '%s'\n", name); 900 *crc = 0; 901 return -1; 902 } 903 904 /* from module-init-tools:elfops_core.c */ 905 #ifndef STT_REGISTER 906 #define STT_REGISTER 13 /* Global register reserved to app. */ 907 #endif 908 909 /* array will be allocated with strings in a single malloc, just free *array */ 910 int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array) 911 { 912 uint64_t versionslen, strtablen, symtablen, str_off, sym_off, ver_off; 913 const void *versions, *strtab, *symtab; 914 struct kmod_modversion *a; 915 char *itr; 916 size_t slen, verlen, symlen, crclen; 917 int i, count, symcount, vercount, err; 918 bool handle_register_symbols; 919 uint8_t *visited_versions; 920 uint64_t *symcrcs; 921 922 err = kmod_elf_get_section(elf, "__versions", &versions, &versionslen); 923 if (err < 0) { 924 versions = NULL; 925 versionslen = 0; 926 verlen = 0; 927 crclen = 0; 928 } else { 929 if (elf->class & KMOD_ELF_32) { 930 struct kmod_modversion32 *mv; 931 verlen = sizeof(*mv); 932 crclen = sizeof(mv->crc); 933 } else { 934 struct kmod_modversion64 *mv; 935 verlen = sizeof(*mv); 936 crclen = sizeof(mv->crc); 937 } 938 if (versionslen % verlen != 0) { 939 ELFDBG(elf, "unexpected __versions of length %"PRIu64", not multiple of %zd as expected.\n", versionslen, verlen); 940 versions = NULL; 941 versionslen = 0; 942 } 943 } 944 945 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen); 946 if (err < 0) { 947 ELFDBG(elf, "no .strtab found.\n"); 948 return -EINVAL; 949 } 950 951 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen); 952 if (err < 0) { 953 ELFDBG(elf, "no .symtab found.\n"); 954 return -EINVAL; 955 } 956 957 if (elf->class & KMOD_ELF_32) 958 symlen = sizeof(Elf32_Sym); 959 else 960 symlen = sizeof(Elf64_Sym); 961 962 if (symtablen % symlen != 0) { 963 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen); 964 return -EINVAL; 965 } 966 967 if (versionslen == 0) { 968 vercount = 0; 969 visited_versions = NULL; 970 } else { 971 vercount = versionslen / verlen; 972 visited_versions = calloc(vercount, sizeof(uint8_t)); 973 if (visited_versions == NULL) 974 return -ENOMEM; 975 } 976 977 handle_register_symbols = (elf->header.machine == EM_SPARC || 978 elf->header.machine == EM_SPARCV9); 979 980 symcount = symtablen / symlen; 981 count = 0; 982 slen = 0; 983 str_off = (const uint8_t *)strtab - elf->memory; 984 sym_off = (const uint8_t *)symtab - elf->memory + symlen; 985 986 symcrcs = calloc(symcount, sizeof(uint64_t)); 987 if (symcrcs == NULL) { 988 free(visited_versions); 989 return -ENOMEM; 990 } 991 992 for (i = 1; i < symcount; i++, sym_off += symlen) { 993 const char *name; 994 uint64_t crc; 995 uint32_t name_off; 996 uint16_t secidx; 997 uint8_t info; 998 int idx; 999 1000 #define READV(field) \ 1001 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\ 1002 sizeof(s->field)) 1003 if (elf->class & KMOD_ELF_32) { 1004 Elf32_Sym *s; 1005 name_off = READV(st_name); 1006 secidx = READV(st_shndx); 1007 info = READV(st_info); 1008 } else { 1009 Elf64_Sym *s; 1010 name_off = READV(st_name); 1011 secidx = READV(st_shndx); 1012 info = READV(st_info); 1013 } 1014 #undef READV 1015 if (secidx != SHN_UNDEF) 1016 continue; 1017 1018 if (handle_register_symbols) { 1019 uint8_t type; 1020 if (elf->class & KMOD_ELF_32) 1021 type = ELF32_ST_TYPE(info); 1022 else 1023 type = ELF64_ST_TYPE(info); 1024 1025 /* Not really undefined: sparc gcc 3.3 creates 1026 * U references when you have global asm 1027 * variables, to avoid anyone else misusing 1028 * them. 1029 */ 1030 if (type == STT_REGISTER) 1031 continue; 1032 } 1033 1034 if (name_off >= strtablen) { 1035 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off); 1036 free(visited_versions); 1037 free(symcrcs); 1038 return -EINVAL; 1039 } 1040 1041 name = elf_get_mem(elf, str_off + name_off); 1042 if (name[0] == '\0') { 1043 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i); 1044 continue; 1045 } 1046 1047 slen += strlen(name) + 1; 1048 count++; 1049 1050 idx = kmod_elf_crc_find(elf, versions, versionslen, name, &crc); 1051 if (idx >= 0 && visited_versions != NULL) 1052 visited_versions[idx] = 1; 1053 symcrcs[i] = crc; 1054 } 1055 1056 if (visited_versions != NULL) { 1057 /* module_layout/struct_module are not visited, but needed */ 1058 ver_off = (const uint8_t *)versions - elf->memory; 1059 for (i = 0; i < vercount; i++) { 1060 if (visited_versions[i] == 0) { 1061 const char *name; 1062 name = elf_get_mem(elf, ver_off + i * verlen + crclen); 1063 slen += strlen(name) + 1; 1064 1065 count++; 1066 } 1067 } 1068 } 1069 1070 if (count == 0) { 1071 free(visited_versions); 1072 free(symcrcs); 1073 *array = NULL; 1074 return 0; 1075 } 1076 1077 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen); 1078 if (*array == NULL) { 1079 free(visited_versions); 1080 free(symcrcs); 1081 return -errno; 1082 } 1083 1084 itr = (char *)(a + count); 1085 count = 0; 1086 str_off = (const uint8_t *)strtab - elf->memory; 1087 sym_off = (const uint8_t *)symtab - elf->memory + symlen; 1088 for (i = 1; i < symcount; i++, sym_off += symlen) { 1089 const char *name; 1090 uint64_t crc; 1091 uint32_t name_off; 1092 uint16_t secidx; 1093 uint8_t info, bind; 1094 1095 #define READV(field) \ 1096 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\ 1097 sizeof(s->field)) 1098 if (elf->class & KMOD_ELF_32) { 1099 Elf32_Sym *s; 1100 name_off = READV(st_name); 1101 secidx = READV(st_shndx); 1102 info = READV(st_info); 1103 } else { 1104 Elf64_Sym *s; 1105 name_off = READV(st_name); 1106 secidx = READV(st_shndx); 1107 info = READV(st_info); 1108 } 1109 #undef READV 1110 if (secidx != SHN_UNDEF) 1111 continue; 1112 1113 if (handle_register_symbols) { 1114 uint8_t type; 1115 if (elf->class & KMOD_ELF_32) 1116 type = ELF32_ST_TYPE(info); 1117 else 1118 type = ELF64_ST_TYPE(info); 1119 1120 /* Not really undefined: sparc gcc 3.3 creates 1121 * U references when you have global asm 1122 * variables, to avoid anyone else misusing 1123 * them. 1124 */ 1125 if (type == STT_REGISTER) 1126 continue; 1127 } 1128 1129 name = elf_get_mem(elf, str_off + name_off); 1130 if (name[0] == '\0') { 1131 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i); 1132 continue; 1133 } 1134 1135 if (elf->class & KMOD_ELF_32) 1136 bind = ELF32_ST_BIND(info); 1137 else 1138 bind = ELF64_ST_BIND(info); 1139 if (bind == STB_WEAK) 1140 bind = KMOD_SYMBOL_WEAK; 1141 else 1142 bind = KMOD_SYMBOL_UNDEF; 1143 1144 slen = strlen(name); 1145 crc = symcrcs[i]; 1146 1147 a[count].crc = crc; 1148 a[count].bind = bind; 1149 a[count].symbol = itr; 1150 memcpy(itr, name, slen); 1151 itr[slen] = '\0'; 1152 itr += slen + 1; 1153 1154 count++; 1155 } 1156 1157 free(symcrcs); 1158 1159 if (visited_versions == NULL) 1160 return count; 1161 1162 /* add unvisited (module_layout/struct_module) */ 1163 ver_off = (const uint8_t *)versions - elf->memory; 1164 for (i = 0; i < vercount; i++) { 1165 const char *name; 1166 uint64_t crc; 1167 1168 if (visited_versions[i] != 0) 1169 continue; 1170 1171 name = elf_get_mem(elf, ver_off + i * verlen + crclen); 1172 slen = strlen(name); 1173 crc = elf_get_uint(elf, ver_off + i * verlen, crclen); 1174 1175 a[count].crc = crc; 1176 a[count].bind = KMOD_SYMBOL_UNDEF; 1177 a[count].symbol = itr; 1178 memcpy(itr, name, slen); 1179 itr[slen] = '\0'; 1180 itr += slen + 1; 1181 1182 count++; 1183 } 1184 free(visited_versions); 1185 return count; 1186 } 1187