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
_elf_dbg(const struct kmod_elf * elf,const char * fname,unsigned line,const char * func,const char * fmt,...)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
elf_identify(const void * memory,uint64_t size)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
elf_get_uint(const struct kmod_elf * elf,uint64_t offset,uint16_t size)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
elf_set_uint(struct kmod_elf * elf,uint64_t offset,uint64_t size,uint64_t value)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
elf_get_mem(const struct kmod_elf * elf,uint64_t offset)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
elf_get_section_header(const struct kmod_elf * elf,uint16_t idx)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
elf_get_section_info(const struct kmod_elf * elf,uint16_t idx,uint64_t * offset,uint64_t * size,uint32_t * nameoff)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
elf_get_strings_section(const struct kmod_elf * elf,uint64_t * size)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
kmod_elf_new(const void * memory,off_t size)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
kmod_elf_unref(struct kmod_elf * elf)362 void kmod_elf_unref(struct kmod_elf *elf)
363 {
364 free(elf->changed);
365 free(elf);
366 }
367
kmod_elf_get_memory(const struct kmod_elf * elf)368 const void *kmod_elf_get_memory(const struct kmod_elf *elf)
369 {
370 return elf->memory;
371 }
372
elf_find_section(const struct kmod_elf * elf,const char * section)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
kmod_elf_get_section(const struct kmod_elf * elf,const char * section,const void ** buf,uint64_t * buf_size)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 */
kmod_elf_get_strings(const struct kmod_elf * elf,const char * section,char *** 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 */
kmod_elf_get_modversions(const struct kmod_elf * elf,struct kmod_modversion ** 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
kmod_elf_strip_section(struct kmod_elf * elf,const char * section)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
kmod_elf_strip_vermagic(struct kmod_elf * elf)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
kmod_elf_get_symbols_symtab(const struct kmod_elf * elf,struct kmod_modversion ** array)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
kmod_symbol_bind_from_elf(uint8_t elf_value)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
kmod_elf_resolve_crc(const struct kmod_elf * elf,uint64_t crc,uint16_t shndx)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 */
kmod_elf_get_symbols(const struct kmod_elf * elf,struct kmod_modversion ** 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
kmod_elf_crc_find(const struct kmod_elf * elf,const void * versions,uint64_t versionslen,const char * name,uint64_t * crc)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 */
kmod_elf_get_dependency_symbols(const struct kmod_elf * elf,struct kmod_modversion ** 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