1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
4 */
5 #include <linux/string.h>
6 #include <linux/elf.h>
7 #include <linux/fcntl.h>
8 #include <linux/slab.h>
9 #include "exec_signature_info.h"
10
11 #if ELF_EXEC_PAGESIZE > PAGE_SIZE
12 #define ELF_PHNUM_SIZE ELF_EXEC_PAGESIZE
13 #else
14 #define ELF_PHNUM_SIZE PAGE_SIZE
15 #endif
16
17 #if ELF_PHNUM_SIZE > 65536
18 #define ELF_PHNUM_MAX_SIZE 65536
19 #else
20 #define ELF_PHNUM_MAX_SIZE ELF_PHNUM_SIZE
21 #endif
22
23 struct elf_info {
24 struct elfhdr elf_ehdr;
25 uint16_t type;
26 uint16_t e_phnum;
27 size_t e_phsize;
28 uintptr_t e_phoff;
29 };
30
read_elf_info(struct file *file, void *buffer, size_t read_size, loff_t pos)31 static int read_elf_info(struct file *file, void *buffer, size_t read_size, loff_t pos)
32 {
33 size_t len;
34
35 len = (size_t)kernel_read(file, buffer, read_size, &pos);
36 if (unlikely(len != read_size))
37 return -EIO;
38
39 return 0;
40 }
41
elf64_get_value(const struct elfhdr *ehdr, uint64_t value)42 static uint64_t elf64_get_value(const struct elfhdr *ehdr, uint64_t value)
43 {
44 if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
45 return be64_to_cpu(value);
46
47 if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
48 return le64_to_cpu(value);
49
50 return value;
51 }
52
elf32_get_value(const struct elfhdr *ehdr, uint32_t value)53 static uint32_t elf32_get_value(const struct elfhdr *ehdr, uint32_t value)
54 {
55 if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
56 return be32_to_cpu(value);
57
58 if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
59 return le32_to_cpu(value);
60
61 return value;
62 }
63
elf16_get_value(const struct elfhdr *ehdr, uint16_t value)64 static uint16_t elf16_get_value(const struct elfhdr *ehdr, uint16_t value)
65 {
66 if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
67 return be16_to_cpu(value);
68
69 if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
70 return le16_to_cpu(value);
71
72 return value;
73 }
74
get_elf32_code_segment_count(struct elf32_phdr *elf_phdr, struct elf_info *elf_info)75 static int get_elf32_code_segment_count(struct elf32_phdr *elf_phdr,
76 struct elf_info *elf_info)
77 {
78 int i;
79 int count = 0;
80 struct elf32_phdr *phdr_info;
81 uint32_t p_flags;
82
83 for (i = 0; i < elf_info->e_phnum; i++) {
84 phdr_info = elf_phdr + i;
85 p_flags = elf32_get_value(&elf_info->elf_ehdr, phdr_info->p_flags);
86 if (!(p_flags & PF_X))
87 continue;
88
89 count++;
90 }
91 return count;
92 }
93
get_elf32_code_segment(struct elf32_phdr *elf_phdr, struct elf_info *elf_info, struct exec_file_signature_info *exec_file_info)94 static int get_elf32_code_segment(struct elf32_phdr *elf_phdr, struct elf_info *elf_info,
95 struct exec_file_signature_info *exec_file_info)
96 {
97 int i;
98 struct elf32_phdr *phdr_info;
99 uint32_t p_flags;
100 uint32_t p_offset;
101 uint32_t p_filesz;
102 uint32_t p_memsz;
103 uint32_t p_addr;
104
105 for (i = 0; i < elf_info->e_phnum; i++) {
106 phdr_info = elf_phdr + i;
107 p_flags = elf32_get_value(&elf_info->elf_ehdr, phdr_info->p_flags);
108 if (!(p_flags & PF_X))
109 continue;
110
111 p_offset = elf32_get_value(&elf_info->elf_ehdr, phdr_info->p_offset);
112 p_filesz = elf32_get_value(&elf_info->elf_ehdr, phdr_info->p_filesz);
113 p_addr = elf32_get_value(&elf_info->elf_ehdr, phdr_info->p_paddr);
114 p_memsz = elf32_get_value(&elf_info->elf_ehdr, phdr_info->p_memsz);
115 if (p_offset + p_filesz < p_offset || p_addr + p_memsz < p_addr)
116 return -ENOEXEC;
117
118 exec_file_info->code_segments[exec_file_info->code_segment_count].file_offset = p_offset;
119 exec_file_info->code_segments[exec_file_info->code_segment_count].size = p_filesz;
120 exec_file_info->code_segment_count++;
121 }
122 return 0;
123 }
124
get_elf64_code_segment_count(struct elf64_phdr *elf_phdr, struct elf_info *elf_info)125 static int get_elf64_code_segment_count(struct elf64_phdr *elf_phdr, struct elf_info *elf_info)
126 {
127 int i;
128 int count = 0;
129 struct elf64_phdr *phdr_info;
130 uint32_t p_flags;
131
132 for (i = 0; i < elf_info->e_phnum; i++) {
133 phdr_info = elf_phdr + i;
134 p_flags = elf32_get_value(&elf_info->elf_ehdr, phdr_info->p_flags);
135 if (!(p_flags & PF_X))
136 continue;
137
138 count++;
139 }
140 return count;
141 }
142
get_elf64_code_segment(struct elf64_phdr *elf_phdr, struct elf_info *elf_info, struct exec_file_signature_info *exec_file_info)143 static int get_elf64_code_segment(struct elf64_phdr *elf_phdr, struct elf_info *elf_info,
144 struct exec_file_signature_info *exec_file_info)
145 {
146 int i;
147 struct elf64_phdr *phdr_info;
148 uint32_t p_flags;
149 uint64_t p_offset;
150 uint64_t p_filesz;
151 uint64_t p_memsz;
152 uint64_t p_addr;
153
154 for (i = 0; i < elf_info->e_phnum; i++) {
155 phdr_info = elf_phdr + i;
156 p_flags = elf32_get_value(&elf_info->elf_ehdr, phdr_info->p_flags);
157 if (!(p_flags & PF_X))
158 continue;
159
160 p_offset = elf64_get_value(&elf_info->elf_ehdr, phdr_info->p_offset);
161 p_filesz = elf64_get_value(&elf_info->elf_ehdr, phdr_info->p_filesz);
162 p_addr = elf64_get_value(&elf_info->elf_ehdr, phdr_info->p_paddr);
163 p_memsz = elf64_get_value(&elf_info->elf_ehdr, phdr_info->p_memsz);
164 if (p_offset + p_filesz < p_offset || p_addr + p_memsz < p_addr)
165 return -ENOEXEC;
166
167 exec_file_info->code_segments[exec_file_info->code_segment_count].file_offset = p_offset;
168 exec_file_info->code_segments[exec_file_info->code_segment_count].size = p_filesz;
169 exec_file_info->code_segment_count++;
170 }
171 return 0;
172 }
173
get_elf32_info(struct elfhdr *elf_ehdr, struct elf_info *elf_info)174 static int get_elf32_info(struct elfhdr *elf_ehdr, struct elf_info *elf_info)
175 {
176 struct elf32_hdr *elf32_ehdr;
177 uint32_t e32_phoff;
178 uint32_t e32_phsize;
179 uint16_t e_ehsize;
180
181 elf_info->type = ELFCLASS32;
182 elf32_ehdr = (struct elf32_hdr *)elf_ehdr;
183 e_ehsize = elf16_get_value(elf_ehdr, elf32_ehdr->e_ehsize);
184 if (e_ehsize != sizeof(struct elf32_hdr))
185 return -ENOEXEC;
186
187 elf_info->e_phnum = elf16_get_value(elf_ehdr, elf32_ehdr->e_phnum);
188 e32_phsize = sizeof(struct elf32_phdr) * elf_info->e_phnum;
189 if (e32_phsize == 0 || e32_phsize > ELF_PHNUM_MAX_SIZE)
190 return -ENOEXEC;
191
192 e32_phoff = elf32_get_value(elf_ehdr, elf32_ehdr->e_phoff);
193 if (e32_phoff + e32_phsize < e32_phoff)
194 return -ENOEXEC;
195
196 elf_info->e_phsize = e32_phsize;
197 elf_info->e_phoff = e32_phoff;
198 return 0;
199 }
200
get_elf64_info(struct elfhdr *elf_ehdr, struct elf_info *elf_info)201 static int get_elf64_info(struct elfhdr *elf_ehdr, struct elf_info *elf_info)
202 {
203 struct elf64_hdr *elf64_ehdr;
204 uint64_t e64_phoff;
205 uint64_t e64_phsize;
206 uint16_t e_ehsize;
207
208 elf_info->type = ELFCLASS64;
209 elf64_ehdr = (struct elf64_hdr *)elf_ehdr;
210 e_ehsize = elf16_get_value(elf_ehdr, elf64_ehdr->e_ehsize);
211 if (e_ehsize != sizeof(struct elf64_hdr))
212 return -ENOEXEC;
213
214 elf_info->e_phnum = elf16_get_value(elf_ehdr, elf64_ehdr->e_phnum);
215 e64_phsize = sizeof(struct elf64_phdr) * elf_info->e_phnum;
216 if (e64_phsize == 0 || e64_phsize > ELF_PHNUM_MAX_SIZE)
217 return -ENOEXEC;
218
219 e64_phoff = elf64_get_value(elf_ehdr, elf64_ehdr->e_phoff);
220 if (e64_phoff + e64_phsize < e64_phoff)
221 return -ENOEXEC;
222
223 elf_info->e_phsize = e64_phsize;
224 elf_info->e_phoff = e64_phoff;
225 return 0;
226 }
227
elf_check_and_get_code_segment_offset(struct file *file, struct elf_info *elf_info, bool *skip)228 static int elf_check_and_get_code_segment_offset(struct file *file, struct elf_info *elf_info, bool *skip)
229 {
230 uint16_t type;
231 struct elfhdr *elf_ehdr = &elf_info->elf_ehdr;
232 int ret;
233
234 ret = read_elf_info(file, (void *)elf_ehdr, sizeof(struct elfhdr), 0);
235 if (ret < 0)
236 return ret;
237
238 if (memcmp(elf_ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
239 // when the file is not an ELF file, skip checking
240 *skip = true;
241 return 0;
242 }
243
244 type = elf16_get_value(elf_ehdr, elf_ehdr->e_type);
245 if (type != ET_EXEC && type != ET_DYN)
246 return -ENOEXEC;
247
248 if (elf_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
249 return get_elf32_info(elf_ehdr, elf_info);
250
251 if (elf_ehdr->e_ident[EI_CLASS] == ELFCLASS64)
252 return get_elf64_info(elf_ehdr, elf_info);
253
254 return -ENOEXEC;
255 }
256
find_elf_code_segment_info(const char *phdr_info, struct elf_info *elf_info, struct exec_file_signature_info **file_info)257 static int find_elf_code_segment_info(const char *phdr_info, struct elf_info *elf_info,
258 struct exec_file_signature_info **file_info)
259 {
260 int ret;
261 size_t size;
262 struct exec_file_signature_info *exec_file_info;
263 int segment_count;
264
265 if (elf_info->type == ELFCLASS32)
266 segment_count = get_elf32_code_segment_count((struct elf32_phdr *)phdr_info, elf_info);
267 else
268 segment_count = get_elf64_code_segment_count((struct elf64_phdr *)phdr_info, elf_info);
269
270 if (segment_count == 0)
271 return -ENOEXEC;
272
273 size = sizeof(struct exec_file_signature_info) + (size_t)segment_count * sizeof(struct exec_segment_info);
274 exec_file_info = kzalloc(size, GFP_KERNEL);
275 if (exec_file_info == NULL)
276 return -ENOMEM;
277
278 exec_file_info->code_segments = (struct exec_segment_info *)((char *)exec_file_info +
279 sizeof(struct exec_file_signature_info));
280 if (elf_info->type == ELFCLASS32)
281 ret = get_elf32_code_segment((struct elf32_phdr *)phdr_info, elf_info, exec_file_info);
282 else
283 ret = get_elf64_code_segment((struct elf64_phdr *)phdr_info, elf_info, exec_file_info);
284
285 if (ret < 0) {
286 kfree(exec_file_info);
287 return ret;
288 }
289 *file_info = exec_file_info;
290 return 0;
291 }
292
handle_skip_case(struct file *file, struct exec_file_signature_info **code_segment_info)293 static int handle_skip_case(struct file *file, struct exec_file_signature_info **code_segment_info) {
294 struct exec_file_signature_info *tmp_info = NULL;
295 if (*code_segment_info == NULL) {
296 tmp_info = kzalloc(sizeof(struct exec_file_signature_info), GFP_KERNEL);
297 if (tmp_info == NULL) {
298 return -ENOMEM;
299 }
300 } else {
301 tmp_info = *code_segment_info;
302 }
303
304 if (tmp_info->code_segments == NULL) {
305 tmp_info->code_segments = kzalloc(sizeof(struct exec_segment_info), GFP_KERNEL);
306 if (tmp_info->code_segments == NULL) {
307 if (*code_segment_info == NULL) {
308 kfree(tmp_info);
309 tmp_info = NULL;
310 }
311 return -ENOMEM;
312 }
313 tmp_info->code_segment_count = 1;
314 }
315
316 tmp_info->code_segments[0].file_offset = 0;
317 tmp_info->code_segments[0].size = file_inode(file)->i_size;
318
319 if (*code_segment_info == NULL) {
320 *code_segment_info = tmp_info;
321 }
322 return 0;
323 }
324
parse_elf_code_segment_info(struct file *file, struct exec_file_signature_info **code_segment_info)325 int parse_elf_code_segment_info(struct file *file,
326 struct exec_file_signature_info **code_segment_info)
327 {
328 const char *phdr_info;
329 struct elf_info elf_info = {0};
330 int ret;
331 bool skip = false;
332 ret = elf_check_and_get_code_segment_offset(file, &elf_info, &skip);
333 if (ret < 0)
334 return ret;
335
336 if (skip) {
337 return handle_skip_case(file, code_segment_info);
338 }
339
340 phdr_info = kzalloc(elf_info.e_phsize, GFP_KERNEL);
341 if (phdr_info == NULL)
342 return -ENOMEM;
343
344 ret = read_elf_info(file, (void *)phdr_info, elf_info.e_phsize, elf_info.e_phoff);
345 if (ret < 0) {
346 kfree(phdr_info);
347 return ret;
348 }
349
350 ret = find_elf_code_segment_info(phdr_info, &elf_info, code_segment_info);
351 kfree(phdr_info);
352 return ret;
353 }
354