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 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 }
   1215