2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011 ProFUSION embedded systems
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.
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.
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
28 #include "libkmod-private.h"
31 KMOD_ELF_32
= (1 << 1),
32 KMOD_ELF_64
= (1 << 2),
33 KMOD_ELF_LSB
= (1 << 3),
34 KMOD_ELF_MSB
= (1 << 4)
37 #ifdef WORDS_BIGENDIAN
38 static const enum kmod_elf_class native_endianess
= KMOD_ELF_MSB
;
40 static const enum kmod_elf_class native_endianess
= KMOD_ELF_LSB
;
44 const uint8_t *memory
;
47 enum kmod_elf_class
class;
48 struct kmod_elf_header
{
55 uint16_t section
; /* index of the strings section */
58 uint32_t nameoff
; /* offset in strings itself */
63 //#define ENABLE_ELFDBG 1
65 #if defined(ENABLE_LOGGING) && defined(ENABLE_ELFDBG)
66 #define ELFDBG(elf, ...) \
67 _elf_dbg(elf, __FILE__, __LINE__, __func__, __VA_ARGS__);
69 static inline void _elf_dbg(const struct kmod_elf
*elf
, const char *fname
, unsigned line
, const char *func
, const char *fmt
, ...)
73 fprintf(stderr
, "ELFDBG-%d%c: %s:%u %s() ",
74 (elf
->class & KMOD_ELF_32
) ? 32 : 64,
75 (elf
->class & KMOD_ELF_MSB
) ? 'M' : 'L',
78 vfprintf(stderr
, fmt
, args
);
82 #define ELFDBG(elf, ...)
86 static int elf_identify(const void *memory
, uint64_t size
)
88 const uint8_t *p
= memory
;
91 if (size
<= EI_NIDENT
|| memcmp(p
, ELFMAG
, SELFMAG
) != 0)
94 switch (p
[EI_CLASS
]) {
96 if (size
<= sizeof(Elf32_Ehdr
))
101 if (size
<= sizeof(Elf64_Ehdr
))
103 class |= KMOD_ELF_64
;
109 switch (p
[EI_DATA
]) {
111 class |= KMOD_ELF_LSB
;
114 class |= KMOD_ELF_MSB
;
123 static inline uint64_t elf_get_uint(const struct kmod_elf
*elf
, uint64_t offset
, uint16_t size
)
129 assert(size
<= sizeof(uint64_t));
130 assert(offset
+ size
<= elf
->size
);
131 if (offset
+ size
> elf
->size
) {
132 ELFDBG(elf
, "out of bounds: %"PRIu64
" + %"PRIu16
" = %"PRIu64
"> %"PRIu64
" (ELF size)\n",
133 offset
, size
, offset
+ size
, elf
->size
);
137 p
= elf
->memory
+ offset
;
138 if (elf
->class & KMOD_ELF_MSB
) {
139 for (i
= 0; i
< size
; i
++)
140 ret
= (ret
<< 8) | p
[i
];
142 for (i
= 1; i
<= size
; i
++)
143 ret
= (ret
<< 8) | p
[size
- i
];
146 ELFDBG(elf
, "size=%"PRIu16
" offset=%"PRIu64
" value=%"PRIu64
"\n",
152 static inline int elf_set_uint(struct kmod_elf
*elf
, uint64_t offset
, uint64_t size
, uint64_t value
)
157 ELFDBG(elf
, "size=%"PRIu16
" offset=%"PRIu64
" value=%"PRIu64
" write memory=%p\n",
158 size
, offset
, value
, elf
->changed
);
160 assert(size
<= sizeof(uint64_t));
161 assert(offset
+ size
<= elf
->size
);
162 if (offset
+ size
> elf
->size
) {
163 ELFDBG(elf
, "out of bounds: %"PRIu64
" + %"PRIu16
" = %"PRIu64
"> %"PRIu64
" (ELF size)\n",
164 offset
, size
, offset
+ size
, elf
->size
);
168 if (elf
->changed
== NULL
) {
169 elf
->changed
= malloc(elf
->size
);
170 if (elf
->changed
== NULL
)
172 memcpy(elf
->changed
, elf
->memory
, elf
->size
);
173 elf
->memory
= elf
->changed
;
174 ELFDBG(elf
, "copied memory to allow writing.\n");
177 p
= elf
->changed
+ offset
;
178 if (elf
->class & KMOD_ELF_MSB
) {
179 for (i
= 1; i
<= size
; i
++) {
180 p
[size
- i
] = value
& 0xff;
181 value
= (value
& 0xffffffffffffff00) >> 8;
184 for (i
= 0; i
< size
; i
++) {
186 value
= (value
& 0xffffffffffffff00) >> 8;
193 static inline const void *elf_get_mem(const struct kmod_elf
*elf
, uint64_t offset
)
195 assert(offset
< elf
->size
);
196 if (offset
>= elf
->size
) {
197 ELFDBG(elf
, "out-of-bounds: %"PRIu64
" >= %"PRIu64
" (ELF size)\n",
201 return elf
->memory
+ offset
;
204 static inline const void *elf_get_section_header(const struct kmod_elf
*elf
, uint16_t idx
)
206 assert(idx
!= SHN_UNDEF
);
207 assert(idx
< elf
->header
.section
.count
);
208 if (idx
== SHN_UNDEF
|| idx
>= elf
->header
.section
.count
) {
209 ELFDBG(elf
, "invalid section number: %"PRIu16
", last=%"PRIu16
"\n",
210 idx
, elf
->header
.section
.count
);
213 return elf_get_mem(elf
, elf
->header
.section
.offset
+
214 idx
* elf
->header
.section
.entry_size
);
217 static inline int elf_get_section_info(const struct kmod_elf
*elf
, uint16_t idx
, uint64_t *offset
, uint64_t *size
, uint32_t *nameoff
)
219 const uint8_t *p
= elf_get_section_header(elf
, idx
);
220 uint64_t min_size
, off
= p
- elf
->memory
;
223 ELFDBG(elf
, "no section at %"PRIu16
"\n", idx
);
230 #define READV(field) \
231 elf_get_uint(elf, off + offsetof(typeof(*hdr), field), sizeof(hdr->field))
233 if (elf
->class & KMOD_ELF_32
) {
234 const Elf32_Shdr
*hdr
= (const Elf32_Shdr
*)p
;
235 *size
= READV(sh_size
);
236 *offset
= READV(sh_offset
);
237 *nameoff
= READV(sh_name
);
239 const Elf64_Shdr
*hdr
= (const Elf64_Shdr
*)p
;
240 *size
= READV(sh_size
);
241 *offset
= READV(sh_offset
);
242 *nameoff
= READV(sh_name
);
246 min_size
= *offset
+ *size
;
247 if (min_size
> elf
->size
) {
248 ELFDBG(elf
, "out-of-bounds: %"PRIu64
" >= %"PRIu64
" (ELF size)\n",
249 min_size
, elf
->size
);
253 ELFDBG(elf
, "section=%"PRIu16
" is: offset=%"PRIu64
" size=%"PRIu64
" nameoff=%"PRIu32
"\n",
254 idx
, *offset
, *size
, *nameoff
);
259 static const char *elf_get_strings_section(const struct kmod_elf
*elf
, uint64_t *size
)
261 *size
= elf
->header
.strings
.size
;
262 return elf_get_mem(elf
, elf
->header
.strings
.offset
);
265 struct kmod_elf
*kmod_elf_new(const void *memory
, off_t size
)
267 struct kmod_elf
*elf
;
268 size_t hdr_size
, shdr_size
, min_size
;
271 assert(sizeof(uint16_t) == sizeof(Elf32_Half
));
272 assert(sizeof(uint16_t) == sizeof(Elf64_Half
));
273 assert(sizeof(uint32_t) == sizeof(Elf32_Word
));
274 assert(sizeof(uint32_t) == sizeof(Elf64_Word
));
276 class = elf_identify(memory
, size
);
282 elf
= malloc(sizeof(struct kmod_elf
));
287 elf
->memory
= memory
;
292 #define READV(field) \
293 elf_get_uint(elf, offsetof(typeof(*hdr), field), sizeof(hdr->field))
295 #define LOAD_HEADER \
296 elf->header.section.offset = READV(e_shoff); \
297 elf->header.section.count = READV(e_shnum); \
298 elf->header.section.entry_size = READV(e_shentsize); \
299 elf->header.strings.section = READV(e_shstrndx)
300 if (elf
->class & KMOD_ELF_32
) {
301 const Elf32_Ehdr
*hdr
= elf_get_mem(elf
, 0);
303 hdr_size
= sizeof(Elf32_Ehdr
);
304 shdr_size
= sizeof(Elf32_Shdr
);
306 const Elf64_Ehdr
*hdr
= elf_get_mem(elf
, 0);
308 hdr_size
= sizeof(Elf64_Ehdr
);
309 shdr_size
= sizeof(Elf64_Shdr
);
314 ELFDBG(elf
, "section: offset=%"PRIu64
" count=%"PRIu16
" entry_size=%"PRIu16
" strings index=%"PRIu16
"\n",
315 elf
->header
.section
.offset
,
316 elf
->header
.section
.count
,
317 elf
->header
.section
.entry_size
,
318 elf
->header
.strings
.section
);
320 if (elf
->header
.section
.entry_size
!= shdr_size
) {
321 ELFDBG(elf
, "unexpected section entry size: %"PRIu16
", expected %"PRIu16
"\n",
322 elf
->header
.section
.entry_size
, shdr_size
);
325 min_size
= hdr_size
+ shdr_size
* elf
->header
.section
.count
;
326 if (min_size
>= elf
->size
) {
327 ELFDBG(elf
, "file is too short to hold sections\n");
331 if (elf_get_section_info(elf
, elf
->header
.strings
.section
,
332 &elf
->header
.strings
.offset
,
333 &elf
->header
.strings
.size
,
334 &elf
->header
.strings
.nameoff
) < 0) {
335 ELFDBG(elf
, "could not get strings section\n");
339 const char *s
= elf_get_strings_section(elf
, &slen
);
340 if (slen
== 0 || s
[slen
- 1] != '\0') {
341 ELFDBG(elf
, "strings section does not ends with \\0\n");
354 void kmod_elf_unref(struct kmod_elf
*elf
)
360 const void *kmod_elf_get_memory(const struct kmod_elf
*elf
)
365 static int kmod_elf_get_section(const struct kmod_elf
*elf
, const char *section
, const void **buf
, uint64_t *buf_size
)
368 const char *names
= elf_get_strings_section(elf
, &nameslen
);
374 for (i
= 1; i
< elf
->header
.section
.count
; i
++) {
378 int err
= elf_get_section_info(elf
, i
, &off
, &size
, &nameoff
);
381 if (nameoff
>= nameslen
)
384 if (!streq(section
, n
))
387 *buf
= elf_get_mem(elf
, off
);
395 /* array will be allocated with strings in a single malloc, just free *array */
396 int kmod_elf_get_strings(const struct kmod_elf
*elf
, const char *section
, char ***array
)
407 err
= kmod_elf_get_section(elf
, section
, &buf
, &size
);
412 if (strings
== NULL
|| size
== 0)
415 /* skip zero padding */
416 while (strings
[0] == '\0' && size
> 1) {
424 for (i
= 0, count
= 0; i
< size
; ) {
425 if (strings
[i
] != '\0') {
430 while (strings
[i
] == '\0' && i
< size
)
436 if (strings
[i
- 1] != '\0')
439 *array
= a
= malloc(size
+ 1 + sizeof(char *) * (count
+ 1));
443 s
= (char *)(a
+ count
+ 1);
444 memcpy(s
, strings
, size
);
446 /* make sure the last string is NULL-terminated */
451 for (i
= 0, j
= 1; j
< count
&& i
< size
; ) {
457 while (strings
[i
] == '\0' && i
< size
)
467 /* array will be allocated with strings in a single malloc, just free *array */
468 int kmod_elf_get_modversions(const struct kmod_elf
*elf
, struct kmod_modversion
**array
)
470 size_t off
, offcrc
, slen
;
472 struct kmod_modversion
*a
;
476 struct kmod_modversion32
{
478 char name
[64 - sizeof(uint32_t)];
480 struct kmod_modversion64
{
482 char name
[64 - sizeof(uint64_t)];
484 #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64))
486 assert(sizeof(struct kmod_modversion64
) ==
487 sizeof(struct kmod_modversion32
));
489 if (elf
->class == KMOD_ELF_32
)
490 offcrc
= sizeof(uint32_t);
492 offcrc
= sizeof(uint64_t);
496 err
= kmod_elf_get_section(elf
, "__versions", &buf
, &size
);
500 if (buf
== NULL
|| size
== 0)
503 if (size
% MODVERSION_SEC_SIZE
!= 0)
506 count
= size
/ MODVERSION_SEC_SIZE
;
508 off
= (const uint8_t *)buf
- elf
->memory
;
511 for (i
= 0; i
< count
; i
++, off
+= MODVERSION_SEC_SIZE
) {
512 const char *symbol
= elf_get_mem(elf
, off
+ offcrc
);
514 if (symbol
[0] == '.')
517 slen
+= strlen(symbol
) + 1;
520 *array
= a
= malloc(sizeof(struct kmod_modversion
) * count
+ slen
);
524 itr
= (char *)(a
+ count
);
525 off
= (const uint8_t *)buf
- elf
->memory
;
527 for (i
= 0; i
< count
; i
++, off
+= MODVERSION_SEC_SIZE
) {
528 uint64_t crc
= elf_get_uint(elf
, off
, offcrc
);
529 const char *symbol
= elf_get_mem(elf
, off
+ offcrc
);
532 if (symbol
[0] == '.')
537 symbollen
= strlen(symbol
) + 1;
538 memcpy(itr
, symbol
, symbollen
);
545 int kmod_elf_strip_section(struct kmod_elf
*elf
, const char *section
)
549 int err
= kmod_elf_get_section(elf
, section
, &buf
, &size
);
553 off
= (const uint8_t *)buf
- elf
->memory
;
555 #define WRITEV(field, value) \
556 elf_set_uint(elf, off + offsetof(typeof(*hdr), field), sizeof(hdr->field), value)
557 if (elf
->class & KMOD_ELF_32
) {
558 const Elf32_Shdr
*hdr
= buf
;
559 uint32_t val
= ~(uint32_t)SHF_ALLOC
;
560 return WRITEV(sh_flags
, val
);
562 const Elf64_Shdr
*hdr
= buf
;
563 uint64_t val
= ~(uint64_t)SHF_ALLOC
;
564 return WRITEV(sh_flags
, val
);
569 int kmod_elf_strip_vermagic(struct kmod_elf
*elf
)
576 err
= kmod_elf_get_section(elf
, ".modinfo", &buf
, &size
);
580 if (strings
== NULL
|| size
== 0)
583 /* skip zero padding */
584 while (strings
[0] == '\0' && size
> 1) {
591 for (i
= 0; i
< size
; i
++) {
595 if (strings
[i
] == '\0')
601 len
= sizeof("vermagic=") - 1;
604 if (strncmp(s
, "vermagic=", len
) != 0) {
609 off
= (const uint8_t *)s
- elf
->memory
;
611 if (elf
->changed
== NULL
) {
612 elf
->changed
= malloc(elf
->size
);
613 if (elf
->changed
== NULL
)
615 memcpy(elf
->changed
, elf
->memory
, elf
->size
);
616 elf
->memory
= elf
->changed
;
617 ELFDBG(elf
, "copied memory to allow writing.\n");
621 ELFDBG(elf
, "clear .modinfo vermagic \"%s\" (%zd bytes)\n",
623 memset(elf
->changed
+ off
, '\0', len
);
627 ELFDBG(elf
, "no vermagic found in .modinfo\n");
632 static int kmod_elf_get_symbols_symtab(const struct kmod_elf
*elf
, struct kmod_modversion
**array
)
634 uint64_t i
, last
, size
;
638 struct kmod_modversion
*a
;
643 err
= kmod_elf_get_section(elf
, "__ksymtab_strings", &buf
, &size
);
647 if (strings
== NULL
|| size
== 0)
650 /* skip zero padding */
651 while (strings
[0] == '\0' && size
> 1) {
659 for (i
= 0, count
= 0; i
< size
; i
++) {
660 if (strings
[i
] == '\0') {
669 if (strings
[i
- 1] != '\0')
672 *array
= a
= malloc(size
+ 1 + sizeof(struct kmod_modversion
) * count
);
676 itr
= (char *)(a
+ count
);
678 for (i
= 0, count
= 0; i
< size
; i
++) {
679 if (strings
[i
] == '\0') {
680 size_t slen
= i
- last
;
686 a
[count
].symbol
= itr
;
687 memcpy(itr
, strings
+ last
, slen
);
694 if (strings
[i
- 1] != '\0') {
695 size_t slen
= i
- last
;
697 a
[count
].symbol
= itr
;
698 memcpy(itr
, strings
+ last
, slen
);
707 /* array will be allocated with strings in a single malloc, just free *array */
708 int kmod_elf_get_symbols(const struct kmod_elf
*elf
, struct kmod_modversion
**array
)
710 static const char crc_str
[] = "__crc_";
711 static const size_t crc_strlen
= sizeof(crc_str
) - 1;
712 uint64_t strtablen
, symtablen
, str_off
, sym_off
;
713 const void *strtab
, *symtab
;
714 struct kmod_modversion
*a
;
717 int i
, count
, symcount
, err
;
719 err
= kmod_elf_get_section(elf
, ".strtab", &strtab
, &strtablen
);
721 ELFDBG(elf
, "no .strtab found.\n");
725 err
= kmod_elf_get_section(elf
, ".symtab", &symtab
, &symtablen
);
727 ELFDBG(elf
, "no .symtab found.\n");
731 if (elf
->class & KMOD_ELF_32
)
732 symlen
= sizeof(Elf32_Sym
);
734 symlen
= sizeof(Elf64_Sym
);
736 if (symtablen
% symlen
!= 0) {
737 ELFDBG(elf
, "unexpected .symtab of length %"PRIu64
", not multiple of %"PRIu64
" as expected.\n", symtablen
, symlen
);
741 symcount
= symtablen
/ symlen
;
744 str_off
= (const uint8_t *)strtab
- elf
->memory
;
745 sym_off
= (const uint8_t *)symtab
- elf
->memory
+ symlen
;
746 for (i
= 1; i
< symcount
; i
++, sym_off
+= symlen
) {
750 #define READV(field) \
751 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
753 if (elf
->class & KMOD_ELF_32
) {
755 name_off
= READV(st_name
);
758 name_off
= READV(st_name
);
761 if (name_off
>= strtablen
) {
762 ELFDBG(elf
, ".strtab is %"PRIu64
" bytes, but .symtab entry %d wants to access offset %"PRIu32
".\n", strtablen
, i
, name_off
);
766 name
= elf_get_mem(elf
, str_off
+ name_off
);
768 if (strncmp(name
, crc_str
, crc_strlen
) != 0)
770 slen
+= strlen(name
+ crc_strlen
) + 1;
777 *array
= a
= malloc(sizeof(struct kmod_modversion
) * count
+ slen
);
781 itr
= (char *)(a
+ count
);
783 str_off
= (const uint8_t *)strtab
- elf
->memory
;
784 sym_off
= (const uint8_t *)symtab
- elf
->memory
+ symlen
;
785 for (i
= 1; i
< symcount
; i
++, sym_off
+= symlen
) {
790 #define READV(field) \
791 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
793 if (elf
->class & KMOD_ELF_32
) {
795 name_off
= READV(st_name
);
796 crc
= READV(st_value
);
799 name_off
= READV(st_name
);
800 crc
= READV(st_value
);
803 name
= elf_get_mem(elf
, str_off
+ name_off
);
804 if (strncmp(name
, crc_str
, crc_strlen
) != 0)
809 a
[count
].symbol
= itr
;
811 memcpy(itr
, name
, slen
);
819 ELFDBG(elf
, "Falling back to __ksymtab_strings!\n");
820 return kmod_elf_get_symbols_symtab(elf
, array
);