efi_loader: validate load option
[oweals/u-boot.git] / lib / efi_selftest / efi_selftest_devicepath.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_devicepath
4  *
5  * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  *
7  * This unit test checks the following protocol services:
8  * DevicePathToText
9  */
10
11 #include <efi_selftest.h>
12
13 static struct efi_boot_services *boottime;
14
15 static efi_handle_t handle1;
16 static efi_handle_t handle2;
17 static efi_handle_t handle3;
18
19 struct interface {
20         void (EFIAPI * inc)(void);
21 } interface;
22
23 static efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
24
25 static efi_guid_t guid_device_path_to_text_protocol =
26         EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
27
28 static efi_guid_t guid_protocol =
29         EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
30                  0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0x7d);
31
32 static efi_guid_t guid_vendor1 =
33         EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
34                  0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xb1);
35
36 static efi_guid_t guid_vendor2 =
37         EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
38                  0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xa2);
39
40 static efi_guid_t guid_vendor3 =
41         EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
42                  0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xc3);
43
44 static u8 *dp1;
45 static u8 *dp2;
46 static u8 *dp3;
47
48 struct efi_device_path_to_text_protocol *device_path_to_text;
49
50 /*
51  * Setup unit test.
52  *
53  * Create three handles. Install a new protocol on two of them and
54  * provide device paths.
55  *
56  * handle1
57  *   guid interface
58  * handle2
59  *   guid interface
60  * handle3
61  *
62  * @handle:     handle of the loaded image
63  * @systable:   system table
64  */
65 static int setup(const efi_handle_t img_handle,
66                  const struct efi_system_table *systable)
67 {
68         struct efi_device_path_vendor vendor_node;
69         struct efi_device_path end_node;
70         efi_status_t ret;
71
72         boottime = systable->boottime;
73
74         ret = boottime->locate_protocol(&guid_device_path_to_text_protocol,
75                                         NULL, (void **)&device_path_to_text);
76         if (ret != EFI_SUCCESS) {
77                 device_path_to_text = NULL;
78                 efi_st_error(
79                         "Device path to text protocol is not available.\n");
80                 return EFI_ST_FAILURE;
81         }
82
83         ret = boottime->allocate_pool(EFI_LOADER_DATA,
84                                       sizeof(struct efi_device_path_vendor) +
85                                       sizeof(struct efi_device_path),
86                                       (void **)&dp1);
87         if (ret != EFI_SUCCESS)
88                 goto out_of_memory;
89
90         ret = boottime->allocate_pool(EFI_LOADER_DATA, 2 *
91                                       sizeof(struct efi_device_path_vendor) +
92                                       sizeof(struct efi_device_path),
93                                       (void **)&dp2);
94         if (ret != EFI_SUCCESS)
95                 goto out_of_memory;
96
97         ret = boottime->allocate_pool(EFI_LOADER_DATA, 3 *
98                                       sizeof(struct efi_device_path_vendor) +
99                                       sizeof(struct efi_device_path),
100                                       (void **)&dp3);
101         if (ret != EFI_SUCCESS)
102                 goto out_of_memory;
103
104         vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
105         vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
106         vendor_node.dp.length = sizeof(struct efi_device_path_vendor);
107
108         boottime->copy_mem(&vendor_node.guid, &guid_vendor1,
109                            sizeof(efi_guid_t));
110         boottime->copy_mem(dp1, &vendor_node,
111                            sizeof(struct efi_device_path_vendor));
112         boottime->copy_mem(dp2, &vendor_node,
113                            sizeof(struct efi_device_path_vendor));
114         boottime->copy_mem(dp3, &vendor_node,
115                            sizeof(struct efi_device_path_vendor));
116
117         boottime->copy_mem(&vendor_node.guid, &guid_vendor2,
118                            sizeof(efi_guid_t));
119         boottime->copy_mem(dp2 + sizeof(struct efi_device_path_vendor),
120                            &vendor_node, sizeof(struct efi_device_path_vendor));
121         boottime->copy_mem(dp3 + sizeof(struct efi_device_path_vendor),
122                            &vendor_node, sizeof(struct efi_device_path_vendor));
123
124         boottime->copy_mem(&vendor_node.guid, &guid_vendor3,
125                            sizeof(efi_guid_t));
126         boottime->copy_mem(dp3 + 2 * sizeof(struct efi_device_path_vendor),
127                            &vendor_node, sizeof(struct efi_device_path_vendor));
128
129         end_node.type = DEVICE_PATH_TYPE_END;
130         end_node.sub_type = DEVICE_PATH_SUB_TYPE_END;
131         end_node.length = sizeof(struct efi_device_path);
132         boottime->copy_mem(dp1 + sizeof(struct efi_device_path_vendor),
133                            &end_node, sizeof(struct efi_device_path));
134         boottime->copy_mem(dp2 + 2 * sizeof(struct efi_device_path_vendor),
135                            &end_node, sizeof(struct efi_device_path));
136         boottime->copy_mem(dp3 + 3 * sizeof(struct efi_device_path_vendor),
137                            &end_node, sizeof(struct efi_device_path));
138
139         ret = boottime->install_protocol_interface(&handle1,
140                                                    &guid_device_path,
141                                                    EFI_NATIVE_INTERFACE,
142                                                    dp1);
143         if (ret != EFI_SUCCESS) {
144                 efi_st_error("InstallProtocolInterface failed\n");
145                 return EFI_ST_FAILURE;
146         }
147         ret = boottime->install_protocol_interface(&handle1,
148                                                    &guid_protocol,
149                                                    EFI_NATIVE_INTERFACE,
150                                                    &interface);
151         if (ret != EFI_SUCCESS) {
152                 efi_st_error("InstallProtocolInterface failed\n");
153                 return EFI_ST_FAILURE;
154         }
155         ret = boottime->install_protocol_interface(&handle2,
156                                                    &guid_device_path,
157                                                    EFI_NATIVE_INTERFACE,
158                                                    dp2);
159         if (ret != EFI_SUCCESS) {
160                 efi_st_error("InstallProtocolInterface failed\n");
161                 return EFI_ST_FAILURE;
162         }
163         ret = boottime->install_protocol_interface(&handle2,
164                                                    &guid_protocol,
165                                                    EFI_NATIVE_INTERFACE,
166                                                    &interface);
167         if (ret != EFI_SUCCESS) {
168                 efi_st_error("InstallProtocolInterface failed\n");
169                 return EFI_ST_FAILURE;
170         }
171         ret = boottime->install_protocol_interface(&handle3,
172                                                    &guid_device_path,
173                                                    EFI_NATIVE_INTERFACE,
174                                                    dp3);
175         if (ret != EFI_SUCCESS) {
176                 efi_st_error("InstallProtocolInterface failed\n");
177                 return EFI_ST_FAILURE;
178         }
179         return EFI_ST_SUCCESS;
180
181 out_of_memory:
182         efi_st_error("Out of memory\n");
183         return EFI_ST_FAILURE;
184 }
185
186 /*
187  * Tear down unit test.
188  *
189  */
190 static int teardown(void)
191 {
192         efi_status_t ret;
193
194         ret = boottime->uninstall_protocol_interface(handle1,
195                                                      &guid_device_path,
196                                                      dp1);
197         if (ret != EFI_SUCCESS) {
198                 efi_st_error("UninstallProtocolInterface failed\n");
199                 return EFI_ST_FAILURE;
200         }
201         ret = boottime->uninstall_protocol_interface(handle1,
202                                                      &guid_protocol,
203                                                      &interface);
204         if (ret != EFI_SUCCESS) {
205                 efi_st_error("UninstallProtocolInterface failed\n");
206                 return EFI_ST_FAILURE;
207         }
208         ret = boottime->uninstall_protocol_interface(handle2,
209                                                      &guid_device_path,
210                                                      dp2);
211         if (ret != EFI_SUCCESS) {
212                 efi_st_error("UninstallProtocolInterface failed\n");
213                 return EFI_ST_FAILURE;
214         }
215         ret = boottime->uninstall_protocol_interface(handle2,
216                                                      &guid_protocol,
217                                                      &interface);
218         if (ret != EFI_SUCCESS) {
219                 efi_st_error("UninstallProtocolInterface failed\n");
220                 return EFI_ST_FAILURE;
221         }
222         ret = boottime->uninstall_protocol_interface(handle3,
223                                                      &guid_device_path,
224                                                      dp3);
225         if (ret != EFI_SUCCESS) {
226                 efi_st_error("UninstallProtocolInterface failed\n");
227                 return EFI_ST_FAILURE;
228         }
229         if (dp1) {
230                 ret = boottime->free_pool(dp1);
231                 if (ret != EFI_SUCCESS) {
232                         efi_st_error("FreePool failed\n");
233                         return EFI_ST_FAILURE;
234                 }
235         }
236         if (dp2) {
237                 ret = boottime->free_pool(dp2);
238                 if (ret != EFI_SUCCESS) {
239                         efi_st_error("FreePool failed\n");
240                         return EFI_ST_FAILURE;
241                 }
242         }
243         if (dp3) {
244                 ret = boottime->free_pool(dp3);
245                 if (ret != EFI_SUCCESS) {
246                         efi_st_error("FreePool failed\n");
247                         return EFI_ST_FAILURE;
248                 }
249         }
250         return EFI_ST_SUCCESS;
251 }
252
253 /*
254  * Execute unit test.
255  *
256  */
257 static int execute(void)
258 {
259         struct efi_device_path *remaining_dp;
260         efi_handle_t handle;
261         /*
262          * This device path node ends with the letter 't' of 'u-boot'.
263          * The following '.bin' does not belong to the node but is
264          * helps to test the correct truncation.
265          */
266         struct {
267                 struct efi_device_path dp;
268                 u16 text[12];
269         } __packed dp_node = {
270                         { DEVICE_PATH_TYPE_MEDIA_DEVICE,
271                           DEVICE_PATH_SUB_TYPE_FILE_PATH,
272                           sizeof(struct efi_device_path) + 12},
273                         L"u-boot.bin",
274                 };
275         u16 *string;
276         efi_status_t ret;
277         efi_uintn_t i, no_handles;
278         efi_handle_t *handles;
279         struct efi_device_path *dp;
280
281         /* Display all available device paths */
282         ret = boottime->locate_handle_buffer(BY_PROTOCOL,
283                                              &guid_device_path,
284                                              NULL, &no_handles, &handles);
285         if (ret != EFI_SUCCESS) {
286                 efi_st_error("Cannot retrieve device path protocols.\n");
287                 return EFI_ST_FAILURE;
288         }
289
290         efi_st_printf("Installed device path protocols:\n");
291         for (i = 0; i < no_handles; ++i) {
292                 ret = boottime->open_protocol(handles[i], &guid_device_path,
293                                               (void **)&dp, NULL, NULL,
294                                               EFI_OPEN_PROTOCOL_GET_PROTOCOL);
295                 if (ret != EFI_SUCCESS) {
296                         efi_st_error("Cannot open device path protocol.\n");
297                         return EFI_ST_FAILURE;
298                 }
299                 string = device_path_to_text->convert_device_path_to_text(
300                                         dp, true, false);
301                 if (!string) {
302                         efi_st_error("ConvertDevicePathToText failed\n");
303                         return EFI_ST_FAILURE;
304                 }
305                 efi_st_printf("%ps\n", string);
306                 ret = boottime->free_pool(string);
307                 if (ret != EFI_SUCCESS) {
308                         efi_st_error("FreePool failed\n");
309                         return EFI_ST_FAILURE;
310                 }
311                 /*
312                  * CloseProtocol cannot be called without agent handle.
313                  * There is no need to close the device path protocol.
314                  */
315         }
316         ret = boottime->free_pool(handles);
317         if (ret != EFI_SUCCESS) {
318                 efi_st_error("FreePool failed\n");
319                 return EFI_ST_FAILURE;
320         }
321
322         /* Test ConvertDevicePathToText */
323         string = device_path_to_text->convert_device_path_to_text(
324                         (struct efi_device_path *)dp2, true, false);
325         if (!string) {
326                 efi_st_error("ConvertDevicePathToText failed\n");
327                 return EFI_ST_FAILURE;
328         }
329         if (efi_st_strcmp_16_8(
330                 string,
331                 "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)")
332             ) {
333                 efi_st_printf("dp2: %ps\n", string);
334                 efi_st_error("Incorrect text from ConvertDevicePathToText\n");
335                 return EFI_ST_FAILURE;
336         }
337         ret = boottime->free_pool(string);
338         if (ret != EFI_SUCCESS) {
339                 efi_st_error("FreePool failed\n");
340                 return EFI_ST_FAILURE;
341         }
342
343         /* Test ConvertDeviceNodeToText */
344         string = device_path_to_text->convert_device_node_to_text(
345                         (struct efi_device_path *)&dp_node, true, false);
346         if (!string) {
347                 efi_st_error("ConvertDeviceNodeToText failed\n");
348                 return EFI_ST_FAILURE;
349         }
350         if (efi_st_strcmp_16_8(string, "u-boot")) {
351                 efi_st_printf("dp_node: %ps\n", string);
352                 efi_st_error(
353                         "Incorrect conversion by ConvertDeviceNodeToText\n");
354                 return EFI_ST_FAILURE;
355         }
356         ret = boottime->free_pool(string);
357         if (ret != EFI_SUCCESS) {
358                 efi_st_error("FreePool failed\n");
359                 return EFI_ST_FAILURE;
360         }
361
362         /* Test LocateDevicePath */
363         remaining_dp = (struct efi_device_path *)dp3;
364         ret = boottime->locate_device_path(&guid_protocol, &remaining_dp,
365                                            &handle);
366         if (ret != EFI_SUCCESS) {
367                 efi_st_error("LocateDevicePath failed\n");
368                 return EFI_ST_FAILURE;
369         }
370         if (handle != handle2) {
371                 efi_st_error("LocateDevicePath returned wrong handle\n");
372                 return EFI_ST_FAILURE;
373         }
374         string = device_path_to_text->convert_device_path_to_text(remaining_dp,
375                                                                   true, false);
376         if (!string) {
377                 efi_st_error("ConvertDevicePathToText failed\n");
378                 return EFI_ST_FAILURE;
379         }
380         if (efi_st_strcmp_16_8(string,
381                                "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)")
382             ) {
383                 efi_st_printf("remaining device path: %ps\n", string);
384                 efi_st_error("LocateDevicePath: wrong remaining device path\n");
385                 return EFI_ST_FAILURE;
386         }
387         ret = boottime->free_pool(string);
388         if (ret != EFI_SUCCESS) {
389                 efi_st_error("FreePool failed\n");
390                 return EFI_ST_FAILURE;
391         }
392
393         return EFI_ST_SUCCESS;
394 }
395
396 EFI_UNIT_TEST(devicepath) = {
397         .name = "device path",
398         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
399         .setup = setup,
400         .execute = execute,
401         .teardown = teardown,
402 };