1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_load_file
4  *
5  * Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  *
7  * This test checks the handling of the LOAD_FILE and the LOAD_FILE2 protocol
8  * by the LoadImage() service.
9  */
10 
11 #include <efi_selftest.h>
12 /* Include containing the miniapp.efi application */
13 #include "efi_miniapp_file_image_exit.h"
14 
15 /* Block size of compressed disk image */
16 #define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
17 
18 /* Binary logarithm of the block size */
19 #define LB_BLOCK_SIZE 9
20 
21 #define GUID_VENDOR \
22 	EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \
23 		 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd1)
24 
25 #define GUID_VENDOR2 \
26 	EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \
27 		 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd2)
28 
29 #define FILE_NAME_SIZE 16
30 
31 static const efi_guid_t efi_st_guid_load_file_protocol =
32 					EFI_LOAD_FILE_PROTOCOL_GUID;
33 static const efi_guid_t efi_st_guid_load_file2_protocol =
34 					EFI_LOAD_FILE2_PROTOCOL_GUID;
35 static const efi_guid_t efi_st_guid_device_path =
36 					EFI_DEVICE_PATH_PROTOCOL_GUID;
37 
38 static efi_handle_t image_handle;
39 static struct efi_boot_services *boottime;
40 static efi_handle_t handle_lf;
41 static efi_handle_t handle_lf2;
42 
43 /* One 8 byte block of the compressed disk image */
44 struct line {
45 	size_t addr;
46 	char *line;
47 };
48 
49 /* Compressed file image */
50 struct compressed_file_image {
51 	size_t length;
52 	struct line lines[];
53 };
54 
55 static struct compressed_file_image img = EFI_ST_DISK_IMG;
56 
57 static int load_file_call_count;
58 static int load_file2_call_count;
59 
60 /* Decompressed file image */
61 static u8 *image;
62 
63 static struct {
64 	struct efi_device_path_vendor v;
65 	struct efi_device_path d;
66 } dp_lf_prot = {
67 	{
68 		{
69 			DEVICE_PATH_TYPE_HARDWARE_DEVICE,
70 			DEVICE_PATH_SUB_TYPE_VENDOR,
71 			sizeof(struct efi_device_path_vendor),
72 		},
73 		GUID_VENDOR,
74 	},
75 	{
76 		DEVICE_PATH_TYPE_END,
77 		DEVICE_PATH_SUB_TYPE_END,
78 		sizeof(struct efi_device_path),
79 	},
80 };
81 
82 static struct {
83 	struct efi_device_path_vendor v;
84 	struct efi_device_path_file_path f;
85 	u16 file_name[FILE_NAME_SIZE];
86 	struct efi_device_path e;
87 } dp_lf_file = {
88 	{
89 		{
90 			DEVICE_PATH_TYPE_HARDWARE_DEVICE,
91 			DEVICE_PATH_SUB_TYPE_VENDOR,
92 			sizeof(struct efi_device_path_vendor),
93 		},
94 		GUID_VENDOR,
95 	},
96 	{
97 		{
98 			DEVICE_PATH_TYPE_MEDIA_DEVICE,
99 			DEVICE_PATH_SUB_TYPE_FILE_PATH,
100 			sizeof(struct efi_device_path_file_path) +
101 			FILE_NAME_SIZE * sizeof(u16),
102 		}
103 	},
104 	u"\\lf.efi",
105 	{
106 		DEVICE_PATH_TYPE_END,
107 		DEVICE_PATH_SUB_TYPE_END,
108 		sizeof(struct efi_device_path),
109 	},
110 };
111 
112 struct efi_device_path *dp_lf_file_remainder = &dp_lf_file.f.dp;
113 
114 static struct {
115 	struct efi_device_path_vendor v;
116 	struct efi_device_path d;
117 } dp_lf2_prot = {
118 	{
119 		{
120 			DEVICE_PATH_TYPE_HARDWARE_DEVICE,
121 			DEVICE_PATH_SUB_TYPE_VENDOR,
122 			sizeof(struct efi_device_path_vendor),
123 		},
124 		GUID_VENDOR2,
125 	},
126 	{
127 		DEVICE_PATH_TYPE_END,
128 		DEVICE_PATH_SUB_TYPE_END,
129 		sizeof(struct efi_device_path),
130 	},
131 };
132 
133 static struct {
134 	struct efi_device_path_vendor v;
135 	struct efi_device_path_file_path f;
136 	u16 file_name[FILE_NAME_SIZE];
137 	struct efi_device_path e;
138 } dp_lf2_file = {
139 	{
140 		{
141 			DEVICE_PATH_TYPE_HARDWARE_DEVICE,
142 			DEVICE_PATH_SUB_TYPE_VENDOR,
143 			sizeof(struct efi_device_path_vendor),
144 		},
145 		GUID_VENDOR2,
146 	},
147 	{
148 		{
149 			DEVICE_PATH_TYPE_MEDIA_DEVICE,
150 			DEVICE_PATH_SUB_TYPE_FILE_PATH,
151 			sizeof(struct efi_device_path_file_path) +
152 			FILE_NAME_SIZE * sizeof(u16),
153 		}
154 	},
155 	u"\\lf2.efi",
156 	{
157 		DEVICE_PATH_TYPE_END,
158 		DEVICE_PATH_SUB_TYPE_END,
159 		sizeof(struct efi_device_path),
160 	},
161 };
162 
163 struct efi_device_path *dp_lf2_file_remainder = &dp_lf2_file.f.dp;
164 
165 /*
166  * Decompress the disk image.
167  *
168  * @image	decompressed disk image
169  * Return:	status code
170  */
decompress(u8 ** image)171 static efi_status_t decompress(u8 **image)
172 {
173 	u8 *buf;
174 	size_t i;
175 	size_t addr;
176 	size_t len;
177 	efi_status_t ret;
178 
179 	ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
180 				      (void **)&buf);
181 	if (ret != EFI_SUCCESS) {
182 		efi_st_error("Out of memory\n");
183 		return ret;
184 	}
185 	boottime->set_mem(buf, img.length, 0);
186 
187 	for (i = 0; ; ++i) {
188 		if (!img.lines[i].line)
189 			break;
190 		addr = img.lines[i].addr;
191 		len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
192 		if (addr + len > img.length)
193 			len = img.length - addr;
194 		boottime->copy_mem(buf + addr, img.lines[i].line, len);
195 	}
196 	*image = buf;
197 	return ret;
198 }
199 
200 /*
201  * load_file() - LoadFile() service of a EFI_LOAD_FILE_PROTOCOL
202  *
203  * @this:		instance of EFI_LOAD_FILE_PROTOCOL
204  * @file_path:		remaining device path
205  * @boot_policy:	true if called by boot manager
206  * @buffer_size:	(required) buffer size
207  * @buffer:		buffer to which the file is to be loaded
208  */
load_file(struct efi_load_file_protocol * this,struct efi_device_path * file_path,bool boot_policy,efi_uintn_t * buffer_size,void * buffer)209 static efi_status_t EFIAPI load_file(struct efi_load_file_protocol *this,
210 				     struct efi_device_path *file_path,
211 				     bool boot_policy,
212 				     efi_uintn_t *buffer_size,
213 				     void *buffer)
214 {
215 	++load_file_call_count;
216 	if (memcmp(file_path, dp_lf_file_remainder,
217 	    sizeof(struct efi_device_path_file_path) +
218 	    FILE_NAME_SIZE * sizeof(u16) +
219 	    sizeof(struct efi_device_path))) {
220 		efi_st_error("Wrong remaining device path\n");
221 		return EFI_NOT_FOUND;
222 	}
223 	if (this->load_file != load_file) {
224 		efi_st_error("wrong this\n");
225 		return EFI_INVALID_PARAMETER;
226 	}
227 	if (*buffer_size < img.length) {
228 		*buffer_size = img.length;
229 		return EFI_BUFFER_TOO_SMALL;
230 	}
231 	memcpy(buffer, image, img.length);
232 	*buffer_size = img.length;
233 	return EFI_SUCCESS;
234 }
235 
236 /*
237  * load_file2() - LoadFile() service of a EFI_LOAD_FILE2_PROTOCOL
238  *
239  * @this:		instance of EFI_LOAD_FILE2_PROTOCOL
240  * @file_path:		remaining device path
241  * @boot_policy:	true if called by boot manager
242  * @buffer_size:	(required) buffer size
243  * @buffer:		buffer to which the file is to be loaded
244  */
load_file2(struct efi_load_file_protocol * this,struct efi_device_path * file_path,bool boot_policy,efi_uintn_t * buffer_size,void * buffer)245 static efi_status_t EFIAPI load_file2(struct efi_load_file_protocol *this,
246 				      struct efi_device_path *file_path,
247 				      bool boot_policy,
248 				      efi_uintn_t *buffer_size,
249 				      void *buffer)
250 {
251 	++load_file2_call_count;
252 	if (memcmp(file_path, dp_lf2_file_remainder,
253 	    sizeof(struct efi_device_path_file_path) +
254 	    FILE_NAME_SIZE * sizeof(u16) +
255 	    sizeof(struct efi_device_path))) {
256 		efi_st_error("Wrong remaining device path\n");
257 		return EFI_NOT_FOUND;
258 	}
259 	if (this->load_file != load_file2) {
260 		efi_st_error("wrong this\n");
261 		return EFI_INVALID_PARAMETER;
262 	}
263 	if (boot_policy) {
264 		efi_st_error("LOAD_FILE2 called with boot_policy = true");
265 		return EFI_INVALID_PARAMETER;
266 	}
267 	if (*buffer_size < img.length) {
268 		*buffer_size = img.length;
269 		return EFI_BUFFER_TOO_SMALL;
270 	}
271 	memcpy(buffer, image, img.length);
272 	*buffer_size = img.length;
273 	return EFI_SUCCESS;
274 }
275 
276 static struct efi_load_file_protocol lf_prot = {load_file};
277 static struct efi_load_file_protocol lf2_prot = {load_file2};
278 
279 /*
280  * Setup unit test.
281  *
282  * Install an EFI_LOAD_FILE_PROTOCOL and an EFI_LOAD_FILE2_PROTOCOL.
283  *
284  * @handle:	handle of the loaded image
285  * @systable:	system table
286  * Return:	EFI_ST_SUCCESS for success
287  */
efi_st_load_file_setup(const efi_handle_t handle,const struct efi_system_table * systable)288 static int efi_st_load_file_setup(const efi_handle_t handle,
289 				  const struct efi_system_table *systable)
290 {
291 	efi_status_t ret;
292 
293 	image_handle = handle;
294 	boottime = systable->boottime;
295 
296 	/* Load the application image into memory */
297 	decompress(&image);
298 
299 	ret = boottime->install_multiple_protocol_interfaces(
300 		&handle_lf,
301 		&efi_st_guid_device_path,
302 		&dp_lf_prot,
303 		&efi_st_guid_load_file_protocol,
304 		&lf_prot,
305 		NULL);
306 	if (ret != EFI_SUCCESS) {
307 		efi_st_error("InstallMultipleProtocolInterfaces failed\n");
308 		return EFI_ST_FAILURE;
309 	}
310 	ret = boottime->install_multiple_protocol_interfaces(
311 		&handle_lf2,
312 		&efi_st_guid_device_path,
313 		&dp_lf2_prot,
314 		&efi_st_guid_load_file2_protocol,
315 		&lf2_prot,
316 		NULL);
317 	if (ret != EFI_SUCCESS) {
318 		efi_st_error("InstallMultipleProtocolInterfaces failed\n");
319 		return EFI_ST_FAILURE;
320 	}
321 
322 	return EFI_ST_SUCCESS;
323 }
324 
325 /*
326  * Tear down unit test.
327  *
328  * Return:	EFI_ST_SUCCESS for success
329  */
efi_st_load_file_teardown(void)330 static int efi_st_load_file_teardown(void)
331 {
332 	efi_status_t ret = EFI_ST_SUCCESS;
333 
334 	if (handle_lf) {
335 		ret = boottime->uninstall_multiple_protocol_interfaces(
336 			handle_lf,
337 			&efi_st_guid_device_path,
338 			&dp_lf_prot,
339 			&efi_st_guid_load_file_protocol,
340 			&lf_prot,
341 			NULL);
342 		if (ret != EFI_SUCCESS) {
343 			efi_st_error(
344 				"UninstallMultipleProtocolInterfaces failed\n");
345 			return EFI_ST_FAILURE;
346 		}
347 	}
348 	if (handle_lf2) {
349 		ret = boottime->uninstall_multiple_protocol_interfaces(
350 			handle_lf2,
351 			&efi_st_guid_device_path,
352 			&dp_lf2_prot,
353 			&efi_st_guid_load_file2_protocol,
354 			&lf2_prot,
355 			NULL);
356 		if (ret != EFI_SUCCESS) {
357 			efi_st_error(
358 				"UninstallMultipleProtocolInterfaces failed\n");
359 			return EFI_ST_FAILURE;
360 		}
361 	}
362 
363 	if (image) {
364 		ret = boottime->free_pool(image);
365 		if (ret != EFI_SUCCESS) {
366 			efi_st_error("Failed to free image\n");
367 			return EFI_ST_FAILURE;
368 		}
369 	}
370 	return ret;
371 }
372 
373 /*
374  * Execute unit test.
375  *
376  * Try loading an image via the EFI_LOAD_FILE_PROTOCOL and the
377  * EFI_LOAD_FILE2_PROTOCOL. Finally execute the image.
378  *
379  * Return:	EFI_ST_SUCCESS for success
380  */
efi_st_load_file_execute(void)381 static int efi_st_load_file_execute(void)
382 {
383 	efi_status_t ret;
384 	efi_handle_t handle;
385 	efi_uintn_t exit_data_size = 0;
386 	u16 *exit_data = NULL;
387 	u16 expected_text[] = EFI_ST_SUCCESS_STR;
388 
389 	load_file_call_count = 0;
390 	load_file2_call_count = 0;
391 	handle = NULL;
392 	ret = boottime->load_image(true, image_handle, &dp_lf_file.v.dp, NULL,
393 				   0, &handle);
394 	if (ret != EFI_SUCCESS) {
395 		efi_st_error("Failed to load image\n");
396 		return EFI_ST_FAILURE;
397 	}
398 	if (load_file2_call_count || !load_file_call_count) {
399 		efi_st_error("Wrong image loaded\n");
400 		return EFI_ST_FAILURE;
401 	}
402 	ret = boottime->unload_image(handle);
403 	if (ret != EFI_SUCCESS) {
404 		efi_st_error("Failed to unload image\n");
405 		return EFI_ST_FAILURE;
406 	}
407 
408 	load_file_call_count = 0;
409 	load_file2_call_count = 0;
410 	handle = NULL;
411 	ret = boottime->load_image(false, image_handle, &dp_lf_file.v.dp, NULL,
412 				   0, &handle);
413 	if (ret != EFI_SUCCESS) {
414 		efi_st_error("Failed to load image\n");
415 		return EFI_ST_FAILURE;
416 	}
417 	if (load_file2_call_count || !load_file_call_count) {
418 		efi_st_error("Wrong image loaded\n");
419 		return EFI_ST_FAILURE;
420 	}
421 	ret = boottime->unload_image(handle);
422 	if (ret != EFI_SUCCESS) {
423 		efi_st_error("Failed to unload image\n");
424 		return EFI_ST_FAILURE;
425 	}
426 
427 	ret = boottime->load_image(true, image_handle, &dp_lf2_file.v.dp, NULL,
428 				   0, &handle);
429 	if (ret != EFI_NOT_FOUND) {
430 		efi_st_error(
431 			"Boot manager should not use LOAD_FILE2_PROTOCOL\n");
432 		return EFI_ST_FAILURE;
433 	}
434 
435 	load_file_call_count = 0;
436 	load_file2_call_count = 0;
437 	handle = NULL;
438 	ret = boottime->load_image(false, image_handle, &dp_lf2_file.v.dp, NULL,
439 				   0, &handle);
440 	if (ret != EFI_SUCCESS) {
441 		efi_st_error("Failed to load image\n");
442 		return EFI_ST_FAILURE;
443 	}
444 	if (!load_file2_call_count || load_file_call_count) {
445 		efi_st_error("Wrong image loaded\n");
446 		return EFI_ST_FAILURE;
447 	}
448 
449 	ret = boottime->start_image(handle, &exit_data_size, &exit_data);
450 	if (ret != EFI_UNSUPPORTED) {
451 		efi_st_error("Wrong return value from application\n");
452 		return EFI_ST_FAILURE;
453 	}
454 	if (!exit_data || exit_data_size != sizeof(expected_text) ||
455 	    memcmp(exit_data, expected_text, sizeof(expected_text))) {
456 		efi_st_error("Incorrect exit data\n");
457 		return EFI_ST_FAILURE;
458 	}
459 	ret = boottime->free_pool(exit_data);
460 	if (ret != EFI_SUCCESS) {
461 		efi_st_error("Failed to free exit data\n");
462 		return EFI_ST_FAILURE;
463 	}
464 
465 	return EFI_ST_SUCCESS;
466 }
467 
468 EFI_UNIT_TEST(load_file_protocol) = {
469 	.name = "load file protocol",
470 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
471 	.setup = efi_st_load_file_setup,
472 	.execute = efi_st_load_file_execute,
473 	.teardown = efi_st_load_file_teardown,
474 };
475