• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
_elf_dbg(const struct kmod_elf * elf,const char * fname,unsigned line,const char * func,const char * fmt,...)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 
elf_identify(const void * memory,uint64_t size)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 
elf_get_uint(const struct kmod_elf * elf,uint64_t offset,uint16_t size)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 
elf_set_uint(struct kmod_elf * elf,uint64_t offset,uint64_t size,uint64_t value)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 
elf_get_mem(const struct kmod_elf * elf,uint64_t offset)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 
elf_get_section_header(const struct kmod_elf * elf,uint16_t idx)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 
elf_get_section_info(const struct kmod_elf * elf,uint16_t idx,uint64_t * offset,uint64_t * size,uint32_t * nameoff)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 
elf_get_strings_section(const struct kmod_elf * elf,uint64_t * size)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 
kmod_elf_new(const void * memory,off_t size)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 
kmod_elf_unref(struct kmod_elf * elf)362 void kmod_elf_unref(struct kmod_elf *elf)
363 {
364 	free(elf->changed);
365 	free(elf);
366 }
367 
kmod_elf_get_memory(const struct kmod_elf * elf)368 const void *kmod_elf_get_memory(const struct kmod_elf *elf)
369 {
370 	return elf->memory;
371 }
372 
elf_find_section(const struct kmod_elf * elf,const char * section)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 
kmod_elf_get_section(const struct kmod_elf * elf,const char * section,const void ** buf,uint64_t * buf_size)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 */
kmod_elf_get_strings(const struct kmod_elf * elf,const char * section,char *** 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 */
kmod_elf_get_modversions(const struct kmod_elf * elf,struct kmod_modversion ** 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 
kmod_elf_strip_section(struct kmod_elf * elf,const char * section)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 
kmod_elf_strip_vermagic(struct kmod_elf * elf)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 
kmod_elf_get_symbols_symtab(const struct kmod_elf * elf,struct kmod_modversion ** array)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 
kmod_symbol_bind_from_elf(uint8_t elf_value)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 */
kmod_elf_get_symbols(const struct kmod_elf * elf,struct kmod_modversion ** 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 
kmod_elf_crc_find(const struct kmod_elf * elf,const void * versions,uint64_t versionslen,const char * name,uint64_t * crc)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 */
kmod_elf_get_dependency_symbols(const struct kmod_elf * elf,struct kmod_modversion ** 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