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