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