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 static uint64_t kmod_elf_resolve_crc(const struct kmod_elf *elf, uint64_t crc, uint16_t shndx) 751 { 752 int err; 753 uint64_t off, size; 754 uint32_t nameoff; 755 756 if (shndx == SHN_ABS || shndx == SHN_UNDEF) 757 return crc; 758 759 err = elf_get_section_info(elf, shndx, &off, &size, &nameoff); 760 if (err < 0) { 761 ELFDBG("Cound not find section index %"PRIu16" for crc", shndx); 762 return (uint64_t)-1; 763 } 764 765 if (crc > (size - sizeof(uint32_t))) { 766 ELFDBG("CRC offset %"PRIu64" is too big, section %"PRIu16" size is %"PRIu64"\n", 767 crc, shndx, size); 768 return (uint64_t)-1; 769 } 770 771 crc = elf_get_uint(elf, off + crc, sizeof(uint32_t)); 772 return crc; 773 } 774 775 /* array will be allocated with strings in a single malloc, just free *array */ 776 int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array) 777 { 778 static const char crc_str[] = "__crc_"; 779 static const size_t crc_strlen = sizeof(crc_str) - 1; 780 uint64_t strtablen, symtablen, str_off, sym_off; 781 const void *strtab, *symtab; 782 struct kmod_modversion *a; 783 char *itr; 784 size_t slen, symlen; 785 int i, count, symcount, err; 786 787 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen); 788 if (err < 0) { 789 ELFDBG(elf, "no .strtab found.\n"); 790 goto fallback; 791 } 792 793 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen); 794 if (err < 0) { 795 ELFDBG(elf, "no .symtab found.\n"); 796 goto fallback; 797 } 798 799 if (elf->class & KMOD_ELF_32) 800 symlen = sizeof(Elf32_Sym); 801 else 802 symlen = sizeof(Elf64_Sym); 803 804 if (symtablen % symlen != 0) { 805 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen); 806 goto fallback; 807 } 808 809 symcount = symtablen / symlen; 810 count = 0; 811 slen = 0; 812 str_off = (const uint8_t *)strtab - elf->memory; 813 sym_off = (const uint8_t *)symtab - elf->memory + symlen; 814 for (i = 1; i < symcount; i++, sym_off += symlen) { 815 const char *name; 816 uint32_t name_off; 817 818 #define READV(field) \ 819 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\ 820 sizeof(s->field)) 821 if (elf->class & KMOD_ELF_32) { 822 Elf32_Sym *s; 823 name_off = READV(st_name); 824 } else { 825 Elf64_Sym *s; 826 name_off = READV(st_name); 827 } 828 #undef READV 829 if (name_off >= strtablen) { 830 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off); 831 goto fallback; 832 } 833 834 name = elf_get_mem(elf, str_off + name_off); 835 836 if (strncmp(name, crc_str, crc_strlen) != 0) 837 continue; 838 slen += strlen(name + crc_strlen) + 1; 839 count++; 840 } 841 842 if (count == 0) 843 goto fallback; 844 845 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen); 846 if (*array == NULL) 847 return -errno; 848 849 itr = (char *)(a + count); 850 count = 0; 851 str_off = (const uint8_t *)strtab - elf->memory; 852 sym_off = (const uint8_t *)symtab - elf->memory + symlen; 853 for (i = 1; i < symcount; i++, sym_off += symlen) { 854 const char *name; 855 uint32_t name_off; 856 uint64_t crc; 857 uint8_t info, bind; 858 uint16_t shndx; 859 860 #define READV(field) \ 861 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\ 862 sizeof(s->field)) 863 if (elf->class & KMOD_ELF_32) { 864 Elf32_Sym *s; 865 name_off = READV(st_name); 866 crc = READV(st_value); 867 info = READV(st_info); 868 shndx = READV(st_shndx); 869 } else { 870 Elf64_Sym *s; 871 name_off = READV(st_name); 872 crc = READV(st_value); 873 info = READV(st_info); 874 shndx = READV(st_shndx); 875 } 876 #undef READV 877 name = elf_get_mem(elf, str_off + name_off); 878 if (strncmp(name, crc_str, crc_strlen) != 0) 879 continue; 880 name += crc_strlen; 881 882 if (elf->class & KMOD_ELF_32) 883 bind = ELF32_ST_BIND(info); 884 else 885 bind = ELF64_ST_BIND(info); 886 887 a[count].crc = kmod_elf_resolve_crc(elf, crc, shndx); 888 a[count].bind = kmod_symbol_bind_from_elf(bind); 889 a[count].symbol = itr; 890 slen = strlen(name); 891 memcpy(itr, name, slen); 892 itr[slen] = '\0'; 893 itr += slen + 1; 894 count++; 895 } 896 return count; 897 898 fallback: 899 ELFDBG(elf, "Falling back to __ksymtab_strings!\n"); 900 return kmod_elf_get_symbols_symtab(elf, array); 901 } 902 903 static int kmod_elf_crc_find(const struct kmod_elf *elf, const void *versions, uint64_t versionslen, const char *name, uint64_t *crc) 904 { 905 size_t verlen, crclen, off; 906 uint64_t i; 907 908 if (elf->class & KMOD_ELF_32) { 909 struct kmod_modversion32 *mv; 910 verlen = sizeof(*mv); 911 crclen = sizeof(mv->crc); 912 } else { 913 struct kmod_modversion64 *mv; 914 verlen = sizeof(*mv); 915 crclen = sizeof(mv->crc); 916 } 917 918 off = (const uint8_t *)versions - elf->memory; 919 for (i = 0; i < versionslen; i += verlen) { 920 const char *symbol = elf_get_mem(elf, off + i + crclen); 921 if (!streq(name, symbol)) 922 continue; 923 *crc = elf_get_uint(elf, off + i, crclen); 924 return i / verlen; 925 } 926 927 ELFDBG(elf, "could not find crc for symbol '%s'\n", name); 928 *crc = 0; 929 return -1; 930 } 931 932 /* from module-init-tools:elfops_core.c */ 933 #ifndef STT_REGISTER 934 #define STT_REGISTER 13 /* Global register reserved to app. */ 935 #endif 936 937 /* array will be allocated with strings in a single malloc, just free *array */ 938 int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array) 939 { 940 uint64_t versionslen, strtablen, symtablen, str_off, sym_off, ver_off; 941 const void *versions, *strtab, *symtab; 942 struct kmod_modversion *a; 943 char *itr; 944 size_t slen, verlen, symlen, crclen; 945 int i, count, symcount, vercount, err; 946 bool handle_register_symbols; 947 uint8_t *visited_versions; 948 uint64_t *symcrcs; 949 950 err = kmod_elf_get_section(elf, "__versions", &versions, &versionslen); 951 if (err < 0) { 952 versions = NULL; 953 versionslen = 0; 954 verlen = 0; 955 crclen = 0; 956 } else { 957 if (elf->class & KMOD_ELF_32) { 958 struct kmod_modversion32 *mv; 959 verlen = sizeof(*mv); 960 crclen = sizeof(mv->crc); 961 } else { 962 struct kmod_modversion64 *mv; 963 verlen = sizeof(*mv); 964 crclen = sizeof(mv->crc); 965 } 966 if (versionslen % verlen != 0) { 967 ELFDBG(elf, "unexpected __versions of length %"PRIu64", not multiple of %zd as expected.\n", versionslen, verlen); 968 versions = NULL; 969 versionslen = 0; 970 } 971 } 972 973 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen); 974 if (err < 0) { 975 ELFDBG(elf, "no .strtab found.\n"); 976 return -EINVAL; 977 } 978 979 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen); 980 if (err < 0) { 981 ELFDBG(elf, "no .symtab found.\n"); 982 return -EINVAL; 983 } 984 985 if (elf->class & KMOD_ELF_32) 986 symlen = sizeof(Elf32_Sym); 987 else 988 symlen = sizeof(Elf64_Sym); 989 990 if (symtablen % symlen != 0) { 991 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen); 992 return -EINVAL; 993 } 994 995 if (versionslen == 0) { 996 vercount = 0; 997 visited_versions = NULL; 998 } else { 999 vercount = versionslen / verlen; 1000 visited_versions = calloc(vercount, sizeof(uint8_t)); 1001 if (visited_versions == NULL) 1002 return -ENOMEM; 1003 } 1004 1005 handle_register_symbols = (elf->header.machine == EM_SPARC || 1006 elf->header.machine == EM_SPARCV9); 1007 1008 symcount = symtablen / symlen; 1009 count = 0; 1010 slen = 0; 1011 str_off = (const uint8_t *)strtab - elf->memory; 1012 sym_off = (const uint8_t *)symtab - elf->memory + symlen; 1013 1014 symcrcs = calloc(symcount, sizeof(uint64_t)); 1015 if (symcrcs == NULL) { 1016 free(visited_versions); 1017 return -ENOMEM; 1018 } 1019 1020 for (i = 1; i < symcount; i++, sym_off += symlen) { 1021 const char *name; 1022 uint64_t crc; 1023 uint32_t name_off; 1024 uint16_t secidx; 1025 uint8_t info; 1026 int idx; 1027 1028 #define READV(field) \ 1029 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\ 1030 sizeof(s->field)) 1031 if (elf->class & KMOD_ELF_32) { 1032 Elf32_Sym *s; 1033 name_off = READV(st_name); 1034 secidx = READV(st_shndx); 1035 info = READV(st_info); 1036 } else { 1037 Elf64_Sym *s; 1038 name_off = READV(st_name); 1039 secidx = READV(st_shndx); 1040 info = READV(st_info); 1041 } 1042 #undef READV 1043 if (secidx != SHN_UNDEF) 1044 continue; 1045 1046 if (handle_register_symbols) { 1047 uint8_t type; 1048 if (elf->class & KMOD_ELF_32) 1049 type = ELF32_ST_TYPE(info); 1050 else 1051 type = ELF64_ST_TYPE(info); 1052 1053 /* Not really undefined: sparc gcc 3.3 creates 1054 * U references when you have global asm 1055 * variables, to avoid anyone else misusing 1056 * them. 1057 */ 1058 if (type == STT_REGISTER) 1059 continue; 1060 } 1061 1062 if (name_off >= strtablen) { 1063 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off); 1064 free(visited_versions); 1065 free(symcrcs); 1066 return -EINVAL; 1067 } 1068 1069 name = elf_get_mem(elf, str_off + name_off); 1070 if (name[0] == '\0') { 1071 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i); 1072 continue; 1073 } 1074 1075 slen += strlen(name) + 1; 1076 count++; 1077 1078 idx = kmod_elf_crc_find(elf, versions, versionslen, name, &crc); 1079 if (idx >= 0 && visited_versions != NULL) 1080 visited_versions[idx] = 1; 1081 symcrcs[i] = crc; 1082 } 1083 1084 if (visited_versions != NULL) { 1085 /* module_layout/struct_module are not visited, but needed */ 1086 ver_off = (const uint8_t *)versions - elf->memory; 1087 for (i = 0; i < vercount; i++) { 1088 if (visited_versions[i] == 0) { 1089 const char *name; 1090 name = elf_get_mem(elf, ver_off + i * verlen + crclen); 1091 slen += strlen(name) + 1; 1092 1093 count++; 1094 } 1095 } 1096 } 1097 1098 if (count == 0) { 1099 free(visited_versions); 1100 free(symcrcs); 1101 *array = NULL; 1102 return 0; 1103 } 1104 1105 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen); 1106 if (*array == NULL) { 1107 free(visited_versions); 1108 free(symcrcs); 1109 return -errno; 1110 } 1111 1112 itr = (char *)(a + count); 1113 count = 0; 1114 str_off = (const uint8_t *)strtab - elf->memory; 1115 sym_off = (const uint8_t *)symtab - elf->memory + symlen; 1116 for (i = 1; i < symcount; i++, sym_off += symlen) { 1117 const char *name; 1118 uint64_t crc; 1119 uint32_t name_off; 1120 uint16_t secidx; 1121 uint8_t info, bind; 1122 1123 #define READV(field) \ 1124 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\ 1125 sizeof(s->field)) 1126 if (elf->class & KMOD_ELF_32) { 1127 Elf32_Sym *s; 1128 name_off = READV(st_name); 1129 secidx = READV(st_shndx); 1130 info = READV(st_info); 1131 } else { 1132 Elf64_Sym *s; 1133 name_off = READV(st_name); 1134 secidx = READV(st_shndx); 1135 info = READV(st_info); 1136 } 1137 #undef READV 1138 if (secidx != SHN_UNDEF) 1139 continue; 1140 1141 if (handle_register_symbols) { 1142 uint8_t type; 1143 if (elf->class & KMOD_ELF_32) 1144 type = ELF32_ST_TYPE(info); 1145 else 1146 type = ELF64_ST_TYPE(info); 1147 1148 /* Not really undefined: sparc gcc 3.3 creates 1149 * U references when you have global asm 1150 * variables, to avoid anyone else misusing 1151 * them. 1152 */ 1153 if (type == STT_REGISTER) 1154 continue; 1155 } 1156 1157 name = elf_get_mem(elf, str_off + name_off); 1158 if (name[0] == '\0') { 1159 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i); 1160 continue; 1161 } 1162 1163 if (elf->class & KMOD_ELF_32) 1164 bind = ELF32_ST_BIND(info); 1165 else 1166 bind = ELF64_ST_BIND(info); 1167 if (bind == STB_WEAK) 1168 bind = KMOD_SYMBOL_WEAK; 1169 else 1170 bind = KMOD_SYMBOL_UNDEF; 1171 1172 slen = strlen(name); 1173 crc = symcrcs[i]; 1174 1175 a[count].crc = crc; 1176 a[count].bind = bind; 1177 a[count].symbol = itr; 1178 memcpy(itr, name, slen); 1179 itr[slen] = '\0'; 1180 itr += slen + 1; 1181 1182 count++; 1183 } 1184 1185 free(symcrcs); 1186 1187 if (visited_versions == NULL) 1188 return count; 1189 1190 /* add unvisited (module_layout/struct_module) */ 1191 ver_off = (const uint8_t *)versions - elf->memory; 1192 for (i = 0; i < vercount; i++) { 1193 const char *name; 1194 uint64_t crc; 1195 1196 if (visited_versions[i] != 0) 1197 continue; 1198 1199 name = elf_get_mem(elf, ver_off + i * verlen + crclen); 1200 slen = strlen(name); 1201 crc = elf_get_uint(elf, ver_off + i * verlen, crclen); 1202 1203 a[count].crc = crc; 1204 a[count].bind = KMOD_SYMBOL_UNDEF; 1205 a[count].symbol = itr; 1206 memcpy(itr, name, slen); 1207 itr[slen] = '\0'; 1208 itr += slen + 1; 1209 1210 count++; 1211 } 1212 free(visited_versions); 1213 return count; 1214 } 1215