xref: /optee_os/ta/remoteproc/src/elf_parser.c (revision 5597ed3855d1350dee2fd619e746d8a863d92069)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2023, STMicroelectronics
4  */
5 
6 #include <assert.h>
7 #include <elf_parser.h>
8 #include <string.h>
9 #include <trace.h>
10 #include <types_ext.h>
11 #include <util.h>
12 
va_in_fwm_image_range(void * va,size_t len,uint8_t * fw,size_t fw_size)13 static bool va_in_fwm_image_range(void *va, size_t len, uint8_t *fw,
14 				  size_t fw_size)
15 {
16 	uint8_t *vaddr = va;
17 	uint8_t *end_vaddr = vaddr + len;
18 	uint8_t *end_fw = fw + fw_size;
19 
20 	if (end_vaddr < vaddr || end_fw < fw)
21 		return false;
22 
23 	return vaddr >= fw && end_vaddr <= end_fw;
24 }
25 
e32_parse_ehdr(uint8_t * fw,size_t size)26 TEE_Result e32_parse_ehdr(uint8_t *fw, size_t size)
27 {
28 	Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw;
29 
30 	if (!fw || !IS_ALIGNED_WITH_TYPE(fw, uint32_t)) {
31 		EMSG("Invalid firmware address");
32 		return TEE_ERROR_BAD_PARAMETERS;
33 	}
34 
35 	if (size < sizeof(Elf32_Ehdr) ||
36 	    size < (ehdr->e_shoff + sizeof(Elf32_Shdr)))
37 		return TEE_ERROR_BAD_FORMAT;
38 
39 	if (!IS_ELF(*ehdr) ||
40 	    ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
41 	    ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
42 	    ehdr->e_phentsize != sizeof(Elf32_Phdr) ||
43 	    ehdr->e_shentsize != sizeof(Elf32_Shdr)) {
44 		EMSG("Invalid header");
45 		return TEE_ERROR_BAD_FORMAT;
46 	}
47 
48 	if (ehdr->e_phnum == 0) {
49 		EMSG("No loadable segment found");
50 		return TEE_ERROR_BAD_FORMAT;
51 	}
52 
53 	return TEE_SUCCESS;
54 }
55 
e32_parser_load_elf_image(uint8_t * fw,size_t fw_size,TEE_Result (* load_seg)(uint8_t * src,uint32_t size,uint32_t da,uint32_t mem_size,void * priv),void * priv_data)56 TEE_Result e32_parser_load_elf_image(uint8_t *fw, size_t fw_size,
57 				     TEE_Result (*load_seg)(uint8_t *src,
58 							    uint32_t size,
59 							    uint32_t da,
60 							    uint32_t mem_size,
61 							    void *priv),
62 				     void *priv_data)
63 {
64 	Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw;
65 	Elf32_Phdr *phdr = (void *)((int8_t *)ehdr + ehdr->e_phoff);
66 	TEE_Result res = TEE_SUCCESS;
67 	unsigned int i = 0;
68 
69 	if (!load_seg || fw + fw_size <= fw)
70 		return TEE_ERROR_BAD_PARAMETERS;
71 
72 	if (!IS_ALIGNED_WITH_TYPE(phdr, uint32_t))
73 		return TEE_ERROR_BAD_FORMAT;
74 
75 	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
76 		uint32_t dst = phdr->p_paddr;
77 		uint8_t *src = NULL;
78 
79 		if (!va_in_fwm_image_range(phdr, sizeof(*phdr), fw, fw_size))
80 			return TEE_ERROR_BAD_FORMAT;
81 
82 		if (phdr->p_type != PT_LOAD)
83 			continue;
84 
85 
86 		src = (uint8_t *)fw + phdr->p_offset;
87 
88 		if (!va_in_fwm_image_range(src, phdr->p_filesz, fw, fw_size))
89 			return TEE_ERROR_BAD_FORMAT;
90 
91 		res = load_seg(src, phdr->p_filesz, dst, phdr->p_memsz,
92 			       priv_data);
93 		if (res)
94 			return res;
95 	}
96 
97 	return TEE_SUCCESS;
98 }
99 
e32_parser_find_rsc_table(uint8_t * fw,size_t fw_size,Elf32_Addr * rsc_addr,Elf32_Word * rsc_size)100 TEE_Result e32_parser_find_rsc_table(uint8_t *fw, size_t fw_size,
101 				     Elf32_Addr *rsc_addr,
102 				     Elf32_Word *rsc_size)
103 {
104 	Elf32_Shdr *shdr = NULL;
105 	unsigned int i = 0;
106 	char *name_table = NULL;
107 	size_t name_table_sz = 0;
108 	struct resource_table *table = NULL;
109 	Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw;
110 	uint8_t *elf_data = fw;
111 	size_t shdr_array_sz = 0;
112 
113 	if (fw + fw_size <= fw || fw + ehdr->e_shoff < fw)
114 		return TEE_ERROR_BAD_PARAMETERS;
115 
116 	shdr = (void *)(fw + ehdr->e_shoff);
117 	if (!IS_ALIGNED_WITH_TYPE(shdr, uint32_t) ||
118 	    MUL_OVERFLOW(sizeof(*shdr), ehdr->e_shnum, &shdr_array_sz) ||
119 	    !va_in_fwm_image_range(shdr, shdr_array_sz, fw, fw_size) ||
120 	     ehdr->e_shstrndx >= ehdr->e_shnum)
121 		return TEE_ERROR_BAD_FORMAT;
122 
123 	name_table_sz = shdr[ehdr->e_shstrndx].sh_size;
124 	name_table = (char *)elf_data + shdr[ehdr->e_shstrndx].sh_offset;
125 	if (!va_in_fwm_image_range(name_table, name_table_sz, fw, fw_size))
126 		return TEE_ERROR_BAD_FORMAT;
127 
128 	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
129 		size_t size = shdr->sh_size;
130 		size_t offset = shdr->sh_offset;
131 		size_t s = 0;
132 
133 		if (shdr->sh_name >= name_table_sz)
134 			return TEE_ERROR_BAD_FORMAT;
135 
136 		if (strncmp(name_table + shdr->sh_name, ".resource_table",
137 			    name_table_sz - shdr->sh_name))
138 			continue;
139 
140 		if (!size)
141 			return TEE_ERROR_NO_DATA;
142 
143 		if (offset + size > fw_size || offset + size < size) {
144 			EMSG("Resource table truncated");
145 			return TEE_ERROR_BAD_FORMAT;
146 		}
147 
148 		if (sizeof(struct resource_table) > size) {
149 			EMSG("No header found in resource table");
150 			return TEE_ERROR_BAD_FORMAT;
151 		}
152 
153 		table = (struct resource_table *)(void *)(elf_data + offset);
154 		if (!IS_ALIGNED_WITH_TYPE(table, uint32_t))
155 			return TEE_ERROR_CORRUPT_OBJECT;
156 
157 		if (table->ver != 1) {
158 			EMSG("Unsupported firmware version %"PRId32,
159 			     table->ver);
160 			return TEE_ERROR_BAD_FORMAT;
161 		}
162 
163 		if (table->reserved[0] || table->reserved[1]) {
164 			EMSG("Non zero reserved bytes");
165 			return TEE_ERROR_BAD_FORMAT;
166 		}
167 
168 		if (MUL_OVERFLOW(table->num, sizeof(*table->offset), &s) ||
169 		    ADD_OVERFLOW(s, sizeof(struct resource_table), &s) ||
170 		    s > size) {
171 			EMSG("Resource table incomplete");
172 			return TEE_ERROR_BAD_FORMAT;
173 		}
174 
175 		DMSG("Resource table address %#"PRIx32", size %"PRIu32,
176 		     shdr->sh_addr, shdr->sh_size);
177 
178 		*rsc_addr = shdr->sh_addr;
179 		*rsc_size = shdr->sh_size;
180 
181 		return TEE_SUCCESS;
182 	}
183 
184 	return TEE_ERROR_NO_DATA;
185 }
186