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