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 	L"\\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 	L"\\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 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 /*
238  * load_file2() - LoadFile() service of a EFI_LOAD_FILE2_PROTOCOL
239  *
240  * @this:		instance of EFI_LOAD_FILE2_PROTOCOL
241  * @file_path:		remaining device path
242  * @boot_policy:	true if called by boot manager
243  * @buffer_size:	(required) buffer size
244  * @buffer:		buffer to which the file is to be loaded
245  */
load_file2(struct efi_load_file_protocol * this,struct efi_device_path * file_path,bool boot_policy,efi_uintn_t * buffer_size,void * buffer)246 efi_status_t EFIAPI load_file2(struct efi_load_file_protocol *this,
247 			       struct efi_device_path *file_path,
248 			       bool boot_policy,
249 			       efi_uintn_t *buffer_size,
250 			       void *buffer)
251 {
252 	++load_file2_call_count;
253 	if (memcmp(file_path, dp_lf2_file_remainder,
254 	    sizeof(struct efi_device_path_file_path) +
255 	    FILE_NAME_SIZE * sizeof(u16) +
256 	    sizeof(struct efi_device_path))) {
257 		efi_st_error("Wrong remaining device path\n");
258 		return EFI_NOT_FOUND;
259 	}
260 	if (this->load_file != load_file2) {
261 		efi_st_error("wrong this\n");
262 		return EFI_INVALID_PARAMETER;
263 	}
264 	if (boot_policy) {
265 		efi_st_error("LOAD_FILE2 called with boot_policy = true");
266 		return EFI_INVALID_PARAMETER;
267 	}
268 	if (*buffer_size < img.length) {
269 		*buffer_size = img.length;
270 		return EFI_BUFFER_TOO_SMALL;
271 	}
272 	memcpy(buffer, image, img.length);
273 	*buffer_size = img.length;
274 	return EFI_SUCCESS;
275 }
276 
277 static struct efi_load_file_protocol lf_prot = {load_file};
278 static struct efi_load_file_protocol lf2_prot = {load_file2};
279 
280 /*
281  * Setup unit test.
282  *
283  * Install an EFI_LOAD_FILE_PROTOCOL and an EFI_LOAD_FILE2_PROTOCOL.
284  *
285  * @handle:	handle of the loaded image
286  * @systable:	system table
287  * @return:	EFI_ST_SUCCESS for success
288  */
efi_st_load_file_setup(const efi_handle_t handle,const struct efi_system_table * systable)289 static int efi_st_load_file_setup(const efi_handle_t handle,
290 				  const struct efi_system_table *systable)
291 {
292 	efi_status_t ret;
293 
294 	image_handle = handle;
295 	boottime = systable->boottime;
296 
297 	/* Load the application image into memory */
298 	decompress(&image);
299 
300 	ret = boottime->install_multiple_protocol_interfaces(
301 		&handle_lf,
302 		&efi_st_guid_device_path,
303 		&dp_lf_prot,
304 		&efi_st_guid_load_file_protocol,
305 		&lf_prot,
306 		NULL);
307 	if (ret != EFI_SUCCESS) {
308 		efi_st_error("InstallMultipleProtocolInterfaces failed\n");
309 		return EFI_ST_FAILURE;
310 	}
311 	ret = boottime->install_multiple_protocol_interfaces(
312 		&handle_lf2,
313 		&efi_st_guid_device_path,
314 		&dp_lf2_prot,
315 		&efi_st_guid_load_file2_protocol,
316 		&lf2_prot,
317 		NULL);
318 	if (ret != EFI_SUCCESS) {
319 		efi_st_error("InstallMultipleProtocolInterfaces failed\n");
320 		return EFI_ST_FAILURE;
321 	}
322 
323 	return EFI_ST_SUCCESS;
324 }
325 
326 /*
327  * Tear down unit test.
328  *
329  * @return:	EFI_ST_SUCCESS for success
330  */
efi_st_load_file_teardown(void)331 static int efi_st_load_file_teardown(void)
332 {
333 	efi_status_t ret = EFI_ST_SUCCESS;
334 
335 	if (handle_lf) {
336 		ret = boottime->uninstall_multiple_protocol_interfaces(
337 			handle_lf,
338 			&efi_st_guid_device_path,
339 			&dp_lf_prot,
340 			&efi_st_guid_load_file_protocol,
341 			&lf_prot,
342 			NULL);
343 		if (ret != EFI_SUCCESS) {
344 			efi_st_error(
345 				"UninstallMultipleProtocolInterfaces failed\n");
346 			return EFI_ST_FAILURE;
347 		}
348 	}
349 	if (handle_lf2) {
350 		ret = boottime->uninstall_multiple_protocol_interfaces(
351 			handle_lf2,
352 			&efi_st_guid_device_path,
353 			&dp_lf2_prot,
354 			&efi_st_guid_load_file2_protocol,
355 			&lf2_prot,
356 			NULL);
357 		if (ret != EFI_SUCCESS) {
358 			efi_st_error(
359 				"UninstallMultipleProtocolInterfaces failed\n");
360 			return EFI_ST_FAILURE;
361 		}
362 	}
363 
364 	if (image) {
365 		ret = boottime->free_pool(image);
366 		if (ret != EFI_SUCCESS) {
367 			efi_st_error("Failed to free image\n");
368 			return EFI_ST_FAILURE;
369 		}
370 	}
371 	return ret;
372 }
373 
374 /*
375  * Execute unit test.
376  *
377  * Try loading an image via the EFI_LOAD_FILE_PROTOCOL and the
378  * EFI_LOAD_FILE2_PROTOCOL. Finally execute the image.
379  *
380  * @return:	EFI_ST_SUCCESS for success
381  */
efi_st_load_file_execute(void)382 static int efi_st_load_file_execute(void)
383 {
384 	efi_status_t ret;
385 	efi_handle_t handle;
386 	efi_uintn_t exit_data_size = 0;
387 	u16 *exit_data = NULL;
388 	u16 expected_text[] = EFI_ST_SUCCESS_STR;
389 
390 	load_file_call_count = 0;
391 	load_file2_call_count = 0;
392 	handle = NULL;
393 	ret = boottime->load_image(true, image_handle, &dp_lf_file.v.dp, NULL,
394 				   0, &handle);
395 	if (ret != EFI_SUCCESS) {
396 		efi_st_error("Failed to load image\n");
397 		return EFI_ST_FAILURE;
398 	}
399 	if (load_file2_call_count || !load_file_call_count) {
400 		efi_st_error("Wrong image loaded\n");
401 		return EFI_ST_FAILURE;
402 	}
403 	ret = boottime->unload_image(handle);
404 	if (ret != EFI_SUCCESS) {
405 		efi_st_error("Failed to unload image\n");
406 		return EFI_ST_FAILURE;
407 	}
408 
409 	load_file_call_count = 0;
410 	load_file2_call_count = 0;
411 	handle = NULL;
412 	ret = boottime->load_image(false, image_handle, &dp_lf_file.v.dp, NULL,
413 				   0, &handle);
414 	if (ret != EFI_SUCCESS) {
415 		efi_st_error("Failed to load image\n");
416 		return EFI_ST_FAILURE;
417 	}
418 	if (load_file2_call_count || !load_file_call_count) {
419 		efi_st_error("Wrong image loaded\n");
420 		return EFI_ST_FAILURE;
421 	}
422 	ret = boottime->unload_image(handle);
423 	if (ret != EFI_SUCCESS) {
424 		efi_st_error("Failed to unload image\n");
425 		return EFI_ST_FAILURE;
426 	}
427 
428 	ret = boottime->load_image(true, image_handle, &dp_lf2_file.v.dp, NULL,
429 				   0, &handle);
430 	if (ret != EFI_NOT_FOUND) {
431 		efi_st_error(
432 			"Boot manager should not use LOAD_FILE2_PROTOCOL\n");
433 		return EFI_ST_FAILURE;
434 	}
435 
436 	load_file_call_count = 0;
437 	load_file2_call_count = 0;
438 	handle = NULL;
439 	ret = boottime->load_image(false, image_handle, &dp_lf2_file.v.dp, NULL,
440 				   0, &handle);
441 	if (ret != EFI_SUCCESS) {
442 		efi_st_error("Failed to load image\n");
443 		return EFI_ST_FAILURE;
444 	}
445 	if (!load_file2_call_count || load_file_call_count) {
446 		efi_st_error("Wrong image loaded\n");
447 		return EFI_ST_FAILURE;
448 	}
449 
450 	ret = boottime->start_image(handle, &exit_data_size, &exit_data);
451 	if (ret != EFI_UNSUPPORTED) {
452 		efi_st_error("Wrong return value from application\n");
453 		return EFI_ST_FAILURE;
454 	}
455 	if (!exit_data || exit_data_size != sizeof(expected_text) ||
456 	    memcmp(exit_data, expected_text, sizeof(expected_text))) {
457 		efi_st_error("Incorrect exit data\n");
458 		return EFI_ST_FAILURE;
459 	}
460 	ret = boottime->free_pool(exit_data);
461 	if (ret != EFI_SUCCESS) {
462 		efi_st_error("Failed to free exit data\n");
463 		return EFI_ST_FAILURE;
464 	}
465 
466 	return EFI_ST_SUCCESS;
467 }
468 
469 EFI_UNIT_TEST(load_file_protocol) = {
470 	.name = "load file protocol",
471 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
472 	.setup = efi_st_load_file_setup,
473 	.execute = efi_st_load_file_execute,
474 	.teardown = efi_st_load_file_teardown,
475 };
476