1 /** @file
2   Internal file explorer functions for SecureBoot configuration module.
3 
4 Copyright (c) 2012 - 2015, 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 "SecureBootConfigImpl.h"
16 
17 ///
18 /// File system selection menu
19 ///
20 SECUREBOOT_MENU_OPTION      FsOptionMenu = {
21   SECUREBOOT_MENU_OPTION_SIGNATURE,
22   {NULL},
23   0
24 };
25 
26 ///
27 /// Files and sub-directories in current directory menu
28 ///
29 SECUREBOOT_MENU_OPTION      DirectoryMenu = {
30   SECUREBOOT_MENU_OPTION_SIGNATURE,
31   {NULL},
32   0
33 };
34 
35 VOID                  *mStartOpCodeHandle = NULL;
36 VOID                  *mEndOpCodeHandle = NULL;
37 EFI_IFR_GUID_LABEL    *mStartLabel = NULL;
38 EFI_IFR_GUID_LABEL    *mEndLabel = NULL;
39 
40 /**
41   Duplicate a string.
42 
43   @param[in]    Src             The source string.
44 
45   @return      A new string which is duplicated copy of the source,
46                or NULL if there is not enough memory.
47 
48 **/
49 CHAR16 *
StrDuplicate(IN CHAR16 * Src)50 StrDuplicate (
51   IN CHAR16   *Src
52   )
53 {
54   CHAR16  *Dest;
55   UINTN   Size;
56 
57   Size  = StrSize (Src);
58   Dest  = AllocateZeroPool (Size);
59   ASSERT (Dest != NULL);
60   if (Dest != NULL) {
61     CopyMem (Dest, Src, Size);
62   }
63 
64   return Dest;
65 }
66 
67 /**
68   Helper function called as part of the code needed to allocate
69   the proper sized buffer for various EFI interfaces.
70 
71   @param[in, out]   Status          Current status
72   @param[in, out]   Buffer          Current allocated buffer, or NULL
73   @param[in]        BufferSize      Current buffer size needed
74 
75   @retval  TRUE         If the buffer was reallocated and the caller
76                         should try the API again.
77   @retval  FALSE        The caller should not call this function again.
78 
79 **/
80 BOOLEAN
GrowBuffer(IN OUT EFI_STATUS * Status,IN OUT VOID ** Buffer,IN UINTN BufferSize)81 GrowBuffer (
82   IN OUT EFI_STATUS   *Status,
83   IN OUT VOID         **Buffer,
84   IN UINTN            BufferSize
85   )
86 {
87   BOOLEAN TryAgain;
88 
89   //
90   // If this is an initial request, buffer will be null with a new buffer size
91   //
92   if ((*Buffer == NULL) && (BufferSize != 0)) {
93     *Status = EFI_BUFFER_TOO_SMALL;
94   }
95   //
96   // If the status code is "buffer too small", resize the buffer
97   //
98   TryAgain = FALSE;
99   if (*Status == EFI_BUFFER_TOO_SMALL) {
100 
101     if (*Buffer != NULL) {
102       FreePool (*Buffer);
103     }
104 
105     *Buffer = AllocateZeroPool (BufferSize);
106 
107     if (*Buffer != NULL) {
108       TryAgain = TRUE;
109     } else {
110       *Status = EFI_OUT_OF_RESOURCES;
111     }
112   }
113   //
114   // If there's an error, free the buffer
115   //
116   if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) {
117     FreePool (*Buffer);
118     *Buffer = NULL;
119   }
120 
121   return TryAgain;
122 }
123 
124 /**
125   Append file name to existing file name, and allocate a new buffer
126   to hold the appended result.
127 
128   @param[in]  Str1  The existing file name
129   @param[in]  Str2  The file name to be appended
130 
131   @return      A new string with appended result.
132 
133 **/
134 CHAR16 *
AppendFileName(IN CHAR16 * Str1,IN CHAR16 * Str2)135 AppendFileName (
136   IN  CHAR16  *Str1,
137   IN  CHAR16  *Str2
138   )
139 {
140   UINTN   Size1;
141   UINTN   Size2;
142   UINTN   BufferSize;
143   CHAR16  *Str;
144   CHAR16  *TmpStr;
145   CHAR16  *Ptr;
146   CHAR16  *LastSlash;
147 
148   Size1 = StrSize (Str1);
149   Size2 = StrSize (Str2);
150   BufferSize = Size1 + Size2 + sizeof (CHAR16);
151   Str   = AllocateZeroPool (BufferSize);
152   ASSERT (Str != NULL);
153 
154   TmpStr = AllocateZeroPool (BufferSize);
155   ASSERT (TmpStr != NULL);
156 
157   StrCatS (Str, BufferSize / sizeof (CHAR16), Str1);
158 
159   if (!((*Str == '\\') && (*(Str + 1) == 0))) {
160     StrCatS (Str, BufferSize / sizeof (CHAR16), L"\\");
161   }
162 
163   StrCatS (Str, BufferSize / sizeof (CHAR16), Str2);
164 
165   Ptr       = Str;
166   LastSlash = Str;
167   while (*Ptr != 0) {
168     if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
169       //
170       // Convert "\Name\..\" to "\"
171       // DO NOT convert the .. if it is at the end of the string. This will
172       // break the .. behavior in changing directories.
173       //
174 
175       //
176       // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
177       // that overlap.
178       //
179       StrCpyS (TmpStr, BufferSize / sizeof (CHAR16), Ptr + 3);
180       StrCpyS (LastSlash, BufferSize / sizeof (CHAR16), TmpStr);
181       Ptr = LastSlash;
182     } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
183       //
184       // Convert a "\.\" to a "\"
185       //
186 
187       //
188       // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
189       // that overlap.
190       //
191       StrCpyS (TmpStr, BufferSize / sizeof (CHAR16), Ptr + 2);
192       StrCpyS (Ptr, BufferSize / sizeof (CHAR16), TmpStr);
193       Ptr = LastSlash;
194     } else if (*Ptr == '\\') {
195       LastSlash = Ptr;
196     }
197 
198     Ptr++;
199   }
200 
201   FreePool (TmpStr);
202 
203   return Str;
204 }
205 
206 /**
207   Create a SECUREBOOT_MENU_ENTRY, and stores it in a buffer allocated from the pool.
208 
209   @return           The new menu entry or NULL of error happens.
210 
211 **/
212 SECUREBOOT_MENU_ENTRY *
CreateMenuEntry(VOID)213 CreateMenuEntry (
214   VOID
215   )
216 {
217   SECUREBOOT_MENU_ENTRY *MenuEntry;
218   UINTN                 ContextSize;
219 
220   //
221   // Create new menu entry
222   //
223   MenuEntry = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY));
224   if (MenuEntry == NULL) {
225     return NULL;
226   }
227 
228   ContextSize = sizeof (SECUREBOOT_FILE_CONTEXT);
229   MenuEntry->FileContext = AllocateZeroPool (ContextSize);
230   if (MenuEntry->FileContext == NULL) {
231     FreePool (MenuEntry);
232     return NULL;
233   }
234 
235   MenuEntry->Signature = SECUREBOOT_MENU_ENTRY_SIGNATURE;
236 
237   return MenuEntry;
238 }
239 
240 /**
241   Get Menu Entry from the Menu Entry List by MenuNumber.
242 
243   If MenuNumber is great or equal to the number of Menu
244   Entry in the list, then ASSERT.
245 
246   @param[in]  MenuOption      The Menu Entry List to read the menu entry.
247   @param[in]  MenuNumber      The index of Menu Entry.
248 
249   @return     The Menu Entry.
250 
251 **/
252 SECUREBOOT_MENU_ENTRY *
GetMenuEntry(IN SECUREBOOT_MENU_OPTION * MenuOption,IN UINTN MenuNumber)253 GetMenuEntry (
254   IN  SECUREBOOT_MENU_OPTION      *MenuOption,
255   IN  UINTN                       MenuNumber
256   )
257 {
258   SECUREBOOT_MENU_ENTRY       *NewMenuEntry;
259   UINTN                       Index;
260   LIST_ENTRY                  *List;
261 
262   ASSERT (MenuNumber < MenuOption->MenuNumber);
263 
264   List = MenuOption->Head.ForwardLink;
265   for (Index = 0; Index < MenuNumber; Index++) {
266     List = List->ForwardLink;
267   }
268 
269   NewMenuEntry = CR (List, SECUREBOOT_MENU_ENTRY, Link, SECUREBOOT_MENU_ENTRY_SIGNATURE);
270 
271   return NewMenuEntry;
272 }
273 
274 /**
275   Create string tokens for a menu from its help strings and display strings.
276 
277   @param[in] HiiHandle          Hii Handle of the package to be updated.
278   @param[in] MenuOption         The Menu whose string tokens need to be created.
279 
280 **/
281 VOID
CreateMenuStringToken(IN EFI_HII_HANDLE HiiHandle,IN SECUREBOOT_MENU_OPTION * MenuOption)282 CreateMenuStringToken (
283   IN EFI_HII_HANDLE                          HiiHandle,
284   IN SECUREBOOT_MENU_OPTION                  *MenuOption
285   )
286 {
287   SECUREBOOT_MENU_ENTRY *NewMenuEntry;
288   UINTN         Index;
289 
290   for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
291     NewMenuEntry = GetMenuEntry (MenuOption, Index);
292 
293     NewMenuEntry->DisplayStringToken = HiiSetString (
294                                          HiiHandle,
295                                          0,
296                                          NewMenuEntry->DisplayString,
297                                          NULL
298                                          );
299 
300     if (NewMenuEntry->HelpString == NULL) {
301       NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
302     } else {
303       NewMenuEntry->HelpStringToken = HiiSetString (
304                                         HiiHandle,
305                                         0,
306                                         NewMenuEntry->HelpString,
307                                         NULL
308                                         );
309     }
310   }
311 }
312 
313 /**
314   Free up all resources allocated for a SECUREBOOT_MENU_ENTRY.
315 
316   @param[in, out]  MenuEntry   A pointer to SECUREBOOT_MENU_ENTRY.
317 
318 **/
319 VOID
DestroyMenuEntry(IN OUT SECUREBOOT_MENU_ENTRY * MenuEntry)320 DestroyMenuEntry (
321   IN OUT SECUREBOOT_MENU_ENTRY         *MenuEntry
322   )
323 {
324   SECUREBOOT_FILE_CONTEXT           *FileContext;
325 
326 
327   FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
328 
329   if (!FileContext->IsRoot && FileContext->DevicePath != NULL) {
330     FreePool (FileContext->DevicePath);
331   } else {
332     if (FileContext->FHandle != NULL) {
333       FileContext->FHandle->Close (FileContext->FHandle);
334     }
335   }
336 
337   if (FileContext->FileName != NULL) {
338     FreePool (FileContext->FileName);
339   }
340   if (FileContext->Info != NULL) {
341     FreePool (FileContext->Info);
342   }
343 
344   FreePool (FileContext);
345 
346   if (MenuEntry->DisplayString != NULL) {
347     FreePool (MenuEntry->DisplayString);
348   }
349   if (MenuEntry->HelpString != NULL) {
350     FreePool (MenuEntry->HelpString);
351   }
352 
353   FreePool (MenuEntry);
354 }
355 
356 /**
357   Free resources allocated in Allocate Rountine.
358 
359   @param[in, out]  MenuOption        Menu to be freed
360 
361 **/
362 VOID
FreeMenu(IN OUT SECUREBOOT_MENU_OPTION * MenuOption)363 FreeMenu (
364   IN OUT SECUREBOOT_MENU_OPTION        *MenuOption
365   )
366 {
367   SECUREBOOT_MENU_ENTRY      *MenuEntry;
368   while (!IsListEmpty (&MenuOption->Head)) {
369     MenuEntry = CR (
370                   MenuOption->Head.ForwardLink,
371                   SECUREBOOT_MENU_ENTRY,
372                   Link,
373                   SECUREBOOT_MENU_ENTRY_SIGNATURE
374                   );
375     RemoveEntryList (&MenuEntry->Link);
376     DestroyMenuEntry (MenuEntry);
377   }
378   MenuOption->MenuNumber = 0;
379 }
380 
381 /**
382   This function gets the file information from an open file descriptor, and stores it
383   in a buffer allocated from pool.
384 
385   @param[in]  FHand           File Handle.
386 
387   @return    A pointer to a buffer with file information or NULL is returned
388 
389 **/
390 EFI_FILE_INFO *
FileInfo(IN EFI_FILE_HANDLE FHand)391 FileInfo (
392   IN EFI_FILE_HANDLE      FHand
393   )
394 {
395   EFI_STATUS    Status;
396   EFI_FILE_INFO *Buffer;
397   UINTN         BufferSize;
398 
399   //
400   // Initialize for GrowBuffer loop
401   //
402   Buffer      = NULL;
403   BufferSize  = SIZE_OF_EFI_FILE_INFO + 200;
404 
405   //
406   // Call the real function
407   //
408   while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
409     Status = FHand->GetInfo (
410                       FHand,
411                       &gEfiFileInfoGuid,
412                       &BufferSize,
413                       Buffer
414                       );
415   }
416 
417   return Buffer;
418 }
419 
420 /**
421   This function gets the file system information from an open file descriptor,
422   and stores it in a buffer allocated from pool.
423 
424   @param[in] FHand       The file handle.
425 
426   @return                A pointer to a buffer with file information.
427   @retval                NULL is returned if failed to get Vaolume Label Info.
428 
429 **/
430 EFI_FILE_SYSTEM_VOLUME_LABEL *
FileSystemVolumeLabelInfo(IN EFI_FILE_HANDLE FHand)431 FileSystemVolumeLabelInfo (
432   IN EFI_FILE_HANDLE      FHand
433   )
434 {
435   EFI_STATUS                        Status;
436   EFI_FILE_SYSTEM_VOLUME_LABEL      *Buffer;
437   UINTN                             BufferSize;
438   //
439   // Initialize for GrowBuffer loop
440   //
441   Buffer      = NULL;
442   BufferSize  = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 200;
443 
444   //
445   // Call the real function
446   //
447   while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
448     Status = FHand->GetInfo (
449                       FHand,
450                       &gEfiFileSystemVolumeLabelInfoIdGuid,
451                       &BufferSize,
452                       Buffer
453                       );
454   }
455 
456   return Buffer;
457 }
458 
459 /**
460   This function will open a file or directory referenced by DevicePath.
461 
462   This function opens a file with the open mode according to the file path. The
463   Attributes is valid only for EFI_FILE_MODE_CREATE.
464 
465   @param[in, out]  FilePath        On input, the device path to the file.
466                                    On output, the remaining device path.
467   @param[out]      FileHandle      Pointer to the file handle.
468   @param[in]       OpenMode        The mode to open the file with.
469   @param[in]       Attributes      The file's file attributes.
470 
471   @retval EFI_SUCCESS              The information was set.
472   @retval EFI_INVALID_PARAMETER    One of the parameters has an invalid value.
473   @retval EFI_UNSUPPORTED          Could not open the file path.
474   @retval EFI_NOT_FOUND            The specified file could not be found on the
475                                    device or the file system could not be found on
476                                    the device.
477   @retval EFI_NO_MEDIA             The device has no medium.
478   @retval EFI_MEDIA_CHANGED        The device has a different medium in it or the
479                                    medium is no longer supported.
480   @retval EFI_DEVICE_ERROR         The device reported an error.
481   @retval EFI_VOLUME_CORRUPTED     The file system structures are corrupted.
482   @retval EFI_WRITE_PROTECTED      The file or medium is write protected.
483   @retval EFI_ACCESS_DENIED        The file was opened read only.
484   @retval EFI_OUT_OF_RESOURCES     Not enough resources were available to open the
485                                    file.
486   @retval EFI_VOLUME_FULL          The volume is full.
487 **/
488 EFI_STATUS
489 EFIAPI
OpenFileByDevicePath(IN OUT EFI_DEVICE_PATH_PROTOCOL ** FilePath,OUT EFI_FILE_HANDLE * FileHandle,IN UINT64 OpenMode,IN UINT64 Attributes)490 OpenFileByDevicePath(
491   IN OUT EFI_DEVICE_PATH_PROTOCOL     **FilePath,
492   OUT EFI_FILE_HANDLE                 *FileHandle,
493   IN UINT64                           OpenMode,
494   IN UINT64                           Attributes
495   )
496 {
497   EFI_STATUS                      Status;
498   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
499   EFI_FILE_PROTOCOL               *Handle1;
500   EFI_FILE_PROTOCOL               *Handle2;
501   EFI_HANDLE                      DeviceHandle;
502 
503   if ((FilePath == NULL || FileHandle == NULL)) {
504     return EFI_INVALID_PARAMETER;
505   }
506 
507   Status = gBS->LocateDevicePath (
508                   &gEfiSimpleFileSystemProtocolGuid,
509                   FilePath,
510                   &DeviceHandle
511                   );
512   if (EFI_ERROR (Status)) {
513     return Status;
514   }
515 
516   Status = gBS->OpenProtocol(
517                   DeviceHandle,
518                   &gEfiSimpleFileSystemProtocolGuid,
519                   (VOID**)&EfiSimpleFileSystemProtocol,
520                   gImageHandle,
521                   NULL,
522                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
523                   );
524   if (EFI_ERROR (Status)) {
525     return Status;
526   }
527 
528   Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
529   if (EFI_ERROR (Status)) {
530     FileHandle = NULL;
531     return Status;
532   }
533 
534   //
535   // go down directories one node at a time.
536   //
537   while (!IsDevicePathEnd (*FilePath)) {
538     //
539     // For file system access each node should be a file path component
540     //
541     if (DevicePathType    (*FilePath) != MEDIA_DEVICE_PATH ||
542         DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
543        ) {
544       FileHandle = NULL;
545       return (EFI_INVALID_PARAMETER);
546     }
547     //
548     // Open this file path node
549     //
550     Handle2  = Handle1;
551     Handle1 = NULL;
552 
553     //
554     // Try to test opening an existing file
555     //
556     Status = Handle2->Open (
557                           Handle2,
558                           &Handle1,
559                           ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
560                           OpenMode &~EFI_FILE_MODE_CREATE,
561                           0
562                          );
563 
564     //
565     // see if the error was that it needs to be created
566     //
567     if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
568       Status = Handle2->Open (
569                             Handle2,
570                             &Handle1,
571                             ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
572                             OpenMode,
573                             Attributes
574                            );
575     }
576     //
577     // Close the last node
578     //
579     Handle2->Close (Handle2);
580 
581     if (EFI_ERROR(Status)) {
582       return (Status);
583     }
584 
585     //
586     // Get the next node
587     //
588     *FilePath = NextDevicePathNode (*FilePath);
589   }
590 
591   //
592   // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
593   //
594   *FileHandle = (VOID*)Handle1;
595   return EFI_SUCCESS;
596 }
597 
598 /**
599   Function opens and returns a file handle to the root directory of a volume.
600 
601   @param[in]   DeviceHandle    A handle for a device
602 
603   @return      A valid file handle or NULL if error happens.
604 
605 **/
606 EFI_FILE_HANDLE
OpenRoot(IN EFI_HANDLE DeviceHandle)607 OpenRoot (
608   IN EFI_HANDLE                   DeviceHandle
609   )
610 {
611   EFI_STATUS                      Status;
612   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
613   EFI_FILE_HANDLE                 File;
614 
615   File = NULL;
616 
617   //
618   // File the file system interface to the device
619   //
620   Status = gBS->HandleProtocol (
621                   DeviceHandle,
622                   &gEfiSimpleFileSystemProtocolGuid,
623                   (VOID *) &Volume
624                   );
625 
626   //
627   // Open the root directory of the volume
628   //
629   if (!EFI_ERROR (Status)) {
630     Status = Volume->OpenVolume (
631                       Volume,
632                       &File
633                       );
634   }
635   //
636   // Done
637   //
638   return EFI_ERROR (Status) ? NULL : File;
639 }
640 
641 /**
642   This function builds the FsOptionMenu list which records all
643   available file system in the system. They include all instances
644   of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
645   and all type of legacy boot device.
646 
647   @retval  EFI_SUCCESS             Success find the file system
648   @retval  EFI_OUT_OF_RESOURCES    Can not create menu entry
649 
650 **/
651 EFI_STATUS
FindFileSystem(VOID)652 FindFileSystem (
653   VOID
654   )
655 {
656   UINTN                     NoBlkIoHandles;
657   UINTN                     NoSimpleFsHandles;
658   EFI_HANDLE                *BlkIoHandle;
659   EFI_HANDLE                *SimpleFsHandle;
660   UINT16                    *VolumeLabel;
661   EFI_BLOCK_IO_PROTOCOL     *BlkIo;
662   UINTN                     Index;
663   EFI_STATUS                Status;
664   SECUREBOOT_MENU_ENTRY     *MenuEntry;
665   SECUREBOOT_FILE_CONTEXT   *FileContext;
666   UINT16                    *TempStr;
667   UINTN                     OptionNumber;
668   VOID                      *Buffer;
669 
670   BOOLEAN                   RemovableMedia;
671 
672 
673   NoSimpleFsHandles = 0;
674   OptionNumber      = 0;
675   InitializeListHead (&FsOptionMenu.Head);
676 
677   //
678   // Locate Handles that support BlockIo protocol
679   //
680   Status = gBS->LocateHandleBuffer (
681                   ByProtocol,
682                   &gEfiBlockIoProtocolGuid,
683                   NULL,
684                   &NoBlkIoHandles,
685                   &BlkIoHandle
686                   );
687   if (!EFI_ERROR (Status)) {
688 
689     for (Index = 0; Index < NoBlkIoHandles; Index++) {
690       Status = gBS->HandleProtocol (
691                       BlkIoHandle[Index],
692                       &gEfiBlockIoProtocolGuid,
693                       (VOID **) &BlkIo
694                       );
695 
696       if (EFI_ERROR (Status)) {
697         continue;
698       }
699 
700       //
701       // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
702       //
703       if (BlkIo->Media->RemovableMedia) {
704         Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
705         if (NULL == Buffer) {
706           FreePool (BlkIoHandle);
707           return EFI_OUT_OF_RESOURCES;
708         }
709 
710         BlkIo->ReadBlocks (
711                 BlkIo,
712                 BlkIo->Media->MediaId,
713                 0,
714                 BlkIo->Media->BlockSize,
715                 Buffer
716                 );
717         FreePool (Buffer);
718       }
719     }
720     FreePool (BlkIoHandle);
721   }
722 
723   //
724   // Locate Handles that support Simple File System protocol
725   //
726   Status = gBS->LocateHandleBuffer (
727                   ByProtocol,
728                   &gEfiSimpleFileSystemProtocolGuid,
729                   NULL,
730                   &NoSimpleFsHandles,
731                   &SimpleFsHandle
732                   );
733   if (!EFI_ERROR (Status)) {
734     //
735     // Find all the instances of the File System prototocol
736     //
737     for (Index = 0; Index < NoSimpleFsHandles; Index++) {
738       Status = gBS->HandleProtocol (
739                       SimpleFsHandle[Index],
740                       &gEfiBlockIoProtocolGuid,
741                       (VOID **) &BlkIo
742                       );
743       if (EFI_ERROR (Status)) {
744         //
745         // If no block IO exists assume it's NOT a removable media
746         //
747         RemovableMedia = FALSE;
748       } else {
749         //
750         // If block IO exists check to see if it's remobable media
751         //
752         RemovableMedia = BlkIo->Media->RemovableMedia;
753       }
754 
755       //
756       // Allocate pool for this instance.
757       //
758       MenuEntry = CreateMenuEntry ();
759       if (NULL == MenuEntry) {
760         FreePool (SimpleFsHandle);
761         return EFI_OUT_OF_RESOURCES;
762       }
763 
764       FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
765 
766       FileContext->Handle     = SimpleFsHandle[Index];
767       MenuEntry->OptionNumber = Index;
768       FileContext->FHandle    = OpenRoot (FileContext->Handle);
769       if (FileContext->FHandle == NULL) {
770         DestroyMenuEntry (MenuEntry);
771         continue;
772       }
773 
774       MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
775       FileContext->Info = FileSystemVolumeLabelInfo (FileContext->FHandle);
776       FileContext->FileName = StrDuplicate (L"\\");
777       FileContext->DevicePath = FileDevicePath (
778                                   FileContext->Handle,
779                                   FileContext->FileName
780                                   );
781       FileContext->IsDir            = TRUE;
782       FileContext->IsRoot           = TRUE;
783       FileContext->IsRemovableMedia = RemovableMedia;
784       FileContext->IsLoadFile       = FALSE;
785 
786       //
787       // Get current file system's Volume Label
788       //
789       if (FileContext->Info == NULL) {
790         VolumeLabel = L"NO FILE SYSTEM INFO";
791       } else {
792         if (FileContext->Info->VolumeLabel == NULL) {
793           VolumeLabel = L"NULL VOLUME LABEL";
794         } else {
795           VolumeLabel = FileContext->Info->VolumeLabel;
796           if (*VolumeLabel == 0x0000) {
797             VolumeLabel = L"NO VOLUME LABEL";
798           }
799         }
800       }
801 
802       TempStr                   = MenuEntry->HelpString;
803       MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);
804       ASSERT (MenuEntry->DisplayString != NULL);
805       UnicodeSPrint (
806         MenuEntry->DisplayString,
807         MAX_CHAR,
808         L"%s, [%s]",
809         VolumeLabel,
810         TempStr
811         );
812       OptionNumber++;
813       InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
814     }
815   }
816 
817   if (NoSimpleFsHandles != 0) {
818     FreePool (SimpleFsHandle);
819   }
820 
821   //
822   // Remember how many file system options are here
823   //
824   FsOptionMenu.MenuNumber = OptionNumber;
825   return EFI_SUCCESS;
826 }
827 
828 
829 /**
830   Find files under the current directory. All files and sub-directories
831   in current directory will be stored in DirectoryMenu for future use.
832 
833   @param[in] MenuEntry     The Menu Entry.
834 
835   @retval EFI_SUCCESS      Get files from current dir successfully.
836   @return Other            Can't get files from current dir.
837 
838 **/
839 EFI_STATUS
FindFiles(IN SECUREBOOT_MENU_ENTRY * MenuEntry)840 FindFiles (
841   IN SECUREBOOT_MENU_ENTRY              *MenuEntry
842   )
843 {
844   EFI_FILE_HANDLE           NewDir;
845   EFI_FILE_HANDLE           Dir;
846   EFI_FILE_INFO             *DirInfo;
847   UINTN                     BufferSize;
848   UINTN                     DirBufferSize;
849   SECUREBOOT_MENU_ENTRY     *NewMenuEntry;
850   SECUREBOOT_FILE_CONTEXT   *FileContext;
851   SECUREBOOT_FILE_CONTEXT   *NewFileContext;
852   UINTN                     Pass;
853   EFI_STATUS                Status;
854   UINTN                     OptionNumber;
855 
856   FileContext   = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
857   Dir           = FileContext->FHandle;
858   OptionNumber  = 0;
859   //
860   // Open current directory to get files from it
861   //
862   Status = Dir->Open (
863                   Dir,
864                   &NewDir,
865                   FileContext->FileName,
866                   EFI_FILE_READ_ONLY,
867                   0
868                   );
869   if (!FileContext->IsRoot) {
870     Dir->Close (Dir);
871   }
872 
873   if (EFI_ERROR (Status)) {
874     return Status;
875   }
876 
877   DirInfo = FileInfo (NewDir);
878   if (DirInfo == NULL) {
879     return EFI_NOT_FOUND;
880   }
881 
882   if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
883     return EFI_INVALID_PARAMETER;
884   }
885 
886   FileContext->DevicePath = FileDevicePath (
887                               FileContext->Handle,
888                               FileContext->FileName
889                               );
890 
891   DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
892   DirInfo       = AllocateZeroPool (DirBufferSize);
893   if (DirInfo == NULL) {
894     return EFI_OUT_OF_RESOURCES;
895   }
896 
897   //
898   // Get all files in current directory
899   // Pass 1 to get Directories
900   // Pass 2 to get files that are EFI images
901   //
902   for (Pass = 1; Pass <= 2; Pass++) {
903     NewDir->SetPosition (NewDir, 0);
904     for (;;) {
905       BufferSize  = DirBufferSize;
906       Status      = NewDir->Read (NewDir, &BufferSize, DirInfo);
907       if (EFI_ERROR (Status) || BufferSize == 0) {
908         break;
909       }
910 
911       if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
912           ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
913           ) {
914         //
915         // Pass 1 is for Directories
916         // Pass 2 is for file names
917         //
918         continue;
919       }
920 
921       NewMenuEntry = CreateMenuEntry ();
922       if (NULL == NewMenuEntry) {
923         return EFI_OUT_OF_RESOURCES;
924       }
925 
926       NewFileContext          = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
927       NewFileContext->Handle  = FileContext->Handle;
928       NewFileContext->FileName = AppendFileName (
929                                   FileContext->FileName,
930                                   DirInfo->FileName
931                                   );
932       NewFileContext->FHandle = NewDir;
933       NewFileContext->DevicePath = FileDevicePath (
934                                     NewFileContext->Handle,
935                                     NewFileContext->FileName
936                                     );
937       NewMenuEntry->HelpString = NULL;
938 
939       NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
940       if (NewFileContext->IsDir) {
941         BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
942         NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
943 
944         UnicodeSPrint (
945           NewMenuEntry->DisplayString,
946           BufferSize,
947           L"<%s>",
948           DirInfo->FileName
949           );
950 
951       } else {
952         NewMenuEntry->DisplayString = StrDuplicate (DirInfo->FileName);
953       }
954 
955       NewFileContext->IsRoot            = FALSE;
956       NewFileContext->IsLoadFile        = FALSE;
957       NewFileContext->IsRemovableMedia  = FALSE;
958 
959       NewMenuEntry->OptionNumber        = OptionNumber;
960       OptionNumber++;
961       InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
962     }
963   }
964 
965   DirectoryMenu.MenuNumber = OptionNumber;
966   FreePool (DirInfo);
967   return EFI_SUCCESS;
968 }
969 
970 /**
971   Refresh the global UpdateData structure.
972 
973 **/
974 VOID
RefreshUpdateData(VOID)975 RefreshUpdateData (
976   VOID
977   )
978 {
979   //
980   // Free current updated date
981   //
982   if (mStartOpCodeHandle != NULL) {
983     HiiFreeOpCodeHandle (mStartOpCodeHandle);
984   }
985 
986   //
987   // Create new OpCode Handle
988   //
989   mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
990 
991   //
992   // Create Hii Extend Label OpCode as the start opcode
993   //
994   mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
995                                          mStartOpCodeHandle,
996                                          &gEfiIfrTianoGuid,
997                                          NULL,
998                                          sizeof (EFI_IFR_GUID_LABEL)
999                                          );
1000   mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1001 }
1002 
1003 /**
1004   Update the File Explore page.
1005 
1006   @param[in] HiiHandle          Hii Handle of the package to be updated.
1007   @param[in] MenuOption         The Menu whose string tokens need to be updated.
1008   @param[in] FeCurrentState     Current file explorer state.
1009 
1010 **/
1011 VOID
UpdateFileExplorePage(IN EFI_HII_HANDLE HiiHandle,IN SECUREBOOT_MENU_OPTION * MenuOption,IN FILE_EXPLORER_STATE FeCurrentState)1012 UpdateFileExplorePage (
1013   IN EFI_HII_HANDLE               HiiHandle,
1014   IN SECUREBOOT_MENU_OPTION       *MenuOption,
1015   IN FILE_EXPLORER_STATE          FeCurrentState
1016   )
1017 {
1018   UINTN                   Index;
1019   SECUREBOOT_MENU_ENTRY   *NewMenuEntry;
1020   SECUREBOOT_FILE_CONTEXT *NewFileContext;
1021   EFI_FORM_ID             FormId;
1022   EFI_FORM_ID             FileFormId;
1023 
1024   if (FeCurrentState == FileExplorerStateEnrollPkFile) {
1025     FormId     = SECUREBOOT_ADD_PK_FILE_FORM_ID;
1026     FileFormId = FORM_FILE_EXPLORER_ID_PK;
1027   } else if (FeCurrentState == FileExplorerStateEnrollKekFile) {
1028     FormId     = FORMID_ENROLL_KEK_FORM;
1029     FileFormId = FORM_FILE_EXPLORER_ID_KEK;
1030   } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {
1031     FormId     = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
1032     FileFormId = FORM_FILE_EXPLORER_ID_DB;
1033   } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {
1034     FormId     = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
1035     FileFormId = FORM_FILE_EXPLORER_ID_DBX;
1036   } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbt) {
1037     FormId     = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
1038     FileFormId = FORM_FILE_EXPLORER_ID_DBT;
1039   } else {
1040     return;
1041   }
1042 
1043   NewMenuEntry    = NULL;
1044   NewFileContext  = NULL;
1045 
1046   RefreshUpdateData ();
1047   mStartLabel->Number = FORM_FILE_EXPLORER_ID;
1048 
1049   for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
1050     NewMenuEntry    = GetMenuEntry (MenuOption, Index);
1051     NewFileContext  = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
1052 
1053     if (NewFileContext->IsDir) {
1054       //
1055       // Create Text opcode for directory.
1056       //
1057       HiiCreateActionOpCode (
1058         mStartOpCodeHandle,
1059         (UINT16) (FILE_OPTION_OFFSET + Index),
1060         NewMenuEntry->DisplayStringToken,
1061         STRING_TOKEN (STR_NULL),
1062         EFI_IFR_FLAG_CALLBACK,
1063         0
1064         );
1065     } else {
1066 
1067       //
1068       // Create Goto opcode for file.
1069       //
1070       HiiCreateGotoOpCode (
1071         mStartOpCodeHandle,
1072         FormId,
1073         NewMenuEntry->DisplayStringToken,
1074         STRING_TOKEN (STR_NULL),
1075         EFI_IFR_FLAG_CALLBACK,
1076         (UINT16) (FILE_OPTION_GOTO_OFFSET + Index)
1077         );
1078     }
1079   }
1080 
1081   HiiUpdateForm (
1082     HiiHandle,
1083     &gSecureBootConfigFormSetGuid,
1084     FileFormId,
1085     mStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
1086     mEndOpCodeHandle    // LABEL_END
1087     );
1088 }
1089 
1090 /**
1091   Update the file explorer page with the refreshed file system.
1092 
1093   @param[in] PrivateData     Module private data.
1094   @param[in] KeyValue        Key value to identify the type of data to expect.
1095 
1096   @retval  TRUE           Inform the caller to create a callback packet to exit file explorer.
1097   @retval  FALSE          Indicate that there is no need to exit file explorer.
1098 
1099 **/
1100 BOOLEAN
UpdateFileExplorer(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN UINT16 KeyValue)1101 UpdateFileExplorer (
1102   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
1103   IN UINT16                           KeyValue
1104   )
1105 {
1106   UINT16                              FileOptionMask;
1107   SECUREBOOT_MENU_ENTRY               *NewMenuEntry;
1108   SECUREBOOT_FILE_CONTEXT             *NewFileContext;
1109   EFI_FORM_ID                         FormId;
1110   BOOLEAN                             ExitFileExplorer;
1111   EFI_STATUS                          Status;
1112   EFI_DEVICE_PATH_PROTOCOL            *TmpDevicePath;
1113 
1114   NewMenuEntry      = NULL;
1115   NewFileContext    = NULL;
1116   ExitFileExplorer  = FALSE;
1117   FileOptionMask    = (UINT16) (FILE_OPTION_MASK & KeyValue);
1118 
1119   if (PrivateData->FeDisplayContext == FileExplorerDisplayUnknown) {
1120     //
1121     // First in, display file system.
1122     //
1123     FreeMenu (&FsOptionMenu);
1124     FindFileSystem ();
1125 
1126     CreateMenuStringToken (PrivateData->HiiHandle, &FsOptionMenu);
1127     UpdateFileExplorePage (PrivateData->HiiHandle, &FsOptionMenu, PrivateData->FeCurrentState);
1128 
1129     PrivateData->FeDisplayContext = FileExplorerDisplayFileSystem;
1130   } else {
1131     if (PrivateData->FeDisplayContext == FileExplorerDisplayFileSystem) {
1132       NewMenuEntry = GetMenuEntry (&FsOptionMenu, FileOptionMask);
1133     } else if (PrivateData->FeDisplayContext == FileExplorerDisplayDirectory) {
1134       NewMenuEntry = GetMenuEntry (&DirectoryMenu, FileOptionMask);
1135     }
1136 
1137     NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
1138 
1139     if (NewFileContext->IsDir ) {
1140       PrivateData->FeDisplayContext = FileExplorerDisplayDirectory;
1141 
1142       RemoveEntryList (&NewMenuEntry->Link);
1143       FreeMenu (&DirectoryMenu);
1144       Status = FindFiles (NewMenuEntry);
1145        if (EFI_ERROR (Status)) {
1146          ExitFileExplorer = TRUE;
1147          goto OnExit;
1148        }
1149       CreateMenuStringToken (PrivateData->HiiHandle, &DirectoryMenu);
1150       DestroyMenuEntry (NewMenuEntry);
1151 
1152       UpdateFileExplorePage (PrivateData->HiiHandle, &DirectoryMenu, PrivateData->FeCurrentState);
1153 
1154     } else {
1155       if (PrivateData->FeCurrentState == FileExplorerStateEnrollPkFile) {
1156         FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;
1157       } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollKekFile) {
1158         FormId = FORMID_ENROLL_KEK_FORM;
1159       } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {
1160         FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
1161       } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {
1162         FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
1163       } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbt) {
1164         FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
1165       } else {
1166         return FALSE;
1167       }
1168 
1169       PrivateData->MenuEntry = NewMenuEntry;
1170       PrivateData->FileContext->FileName = NewFileContext->FileName;
1171 
1172       TmpDevicePath = NewFileContext->DevicePath;
1173       OpenFileByDevicePath (
1174         &TmpDevicePath,
1175         &PrivateData->FileContext->FHandle,
1176         EFI_FILE_MODE_READ,
1177         0
1178         );
1179 
1180       //
1181       // Create Subtitle op-code for the display string of the option.
1182       //
1183       RefreshUpdateData ();
1184       mStartLabel->Number = FormId;
1185 
1186       HiiCreateSubTitleOpCode (
1187         mStartOpCodeHandle,
1188         NewMenuEntry->DisplayStringToken,
1189         0,
1190         0,
1191         0
1192         );
1193 
1194       HiiUpdateForm (
1195         PrivateData->HiiHandle,
1196         &gSecureBootConfigFormSetGuid,
1197         FormId,
1198         mStartOpCodeHandle, // Label FormId
1199         mEndOpCodeHandle    // LABEL_END
1200         );
1201     }
1202   }
1203 
1204 OnExit:
1205   return ExitFileExplorer;
1206 }
1207 
1208 /**
1209   Clean up the dynamic opcode at label and form specified by both LabelId.
1210 
1211   @param[in] LabelId         It is both the Form ID and Label ID for opcode deletion.
1212   @param[in] PrivateData     Module private data.
1213 
1214 **/
1215 VOID
CleanUpPage(IN UINT16 LabelId,IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData)1216 CleanUpPage (
1217   IN UINT16                           LabelId,
1218   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData
1219   )
1220 {
1221   RefreshUpdateData ();
1222 
1223   //
1224   // Remove all op-codes from dynamic page
1225   //
1226   mStartLabel->Number = LabelId;
1227   HiiUpdateForm (
1228     PrivateData->HiiHandle,
1229     &gSecureBootConfigFormSetGuid,
1230     LabelId,
1231     mStartOpCodeHandle, // Label LabelId
1232     mEndOpCodeHandle    // LABEL_END
1233     );
1234 }
1235