efi_loader: validate load option
[oweals/u-boot.git] / lib / efi_selftest / efi_selftest_load_initrd.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_load_initrd
4  *
5  * Copyright (c) 2020 Ilias Apalodimas <ilias.apalodimas@linaro.org>
6  *
7  * This test checks the FileLoad2 protocol.
8  * A known file is read from the file system and verified.
9  *
10  * An example usage - given a file image with a file system in partition 1
11  * holding file initrd - is:
12  *
13  * * Configure the sandbox with
14  *
15  *   CONFIG_EFI_SELFTEST=y
16  *   CONFIG_EFI_LOAD_FILE2_INITRD=y
17  *   CONFIG_EFI_INITRD_FILESPEC="host 0:1 initrd"
18  *
19  * * Run ./u-boot and execute
20  *
21  *   host bind 0 image
22  *   setenv efi_selftest load initrd
23  *   bootefi selftest
24  *
25  * This would provide a test output like:
26  *
27  *   Testing EFI API implementation
28  *
29  *   Selected test: 'load initrd'
30  *
31  *   Setting up 'load initrd'
32  *   Setting up 'load initrd' succeeded
33  *
34  *   Executing 'load initrd'
35  *   Loaded 12378613 bytes
36  *   CRC32 2997478465
37  *
38  * Now the size and CRC32 can be compared to the provided file.
39  */
40
41 #include <efi_selftest.h>
42 #include <efi_loader.h>
43 #include <efi_load_initrd.h>
44
45 static struct efi_boot_services *boottime;
46
47 static struct efi_initrd_dp dp = {
48         .vendor = {
49                 {
50                    DEVICE_PATH_TYPE_MEDIA_DEVICE,
51                    DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
52                    sizeof(dp.vendor),
53                 },
54                 EFI_INITRD_MEDIA_GUID,
55         },
56         .end = {
57                 DEVICE_PATH_TYPE_END,
58                 DEVICE_PATH_SUB_TYPE_END,
59                 sizeof(dp.end),
60         }
61 };
62
63 static struct efi_initrd_dp dp_invalid = {
64         .vendor = {
65                 {
66                    DEVICE_PATH_TYPE_MEDIA_DEVICE,
67                    DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
68                    sizeof(dp.vendor),
69                 },
70                 EFI_INITRD_MEDIA_GUID,
71         },
72         .end = {
73                 0x8f, /* invalid */
74                 0xfe, /* invalid */
75                 sizeof(dp.end),
76         }
77 };
78
79 static int setup(const efi_handle_t handle,
80                  const struct efi_system_table *systable)
81 {
82         boottime = systable->boottime;
83
84         return EFI_ST_SUCCESS;
85 }
86
87 static int execute(void)
88 {
89         efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
90         struct efi_load_file_protocol *lf2;
91         struct efi_device_path *dp2, *dp2_invalid;
92         efi_status_t status;
93         efi_handle_t handle;
94         char buffer[64];
95         efi_uintn_t buffer_size;
96         void *buf;
97         u32 crc32;
98
99         memset(buffer, 0, sizeof(buffer));
100
101         dp2 = (struct efi_device_path *)&dp;
102         status = boottime->locate_device_path(&lf2_proto_guid, &dp2, &handle);
103         if (status != EFI_SUCCESS) {
104                 efi_st_error("Unable to locate device path\n");
105                 return EFI_ST_FAILURE;
106         }
107
108         status = boottime->handle_protocol(handle, &lf2_proto_guid,
109                                            (void **)&lf2);
110         if (status != EFI_SUCCESS) {
111                 efi_st_error("Unable to locate protocol\n");
112                 return EFI_ST_FAILURE;
113         }
114
115         /* Case 1:
116          * buffer_size can't be NULL
117          * protocol can't be NULL
118          */
119         status = lf2->load_file(lf2, dp2, false, NULL, &buffer);
120         if (status != EFI_INVALID_PARAMETER) {
121                 efi_st_error("Buffer size can't be NULL\n");
122                 return EFI_ST_FAILURE;
123         }
124         buffer_size = sizeof(buffer);
125         status = lf2->load_file(NULL, dp2, false, &buffer_size, &buffer);
126         if (status != EFI_INVALID_PARAMETER) {
127                 efi_st_error("Protocol can't be NULL\n");
128                 return EFI_ST_FAILURE;
129         }
130
131         /*
132          * Case 2: Match end node type/sub-type on device path
133          */
134         dp2_invalid = (struct efi_device_path *)&dp_invalid;
135         buffer_size = sizeof(buffer);
136         status = lf2->load_file(lf2, dp2_invalid, false, &buffer_size, &buffer);
137         if (status != EFI_INVALID_PARAMETER) {
138                 efi_st_error("Invalid device path type must return EFI_INVALID_PARAMETER\n");
139                 return EFI_ST_FAILURE;
140         }
141
142         status = lf2->load_file(lf2, dp2_invalid, false, &buffer_size, &buffer);
143         if (status != EFI_INVALID_PARAMETER) {
144                 efi_st_error("Invalid device path sub-type must return EFI_INVALID_PARAMETER\n");
145                 return EFI_ST_FAILURE;
146         }
147
148         /*
149          * Case 3:
150          * BootPolicy 'true' must return EFI_UNSUPPORTED
151          */
152         buffer_size = sizeof(buffer);
153         status = lf2->load_file(lf2, dp2, true, &buffer_size, &buffer);
154         if (status != EFI_UNSUPPORTED) {
155                 efi_st_error("BootPolicy true must return EFI_UNSUPPORTED\n");
156                 return EFI_ST_FAILURE;
157         }
158
159         /*
160          * Case: Pass buffer size as zero, firmware must return
161          * EFI_BUFFER_TOO_SMALL and an appropriate size
162          */
163         buffer_size = 0;
164         status = lf2->load_file(lf2, dp2, false, &buffer_size, NULL);
165         if (status != EFI_BUFFER_TOO_SMALL || !buffer_size) {
166                 efi_st_printf("buffer_size: %u\n", (unsigned int)buffer_size);
167                 efi_st_printf("status: %x\n", (unsigned int)status);
168                 efi_st_error("Buffer size not updated\n");
169                 return EFI_ST_FAILURE;
170         }
171
172         /*
173          * Case: Pass buffer size as smaller than the file_size,
174          * firmware must return * EFI_BUFFER_TOO_SMALL and an appropriate size
175          */
176         buffer_size = 1;
177         status = lf2->load_file(lf2, dp2, false, &buffer_size, &buffer);
178         if (status != EFI_BUFFER_TOO_SMALL || buffer_size <= 1) {
179                 efi_st_error("Buffer size not updated\n");
180                 return EFI_ST_FAILURE;
181         }
182
183         status = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size,
184                                          &buf);
185         if (status != EFI_SUCCESS) {
186                 efi_st_error("Cannot allocate buffer\n");
187                 return EFI_ST_FAILURE;
188         }
189
190         /* Case: Pass correct buffer, load the file and verify checksum*/
191         status = lf2->load_file(lf2, dp2, false, &buffer_size, buf);
192         if (status != EFI_SUCCESS) {
193                 efi_st_error("Loading initrd failed\n");
194                 return EFI_ST_FAILURE;
195         }
196
197         efi_st_printf("Loaded %u bytes\n", (unsigned int)buffer_size);
198         status = boottime->calculate_crc32(buf, buffer_size, &crc32);
199         if (status != EFI_SUCCESS) {
200                 efi_st_error("Could not determine CRC32\n");
201                 return EFI_ST_FAILURE;
202         }
203         efi_st_printf("CRC32 %u\n", (unsigned int)crc32);
204
205         status = boottime->free_pool(buf);
206         if (status != EFI_SUCCESS) {
207                 efi_st_error("Cannot free buffer\n");
208                 return EFI_ST_FAILURE;
209         }
210
211         return EFI_ST_SUCCESS;
212 }
213
214 EFI_UNIT_TEST(load_initrd) = {
215         .name = "load initrd",
216         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
217         .setup = setup,
218         .execute = execute,
219         .on_request = true,
220 };