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