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