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