]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
MdeModulePkg/DxeCapsuleLibFmp: Add missing NULL pointer check.
[mirror_edk2.git] / SecurityPkg / Library / DxeDeferImageLoadLib / DxeDeferImageLoadLib.c
CommitLineData
0c18794e 1/** @file\r
2 Implement defer image load services for user identification in UEFI2.2.\r
3\r
b3548d32 4Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
289b714b 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
0c18794e 6\r
7**/\r
8\r
9#include "DxeDeferImageLoadLib.h"\r
10\r
11//\r
12// Handle for the Deferred Image Load Protocol instance produced by this driver.\r
13//\r
14EFI_HANDLE mDeferredImageHandle = NULL;\r
15BOOLEAN mIsProtocolInstalled = FALSE;\r
16EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;\r
17DEFERRED_IMAGE_TABLE mDeferredImage = {\r
18 0, // Deferred image count\r
19 NULL // The deferred image info\r
20};\r
21\r
22EFI_DEFERRED_IMAGE_LOAD_PROTOCOL gDeferredImageLoad = {\r
23 GetDefferedImageInfo\r
24};\r
25\r
26/**\r
27 Get the image type.\r
28\r
29 @param[in] File This is a pointer to the device path of the file\r
b3548d32 30 that is being dispatched.\r
0c18794e 31\r
b3548d32 32 @return UINT32 Image Type\r
0c18794e 33\r
34**/\r
35UINT32\r
36GetFileType (\r
37 IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
38 )\r
39{\r
40 EFI_STATUS Status;\r
b3548d32 41 EFI_HANDLE DeviceHandle;\r
0c18794e 42 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
43 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
44\r
45 //\r
46 // First check to see if File is from a Firmware Volume\r
47 //\r
48 DeviceHandle = NULL;\r
49 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
50 Status = gBS->LocateDevicePath (\r
51 &gEfiFirmwareVolume2ProtocolGuid,\r
52 &TempDevicePath,\r
53 &DeviceHandle\r
54 );\r
55 if (!EFI_ERROR (Status)) {\r
56 Status = gBS->OpenProtocol (\r
57 DeviceHandle,\r
58 &gEfiFirmwareVolume2ProtocolGuid,\r
59 NULL,\r
60 NULL,\r
61 NULL,\r
62 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
63 );\r
64 if (!EFI_ERROR (Status)) {\r
65 return IMAGE_FROM_FV;\r
66 }\r
67 }\r
68\r
69 //\r
70 // Next check to see if File is from a Block I/O device\r
71 //\r
72 DeviceHandle = NULL;\r
73 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
74 Status = gBS->LocateDevicePath (\r
75 &gEfiBlockIoProtocolGuid,\r
76 &TempDevicePath,\r
77 &DeviceHandle\r
78 );\r
79 if (!EFI_ERROR (Status)) {\r
80 BlockIo = NULL;\r
81 Status = gBS->OpenProtocol (\r
82 DeviceHandle,\r
83 &gEfiBlockIoProtocolGuid,\r
84 (VOID **) &BlockIo,\r
85 NULL,\r
86 NULL,\r
87 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
88 );\r
89 if (!EFI_ERROR (Status) && BlockIo != NULL) {\r
90 if (BlockIo->Media != NULL) {\r
91 if (BlockIo->Media->RemovableMedia) {\r
92 //\r
93 // Block I/O is present and specifies the media is removable\r
94 //\r
95 return IMAGE_FROM_REMOVABLE_MEDIA;\r
96 } else {\r
97 //\r
98 // Block I/O is present and specifies the media is not removable\r
99 //\r
100 return IMAGE_FROM_FIXED_MEDIA;\r
101 }\r
102 }\r
103 }\r
104 }\r
105\r
106 //\r
b3548d32 107 // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r
0c18794e 108 // the device path supports the Simple File System Protocol.\r
109 //\r
110 DeviceHandle = NULL;\r
111 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
112 Status = gBS->LocateDevicePath (\r
113 &gEfiSimpleFileSystemProtocolGuid,\r
114 &TempDevicePath,\r
115 &DeviceHandle\r
116 );\r
117 if (!EFI_ERROR (Status)) {\r
118 //\r
119 // Simple File System is present without Block I/O, so assume media is fixed.\r
120 //\r
121 return IMAGE_FROM_FIXED_MEDIA;\r
122 }\r
123\r
124 //\r
125 // File is not from an FV, Block I/O or Simple File System, so the only options\r
b3548d32 126 // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r
0c18794e 127 //\r
128 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
129 while (!IsDevicePathEndType (TempDevicePath)) {\r
130 switch (DevicePathType (TempDevicePath)) {\r
b3548d32 131\r
0c18794e 132 case MEDIA_DEVICE_PATH:\r
133 if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
134 return IMAGE_FROM_OPTION_ROM;\r
135 }\r
136 break;\r
137\r
138 case MESSAGING_DEVICE_PATH:\r
139 if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
140 return IMAGE_FROM_REMOVABLE_MEDIA;\r
b3548d32 141 }\r
0c18794e 142 break;\r
143\r
144 default:\r
145 break;\r
146 }\r
147 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
148 }\r
b3548d32 149 return IMAGE_UNKNOWN;\r
0c18794e 150}\r
151\r
152\r
153/**\r
154 Get current user's access right.\r
155\r
156 @param[out] AccessControl Points to the user's access control data, the\r
157 caller should free data buffer.\r
158 @param[in] AccessType The type of user access control.\r
159\r
160 @retval EFI_SUCCESS Get current user access control successfully\r
161 @retval others Fail to get current user access control\r
162\r
163**/\r
164EFI_STATUS\r
165GetAccessControl (\r
166 OUT EFI_USER_INFO_ACCESS_CONTROL **AccessControl,\r
167 IN UINT32 AccessType\r
168 )\r
169{\r
170 EFI_STATUS Status;\r
171 EFI_USER_INFO_HANDLE UserInfo;\r
172 EFI_USER_INFO *Info;\r
173 UINTN InfoSize;\r
174 EFI_USER_INFO_ACCESS_CONTROL *Access;\r
175 EFI_USER_PROFILE_HANDLE CurrentUser;\r
176 UINTN CheckLen;\r
177 EFI_USER_MANAGER_PROTOCOL *UserManager;\r
178\r
179 CurrentUser = NULL;\r
180 Status = gBS->LocateProtocol (\r
181 &gEfiUserManagerProtocolGuid,\r
182 NULL,\r
183 (VOID **) &UserManager\r
184 );\r
185 if (EFI_ERROR (Status)) {\r
186 return EFI_NOT_FOUND;\r
187 }\r
b3548d32 188\r
0c18794e 189 //\r
190 // Get current user access information.\r
191 //\r
192 UserManager->Current (UserManager, &CurrentUser);\r
193\r
194 UserInfo = NULL;\r
195 Info = NULL;\r
196 InfoSize = 0;\r
197 while (TRUE) {\r
198 //\r
199 // Get next user information.\r
200 //\r
201 Status = UserManager->GetNextInfo (UserManager, CurrentUser, &UserInfo);\r
202 if (EFI_ERROR (Status)) {\r
203 return Status;\r
204 }\r
205\r
206 Status = UserManager->GetInfo (\r
207 UserManager,\r
208 CurrentUser,\r
209 UserInfo,\r
210 Info,\r
211 &InfoSize\r
212 );\r
213 if (Status == EFI_BUFFER_TOO_SMALL) {\r
214 if (Info != NULL) {\r
215 FreePool (Info);\r
216 }\r
217 Info = AllocateZeroPool (InfoSize);\r
218 ASSERT (Info != NULL);\r
219 Status = UserManager->GetInfo (\r
220 UserManager,\r
221 CurrentUser,\r
222 UserInfo,\r
223 Info,\r
224 &InfoSize\r
225 );\r
226 }\r
227\r
228 if (EFI_ERROR (Status)) {\r
229 break;\r
230 }\r
b3548d32 231\r
0c18794e 232 ASSERT (Info != NULL);\r
233 if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) {\r
234 continue;\r
235 }\r
b3548d32 236\r
0c18794e 237 //\r
238 // Get specified access information.\r
239 //\r
240 CheckLen = 0;\r
241 while (CheckLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {\r
242 Access = (EFI_USER_INFO_ACCESS_CONTROL *) ((UINT8 *) (Info + 1) + CheckLen);\r
9a70350f 243 if (Access->Type == AccessType) {\r
0c18794e 244 *AccessControl = AllocateZeroPool (Access->Size);\r
245 ASSERT (*AccessControl != NULL);\r
246 CopyMem (*AccessControl, Access, Access->Size);\r
247 FreePool (Info);\r
248 return EFI_SUCCESS;\r
249 }\r
250 CheckLen += Access->Size;\r
251 }\r
252 }\r
b3548d32 253\r
0c18794e 254 if (Info != NULL) {\r
255 FreePool (Info);\r
256 }\r
257 return EFI_NOT_FOUND;\r
258}\r
259\r
0c18794e 260/**\r
5ec61d41 261 Get file name from device path.\r
0c18794e 262\r
b3548d32
LG
263 The file name may contain one or more device path node. Save the file name in a\r
264 buffer if file name is found. The caller is responsible to free the buffer.\r
265\r
5ec61d41
DG
266 @param[in] DevicePath A pointer to a device path.\r
267 @param[out] FileName The callee allocated buffer to save the file name if file name is found.\r
268 @param[out] FileNameOffset The offset of file name in device path if file name is found.\r
b3548d32 269\r
5ec61d41 270 @retval UINTN The file name length. 0 means file name is not found.\r
0c18794e 271\r
272**/\r
b3548d32 273UINTN\r
5ec61d41
DG
274GetFileName (\r
275 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
276 OUT UINT8 **FileName,\r
277 OUT UINTN *FileNameOffset\r
0c18794e 278 )\r
279{\r
5ec61d41
DG
280 UINTN Length;\r
281 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
282 EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;\r
283 CHAR8 *NodeStr;\r
284 UINTN NodeStrLength;\r
285 CHAR16 LastNodeChar;\r
286 CHAR16 FirstNodeChar;\r
287\r
288 //\r
289 // Get the length of DevicePath before file name.\r
290 //\r
291 Length = 0;\r
292 RootDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
293 while (!IsDevicePathEnd (RootDevicePath)) {\r
294 if ((DevicePathType(RootDevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType(RootDevicePath) == MEDIA_FILEPATH_DP)) {\r
295 break;\r
296 }\r
297 Length += DevicePathNodeLength (RootDevicePath);\r
298 RootDevicePath = NextDevicePathNode (RootDevicePath);\r
299 }\r
0c18794e 300\r
5ec61d41
DG
301 *FileNameOffset = Length;\r
302 if (Length == 0) {\r
303 return 0;\r
0c18794e 304 }\r
5ec61d41 305\r
0c18794e 306 //\r
5ec61d41 307 // Get the file name length.\r
0c18794e 308 //\r
5ec61d41
DG
309 Length = 0;\r
310 TmpDevicePath = RootDevicePath;\r
311 while (!IsDevicePathEnd (TmpDevicePath)) {\r
312 if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {\r
313 break;\r
0c18794e 314 }\r
5ec61d41
DG
315 Length += DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
316 TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
317 }\r
318 if (Length == 0) {\r
319 return 0;\r
320 }\r
0c18794e 321\r
5ec61d41
DG
322 *FileName = AllocateZeroPool (Length);\r
323 ASSERT (*FileName != NULL);\r
324\r
325 //\r
326 // Copy the file name to the buffer.\r
327 //\r
328 Length = 0;\r
329 LastNodeChar = '\\';\r
330 TmpDevicePath = RootDevicePath;\r
331 while (!IsDevicePathEnd (TmpDevicePath)) {\r
332 if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {\r
333 break;\r
334 }\r
335\r
336 FirstNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *)((UINT8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL)));\r
337 NodeStr = (CHAR8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
338 NodeStrLength = DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL) - sizeof(CHAR16);\r
b3548d32 339\r
5ec61d41
DG
340 if ((FirstNodeChar == '\\') && (LastNodeChar == '\\')) {\r
341 //\r
342 // Skip separator "\" when there are two separators.\r
343 //\r
344 NodeStr += sizeof (CHAR16);\r
b3548d32 345 NodeStrLength -= sizeof (CHAR16);\r
5ec61d41
DG
346 } else if ((FirstNodeChar != '\\') && (LastNodeChar != '\\')) {\r
347 //\r
348 // Add separator "\" when there is no separator.\r
349 //\r
350 WriteUnaligned16 ((UINT16 *)(*FileName + Length), '\\');\r
351 Length += sizeof (CHAR16);\r
b3548d32 352 }\r
5ec61d41
DG
353 CopyMem (*FileName + Length, NodeStr, NodeStrLength);\r
354 Length += NodeStrLength;\r
b3548d32 355\r
5ec61d41
DG
356 LastNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *) (NodeStr + NodeStrLength - sizeof(CHAR16)));\r
357 TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
b3548d32 358 }\r
5ec61d41
DG
359\r
360 return Length;\r
0c18794e 361}\r
362\r
363\r
364/**\r
365 Check whether the DevicePath2 is identical with DevicePath1, or identical with\r
366 DevicePath1's child device path.\r
367\r
368 If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device\r
369 path, then TRUE returned. Otherwise, FALSE is returned.\r
b3548d32 370\r
0c18794e 371 If DevicePath1 is NULL, then ASSERT().\r
372 If DevicePath2 is NULL, then ASSERT().\r
373\r
374 @param[in] DevicePath1 A pointer to a device path.\r
375 @param[in] DevicePath2 A pointer to a device path.\r
376\r
b3548d32 377 @retval TRUE Two device paths are identical , or DevicePath2 is\r
0c18794e 378 DevicePath1's child device path.\r
b3548d32 379 @retval FALSE Two device paths are not identical, and DevicePath2\r
0c18794e 380 is not DevicePath1's child device path.\r
381\r
382**/\r
383BOOLEAN\r
384CheckDevicePath (\r
385 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,\r
386 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2\r
387 )\r
388{\r
5ec61d41
DG
389 UINTN DevicePathSize;\r
390 UINTN FileNameSize1;\r
391 UINTN FileNameSize2;\r
392 UINT8 *FileName1;\r
393 UINT8 *FileName2;\r
394 UINTN FileNameOffset1;\r
395 UINTN FileNameOffset2;\r
396 BOOLEAN DevicePathEqual;\r
397\r
398 FileName1 = NULL;\r
399 FileName2 = NULL;\r
400 DevicePathEqual = TRUE;\r
0c18794e 401\r
402 ASSERT (DevicePath1 != NULL);\r
403 ASSERT (DevicePath2 != NULL);\r
5ec61d41
DG
404 if (IsDevicePathEnd (DevicePath1)) {\r
405 return FALSE;\r
406 }\r
b3548d32 407\r
0c18794e 408 //\r
b3548d32 409 // The file name may contain one or more device path node.\r
5ec61d41 410 // To compare the file name, copy file name to a buffer and compare the buffer.\r
0c18794e 411 //\r
5ec61d41
DG
412 FileNameSize1 = GetFileName (DevicePath1, &FileName1, &FileNameOffset1);\r
413 if (FileNameSize1 != 0) {\r
414 FileNameSize2 = GetFileName (DevicePath2, &FileName2, &FileNameOffset2);\r
415 if (FileNameOffset1 != FileNameOffset2) {\r
416 DevicePathEqual = FALSE;\r
417 goto Done;\r
418 }\r
b3548d32 419 if (CompareMem (DevicePath1, DevicePath2, FileNameOffset1) != 0) {\r
5ec61d41
DG
420 DevicePathEqual = FALSE;\r
421 goto Done;\r
422 }\r
423 if (FileNameSize1 > FileNameSize2) {\r
424 DevicePathEqual = FALSE;\r
425 goto Done;\r
426 }\r
b3548d32 427 if (CompareMem (FileName1, FileName2, FileNameSize1) != 0) {\r
5ec61d41
DG
428 DevicePathEqual = FALSE;\r
429 goto Done;\r
430 }\r
431 DevicePathEqual = TRUE;\r
432 goto Done;\r
433 }\r
434\r
435 DevicePathSize = GetDevicePathSize (DevicePath1);\r
436 if (DevicePathSize > GetDevicePathSize (DevicePath2)) {\r
437 return FALSE;\r
438 }\r
439\r
0c18794e 440 //\r
5ec61d41 441 // Exclude the end of device path node.\r
0c18794e 442 //\r
5ec61d41
DG
443 DevicePathSize -= sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
444 if (CompareMem (DevicePath1, DevicePath2, DevicePathSize) != 0) {\r
0c18794e 445 DevicePathEqual = FALSE;\r
b3548d32
LG
446 }\r
447\r
448Done:\r
5ec61d41
DG
449 if (FileName1 != NULL) {\r
450 FreePool (FileName1);\r
451 }\r
452 if (FileName2 != NULL) {\r
453 FreePool (FileName2);\r
0c18794e 454 }\r
0c18794e 455 return DevicePathEqual;\r
456}\r
457\r
458\r
459/**\r
b3548d32
LG
460 Check whether the image pointed to by DevicePath is in the device path list\r
461 specified by AccessType.\r
0c18794e 462\r
463 @param[in] DevicePath Points to device path.\r
464 @param[in] AccessType The type of user access control.\r
b3548d32 465\r
0ab475c9 466 @retval TRUE The DevicePath is in the specified List.\r
0c18794e 467 @retval FALSE The DevicePath is not in the specified List.\r
468\r
469**/\r
470BOOLEAN\r
471IsDevicePathInList (\r
472 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
473 IN UINT32 AccessType\r
474 )\r
475{\r
476 EFI_STATUS Status;\r
477 EFI_USER_INFO_ACCESS_CONTROL *Access;\r
478 EFI_DEVICE_PATH_PROTOCOL *Path;\r
b3548d32 479 UINTN OffSet;\r
0c18794e 480\r
481 Status = GetAccessControl (&Access, AccessType);\r
482 if (EFI_ERROR (Status)) {\r
483 return FALSE;\r
b3548d32 484 }\r
0c18794e 485\r
486 OffSet = 0;\r
487 while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {\r
b3548d32 488 Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet);\r
0c18794e 489 if (CheckDevicePath (Path, DevicePath)) {\r
490 //\r
491 // The device path is found in list.\r
492 //\r
493 FreePool (Access);\r
494 return TRUE;\r
b3548d32 495 }\r
0c18794e 496 OffSet += GetDevicePathSize (Path);\r
497 }\r
b3548d32 498\r
0c18794e 499 FreePool (Access);\r
b3548d32 500 return FALSE;\r
0c18794e 501}\r
502\r
503\r
504/**\r
b3548d32 505 Check whether the image pointed to by DevicePath is permitted to load.\r
0c18794e 506\r
507 @param[in] DevicePath Points to device path\r
b3548d32 508\r
0ab475c9 509 @retval TRUE The image pointed by DevicePath is permitted to load.\r
0c18794e 510 @retval FALSE The image pointed by DevicePath is forbidden to load.\r
511\r
512**/\r
513BOOLEAN\r
514VerifyDevicePath (\r
515 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
516 )\r
517{\r
518 if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {\r
519 //\r
b3548d32 520 // This access control overrides any restrictions put in place by the\r
0c18794e 521 // EFI_USER_INFO_ACCESS_FORBID_LOAD record.\r
522 //\r
523 return TRUE;\r
524 }\r
b3548d32 525\r
0c18794e 526 if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {\r
527 //\r
528 // The device path is found in the forbidden list.\r
529 //\r
530 return FALSE;\r
531 }\r
b3548d32
LG
532\r
533 return TRUE;\r
0c18794e 534}\r
535\r
536\r
537/**\r
b3548d32 538 Check the image pointed by DevicePath is a boot option or not.\r
0c18794e 539\r
540 @param[in] DevicePath Points to device path.\r
b3548d32 541\r
0ab475c9 542 @retval TRUE The image pointed by DevicePath is a boot option.\r
0c18794e 543 @retval FALSE The image pointed by DevicePath is not a boot option.\r
544\r
545**/\r
546BOOLEAN\r
547IsBootOption (\r
548 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
549 )\r
550{\r
551 EFI_STATUS Status;\r
552 UINT16 *BootOrderList;\r
553 UINTN BootOrderListSize;\r
554 UINTN Index;\r
555 CHAR16 StrTemp[20];\r
556 UINT8 *OptionBuffer;\r
557 UINT8 *OptionPtr;\r
558 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
b3548d32 559\r
0c18794e 560 //\r
561 // Get BootOrder\r
562 //\r
563 BootOrderListSize = 0;\r
b3548d32 564 BootOrderList = NULL;\r
0c18794e 565 Status = gRT->GetVariable (\r
b3548d32
LG
566 L"BootOrder",\r
567 &gEfiGlobalVariableGuid,\r
568 NULL,\r
569 &BootOrderListSize,\r
0c18794e 570 NULL\r
571 );\r
572 if (Status == EFI_BUFFER_TOO_SMALL) {\r
573 BootOrderList = AllocateZeroPool (BootOrderListSize);\r
574 ASSERT (BootOrderList != NULL);\r
575 Status = gRT->GetVariable (\r
b3548d32
LG
576 L"BootOrder",\r
577 &gEfiGlobalVariableGuid,\r
578 NULL,\r
579 &BootOrderListSize,\r
0c18794e 580 BootOrderList\r
581 );\r
582 }\r
b3548d32 583\r
0c18794e 584 if (EFI_ERROR (Status)) {\r
585 //\r
586 // No Boot option\r
587 //\r
588 return FALSE;\r
589 }\r
590\r
591 OptionBuffer = NULL;\r
592 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
593 //\r
594 // Try to find the DevicePath in BootOption\r
595 //\r
596 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);\r
f01b91ae 597 GetEfiGlobalVariable2 (StrTemp, (VOID**)&OptionBuffer, NULL);\r
0c18794e 598 if (OptionBuffer == NULL) {\r
599 continue;\r
600 }\r
601\r
602 //\r
603 // Check whether the image is forbidden.\r
604 //\r
b3548d32 605\r
0c18794e 606 OptionPtr = OptionBuffer;\r
607 //\r
608 // Skip attribute.\r
609 //\r
610 OptionPtr += sizeof (UINT32);\r
611\r
612 //\r
613 // Skip device path length.\r
614 //\r
615 OptionPtr += sizeof (UINT16);\r
616\r
617 //\r
618 // Skip descript string\r
619 //\r
620 OptionPtr += StrSize ((UINT16 *) OptionPtr);\r
b3548d32 621\r
0c18794e 622 //\r
623 // Now OptionPtr points to Device Path.\r
624 //\r
625 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr;\r
626\r
627 if (CheckDevicePath (DevicePath, OptionDevicePath)) {\r
628 FreePool (OptionBuffer);\r
629 OptionBuffer = NULL;\r
630 return TRUE;\r
631 }\r
632 FreePool (OptionBuffer);\r
633 OptionBuffer = NULL;\r
634 }\r
635\r
636 if (BootOrderList != NULL) {\r
637 FreePool (BootOrderList);\r
638 }\r
639\r
640 return FALSE;\r
641}\r
642\r
643\r
644/**\r
645 Add the image info to a deferred image list.\r
646\r
b3548d32
LG
647 @param[in] ImageDevicePath A pointer to the device path of a image.\r
648 @param[in] Image Points to the first byte of the image, or NULL if the\r
0c18794e 649 image is not available.\r
650 @param[in] ImageSize The size of the image, or 0 if the image is not available.\r
b3548d32 651\r
0c18794e 652**/\r
653VOID\r
654PutDefferedImageInfo (\r
655 IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r
656 IN VOID *Image,\r
657 IN UINTN ImageSize\r
658 )\r
659{\r
660 DEFERRED_IMAGE_INFO *CurImageInfo;\r
661 UINTN PathSize;\r
662\r
663 //\r
664 // Expand memory for the new deferred image.\r
665 //\r
666 if (mDeferredImage.Count == 0) {\r
667 mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO));\r
668 ASSERT (mDeferredImage.ImageInfo != NULL);\r
669 } else {\r
670 CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO));\r
671 ASSERT (CurImageInfo != NULL);\r
b3548d32 672\r
0c18794e 673 CopyMem (\r
b3548d32 674 CurImageInfo,\r
0c18794e 675 mDeferredImage.ImageInfo,\r
676 mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO)\r
677 );\r
678 FreePool (mDeferredImage.ImageInfo);\r
679 mDeferredImage.ImageInfo = CurImageInfo;\r
680 }\r
681 mDeferredImage.Count++;\r
b3548d32 682\r
0c18794e 683 //\r
684 // Save the deferred image information.\r
685 //\r
686 CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1];\r
687 PathSize = GetDevicePathSize (ImageDevicePath);\r
688 CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize);\r
689 ASSERT (CurImageInfo->ImageDevicePath != NULL);\r
690 CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize);\r
691\r
692 CurImageInfo->Image = Image;\r
693 CurImageInfo->ImageSize = ImageSize;\r
694 CurImageInfo->BootOption = IsBootOption (ImageDevicePath);\r
695}\r
696\r
697\r
698/**\r
699 Returns information about a deferred image.\r
700\r
b3548d32
LG
701 This function returns information about a single deferred image. The deferred images are\r
702 numbered consecutively, starting with 0. If there is no image which corresponds to\r
703 ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by\r
0c18794e 704 iteratively calling this function until EFI_NOT_FOUND is returned.\r
b3548d32
LG
705 Image may be NULL and ImageSize set to 0 if the decision to defer execution was made\r
706 because of the location of the executable image, rather than its actual contents.\r
0c18794e 707\r
708 @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.\r
709 @param[in] ImageIndex Zero-based index of the deferred index.\r
b3548d32
LG
710 @param[out] ImageDevicePath On return, points to a pointer to the device path of the image.\r
711 The device path should not be freed by the caller.\r
712 @param[out] Image On return, points to the first byte of the image or NULL if the\r
0c18794e 713 image is not available. The image should not be freed by the caller\r
b3548d32 714 unless LoadImage() has been successfully called.\r
0c18794e 715 @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.\r
b3548d32
LG
716 @param[out] BootOption On return, points to TRUE if the image was intended as a boot option\r
717 or FALSE if it was not intended as a boot option.\r
718\r
0c18794e 719 @retval EFI_SUCCESS Image information returned successfully.\r
720 @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.\r
b3548d32 721 @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or\r
0c18794e 722 BootOption is NULL.\r
b3548d32 723\r
0c18794e 724**/\r
725EFI_STATUS\r
726EFIAPI\r
727GetDefferedImageInfo (\r
728 IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,\r
729 IN UINTN ImageIndex,\r
730 OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,\r
731 OUT VOID **Image,\r
732 OUT UINTN *ImageSize,\r
733 OUT BOOLEAN *BootOption\r
734 )\r
735{\r
736 DEFERRED_IMAGE_INFO *ReqImageInfo;\r
737\r
738 //\r
739 // Check the parameter.\r
740 //\r
741\r
742 if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {\r
743 return EFI_INVALID_PARAMETER;\r
744 }\r
b3548d32 745\r
0c18794e 746 if ((ImageDevicePath == NULL) || (BootOption == NULL)) {\r
747 return EFI_INVALID_PARAMETER;\r
748 }\r
749\r
750 if (ImageIndex >= mDeferredImage.Count) {\r
751 return EFI_NOT_FOUND;\r
752 }\r
b3548d32 753\r
0c18794e 754 //\r
755 // Get the request deferred image.\r
b3548d32 756 //\r
0c18794e 757 ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex];\r
b3548d32 758\r
0c18794e 759 *ImageDevicePath = ReqImageInfo->ImageDevicePath;\r
760 *Image = ReqImageInfo->Image;\r
761 *ImageSize = ReqImageInfo->ImageSize;\r
762 *BootOption = ReqImageInfo->BootOption;\r
b3548d32 763\r
0c18794e 764 return EFI_SUCCESS;\r
765}\r
766\r
767\r
768/**\r
769 Provides the service of deferring image load based on platform policy control,\r
770 and installs Deferred Image Load Protocol.\r
771\r
b3548d32 772 @param[in] AuthenticationStatus This is the authentication status returned from the\r
0c18794e 773 security measurement services for the input file.\r
774 @param[in] File This is a pointer to the device path of the file that\r
775 is being dispatched. This will optionally be used for\r
776 logging.\r
777 @param[in] FileBuffer File buffer matches the input file device path.\r
778 @param[in] FileSize Size of File buffer matches the input file device path.\r
5db28a67
LG
779 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
780\r
781 @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start\r
782 UEFI device drivers on the device path specified by DevicePath.\r
783 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
784 FileBuffer did authenticate, and the platform policy dictates\r
785 that the DXE Foundation may use the file.\r
786 @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no\r
787 permission to start UEFI device drivers on the device path specified\r
788 by DevicePath.\r
789 @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load\r
790 drivers from the device path specified by DevicePath. The\r
791 image has been added into the list of the deferred images.\r
792 @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r
793 authenticate, and the platform policy dictates that the DXE\r
794 Foundation many not use File.\r
0c18794e 795\r
796**/\r
797EFI_STATUS\r
798EFIAPI\r
799DxeDeferImageLoadHandler (\r
800 IN UINT32 AuthenticationStatus,\r
801 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
802 IN VOID *FileBuffer,\r
5db28a67
LG
803 IN UINTN FileSize,\r
804 IN BOOLEAN BootPolicy\r
0c18794e 805 )\r
0c18794e 806{\r
807 EFI_STATUS Status;\r
808 EFI_USER_PROFILE_HANDLE CurrentUser;\r
809 UINT32 Policy;\r
810 UINT32 FileType;\r
811\r
5db28a67
LG
812 //\r
813 // Ignore if File is NULL.\r
814 //\r
0c18794e 815 if (File == NULL) {\r
5db28a67 816 return EFI_SUCCESS;\r
0c18794e 817 }\r
818\r
819 //\r
820 // Check whether user has a logon.\r
b3548d32 821 //\r
0c18794e 822 CurrentUser = NULL;\r
823 if (mUserManager != NULL) {\r
824 mUserManager->Current (mUserManager, &CurrentUser);\r
825 if (CurrentUser != NULL) {\r
826 //\r
827 // The user is logon; verify the FilePath by current user access policy.\r
828 //\r
829 if (!VerifyDevicePath (File)) {\r
830 DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));\r
5db28a67 831 return EFI_SECURITY_VIOLATION;\r
0c18794e 832 }\r
833 return EFI_SUCCESS;\r
834 }\r
835 }\r
b3548d32 836\r
0c18794e 837 //\r
838 // Still no user logon.\r
839 // Check the file type and get policy setting.\r
840 //\r
841 FileType = GetFileType (File);\r
842 Policy = PcdGet32 (PcdDeferImageLoadPolicy);\r
843 if ((Policy & FileType) == FileType) {\r
844 //\r
845 // This file type is secure to load.\r
846 //\r
847 return EFI_SUCCESS;\r
848 }\r
b3548d32 849\r
33985e3b 850 DEBUG ((EFI_D_INFO, "[Security] No user identified, the image is deferred to load!\n"));\r
5db28a67 851 PutDefferedImageInfo (File, FileBuffer, FileSize);\r
0c18794e 852\r
853 //\r
854 // Install the Deferred Image Load Protocol onto a new handle.\r
855 //\r
856 if (!mIsProtocolInstalled) {\r
857 Status = gBS->InstallMultipleProtocolInterfaces (\r
858 &mDeferredImageHandle,\r
859 &gEfiDeferredImageLoadProtocolGuid,\r
860 &gDeferredImageLoad,\r
861 NULL\r
862 );\r
863 ASSERT_EFI_ERROR (Status);\r
864 mIsProtocolInstalled = TRUE;\r
865 }\r
866\r
867 return EFI_ACCESS_DENIED;\r
868}\r
869\r
870/**\r
b3548d32 871 Locate user manager protocol when user manager is installed.\r
0c18794e 872\r
873 @param[in] Event The Event that is being processed, not used.\r
b3548d32 874 @param[in] Context Event Context, not used.\r
0c18794e 875\r
876**/\r
877VOID\r
878EFIAPI\r
879FindUserManagerProtocol (\r
880 IN EFI_EVENT Event,\r
881 IN VOID* Context\r
882 )\r
883{\r
884 gBS->LocateProtocol (\r
885 &gEfiUserManagerProtocolGuid,\r
886 NULL,\r
887 (VOID **) &mUserManager\r
888 );\r
b3548d32 889\r
0c18794e 890}\r
891\r
892\r
893/**\r
894 Register security handler for deferred image load.\r
895\r
896 @param[in] ImageHandle ImageHandle of the loaded driver.\r
897 @param[in] SystemTable Pointer to the EFI System Table.\r
898\r
899 @retval EFI_SUCCESS The handlers were registered successfully.\r
900**/\r
901EFI_STATUS\r
902EFIAPI\r
903DxeDeferImageLoadLibConstructor (\r
904 IN EFI_HANDLE ImageHandle,\r
905 IN EFI_SYSTEM_TABLE *SystemTable\r
906 )\r
907{\r
908 VOID *Registration;\r
b3548d32 909\r
0c18794e 910 //\r
911 // Register user manager notification function.\r
912 //\r
913 EfiCreateProtocolNotifyEvent (\r
b3548d32 914 &gEfiUserManagerProtocolGuid,\r
0c18794e 915 TPL_CALLBACK,\r
916 FindUserManagerProtocol,\r
917 NULL,\r
918 &Registration\r
919 );\r
b3548d32 920\r
5db28a67 921 return RegisterSecurity2Handler (\r
0c18794e 922 DxeDeferImageLoadHandler,\r
b3548d32
LG
923 EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD\r
924 );\r
0c18794e 925}\r
926\r
927\r