Add PI1.2.1 SAP2 support and UEFI231B mantis 896
[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
bf4a3dbd 4Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
0c18794e 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
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
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
36 that is being dispatched. \r
37\r
38 @return UINT32 Image Type \r
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
47 EFI_HANDLE DeviceHandle; \r
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
113 // File is not in a Firmware Volume or on a Block I/O device, so check to see if \r
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
132 // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. \r
133 //\r
134 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
135 while (!IsDevicePathEndType (TempDevicePath)) {\r
136 switch (DevicePathType (TempDevicePath)) {\r
137 \r
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
147 } \r
148 break;\r
149\r
150 default:\r
151 break;\r
152 }\r
153 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
154 }\r
155 return IMAGE_UNKNOWN; \r
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
194 \r
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
237 \r
238 ASSERT (Info != NULL);\r
239 if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) {\r
240 continue;\r
241 }\r
242 \r
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
249 if ((Access->Type == AccessType)) {\r
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
259 \r
260 if (Info != NULL) {\r
261 FreePool (Info);\r
262 }\r
263 return EFI_NOT_FOUND;\r
264}\r
265\r
266\r
267/**\r
268 Convert the '/' to '\' in the specified string.\r
269\r
270 @param[in, out] Str Points to the string to convert.\r
271\r
272**/\r
273VOID\r
274ConvertDPStr (\r
275 IN OUT EFI_STRING Str \r
276 )\r
277{\r
278 INTN Count;\r
279 INTN Index;\r
280 \r
281 Count = StrSize(Str) / 2 - 1;\r
282\r
283 if (Count < 4) {\r
284 return;\r
285 }\r
286 \r
287 //\r
288 // Convert device path string.\r
289 //\r
290 Index = Count - 1;\r
291 while (Index > 0) {\r
292 //\r
293 // Find the last '/'.\r
294 //\r
295 for (Index = Count - 1; Index > 0; Index--) {\r
296 if (Str[Index] == L'/')\r
297 break;\r
298 }\r
299\r
300 //\r
301 // Check next char.\r
302 //\r
303 if (Str[Index + 1] == L'\\')\r
304 return;\r
305 \r
306 Str[Index] = L'\\';\r
307 \r
308 //\r
309 // Check previous char.\r
310 //\r
311 if ((Index > 0) && (Str[Index - 1] == L'\\')) {\r
312 CopyMem (&Str[Index - 1], &Str[Index], (UINTN) ((Count - Index + 1) * sizeof (CHAR16)));\r
313 return;\r
314 }\r
315 Index--;\r
316 }\r
317}\r
318\r
319\r
320/**\r
321 Check whether the DevicePath2 is identical with DevicePath1, or identical with\r
322 DevicePath1's child device path.\r
323\r
324 If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device\r
325 path, then TRUE returned. Otherwise, FALSE is returned.\r
326 \r
327 If DevicePath1 is NULL, then ASSERT().\r
328 If DevicePath2 is NULL, then ASSERT().\r
329\r
330 @param[in] DevicePath1 A pointer to a device path.\r
331 @param[in] DevicePath2 A pointer to a device path.\r
332\r
333 @retval TRUE Two device paths are identical , or DevicePath2 is \r
334 DevicePath1's child device path.\r
335 @retval FALSE Two device paths are not identical, and DevicePath2 \r
336 is not DevicePath1's child device path.\r
337\r
338**/\r
339BOOLEAN\r
340CheckDevicePath (\r
341 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,\r
342 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2\r
343 )\r
344{\r
345 EFI_STATUS Status;\r
346 EFI_STRING DevicePathStr1;\r
347 EFI_STRING DevicePathStr2;\r
348 UINTN StrLen1;\r
349 UINTN StrLen2;\r
350 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathText;\r
351 BOOLEAN DevicePathEqual;\r
352\r
353 ASSERT (DevicePath1 != NULL);\r
354 ASSERT (DevicePath2 != NULL);\r
355 \r
356 DevicePathEqual = FALSE;\r
357 DevicePathText = NULL;\r
358 Status = gBS->LocateProtocol ( \r
359 &gEfiDevicePathToTextProtocolGuid,\r
360 NULL,\r
361 (VOID **) &DevicePathText\r
362 );\r
363 ASSERT (Status == EFI_SUCCESS);\r
364 \r
365 //\r
366 // Get first device path string.\r
367 //\r
368 DevicePathStr1 = DevicePathText->ConvertDevicePathToText (DevicePath1, TRUE, TRUE);\r
369 ConvertDPStr (DevicePathStr1);\r
370 //\r
371 // Get second device path string.\r
372 //\r
373 DevicePathStr2 = DevicePathText->ConvertDevicePathToText (DevicePath2, TRUE, TRUE);\r
374 ConvertDPStr (DevicePathStr2);\r
375 \r
376 //\r
377 // Compare device path string.\r
378 //\r
379 StrLen1 = StrSize (DevicePathStr1);\r
380 StrLen2 = StrSize (DevicePathStr2);\r
381 if (StrLen1 > StrLen2) {\r
382 DevicePathEqual = FALSE;\r
383 goto Done;\r
384 }\r
385 \r
386 if (CompareMem (DevicePathStr1, DevicePathStr2, StrLen1) == 0) {\r
387 DevicePathEqual = TRUE;\r
388 }\r
389\r
390Done:\r
391 FreePool (DevicePathStr1);\r
392 FreePool (DevicePathStr2);\r
393 return DevicePathEqual;\r
394}\r
395\r
396\r
397/**\r
398 Check whether the image pointed to by DevicePath is in the device path list \r
399 specified by AccessType. \r
400\r
401 @param[in] DevicePath Points to device path.\r
402 @param[in] AccessType The type of user access control.\r
403 \r
404 @retval TURE The DevicePath is in the specified List.\r
405 @retval FALSE The DevicePath is not in the specified List.\r
406\r
407**/\r
408BOOLEAN\r
409IsDevicePathInList (\r
410 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
411 IN UINT32 AccessType\r
412 )\r
413{\r
414 EFI_STATUS Status;\r
415 EFI_USER_INFO_ACCESS_CONTROL *Access;\r
416 EFI_DEVICE_PATH_PROTOCOL *Path;\r
417 UINTN OffSet; \r
418\r
419 Status = GetAccessControl (&Access, AccessType);\r
420 if (EFI_ERROR (Status)) {\r
421 return FALSE;\r
422 } \r
423\r
424 OffSet = 0;\r
425 while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {\r
426 Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet); \r
427 if (CheckDevicePath (Path, DevicePath)) {\r
428 //\r
429 // The device path is found in list.\r
430 //\r
431 FreePool (Access);\r
432 return TRUE;\r
433 } \r
434 OffSet += GetDevicePathSize (Path);\r
435 }\r
436 \r
437 FreePool (Access);\r
438 return FALSE; \r
439}\r
440\r
441\r
442/**\r
443 Check whether the image pointed to by DevicePath is permitted to load. \r
444\r
445 @param[in] DevicePath Points to device path\r
446 \r
447 @retval TURE The image pointed by DevicePath is permitted to load.\r
448 @retval FALSE The image pointed by DevicePath is forbidden to load.\r
449\r
450**/\r
451BOOLEAN\r
452VerifyDevicePath (\r
453 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
454 )\r
455{\r
456 if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {\r
457 //\r
458 // This access control overrides any restrictions put in place by the \r
459 // EFI_USER_INFO_ACCESS_FORBID_LOAD record.\r
460 //\r
461 return TRUE;\r
462 }\r
463 \r
464 if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {\r
465 //\r
466 // The device path is found in the forbidden list.\r
467 //\r
468 return FALSE;\r
469 }\r
470 \r
471 return TRUE; \r
472}\r
473\r
474\r
475/**\r
476 Check the image pointed by DevicePath is a boot option or not. \r
477\r
478 @param[in] DevicePath Points to device path.\r
479 \r
480 @retval TURE The image pointed by DevicePath is a boot option.\r
481 @retval FALSE The image pointed by DevicePath is not a boot option.\r
482\r
483**/\r
484BOOLEAN\r
485IsBootOption (\r
486 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
487 )\r
488{\r
489 EFI_STATUS Status;\r
490 UINT16 *BootOrderList;\r
491 UINTN BootOrderListSize;\r
492 UINTN Index;\r
493 CHAR16 StrTemp[20];\r
494 UINT8 *OptionBuffer;\r
495 UINT8 *OptionPtr;\r
496 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
497 \r
498 //\r
499 // Get BootOrder\r
500 //\r
501 BootOrderListSize = 0;\r
502 BootOrderList = NULL; \r
503 Status = gRT->GetVariable (\r
504 L"BootOrder", \r
505 &gEfiGlobalVariableGuid, \r
506 NULL, \r
507 &BootOrderListSize, \r
508 NULL\r
509 );\r
510 if (Status == EFI_BUFFER_TOO_SMALL) {\r
511 BootOrderList = AllocateZeroPool (BootOrderListSize);\r
512 ASSERT (BootOrderList != NULL);\r
513 Status = gRT->GetVariable (\r
514 L"BootOrder", \r
515 &gEfiGlobalVariableGuid, \r
516 NULL, \r
517 &BootOrderListSize, \r
518 BootOrderList\r
519 );\r
520 }\r
521 \r
522 if (EFI_ERROR (Status)) {\r
523 //\r
524 // No Boot option\r
525 //\r
526 return FALSE;\r
527 }\r
528\r
529 OptionBuffer = NULL;\r
530 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
531 //\r
532 // Try to find the DevicePath in BootOption\r
533 //\r
534 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);\r
f01b91ae 535 GetEfiGlobalVariable2 (StrTemp, (VOID**)&OptionBuffer, NULL);\r
0c18794e 536 if (OptionBuffer == NULL) {\r
537 continue;\r
538 }\r
539\r
540 //\r
541 // Check whether the image is forbidden.\r
542 //\r
543 \r
544 OptionPtr = OptionBuffer;\r
545 //\r
546 // Skip attribute.\r
547 //\r
548 OptionPtr += sizeof (UINT32);\r
549\r
550 //\r
551 // Skip device path length.\r
552 //\r
553 OptionPtr += sizeof (UINT16);\r
554\r
555 //\r
556 // Skip descript string\r
557 //\r
558 OptionPtr += StrSize ((UINT16 *) OptionPtr);\r
559 \r
560 //\r
561 // Now OptionPtr points to Device Path.\r
562 //\r
563 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr;\r
564\r
565 if (CheckDevicePath (DevicePath, OptionDevicePath)) {\r
566 FreePool (OptionBuffer);\r
567 OptionBuffer = NULL;\r
568 return TRUE;\r
569 }\r
570 FreePool (OptionBuffer);\r
571 OptionBuffer = NULL;\r
572 }\r
573\r
574 if (BootOrderList != NULL) {\r
575 FreePool (BootOrderList);\r
576 }\r
577\r
578 return FALSE;\r
579}\r
580\r
581\r
582/**\r
583 Add the image info to a deferred image list.\r
584\r
585 @param[in] ImageDevicePath A pointer to the device path of a image. \r
586 @param[in] Image Points to the first byte of the image, or NULL if the \r
587 image is not available.\r
588 @param[in] ImageSize The size of the image, or 0 if the image is not available.\r
589 \r
590**/\r
591VOID\r
592PutDefferedImageInfo (\r
593 IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r
594 IN VOID *Image,\r
595 IN UINTN ImageSize\r
596 )\r
597{\r
598 DEFERRED_IMAGE_INFO *CurImageInfo;\r
599 UINTN PathSize;\r
600\r
601 //\r
602 // Expand memory for the new deferred image.\r
603 //\r
604 if (mDeferredImage.Count == 0) {\r
605 mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO));\r
606 ASSERT (mDeferredImage.ImageInfo != NULL);\r
607 } else {\r
608 CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO));\r
609 ASSERT (CurImageInfo != NULL);\r
610 \r
611 CopyMem (\r
612 CurImageInfo, \r
613 mDeferredImage.ImageInfo,\r
614 mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO)\r
615 );\r
616 FreePool (mDeferredImage.ImageInfo);\r
617 mDeferredImage.ImageInfo = CurImageInfo;\r
618 }\r
619 mDeferredImage.Count++;\r
620 \r
621 //\r
622 // Save the deferred image information.\r
623 //\r
624 CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1];\r
625 PathSize = GetDevicePathSize (ImageDevicePath);\r
626 CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize);\r
627 ASSERT (CurImageInfo->ImageDevicePath != NULL);\r
628 CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize);\r
629\r
630 CurImageInfo->Image = Image;\r
631 CurImageInfo->ImageSize = ImageSize;\r
632 CurImageInfo->BootOption = IsBootOption (ImageDevicePath);\r
633}\r
634\r
635\r
636/**\r
637 Returns information about a deferred image.\r
638\r
639 This function returns information about a single deferred image. The deferred images are \r
640 numbered consecutively, starting with 0. If there is no image which corresponds to \r
641 ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by \r
642 iteratively calling this function until EFI_NOT_FOUND is returned.\r
643 Image may be NULL and ImageSize set to 0 if the decision to defer execution was made \r
644 because of the location of the executable image, rather than its actual contents. \r
645\r
646 @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.\r
647 @param[in] ImageIndex Zero-based index of the deferred index.\r
648 @param[out] ImageDevicePath On return, points to a pointer to the device path of the image. \r
649 The device path should not be freed by the caller. \r
650 @param[out] Image On return, points to the first byte of the image or NULL if the \r
651 image is not available. The image should not be freed by the caller\r
652 unless LoadImage() has been successfully called. \r
653 @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.\r
654 @param[out] BootOption On return, points to TRUE if the image was intended as a boot option \r
655 or FALSE if it was not intended as a boot option. \r
656 \r
657 @retval EFI_SUCCESS Image information returned successfully.\r
658 @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.\r
659 @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or \r
660 BootOption is NULL.\r
661 \r
662**/\r
663EFI_STATUS\r
664EFIAPI\r
665GetDefferedImageInfo (\r
666 IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,\r
667 IN UINTN ImageIndex,\r
668 OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,\r
669 OUT VOID **Image,\r
670 OUT UINTN *ImageSize,\r
671 OUT BOOLEAN *BootOption\r
672 )\r
673{\r
674 DEFERRED_IMAGE_INFO *ReqImageInfo;\r
675\r
676 //\r
677 // Check the parameter.\r
678 //\r
679\r
680 if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {\r
681 return EFI_INVALID_PARAMETER;\r
682 }\r
683 \r
684 if ((ImageDevicePath == NULL) || (BootOption == NULL)) {\r
685 return EFI_INVALID_PARAMETER;\r
686 }\r
687\r
688 if (ImageIndex >= mDeferredImage.Count) {\r
689 return EFI_NOT_FOUND;\r
690 }\r
691 \r
692 //\r
693 // Get the request deferred image.\r
694 // \r
695 ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex];\r
696 \r
697 *ImageDevicePath = ReqImageInfo->ImageDevicePath;\r
698 *Image = ReqImageInfo->Image;\r
699 *ImageSize = ReqImageInfo->ImageSize;\r
700 *BootOption = ReqImageInfo->BootOption;\r
701 \r
702 return EFI_SUCCESS;\r
703}\r
704\r
705\r
706/**\r
707 Provides the service of deferring image load based on platform policy control,\r
708 and installs Deferred Image Load Protocol.\r
709\r
710 @param[in] AuthenticationStatus This is the authentication status returned from the \r
711 security measurement services for the input file.\r
712 @param[in] File This is a pointer to the device path of the file that\r
713 is being dispatched. This will optionally be used for\r
714 logging.\r
715 @param[in] FileBuffer File buffer matches the input file device path.\r
716 @param[in] FileSize Size of File buffer matches the input file device path.\r
5db28a67
LG
717 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
718\r
719 @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start\r
720 UEFI device drivers on the device path specified by DevicePath.\r
721 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
722 FileBuffer did authenticate, and the platform policy dictates\r
723 that the DXE Foundation may use the file.\r
724 @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no\r
725 permission to start UEFI device drivers on the device path specified\r
726 by DevicePath.\r
727 @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load\r
728 drivers from the device path specified by DevicePath. The\r
729 image has been added into the list of the deferred images.\r
730 @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r
731 authenticate, and the platform policy dictates that the DXE\r
732 Foundation many not use File.\r
0c18794e 733\r
734**/\r
735EFI_STATUS\r
736EFIAPI\r
737DxeDeferImageLoadHandler (\r
738 IN UINT32 AuthenticationStatus,\r
739 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
740 IN VOID *FileBuffer,\r
5db28a67
LG
741 IN UINTN FileSize,\r
742 IN BOOLEAN BootPolicy\r
0c18794e 743 )\r
0c18794e 744{\r
745 EFI_STATUS Status;\r
746 EFI_USER_PROFILE_HANDLE CurrentUser;\r
747 UINT32 Policy;\r
748 UINT32 FileType;\r
749\r
5db28a67
LG
750 //\r
751 // Ignore if File is NULL.\r
752 //\r
0c18794e 753 if (File == NULL) {\r
5db28a67 754 return EFI_SUCCESS;\r
0c18794e 755 }\r
756\r
757 //\r
758 // Check whether user has a logon.\r
759 // \r
760 CurrentUser = NULL;\r
761 if (mUserManager != NULL) {\r
762 mUserManager->Current (mUserManager, &CurrentUser);\r
763 if (CurrentUser != NULL) {\r
764 //\r
765 // The user is logon; verify the FilePath by current user access policy.\r
766 //\r
767 if (!VerifyDevicePath (File)) {\r
768 DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));\r
5db28a67 769 return EFI_SECURITY_VIOLATION;\r
0c18794e 770 }\r
771 return EFI_SUCCESS;\r
772 }\r
773 }\r
774 \r
775 //\r
776 // Still no user logon.\r
777 // Check the file type and get policy setting.\r
778 //\r
779 FileType = GetFileType (File);\r
780 Policy = PcdGet32 (PcdDeferImageLoadPolicy);\r
781 if ((Policy & FileType) == FileType) {\r
782 //\r
783 // This file type is secure to load.\r
784 //\r
785 return EFI_SUCCESS;\r
786 }\r
787 \r
788 DEBUG ((EFI_D_ERROR, "[Security] No user identified, the image is deferred to load!\n"));\r
5db28a67 789 PutDefferedImageInfo (File, FileBuffer, FileSize);\r
0c18794e 790\r
791 //\r
792 // Install the Deferred Image Load Protocol onto a new handle.\r
793 //\r
794 if (!mIsProtocolInstalled) {\r
795 Status = gBS->InstallMultipleProtocolInterfaces (\r
796 &mDeferredImageHandle,\r
797 &gEfiDeferredImageLoadProtocolGuid,\r
798 &gDeferredImageLoad,\r
799 NULL\r
800 );\r
801 ASSERT_EFI_ERROR (Status);\r
802 mIsProtocolInstalled = TRUE;\r
803 }\r
804\r
805 return EFI_ACCESS_DENIED;\r
806}\r
807\r
808/**\r
809 Locate user manager protocol when user manager is installed. \r
810\r
811 @param[in] Event The Event that is being processed, not used.\r
812 @param[in] Context Event Context, not used. \r
813\r
814**/\r
815VOID\r
816EFIAPI\r
817FindUserManagerProtocol (\r
818 IN EFI_EVENT Event,\r
819 IN VOID* Context\r
820 )\r
821{\r
822 gBS->LocateProtocol (\r
823 &gEfiUserManagerProtocolGuid,\r
824 NULL,\r
825 (VOID **) &mUserManager\r
826 );\r
827 \r
828}\r
829\r
830\r
831/**\r
832 Register security handler for deferred image load.\r
833\r
834 @param[in] ImageHandle ImageHandle of the loaded driver.\r
835 @param[in] SystemTable Pointer to the EFI System Table.\r
836\r
837 @retval EFI_SUCCESS The handlers were registered successfully.\r
838**/\r
839EFI_STATUS\r
840EFIAPI\r
841DxeDeferImageLoadLibConstructor (\r
842 IN EFI_HANDLE ImageHandle,\r
843 IN EFI_SYSTEM_TABLE *SystemTable\r
844 )\r
845{\r
846 VOID *Registration;\r
847 \r
848 //\r
849 // Register user manager notification function.\r
850 //\r
851 EfiCreateProtocolNotifyEvent (\r
852 &gEfiUserManagerProtocolGuid, \r
853 TPL_CALLBACK,\r
854 FindUserManagerProtocol,\r
855 NULL,\r
856 &Registration\r
857 );\r
858 \r
5db28a67 859 return RegisterSecurity2Handler (\r
0c18794e 860 DxeDeferImageLoadHandler,\r
861 EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \r
862 ); \r
863}\r
864\r
865\r