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