gitignore: ignore release files
[platform/upstream/kmod.git] / libkmod / libkmod-elf.c
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 }