]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / SecurityStubDxe / Defer3rdPartyImageLoad.c
CommitLineData
8be37a5c
RN
1/** @file\r
2 Implement defer image load services for user identification in UEFI2.2.\r
3\r
4Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
8be37a5c
RN
6\r
7**/\r
8#include "Defer3rdPartyImageLoad.h"\r
9\r
10//\r
11// The structure to save the deferred 3rd party image information.\r
12//\r
13typedef struct {\r
1436aea4
MK
14 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;\r
15 BOOLEAN BootOption;\r
16 BOOLEAN Loaded;\r
8be37a5c
RN
17} DEFERRED_3RD_PARTY_IMAGE_INFO;\r
18\r
19//\r
20// The table to save the deferred 3rd party image item.\r
21//\r
22typedef struct {\r
1436aea4
MK
23 UINTN Count; ///< deferred 3rd party image count\r
24 DEFERRED_3RD_PARTY_IMAGE_INFO *ImageInfo; ///< deferred 3rd party image item\r
8be37a5c
RN
25} DEFERRED_3RD_PARTY_IMAGE_TABLE;\r
26\r
1436aea4
MK
27BOOLEAN mImageLoadedAfterEndOfDxe = FALSE;\r
28BOOLEAN mEndOfDxe = FALSE;\r
29DEFERRED_3RD_PARTY_IMAGE_TABLE mDeferred3rdPartyImage = {\r
8be37a5c
RN
30 0, // Deferred image count\r
31 NULL // The deferred image info\r
32};\r
33\r
1436aea4 34EFI_DEFERRED_IMAGE_LOAD_PROTOCOL mDeferredImageLoad = {\r
8be37a5c
RN
35 GetDefferedImageInfo\r
36};\r
37\r
38/**\r
39 Return whether the file comes from FV.\r
40\r
41 @param[in] File This is a pointer to the device path of the file\r
42 that is being dispatched.\r
43\r
44 @retval TRUE File comes from FV.\r
45 @retval FALSE File doesn't come from FV.\r
46**/\r
47BOOLEAN\r
48FileFromFv (\r
1436aea4 49 IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
8be37a5c
RN
50 )\r
51{\r
1436aea4
MK
52 EFI_STATUS Status;\r
53 EFI_HANDLE DeviceHandle;\r
54 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
8be37a5c
RN
55\r
56 //\r
57 // First check to see if File is from a Firmware Volume\r
58 //\r
59 DeviceHandle = NULL;\r
1436aea4
MK
60 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
61 Status = gBS->LocateDevicePath (\r
62 &gEfiFirmwareVolume2ProtocolGuid,\r
63 &TempDevicePath,\r
64 &DeviceHandle\r
65 );\r
8be37a5c
RN
66 if (!EFI_ERROR (Status)) {\r
67 Status = gBS->OpenProtocol (\r
68 DeviceHandle,\r
69 &gEfiFirmwareVolume2ProtocolGuid,\r
70 NULL,\r
71 NULL,\r
72 NULL,\r
73 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
74 );\r
75 if (!EFI_ERROR (Status)) {\r
76 return TRUE;\r
77 }\r
78 }\r
79\r
80 return FALSE;\r
81}\r
82\r
83/**\r
84 Find the deferred image which matches the device path.\r
85\r
86 @param[in] ImageDevicePath A pointer to the device path of a image.\r
87 @param[in] BootOption Whether the image is a boot option.\r
88\r
89 @return Pointer to the found deferred image or NULL if not found.\r
90**/\r
91DEFERRED_3RD_PARTY_IMAGE_INFO *\r
92LookupImage (\r
1436aea4
MK
93 IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r
94 IN BOOLEAN BootOption\r
8be37a5c
RN
95 )\r
96{\r
1436aea4
MK
97 UINTN Index;\r
98 UINTN DevicePathSize;\r
8be37a5c
RN
99\r
100 DevicePathSize = GetDevicePathSize (ImageDevicePath);\r
101\r
102 for (Index = 0; Index < mDeferred3rdPartyImage.Count; Index++) {\r
103 if (CompareMem (ImageDevicePath, mDeferred3rdPartyImage.ImageInfo[Index].ImageDevicePath, DevicePathSize) == 0) {\r
104 ASSERT (mDeferred3rdPartyImage.ImageInfo[Index].BootOption == BootOption);\r
105 return &mDeferred3rdPartyImage.ImageInfo[Index];\r
106 }\r
107 }\r
108\r
109 return NULL;\r
110}\r
111\r
112/**\r
113 Add the image info to a deferred image list.\r
114\r
115 @param[in] ImageDevicePath A pointer to the device path of a image.\r
116 @param[in] BootOption Whether the image is a boot option.\r
117\r
118**/\r
119VOID\r
120QueueImage (\r
1436aea4
MK
121 IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r
122 IN BOOLEAN BootOption\r
8be37a5c
RN
123 )\r
124{\r
1436aea4 125 DEFERRED_3RD_PARTY_IMAGE_INFO *ImageInfo;\r
8be37a5c
RN
126\r
127 //\r
128 // Expand memory for the new deferred image.\r
129 //\r
130 ImageInfo = ReallocatePool (\r
131 mDeferred3rdPartyImage.Count * sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO),\r
132 (mDeferred3rdPartyImage.Count + 1) * sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO),\r
133 mDeferred3rdPartyImage.ImageInfo\r
1436aea4 134 );\r
8be37a5c
RN
135 if (ImageInfo == NULL) {\r
136 return;\r
137 }\r
1436aea4 138\r
8be37a5c
RN
139 mDeferred3rdPartyImage.ImageInfo = ImageInfo;\r
140\r
141 //\r
142 // Save the deferred image information.\r
143 //\r
1436aea4 144 ImageInfo = &mDeferred3rdPartyImage.ImageInfo[mDeferred3rdPartyImage.Count];\r
8be37a5c
RN
145 ImageInfo->ImageDevicePath = DuplicateDevicePath (ImageDevicePath);\r
146 if (ImageInfo->ImageDevicePath == NULL) {\r
147 return;\r
148 }\r
1436aea4 149\r
8be37a5c
RN
150 ImageInfo->BootOption = BootOption;\r
151 ImageInfo->Loaded = FALSE;\r
152 mDeferred3rdPartyImage.Count++;\r
153}\r
154\r
8be37a5c
RN
155/**\r
156 Returns information about a deferred image.\r
157\r
158 This function returns information about a single deferred image. The deferred images are\r
159 numbered consecutively, starting with 0. If there is no image which corresponds to\r
160 ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by\r
161 iteratively calling this function until EFI_NOT_FOUND is returned.\r
162 Image may be NULL and ImageSize set to 0 if the decision to defer execution was made\r
163 because of the location of the executable image, rather than its actual contents.\r
164\r
165 @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.\r
166 @param[in] ImageIndex Zero-based index of the deferred index.\r
167 @param[out] ImageDevicePath On return, points to a pointer to the device path of the image.\r
168 The device path should not be freed by the caller.\r
169 @param[out] Image On return, points to the first byte of the image or NULL if the\r
170 image is not available. The image should not be freed by the caller\r
171 unless LoadImage() has been successfully called.\r
172 @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.\r
173 @param[out] BootOption On return, points to TRUE if the image was intended as a boot option\r
174 or FALSE if it was not intended as a boot option.\r
175\r
176 @retval EFI_SUCCESS Image information returned successfully.\r
177 @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.\r
178 @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or\r
179 BootOption is NULL.\r
180\r
181**/\r
182EFI_STATUS\r
183EFIAPI\r
184GetDefferedImageInfo (\r
185 IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,\r
186 IN UINTN ImageIndex,\r
1436aea4
MK
187 OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,\r
188 OUT VOID **Image,\r
189 OUT UINTN *ImageSize,\r
190 OUT BOOLEAN *BootOption\r
8be37a5c
RN
191 )\r
192{\r
1436aea4
MK
193 UINTN Index;\r
194 UINTN NewCount;\r
8be37a5c
RN
195\r
196 if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {\r
197 return EFI_INVALID_PARAMETER;\r
198 }\r
199\r
200 if ((ImageDevicePath == NULL) || (BootOption == NULL)) {\r
201 return EFI_INVALID_PARAMETER;\r
202 }\r
203\r
204 //\r
205 // Remove the loaded images from the defer list in the first call.\r
206 //\r
207 if (ImageIndex == 0) {\r
208 NewCount = 0;\r
209 for (Index = 0; Index < mDeferred3rdPartyImage.Count; Index++) {\r
210 if (!mDeferred3rdPartyImage.ImageInfo[Index].Loaded) {\r
211 CopyMem (\r
212 &mDeferred3rdPartyImage.ImageInfo[NewCount],\r
213 &mDeferred3rdPartyImage.ImageInfo[Index],\r
214 sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO)\r
215 );\r
216 NewCount++;\r
217 }\r
218 }\r
219\r
220 mDeferred3rdPartyImage.Count = NewCount;\r
221 }\r
222\r
223 if (ImageIndex >= mDeferred3rdPartyImage.Count) {\r
224 return EFI_NOT_FOUND;\r
225 }\r
226\r
227 //\r
228 // Get the request deferred image.\r
229 //\r
230 *ImageDevicePath = mDeferred3rdPartyImage.ImageInfo[ImageIndex].ImageDevicePath;\r
231 *BootOption = mDeferred3rdPartyImage.ImageInfo[ImageIndex].BootOption;\r
232 *Image = NULL;\r
233 *ImageSize = 0;\r
234\r
235 return EFI_SUCCESS;\r
236}\r
237\r
238/**\r
239 Callback function executed when the EndOfDxe event group is signaled.\r
240\r
241 @param[in] Event Event whose notification function is being invoked.\r
242 @param[in] Context The pointer to the notification function's context, which\r
243 is implementation-dependent.\r
244**/\r
245VOID\r
246EFIAPI\r
247EndOfDxe (\r
248 IN EFI_EVENT Event,\r
249 IN VOID *Context\r
250 )\r
251{\r
252 mEndOfDxe = TRUE;\r
253}\r
254\r
e048823f
RN
255/**\r
256 Event notification for gEfiDxeSmmReadyToLockProtocolGuid event.\r
257\r
258 This function reports failure if any deferred image is loaded before\r
259 this callback.\r
260 Platform should publish ReadyToLock protocol immediately after signaling\r
261 of the End of DXE Event.\r
262\r
263 @param Event The Event that is being processed, not used.\r
264 @param Context Event Context, not used.\r
265\r
266**/\r
267VOID\r
268EFIAPI\r
269DxeSmmReadyToLock (\r
270 IN EFI_EVENT Event,\r
271 IN VOID *Context\r
272 )\r
273{\r
1436aea4
MK
274 EFI_STATUS Status;\r
275 VOID *Interface;\r
e048823f
RN
276\r
277 Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);\r
278 if (EFI_ERROR (Status)) {\r
279 return;\r
280 }\r
281\r
282 gBS->CloseEvent (Event);\r
283\r
284 if (mImageLoadedAfterEndOfDxe) {\r
285 //\r
286 // Platform should not dispatch the 3rd party images after signaling EndOfDxe event\r
287 // but before publishing DxeSmmReadyToLock protocol.\r
288 //\r
289 DEBUG ((\r
290 DEBUG_ERROR,\r
291 "[Security] 3rd party images must be dispatched after DxeSmmReadyToLock Protocol installation!\n"\r
292 ));\r
293 REPORT_STATUS_CODE (\r
294 EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,\r
295 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)\r
296 );\r
297 ASSERT (FALSE);\r
298 CpuDeadLoop ();\r
299 }\r
300}\r
301\r
8be37a5c
RN
302/**\r
303 Defer the 3rd party image load and installs Deferred Image Load Protocol.\r
304\r
305 @param[in] File This is a pointer to the device path of the file that\r
306 is being dispatched. This will optionally be used for\r
307 logging.\r
308 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
309\r
310 @retval EFI_SUCCESS The file is not 3rd party image and can be loaded immediately.\r
311 @retval EFI_ACCESS_DENIED The file is 3rd party image and needs deferred.\r
312**/\r
313EFI_STATUS\r
314Defer3rdPartyImageLoad (\r
1436aea4
MK
315 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
316 IN BOOLEAN BootPolicy\r
8be37a5c
RN
317 )\r
318{\r
1436aea4 319 DEFERRED_3RD_PARTY_IMAGE_INFO *ImageInfo;\r
8be37a5c
RN
320\r
321 //\r
322 // Ignore if File is NULL.\r
323 //\r
324 if (File == NULL) {\r
325 return EFI_SUCCESS;\r
326 }\r
327\r
328 if (FileFromFv (File)) {\r
329 return EFI_SUCCESS;\r
330 }\r
331\r
332 ImageInfo = LookupImage (File, BootPolicy);\r
333\r
db52c7f7 334 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
335 CHAR16 *DevicePathStr;\r
336\r
337 DevicePathStr = ConvertDevicePathToText (File, FALSE, FALSE);\r
338 DEBUG ((\r
339 DEBUG_INFO,\r
340 "[Security] 3rd party image[%p] %s EndOfDxe: %s.\n",\r
341 ImageInfo,\r
342 mEndOfDxe ? L"can be loaded after" : L"is deferred to load before",\r
343 DevicePathStr\r
344 ));\r
345 if (DevicePathStr != NULL) {\r
346 FreePool (DevicePathStr);\r
347 }\r
348\r
db52c7f7 349 DEBUG_CODE_END ();\r
8be37a5c
RN
350\r
351 if (mEndOfDxe) {\r
e048823f 352 mImageLoadedAfterEndOfDxe = TRUE;\r
8be37a5c
RN
353 //\r
354 // The image might be first time loaded after EndOfDxe,\r
355 // So ImageInfo can be NULL.\r
356 //\r
357 if (ImageInfo != NULL) {\r
358 ImageInfo->Loaded = TRUE;\r
359 }\r
1436aea4 360\r
8be37a5c
RN
361 return EFI_SUCCESS;\r
362 } else {\r
363 //\r
364 // The image might be second time loaded before EndOfDxe,\r
365 // So ImageInfo can be non-NULL.\r
366 //\r
367 if (ImageInfo == NULL) {\r
368 QueueImage (File, BootPolicy);\r
369 }\r
1436aea4 370\r
8be37a5c
RN
371 return EFI_ACCESS_DENIED;\r
372 }\r
373}\r
374\r
375/**\r
376 Installs DeferredImageLoad Protocol and listens EndOfDxe event.\r
377**/\r
378VOID\r
379Defer3rdPartyImageLoadInitialize (\r
380 VOID\r
381 )\r
382{\r
1436aea4
MK
383 EFI_STATUS Status;\r
384 EFI_HANDLE Handle;\r
385 EFI_EVENT Event;\r
386 VOID *Registration;\r
8be37a5c
RN
387\r
388 Handle = NULL;\r
389 Status = gBS->InstallMultipleProtocolInterfaces (\r
390 &Handle,\r
391 &gEfiDeferredImageLoadProtocolGuid,\r
392 &mDeferredImageLoad,\r
393 NULL\r
394 );\r
395 ASSERT_EFI_ERROR (Status);\r
396\r
397 Status = gBS->CreateEventEx (\r
398 EVT_NOTIFY_SIGNAL,\r
399 TPL_CALLBACK,\r
400 EndOfDxe,\r
401 NULL,\r
402 &gEfiEndOfDxeEventGroupGuid,\r
403 &Event\r
404 );\r
405 ASSERT_EFI_ERROR (Status);\r
e048823f
RN
406\r
407 EfiCreateProtocolNotifyEvent (\r
408 &gEfiDxeSmmReadyToLockProtocolGuid,\r
409 TPL_CALLBACK,\r
410 DxeSmmReadyToLock,\r
411 NULL,\r
412 &Registration\r
413 );\r
8be37a5c 414}\r