xref: /aosp_15_r20/external/kmod/libkmod/libkmod-elf.c (revision cc4ad7da8cefe208cb129ac2aa9a357c7c72deb2)
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 	if (!memory) {
285 		errno = -EINVAL;
286 		return NULL;
287 	}
288 
289 	class = elf_identify(memory, size);
290 	if (class < 0) {
291 		errno = -class;
292 		return NULL;
293 	}
294 
295 	elf = malloc(sizeof(struct kmod_elf));
296 	if (elf == NULL) {
297 		return NULL;
298 	}
299 
300 	elf->memory = memory;
301 	elf->changed = NULL;
302 	elf->size = size;
303 	elf->class = class;
304 
305 #define READV(field) \
306 	elf_get_uint(elf, offsetof(typeof(*hdr), field), sizeof(hdr->field))
307 
308 #define LOAD_HEADER						\
309 	elf->header.section.offset = READV(e_shoff);		\
310 	elf->header.section.count = READV(e_shnum);		\
311 	elf->header.section.entry_size = READV(e_shentsize);	\
312 	elf->header.strings.section = READV(e_shstrndx);	\
313 	elf->header.machine = READV(e_machine)
314 	if (elf->class & KMOD_ELF_32) {
315 		const Elf32_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
316 		LOAD_HEADER;
317 		shdr_size = sizeof(Elf32_Shdr);
318 	} else {
319 		const Elf64_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
320 		LOAD_HEADER;
321 		shdr_size = sizeof(Elf64_Shdr);
322 	}
323 #undef LOAD_HEADER
324 #undef READV
325 
326 	ELFDBG(elf, "section: offset=%"PRIu64" count=%"PRIu16" entry_size=%"PRIu16" strings index=%"PRIu16"\n",
327 	       elf->header.section.offset,
328 	       elf->header.section.count,
329 	       elf->header.section.entry_size,
330 	       elf->header.strings.section);
331 
332 	if (elf->header.section.entry_size != shdr_size) {
333 		ELFDBG(elf, "unexpected section entry size: %"PRIu16", expected %"PRIu16"\n",
334 		       elf->header.section.entry_size, shdr_size);
335 		goto invalid;
336 	}
337 	shdrs_size = shdr_size * elf->header.section.count;
338 	if (addu64_overflow(shdrs_size, elf->header.section.offset, &min_size)
339 	    || min_size > elf->size) {
340 		ELFDBG(elf, "file is too short to hold sections\n");
341 		goto invalid;
342 	}
343 
344 	if (elf_get_section_info(elf, elf->header.strings.section,
345 					&elf->header.strings.offset,
346 					&elf->header.strings.size,
347 					&elf->header.strings.nameoff) < 0) {
348 		ELFDBG(elf, "could not get strings section\n");
349 		goto invalid;
350 	} else {
351 		uint64_t slen;
352 		const char *s = elf_get_strings_section(elf, &slen);
353 		if (slen == 0 || s[slen - 1] != '\0') {
354 			ELFDBG(elf, "strings section does not ends with \\0\n");
355 			goto invalid;
356 		}
357 	}
358 
359 	return elf;
360 
361 invalid:
362 	free(elf);
363 	errno = EINVAL;
364 	return NULL;
365 }
366 
kmod_elf_unref(struct kmod_elf * elf)367 void kmod_elf_unref(struct kmod_elf *elf)
368 {
369 	free(elf->changed);
370 	free(elf);
371 }
372 
kmod_elf_get_memory(const struct kmod_elf * elf)373 const void *kmod_elf_get_memory(const struct kmod_elf *elf)
374 {
375 	return elf->memory;
376 }
377 
elf_find_section(const struct kmod_elf * elf,const char * section)378 static int elf_find_section(const struct kmod_elf *elf, const char *section)
379 {
380 	uint64_t nameslen;
381 	const char *names = elf_get_strings_section(elf, &nameslen);
382 	uint16_t i;
383 
384 	for (i = 1; i < elf->header.section.count; i++) {
385 		uint64_t off, size;
386 		uint32_t nameoff;
387 		const char *n;
388 		int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
389 		if (err < 0)
390 			continue;
391 		if (nameoff >= nameslen)
392 			continue;
393 		n = names + nameoff;
394 		if (!streq(section, n))
395 			continue;
396 
397 		return i;
398 	}
399 
400 	return -ENODATA;
401 }
402 
kmod_elf_get_section(const struct kmod_elf * elf,const char * section,const void ** buf,uint64_t * buf_size)403 int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, const void **buf, uint64_t *buf_size)
404 {
405 	uint64_t nameslen;
406 	const char *names = elf_get_strings_section(elf, &nameslen);
407 	uint16_t i;
408 
409 	*buf = NULL;
410 	*buf_size = 0;
411 
412 	for (i = 1; i < elf->header.section.count; i++) {
413 		uint64_t off, size;
414 		uint32_t nameoff;
415 		const char *n;
416 		int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
417 		if (err < 0)
418 			continue;
419 		if (nameoff >= nameslen)
420 			continue;
421 		n = names + nameoff;
422 		if (!streq(section, n))
423 			continue;
424 
425 		*buf = elf_get_mem(elf, off);
426 		*buf_size = size;
427 		return 0;
428 	}
429 
430 	return -ENODATA;
431 }
432 
433 /* 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)434 int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array)
435 {
436 	size_t i, j, count;
437 	uint64_t size;
438 	const void *buf;
439 	const char *strings;
440 	char *s, **a;
441 	int err;
442 
443 	*array = NULL;
444 
445 	err = kmod_elf_get_section(elf, section, &buf, &size);
446 	if (err < 0)
447 		return err;
448 
449 	strings = buf;
450 	if (strings == NULL || size == 0)
451 		return 0;
452 
453 	/* skip zero padding */
454 	while (strings[0] == '\0' && size > 1) {
455 		strings++;
456 		size--;
457 	}
458 
459 	if (size <= 1)
460 		return 0;
461 
462 	for (i = 0, count = 0; i < size; ) {
463 		if (strings[i] != '\0') {
464 			i++;
465 			continue;
466 		}
467 
468 		while (strings[i] == '\0' && i < size)
469 			i++;
470 
471 		count++;
472 	}
473 
474 	if (strings[i - 1] != '\0')
475 		count++;
476 
477 	*array = a = malloc(size + 1 + sizeof(char *) * (count + 1));
478 	if (*array == NULL)
479 		return -errno;
480 
481 	s = (char *)(a + count + 1);
482 	memcpy(s, strings, size);
483 
484 	/* make sure the last string is NULL-terminated */
485 	s[size] = '\0';
486 	a[count] = NULL;
487 	a[0] = s;
488 
489 	for (i = 0, j = 1; j < count && i < size; ) {
490 		if (s[i] != '\0') {
491 			i++;
492 			continue;
493 		}
494 
495 		while (strings[i] == '\0' && i < size)
496 			i++;
497 
498 		a[j] = &s[i];
499 		j++;
500 	}
501 
502 	return count;
503 }
504 
505 /* 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)506 int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array)
507 {
508 	size_t off, offcrc, slen;
509 	uint64_t size;
510 	struct kmod_modversion *a;
511 	const void *buf;
512 	char *itr;
513 	int i, count, err;
514 #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64))
515 
516 	assert_cc(sizeof(struct kmod_modversion64) ==
517 					sizeof(struct kmod_modversion32));
518 
519 	if (elf->class & KMOD_ELF_32)
520 		offcrc = sizeof(uint32_t);
521 	else
522 		offcrc = sizeof(uint64_t);
523 
524 	*array = NULL;
525 
526 	err = kmod_elf_get_section(elf, "__versions", &buf, &size);
527 	if (err < 0)
528 		return err;
529 
530 	if (buf == NULL || size == 0)
531 		return 0;
532 
533 	if (size % MODVERSION_SEC_SIZE != 0)
534 		return -EINVAL;
535 
536 	count = size / MODVERSION_SEC_SIZE;
537 
538 	off = (const uint8_t *)buf - elf->memory;
539 	slen = 0;
540 
541 	for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
542 		const char *symbol = elf_get_mem(elf, off + offcrc);
543 
544 		if (symbol[0] == '.')
545 			symbol++;
546 
547 		slen += strlen(symbol) + 1;
548 	}
549 
550 	*array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
551 	if (*array == NULL)
552 		return -errno;
553 
554 	itr = (char *)(a + count);
555 	off = (const uint8_t *)buf - elf->memory;
556 
557 	for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
558 		uint64_t crc = elf_get_uint(elf, off, offcrc);
559 		const char *symbol = elf_get_mem(elf, off + offcrc);
560 		size_t symbollen;
561 
562 		if (symbol[0] == '.')
563 			symbol++;
564 
565 		a[i].crc = crc;
566 		a[i].bind = KMOD_SYMBOL_UNDEF;
567 		a[i].symbol = itr;
568 		symbollen = strlen(symbol) + 1;
569 		memcpy(itr, symbol, symbollen);
570 		itr += symbollen;
571 	}
572 
573 	return count;
574 }
575 
kmod_elf_strip_section(struct kmod_elf * elf,const char * section)576 int kmod_elf_strip_section(struct kmod_elf *elf, const char *section)
577 {
578 	uint64_t off, size;
579 	const void *buf;
580 	int idx = elf_find_section(elf, section);
581 	uint64_t val;
582 
583 	if (idx < 0)
584 		return idx;
585 
586 	buf = elf_get_section_header(elf, idx);
587 	off = (const uint8_t *)buf - elf->memory;
588 
589 	if (elf->class & KMOD_ELF_32) {
590 		off += offsetof(Elf32_Shdr, sh_flags);
591 		size = sizeof(((Elf32_Shdr *)buf)->sh_flags);
592 	} else {
593 		off += offsetof(Elf64_Shdr, sh_flags);
594 		size = sizeof(((Elf64_Shdr *)buf)->sh_flags);
595 	}
596 
597 	val = elf_get_uint(elf, off, size);
598 	val &= ~(uint64_t)SHF_ALLOC;
599 
600 	return elf_set_uint(elf, off, size, val);
601 }
602 
kmod_elf_strip_vermagic(struct kmod_elf * elf)603 int kmod_elf_strip_vermagic(struct kmod_elf *elf)
604 {
605 	uint64_t i, size;
606 	const void *buf;
607 	const char *strings;
608 	int err;
609 
610 	err = kmod_elf_get_section(elf, ".modinfo", &buf, &size);
611 	if (err < 0)
612 		return err;
613 	strings = buf;
614 	if (strings == NULL || size == 0)
615 		return 0;
616 
617 	/* skip zero padding */
618 	while (strings[0] == '\0' && size > 1) {
619 		strings++;
620 		size--;
621 	}
622 	if (size <= 1)
623 		return 0;
624 
625 	for (i = 0; i < size; i++) {
626 		const char *s;
627 		size_t off, len;
628 
629 		if (strings[i] == '\0')
630 			continue;
631 		if (i + 1 >= size)
632 			continue;
633 
634 		s = strings + i;
635 		len = sizeof("vermagic=") - 1;
636 		if (i + len >= size)
637 			continue;
638 		if (strncmp(s, "vermagic=", len) != 0) {
639 			i += strlen(s);
640 			continue;
641 		}
642 		off = (const uint8_t *)s - elf->memory;
643 
644 		if (elf->changed == NULL) {
645 			elf->changed = malloc(elf->size);
646 			if (elf->changed == NULL)
647 				return -errno;
648 			memcpy(elf->changed, elf->memory, elf->size);
649 			elf->memory = elf->changed;
650 			ELFDBG(elf, "copied memory to allow writing.\n");
651 		}
652 
653 		len = strlen(s);
654 		ELFDBG(elf, "clear .modinfo vermagic \"%s\" (%zd bytes)\n",
655 		       s, len);
656 		memset(elf->changed + off, '\0', len);
657 		return 0;
658 	}
659 
660 	ELFDBG(elf, "no vermagic found in .modinfo\n");
661 	return -ENODATA;
662 }
663 
664 
kmod_elf_get_symbols_symtab(const struct kmod_elf * elf,struct kmod_modversion ** array)665 static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_modversion **array)
666 {
667 	uint64_t i, last, size;
668 	const void *buf;
669 	const char *strings;
670 	char *itr;
671 	struct kmod_modversion *a;
672 	int count, err;
673 
674 	*array = NULL;
675 
676 	err = kmod_elf_get_section(elf, "__ksymtab_strings", &buf, &size);
677 	if (err < 0)
678 		return err;
679 	strings = buf;
680 	if (strings == NULL || size == 0)
681 		return 0;
682 
683 	/* skip zero padding */
684 	while (strings[0] == '\0' && size > 1) {
685 		strings++;
686 		size--;
687 	}
688 	if (size <= 1)
689 		return 0;
690 
691 	last = 0;
692 	for (i = 0, count = 0; i < size; i++) {
693 		if (strings[i] == '\0') {
694 			if (last == i) {
695 				last = i + 1;
696 				continue;
697 			}
698 			count++;
699 			last = i + 1;
700 		}
701 	}
702 	if (strings[i - 1] != '\0')
703 		count++;
704 
705 	*array = a = malloc(size + 1 + sizeof(struct kmod_modversion) * count);
706 	if (*array == NULL)
707 		return -errno;
708 
709 	itr = (char *)(a + count);
710 	last = 0;
711 	for (i = 0, count = 0; i < size; i++) {
712 		if (strings[i] == '\0') {
713 			size_t slen = i - last;
714 			if (last == i) {
715 				last = i + 1;
716 				continue;
717 			}
718 			a[count].crc = 0;
719 			a[count].bind = KMOD_SYMBOL_GLOBAL;
720 			a[count].symbol = itr;
721 			memcpy(itr, strings + last, slen);
722 			itr[slen] = '\0';
723 			itr += slen + 1;
724 			count++;
725 			last = i + 1;
726 		}
727 	}
728 	if (strings[i - 1] != '\0') {
729 		size_t slen = i - last;
730 		a[count].crc = 0;
731 		a[count].bind = KMOD_SYMBOL_GLOBAL;
732 		a[count].symbol = itr;
733 		memcpy(itr, strings + last, slen);
734 		itr[slen] = '\0';
735 		count++;
736 	}
737 
738 	return count;
739 }
740 
kmod_symbol_bind_from_elf(uint8_t elf_value)741 static inline uint8_t kmod_symbol_bind_from_elf(uint8_t elf_value)
742 {
743 	switch (elf_value) {
744 	case STB_LOCAL:
745 		return KMOD_SYMBOL_LOCAL;
746 	case STB_GLOBAL:
747 		return KMOD_SYMBOL_GLOBAL;
748 	case STB_WEAK:
749 		return KMOD_SYMBOL_WEAK;
750 	default:
751 		return KMOD_SYMBOL_NONE;
752 	}
753 }
754 
kmod_elf_resolve_crc(const struct kmod_elf * elf,uint64_t crc,uint16_t shndx)755 static uint64_t kmod_elf_resolve_crc(const struct kmod_elf *elf, uint64_t crc, uint16_t shndx)
756 {
757 	int err;
758 	uint64_t off, size;
759 	uint32_t nameoff;
760 
761 	if (shndx == SHN_ABS || shndx == SHN_UNDEF)
762 		return crc;
763 
764 	err = elf_get_section_info(elf, shndx, &off, &size, &nameoff);
765 	if (err < 0) {
766 		ELFDBG("Cound not find section index %"PRIu16" for crc", shndx);
767 		return (uint64_t)-1;
768 	}
769 
770 	if (crc > (size - sizeof(uint32_t))) {
771 		ELFDBG("CRC offset %"PRIu64" is too big, section %"PRIu16" size is %"PRIu64"\n",
772 		       crc, shndx, size);
773 		return (uint64_t)-1;
774 	}
775 
776 	crc = elf_get_uint(elf, off + crc, sizeof(uint32_t));
777 	return crc;
778 }
779 
780 /* 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)781 int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
782 {
783 	static const char crc_str[] = "__crc_";
784 	static const size_t crc_strlen = sizeof(crc_str) - 1;
785 	uint64_t strtablen, symtablen, str_off, sym_off;
786 	const void *strtab, *symtab;
787 	struct kmod_modversion *a;
788 	char *itr;
789 	size_t slen, symlen;
790 	int i, count, symcount, err;
791 
792 	err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
793 	if (err < 0) {
794 		ELFDBG(elf, "no .strtab found.\n");
795 		goto fallback;
796 	}
797 
798 	err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
799 	if (err < 0) {
800 		ELFDBG(elf, "no .symtab found.\n");
801 		goto fallback;
802 	}
803 
804 	if (elf->class & KMOD_ELF_32)
805 		symlen = sizeof(Elf32_Sym);
806 	else
807 		symlen = sizeof(Elf64_Sym);
808 
809 	if (symtablen % symlen != 0) {
810 		ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
811 		goto fallback;
812 	}
813 
814 	symcount = symtablen / symlen;
815 	count = 0;
816 	slen = 0;
817 	str_off = (const uint8_t *)strtab - elf->memory;
818 	sym_off = (const uint8_t *)symtab - elf->memory + symlen;
819 	for (i = 1; i < symcount; i++, sym_off += symlen) {
820 		const char *name;
821 		uint32_t name_off;
822 
823 #define READV(field)							\
824 		elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
825 			     sizeof(s->field))
826 		if (elf->class & KMOD_ELF_32) {
827 			Elf32_Sym *s;
828 			name_off = READV(st_name);
829 		} else {
830 			Elf64_Sym *s;
831 			name_off = READV(st_name);
832 		}
833 #undef READV
834 		if (name_off >= strtablen) {
835 			ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
836 			goto fallback;
837 		}
838 
839 		name = elf_get_mem(elf, str_off + name_off);
840 
841 		if (strncmp(name, crc_str, crc_strlen) != 0)
842 			continue;
843 		slen += strlen(name + crc_strlen) + 1;
844 		count++;
845 	}
846 
847 	if (count == 0)
848 		goto fallback;
849 
850 	*array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
851 	if (*array == NULL)
852 		return -errno;
853 
854 	itr = (char *)(a + count);
855 	count = 0;
856 	str_off = (const uint8_t *)strtab - elf->memory;
857 	sym_off = (const uint8_t *)symtab - elf->memory + symlen;
858 	for (i = 1; i < symcount; i++, sym_off += symlen) {
859 		const char *name;
860 		uint32_t name_off;
861 		uint64_t crc;
862 		uint8_t info, bind;
863 		uint16_t shndx;
864 
865 #define READV(field)							\
866 		elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
867 			     sizeof(s->field))
868 		if (elf->class & KMOD_ELF_32) {
869 			Elf32_Sym *s;
870 			name_off = READV(st_name);
871 			crc = READV(st_value);
872 			info = READV(st_info);
873 			shndx = READV(st_shndx);
874 		} else {
875 			Elf64_Sym *s;
876 			name_off = READV(st_name);
877 			crc = READV(st_value);
878 			info = READV(st_info);
879 			shndx = READV(st_shndx);
880 		}
881 #undef READV
882 		name = elf_get_mem(elf, str_off + name_off);
883 		if (strncmp(name, crc_str, crc_strlen) != 0)
884 			continue;
885 		name += crc_strlen;
886 
887 		if (elf->class & KMOD_ELF_32)
888 			bind = ELF32_ST_BIND(info);
889 		else
890 			bind = ELF64_ST_BIND(info);
891 
892 		a[count].crc = kmod_elf_resolve_crc(elf, crc, shndx);
893 		a[count].bind = kmod_symbol_bind_from_elf(bind);
894 		a[count].symbol = itr;
895 		slen = strlen(name);
896 		memcpy(itr, name, slen);
897 		itr[slen] = '\0';
898 		itr += slen + 1;
899 		count++;
900 	}
901 	return count;
902 
903 fallback:
904 	ELFDBG(elf, "Falling back to __ksymtab_strings!\n");
905 	return kmod_elf_get_symbols_symtab(elf, array);
906 }
907 
kmod_elf_crc_find(const struct kmod_elf * elf,const void * versions,uint64_t versionslen,const char * name,uint64_t * crc)908 static int kmod_elf_crc_find(const struct kmod_elf *elf, const void *versions, uint64_t versionslen, const char *name, uint64_t *crc)
909 {
910 	size_t verlen, crclen, off;
911 	uint64_t i;
912 
913 	if (elf->class & KMOD_ELF_32) {
914 		struct kmod_modversion32 *mv;
915 		verlen = sizeof(*mv);
916 		crclen = sizeof(mv->crc);
917 	} else {
918 		struct kmod_modversion64 *mv;
919 		verlen = sizeof(*mv);
920 		crclen = sizeof(mv->crc);
921 	}
922 
923 	off = (const uint8_t *)versions - elf->memory;
924 	for (i = 0; i < versionslen; i += verlen) {
925 		const char *symbol = elf_get_mem(elf, off + i + crclen);
926 		if (!streq(name, symbol))
927 			continue;
928 		*crc = elf_get_uint(elf, off + i, crclen);
929 		return i / verlen;
930 	}
931 
932 	ELFDBG(elf, "could not find crc for symbol '%s'\n", name);
933 	*crc = 0;
934 	return -1;
935 }
936 
937 /* from module-init-tools:elfops_core.c */
938 #ifndef STT_REGISTER
939 #define STT_REGISTER    13              /* Global register reserved to app. */
940 #endif
941 
942 /* 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)943 int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
944 {
945 	uint64_t versionslen, strtablen, symtablen, str_off, sym_off, ver_off;
946 	const void *versions, *strtab, *symtab;
947 	struct kmod_modversion *a;
948 	char *itr;
949 	size_t slen, verlen, symlen, crclen;
950 	int i, count, symcount, vercount, err;
951 	bool handle_register_symbols;
952 	uint8_t *visited_versions;
953 	uint64_t *symcrcs;
954 
955 	err = kmod_elf_get_section(elf, "__versions", &versions, &versionslen);
956 	if (err < 0) {
957 		versions = NULL;
958 		versionslen = 0;
959 		verlen = 0;
960 		crclen = 0;
961 	} else {
962 		if (elf->class & KMOD_ELF_32) {
963 			struct kmod_modversion32 *mv;
964 			verlen = sizeof(*mv);
965 			crclen = sizeof(mv->crc);
966 		} else {
967 			struct kmod_modversion64 *mv;
968 			verlen = sizeof(*mv);
969 			crclen = sizeof(mv->crc);
970 		}
971 		if (versionslen % verlen != 0) {
972 			ELFDBG(elf, "unexpected __versions of length %"PRIu64", not multiple of %zd as expected.\n", versionslen, verlen);
973 			versions = NULL;
974 			versionslen = 0;
975 		}
976 	}
977 
978 	err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
979 	if (err < 0) {
980 		ELFDBG(elf, "no .strtab found.\n");
981 		return -EINVAL;
982 	}
983 
984 	err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
985 	if (err < 0) {
986 		ELFDBG(elf, "no .symtab found.\n");
987 		return -EINVAL;
988 	}
989 
990 	if (elf->class & KMOD_ELF_32)
991 		symlen = sizeof(Elf32_Sym);
992 	else
993 		symlen = sizeof(Elf64_Sym);
994 
995 	if (symtablen % symlen != 0) {
996 		ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
997 		return -EINVAL;
998 	}
999 
1000 	if (versionslen == 0) {
1001 		vercount = 0;
1002 		visited_versions = NULL;
1003 	} else {
1004 		vercount = versionslen / verlen;
1005 		visited_versions = calloc(vercount, sizeof(uint8_t));
1006 		if (visited_versions == NULL)
1007 			return -ENOMEM;
1008 	}
1009 
1010 	handle_register_symbols = (elf->header.machine == EM_SPARC ||
1011 				   elf->header.machine == EM_SPARCV9);
1012 
1013 	symcount = symtablen / symlen;
1014 	count = 0;
1015 	slen = 0;
1016 	str_off = (const uint8_t *)strtab - elf->memory;
1017 	sym_off = (const uint8_t *)symtab - elf->memory + symlen;
1018 
1019 	symcrcs = calloc(symcount, sizeof(uint64_t));
1020 	if (symcrcs == NULL) {
1021 		free(visited_versions);
1022 		return -ENOMEM;
1023 	}
1024 
1025 	for (i = 1; i < symcount; i++, sym_off += symlen) {
1026 		const char *name;
1027 		uint64_t crc;
1028 		uint32_t name_off;
1029 		uint16_t secidx;
1030 		uint8_t info;
1031 		int idx;
1032 
1033 #define READV(field)							\
1034 		elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1035 			     sizeof(s->field))
1036 		if (elf->class & KMOD_ELF_32) {
1037 			Elf32_Sym *s;
1038 			name_off = READV(st_name);
1039 			secidx = READV(st_shndx);
1040 			info = READV(st_info);
1041 		} else {
1042 			Elf64_Sym *s;
1043 			name_off = READV(st_name);
1044 			secidx = READV(st_shndx);
1045 			info = READV(st_info);
1046 		}
1047 #undef READV
1048 		if (secidx != SHN_UNDEF)
1049 			continue;
1050 
1051 		if (handle_register_symbols) {
1052 			uint8_t type;
1053 			if (elf->class & KMOD_ELF_32)
1054 				type = ELF32_ST_TYPE(info);
1055 			else
1056 				type = ELF64_ST_TYPE(info);
1057 
1058 			/* Not really undefined: sparc gcc 3.3 creates
1059 			 * U references when you have global asm
1060 			 * variables, to avoid anyone else misusing
1061 			 * them.
1062 			 */
1063 			if (type == STT_REGISTER)
1064 				continue;
1065 		}
1066 
1067 		if (name_off >= strtablen) {
1068 			ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
1069 			free(visited_versions);
1070 			free(symcrcs);
1071 			return -EINVAL;
1072 		}
1073 
1074 		name = elf_get_mem(elf, str_off + name_off);
1075 		if (name[0] == '\0') {
1076 			ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1077 			continue;
1078 		}
1079 
1080 		slen += strlen(name) + 1;
1081 		count++;
1082 
1083 		idx = kmod_elf_crc_find(elf, versions, versionslen, name, &crc);
1084 		if (idx >= 0 && visited_versions != NULL)
1085 			visited_versions[idx] = 1;
1086 		symcrcs[i] = crc;
1087 	}
1088 
1089 	if (visited_versions != NULL) {
1090 		/* module_layout/struct_module are not visited, but needed */
1091 		ver_off = (const uint8_t *)versions - elf->memory;
1092 		for (i = 0; i < vercount; i++) {
1093 			if (visited_versions[i] == 0) {
1094 				const char *name;
1095 				name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1096 				slen += strlen(name) + 1;
1097 
1098 				count++;
1099 			}
1100 		}
1101 	}
1102 
1103 	if (count == 0) {
1104 		free(visited_versions);
1105 		free(symcrcs);
1106 		*array = NULL;
1107 		return 0;
1108 	}
1109 
1110 	*array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
1111 	if (*array == NULL) {
1112 		free(visited_versions);
1113 		free(symcrcs);
1114 		return -errno;
1115 	}
1116 
1117 	itr = (char *)(a + count);
1118 	count = 0;
1119 	str_off = (const uint8_t *)strtab - elf->memory;
1120 	sym_off = (const uint8_t *)symtab - elf->memory + symlen;
1121 	for (i = 1; i < symcount; i++, sym_off += symlen) {
1122 		const char *name;
1123 		uint64_t crc;
1124 		uint32_t name_off;
1125 		uint16_t secidx;
1126 		uint8_t info, bind;
1127 
1128 #define READV(field)							\
1129 		elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1130 			     sizeof(s->field))
1131 		if (elf->class & KMOD_ELF_32) {
1132 			Elf32_Sym *s;
1133 			name_off = READV(st_name);
1134 			secidx = READV(st_shndx);
1135 			info = READV(st_info);
1136 		} else {
1137 			Elf64_Sym *s;
1138 			name_off = READV(st_name);
1139 			secidx = READV(st_shndx);
1140 			info = READV(st_info);
1141 		}
1142 #undef READV
1143 		if (secidx != SHN_UNDEF)
1144 			continue;
1145 
1146 		if (handle_register_symbols) {
1147 			uint8_t type;
1148 			if (elf->class & KMOD_ELF_32)
1149 				type = ELF32_ST_TYPE(info);
1150 			else
1151 				type = ELF64_ST_TYPE(info);
1152 
1153 			/* Not really undefined: sparc gcc 3.3 creates
1154 			 * U references when you have global asm
1155 			 * variables, to avoid anyone else misusing
1156 			 * them.
1157 			 */
1158 			if (type == STT_REGISTER)
1159 				continue;
1160 		}
1161 
1162 		name = elf_get_mem(elf, str_off + name_off);
1163 		if (name[0] == '\0') {
1164 			ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1165 			continue;
1166 		}
1167 
1168 		if (elf->class & KMOD_ELF_32)
1169 			bind = ELF32_ST_BIND(info);
1170 		else
1171 			bind = ELF64_ST_BIND(info);
1172 		if (bind == STB_WEAK)
1173 			bind = KMOD_SYMBOL_WEAK;
1174 		else
1175 			bind = KMOD_SYMBOL_UNDEF;
1176 
1177 		slen = strlen(name);
1178 		crc = symcrcs[i];
1179 
1180 		a[count].crc = crc;
1181 		a[count].bind = bind;
1182 		a[count].symbol = itr;
1183 		memcpy(itr, name, slen);
1184 		itr[slen] = '\0';
1185 		itr += slen + 1;
1186 
1187 		count++;
1188 	}
1189 
1190 	free(symcrcs);
1191 
1192 	if (visited_versions == NULL)
1193 		return count;
1194 
1195 	/* add unvisited (module_layout/struct_module) */
1196 	ver_off = (const uint8_t *)versions - elf->memory;
1197 	for (i = 0; i < vercount; i++) {
1198 		const char *name;
1199 		uint64_t crc;
1200 
1201 		if (visited_versions[i] != 0)
1202 			continue;
1203 
1204 		name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1205 		slen = strlen(name);
1206 		crc = elf_get_uint(elf, ver_off + i * verlen, crclen);
1207 
1208 		a[count].crc = crc;
1209 		a[count].bind = KMOD_SYMBOL_UNDEF;
1210 		a[count].symbol = itr;
1211 		memcpy(itr, name, slen);
1212 		itr[slen] = '\0';
1213 		itr += slen + 1;
1214 
1215 		count++;
1216 	}
1217 	free(visited_versions);
1218 	return count;
1219 }
1220