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