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