• 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 
kmod_elf_resolve_crc(const struct kmod_elf * elf,uint64_t crc,uint16_t shndx)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 */
kmod_elf_get_symbols(const struct kmod_elf * elf,struct kmod_modversion ** 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 
kmod_elf_crc_find(const struct kmod_elf * elf,const void * versions,uint64_t versionslen,const char * name,uint64_t * crc)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 */
kmod_elf_get_dependency_symbols(const struct kmod_elf * elf,struct kmod_modversion ** 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