1 /** @file
2   Implement defer image load services for user identification in UEFI2.2.
3 
4 Copyright (c) 2009 - 2014, 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
GetFileType(IN CONST EFI_DEVICE_PATH_PROTOCOL * File)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
GetAccessControl(OUT EFI_USER_INFO_ACCESS_CONTROL ** AccessControl,IN UINT32 AccessType)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
GetFileName(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT UINT8 ** FileName,OUT UINTN * FileNameOffset)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
CheckDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath1,IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath2)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    TURE        The DevicePath is in the specified List.
473   @retval    FALSE       The DevicePath is not in the specified List.
474 
475 **/
476 BOOLEAN
IsDevicePathInList(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINT32 AccessType)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    TURE        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
VerifyDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)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    TURE        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
IsBootOption(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
PutDefferedImageInfo(IN CONST EFI_DEVICE_PATH_PROTOCOL * ImageDevicePath,IN VOID * Image,IN UINTN ImageSize)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
GetDefferedImageInfo(IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL * This,IN UINTN ImageIndex,OUT EFI_DEVICE_PATH_PROTOCOL ** ImageDevicePath,OUT VOID ** Image,OUT UINTN * ImageSize,OUT BOOLEAN * BootOption)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
DxeDeferImageLoadHandler(IN UINT32 AuthenticationStatus,IN CONST EFI_DEVICE_PATH_PROTOCOL * File,IN VOID * FileBuffer,IN UINTN FileSize,IN BOOLEAN BootPolicy)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
FindUserManagerProtocol(IN EFI_EVENT Event,IN VOID * Context)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
DxeDeferImageLoadLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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 
934