• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Section Extraction Protocol implementation.
3 
4   Stream database is implemented as a linked list of section streams,
5   where each stream contains a linked list of children, which may be leaves or
6   encapsulations.
7 
8   Children that are encapsulations generate new stream entries
9   when they are created.  Streams can also be created by calls to
10   SEP->OpenSectionStream().
11 
12   The database is only created far enough to return the requested data from
13   any given stream, or to determine that the requested data is not found.
14 
15   If a GUIDed encapsulation is encountered, there are three possiblilites.
16 
17   1) A support protocol is found, in which the stream is simply processed with
18      the support protocol.
19 
20   2) A support protocol is not found, but the data is available to be read
21      without processing.  In this case, the database is built up through the
22      recursions to return the data, and a RPN event is set that will enable
23      the stream in question to be refreshed if and when the required section
24      extraction protocol is published.This insures the AuthenticationStatus
25      does not become stale in the cache.
26 
27   3) A support protocol is not found, and the data is not available to be read
28      without it.  This results in EFI_PROTOCOL_ERROR.
29 
30 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
31 This program and the accompanying materials
32 are licensed and made available under the terms and conditions of the BSD License
33 which accompanies this distribution.  The full text of the license may be found at
34 http://opensource.org/licenses/bsd-license.php
35 
36 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
37 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
38 
39 **/
40 
41 #include "DxeMain.h"
42 
43 //
44 // Local defines and typedefs
45 //
46 #define CORE_SECTION_CHILD_SIGNATURE  SIGNATURE_32('S','X','C','S')
47 #define CHILD_SECTION_NODE_FROM_LINK(Node) \
48   CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
49 
50 typedef struct {
51   UINT32                      Signature;
52   LIST_ENTRY                  Link;
53   UINT32                      Type;
54   UINT32                      Size;
55   //
56   // StreamBase + OffsetInStream == pointer to section header in stream.  The
57   // stream base is always known when walking the sections within.
58   //
59   UINT32                      OffsetInStream;
60   //
61   // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
62   // encapsulating section.  Otherwise, it contains the stream handle
63   // of the encapsulated stream.  This handle is ALWAYS produced any time an
64   // encapsulating child is encountered, irrespective of whether the
65   // encapsulated stream is processed further.
66   //
67   UINTN                       EncapsulatedStreamHandle;
68   EFI_GUID                    *EncapsulationGuid;
69   //
70   // If the section REQUIRES an extraction protocol, register for RPN
71   // when the required GUIDed extraction protocol becomes available.
72   //
73   EFI_EVENT                   Event;
74 } CORE_SECTION_CHILD_NODE;
75 
76 #define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
77 #define STREAM_NODE_FROM_LINK(Node) \
78   CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
79 
80 typedef struct {
81   UINT32                      Signature;
82   LIST_ENTRY                  Link;
83   UINTN                       StreamHandle;
84   UINT8                       *StreamBuffer;
85   UINTN                       StreamLength;
86   LIST_ENTRY                  Children;
87   //
88   // Authentication status is from GUIDed encapsulations.
89   //
90   UINT32                      AuthenticationStatus;
91 } CORE_SECTION_STREAM_NODE;
92 
93 #define NULL_STREAM_HANDLE    0
94 
95 typedef struct {
96   CORE_SECTION_CHILD_NODE     *ChildNode;
97   CORE_SECTION_STREAM_NODE    *ParentStream;
98   VOID                        *Registration;
99 } RPN_EVENT_CONTEXT;
100 
101 
102 /**
103   The ExtractSection() function processes the input section and
104   allocates a buffer from the pool in which it returns the section
105   contents. If the section being extracted contains
106   authentication information (the section's
107   GuidedSectionHeader.Attributes field has the
108   EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
109   returned in AuthenticationStatus must reflect the results of
110   the authentication operation. Depending on the algorithm and
111   size of the encapsulated data, the time that is required to do
112   a full authentication may be prohibitively long for some
113   classes of systems. To indicate this, use
114   EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
115   the security policy driver (see the Platform Initialization
116   Driver Execution Environment Core Interface Specification for
117   more details and the GUID definition). If the
118   EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
119   database, then, if possible, full authentication should be
120   skipped and the section contents simply returned in the
121   OutputBuffer. In this case, the
122   EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
123   must be set on return. ExtractSection() is callable only from
124   TPL_NOTIFY and below. Behavior of ExtractSection() at any
125   EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
126   defined in RaiseTPL() in the UEFI 2.0 specification.
127 
128 
129   @param This         Indicates the
130                       EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
131   @param InputSection Buffer containing the input GUIDed section
132                       to be processed. OutputBuffer OutputBuffer
133                       is allocated from boot services pool
134                       memory and contains the new section
135                       stream. The caller is responsible for
136                       freeing this buffer.
137   @param OutputBuffer *OutputBuffer is allocated from boot services
138                       pool memory and contains the new section stream.
139                       The caller is responsible for freeing this buffer.
140   @param OutputSize   A pointer to a caller-allocated UINTN in
141                       which the size of OutputBuffer allocation
142                       is stored. If the function returns
143                       anything other than EFI_SUCCESS, the value
144                       of OutputSize is undefined.
145 
146   @param AuthenticationStatus A pointer to a caller-allocated
147                               UINT32 that indicates the
148                               authentication status of the
149                               output buffer. If the input
150                               section's
151                               GuidedSectionHeader.Attributes
152                               field has the
153                               EFI_GUIDED_SECTION_AUTH_STATUS_VAL
154                               bit as clear, AuthenticationStatus
155                               must return zero. Both local bits
156                               (19:16) and aggregate bits (3:0)
157                               in AuthenticationStatus are
158                               returned by ExtractSection().
159                               These bits reflect the status of
160                               the extraction operation. The bit
161                               pattern in both regions must be
162                               the same, as the local and
163                               aggregate authentication statuses
164                               have equivalent meaning at this
165                               level. If the function returns
166                               anything other than EFI_SUCCESS,
167                               the value of AuthenticationStatus
168                               is undefined.
169 
170 
171   @retval EFI_SUCCESS          The InputSection was successfully
172                                processed and the section contents were
173                                returned.
174 
175   @retval EFI_OUT_OF_RESOURCES The system has insufficient
176                                resources to process the
177                                request.
178 
179   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
180                                 not match this instance of the
181                                 GUIDed Section Extraction
182                                 Protocol.
183 
184 **/
185 EFI_STATUS
186 EFIAPI
187 CustomGuidedSectionExtract (
188   IN CONST  EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
189   IN CONST  VOID                                   *InputSection,
190   OUT       VOID                                   **OutputBuffer,
191   OUT       UINTN                                  *OutputSize,
192   OUT       UINT32                                 *AuthenticationStatus
193   );
194 
195 //
196 // Module globals
197 //
198 LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
199 
200 EFI_HANDLE mSectionExtractionHandle = NULL;
201 
202 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
203   CustomGuidedSectionExtract
204 };
205 
206 
207 /**
208   Entry point of the section extraction code. Initializes an instance of the
209   section extraction interface and installs it on a new handle.
210 
211   @param  ImageHandle   A handle for the image that is initializing this driver
212   @param  SystemTable   A pointer to the EFI system table
213 
214   @retval EFI_SUCCESS           Driver initialized successfully
215   @retval EFI_OUT_OF_RESOURCES  Could not allocate needed resources
216 
217 **/
218 EFI_STATUS
219 EFIAPI
InitializeSectionExtraction(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)220 InitializeSectionExtraction (
221   IN EFI_HANDLE                   ImageHandle,
222   IN EFI_SYSTEM_TABLE             *SystemTable
223   )
224 {
225   EFI_STATUS                         Status;
226   EFI_GUID                           *ExtractHandlerGuidTable;
227   UINTN                              ExtractHandlerNumber;
228 
229   //
230   // Get custom extract guided section method guid list
231   //
232   ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
233 
234   Status = EFI_SUCCESS;
235   //
236   // Install custom guided extraction protocol
237   //
238   while (ExtractHandlerNumber-- > 0) {
239     Status = CoreInstallProtocolInterface (
240               &mSectionExtractionHandle,
241               &ExtractHandlerGuidTable [ExtractHandlerNumber],
242               EFI_NATIVE_INTERFACE,
243               &mCustomGuidedSectionExtractionProtocol
244               );
245     ASSERT_EFI_ERROR (Status);
246   }
247 
248   return Status;
249 }
250 
251 
252 /**
253   Check if a stream is valid.
254 
255   @param  SectionStream          The section stream to be checked
256   @param  SectionStreamLength    The length of section stream
257 
258   @return A boolean value indicating the validness of the section stream.
259 
260 **/
261 BOOLEAN
IsValidSectionStream(IN VOID * SectionStream,IN UINTN SectionStreamLength)262 IsValidSectionStream (
263   IN  VOID              *SectionStream,
264   IN  UINTN             SectionStreamLength
265   )
266 {
267   UINTN                       TotalLength;
268   UINTN                       SectionLength;
269   EFI_COMMON_SECTION_HEADER   *SectionHeader;
270   EFI_COMMON_SECTION_HEADER   *NextSectionHeader;
271 
272   TotalLength = 0;
273   SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
274 
275   while (TotalLength < SectionStreamLength) {
276     if (IS_SECTION2 (SectionHeader)) {
277       SectionLength = SECTION2_SIZE (SectionHeader);
278     } else {
279       SectionLength = SECTION_SIZE (SectionHeader);
280     }
281     TotalLength += SectionLength;
282 
283     if (TotalLength == SectionStreamLength) {
284       return TRUE;
285     }
286 
287     //
288     // Move to the next byte following the section...
289     //
290     SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
291 
292     //
293     // Figure out where the next section begins
294     //
295     NextSectionHeader = ALIGN_POINTER(SectionHeader, 4);
296     TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
297     SectionHeader = NextSectionHeader;
298   }
299 
300   ASSERT (FALSE);
301   return FALSE;
302 }
303 
304 
305 /**
306   Worker function.  Constructor for section streams.
307 
308   @param  SectionStreamLength    Size in bytes of the section stream.
309   @param  SectionStream          Buffer containing the new section stream.
310   @param  AllocateBuffer         Indicates whether the stream buffer is to be
311                                  copied or the input buffer is to be used in
312                                  place. AuthenticationStatus- Indicates the
313                                  default authentication status for the new
314                                  stream.
315   @param  AuthenticationStatus   A pointer to a caller-allocated UINT32 that
316                                  indicates the authentication status of the
317                                  output buffer. If the input section's
318                                  GuidedSectionHeader.Attributes field
319                                  has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
320                                  bit as clear, AuthenticationStatus must return
321                                  zero. Both local bits (19:16) and aggregate
322                                  bits (3:0) in AuthenticationStatus are returned
323                                  by ExtractSection(). These bits reflect the
324                                  status of the extraction operation. The bit
325                                  pattern in both regions must be the same, as
326                                  the local and aggregate authentication statuses
327                                  have equivalent meaning at this level. If the
328                                  function returns anything other than
329                                  EFI_SUCCESS, the value of *AuthenticationStatus
330                                  is undefined.
331   @param  SectionStreamHandle    A pointer to a caller allocated section stream
332                                  handle.
333 
334   @retval EFI_SUCCESS            Stream was added to stream database.
335   @retval EFI_OUT_OF_RESOURCES   memory allocation failed.
336 
337 **/
338 EFI_STATUS
OpenSectionStreamEx(IN UINTN SectionStreamLength,IN VOID * SectionStream,IN BOOLEAN AllocateBuffer,IN UINT32 AuthenticationStatus,OUT UINTN * SectionStreamHandle)339 OpenSectionStreamEx (
340   IN     UINTN                                     SectionStreamLength,
341   IN     VOID                                      *SectionStream,
342   IN     BOOLEAN                                   AllocateBuffer,
343   IN     UINT32                                    AuthenticationStatus,
344      OUT UINTN                                     *SectionStreamHandle
345   )
346 {
347   CORE_SECTION_STREAM_NODE    *NewStream;
348   EFI_TPL                     OldTpl;
349 
350   //
351   // Allocate a new stream
352   //
353   NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
354   if (NewStream == NULL) {
355     return EFI_OUT_OF_RESOURCES;
356   }
357 
358   if (AllocateBuffer) {
359     //
360     // if we're here, we're double buffering, allocate the buffer and copy the
361     // data in
362     //
363     if (SectionStreamLength > 0) {
364       NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
365       if (NewStream->StreamBuffer == NULL) {
366         CoreFreePool (NewStream);
367         return EFI_OUT_OF_RESOURCES;
368       }
369       //
370       // Copy in stream data
371       //
372       CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
373     } else {
374       //
375       // It's possible to have a zero length section stream.
376       //
377       NewStream->StreamBuffer = NULL;
378     }
379   } else {
380     //
381     // If were here, the caller has supplied the buffer (it's an internal call)
382     // so just assign the buffer.  This happens when we open section streams
383     // as a result of expanding an encapsulating section.
384     //
385     NewStream->StreamBuffer = SectionStream;
386   }
387 
388   //
389   // Initialize the rest of the section stream
390   //
391   NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;
392   NewStream->StreamHandle = (UINTN) NewStream;
393   NewStream->StreamLength = SectionStreamLength;
394   InitializeListHead (&NewStream->Children);
395   NewStream->AuthenticationStatus = AuthenticationStatus;
396 
397   //
398   // Add new stream to stream list
399   //
400   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
401   InsertTailList (&mStreamRoot, &NewStream->Link);
402   CoreRestoreTpl (OldTpl);
403 
404   *SectionStreamHandle = NewStream->StreamHandle;
405 
406   return EFI_SUCCESS;
407 }
408 
409 
410 /**
411   SEP member function.  This function creates and returns a new section stream
412   handle to represent the new section stream.
413 
414   @param  SectionStreamLength    Size in bytes of the section stream.
415   @param  SectionStream          Buffer containing the new section stream.
416   @param  SectionStreamHandle    A pointer to a caller allocated UINTN that on
417                                  output contains the new section stream handle.
418 
419   @retval EFI_SUCCESS            The section stream is created successfully.
420   @retval EFI_OUT_OF_RESOURCES   memory allocation failed.
421   @retval EFI_INVALID_PARAMETER  Section stream does not end concident with end
422                                  of last section.
423 
424 **/
425 EFI_STATUS
426 EFIAPI
OpenSectionStream(IN UINTN SectionStreamLength,IN VOID * SectionStream,OUT UINTN * SectionStreamHandle)427 OpenSectionStream (
428   IN     UINTN                                     SectionStreamLength,
429   IN     VOID                                      *SectionStream,
430      OUT UINTN                                     *SectionStreamHandle
431   )
432 {
433   //
434   // Check to see section stream looks good...
435   //
436   if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
437     return EFI_INVALID_PARAMETER;
438   }
439 
440   return OpenSectionStreamEx (
441            SectionStreamLength,
442            SectionStream,
443            FALSE,
444            0,
445            SectionStreamHandle
446            );
447 }
448 
449 
450 
451 /**
452   Worker function.  Determine if the input stream:child matches the input type.
453 
454   @param  Stream                 Indicates the section stream associated with the
455                                  child
456   @param  Child                  Indicates the child to check
457   @param  SearchType             Indicates the type of section to check against
458                                  for
459   @param  SectionDefinitionGuid  Indicates the GUID to check against if the type
460                                  is EFI_SECTION_GUID_DEFINED
461 
462   @retval TRUE                   The child matches
463   @retval FALSE                  The child doesn't match
464 
465 **/
466 BOOLEAN
ChildIsType(IN CORE_SECTION_STREAM_NODE * Stream,IN CORE_SECTION_CHILD_NODE * Child,IN EFI_SECTION_TYPE SearchType,IN EFI_GUID * SectionDefinitionGuid)467 ChildIsType (
468   IN CORE_SECTION_STREAM_NODE *Stream,
469   IN CORE_SECTION_CHILD_NODE  *Child,
470   IN EFI_SECTION_TYPE         SearchType,
471   IN EFI_GUID                 *SectionDefinitionGuid
472   )
473 {
474   EFI_GUID_DEFINED_SECTION    *GuidedSection;
475 
476   if (SearchType == EFI_SECTION_ALL) {
477     return TRUE;
478   }
479   if (Child->Type != SearchType) {
480     return FALSE;
481   }
482   if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
483     return TRUE;
484   }
485   GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);
486   if (IS_SECTION2 (GuidedSection)) {
487     return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *) GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
488   } else {
489     return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
490   }
491 }
492 
493 /**
494   Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
495 
496   @param GuidedSectionGuid          The Guided Section GUID.
497   @param GuidedSectionExtraction    A pointer to the pointer to the supported Guided Section Extraction Protocol
498                                     for the Guided Section.
499 
500   @return TRUE      The GuidedSectionGuid could be identified, and the pointer to
501                     the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
502   @return FALSE     The GuidedSectionGuid could not be identified, or
503                     the Guided Section Extraction Protocol has not been installed yet.
504 
505 **/
506 BOOLEAN
VerifyGuidedSectionGuid(IN EFI_GUID * GuidedSectionGuid,OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL ** GuidedSectionExtraction)507 VerifyGuidedSectionGuid (
508   IN  EFI_GUID                                  *GuidedSectionGuid,
509   OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL    **GuidedSectionExtraction
510   )
511 {
512   EFI_GUID              *GuidRecorded;
513   VOID                  *Interface;
514   EFI_STATUS            Status;
515 
516   Interface = NULL;
517 
518   //
519   // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
520   //
521   Status = EfiGetSystemConfigurationTable (GuidedSectionGuid, (VOID **) &GuidRecorded);
522   if (Status == EFI_SUCCESS) {
523     if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
524       //
525       // Found the recorded GuidedSectionGuid.
526       //
527       Status = CoreLocateProtocol (GuidedSectionGuid, NULL, (VOID **) &Interface);
528       if (!EFI_ERROR (Status) && Interface != NULL) {
529         //
530         // Found the supported Guided Section Extraction Porotocol for the Guided Section.
531         //
532         *GuidedSectionExtraction = (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *) Interface;
533         return TRUE;
534       }
535       return FALSE;
536     }
537   }
538 
539   return FALSE;
540 }
541 
542 /**
543   RPN callback function. Initializes the section stream
544   when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
545 
546   @param Event               The event that fired
547   @param RpnContext          A pointer to the context that allows us to identify
548                              the relevent encapsulation.
549 **/
550 VOID
551 EFIAPI
NotifyGuidedExtraction(IN EFI_EVENT Event,IN VOID * RpnContext)552 NotifyGuidedExtraction (
553   IN   EFI_EVENT   Event,
554   IN   VOID        *RpnContext
555   )
556 {
557   EFI_STATUS                              Status;
558   EFI_GUID_DEFINED_SECTION                *GuidedHeader;
559   EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL  *GuidedExtraction;
560   VOID                                    *NewStreamBuffer;
561   UINTN                                   NewStreamBufferSize;
562   UINT32                                  AuthenticationStatus;
563   RPN_EVENT_CONTEXT                       *Context;
564 
565   Context = RpnContext;
566 
567   GuidedHeader = (EFI_GUID_DEFINED_SECTION *) (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
568   ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
569 
570   if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {
571     return;
572   }
573 
574   Status = GuidedExtraction->ExtractSection (
575                                GuidedExtraction,
576                                GuidedHeader,
577                                &NewStreamBuffer,
578                                &NewStreamBufferSize,
579                                &AuthenticationStatus
580                                );
581   ASSERT_EFI_ERROR (Status);
582 
583   //
584   // Make sure we initialize the new stream with the correct
585   // authentication status for both aggregate and local status fields.
586   //
587   if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
588     //
589     // OR in the parent stream's aggregate status.
590     //
591     AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
592   } else {
593     //
594     // since there's no authentication data contributed by the section,
595     // just inherit the full value from our immediate parent.
596     //
597     AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
598   }
599 
600   Status = OpenSectionStreamEx (
601              NewStreamBufferSize,
602              NewStreamBuffer,
603              FALSE,
604              AuthenticationStatus,
605              &Context->ChildNode->EncapsulatedStreamHandle
606              );
607   ASSERT_EFI_ERROR (Status);
608 
609   //
610   //  Close the event when done.
611   //
612   gBS->CloseEvent (Event);
613   Context->ChildNode->Event = NULL;
614   FreePool (Context);
615 }
616 
617 /**
618   Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
619 
620   @param ParentStream        Indicates the parent of the ecnapsulation section (child)
621   @param ChildNode           Indicates the child node that is the encapsulation section.
622 
623 **/
624 VOID
CreateGuidedExtractionRpnEvent(IN CORE_SECTION_STREAM_NODE * ParentStream,IN CORE_SECTION_CHILD_NODE * ChildNode)625 CreateGuidedExtractionRpnEvent (
626   IN CORE_SECTION_STREAM_NODE      *ParentStream,
627   IN CORE_SECTION_CHILD_NODE       *ChildNode
628   )
629 {
630   RPN_EVENT_CONTEXT *Context;
631 
632   //
633   // Allocate new event structure and context
634   //
635   Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
636   ASSERT (Context != NULL);
637 
638   Context->ChildNode = ChildNode;
639   Context->ParentStream = ParentStream;
640 
641   Context->ChildNode->Event = EfiCreateProtocolNotifyEvent (
642                                 Context->ChildNode->EncapsulationGuid,
643                                 TPL_NOTIFY,
644                                 NotifyGuidedExtraction,
645                                 Context,
646                                 &Context->Registration
647                                 );
648 }
649 
650 /**
651   Worker function.  Constructor for new child nodes.
652 
653   @param  Stream                 Indicates the section stream in which to add the
654                                  child.
655   @param  ChildOffset            Indicates the offset in Stream that is the
656                                  beginning of the child section.
657   @param  ChildNode              Indicates the Callee allocated and initialized
658                                  child.
659 
660   @retval EFI_SUCCESS            Child node was found and returned.
661                                  EFI_OUT_OF_RESOURCES- Memory allocation failed.
662   @retval EFI_PROTOCOL_ERROR     Encapsulation sections produce new stream
663                                  handles when the child node is created.  If the
664                                  section type is GUID defined, and the extraction
665                                  GUID does not exist, and producing the stream
666                                  requires the GUID, then a protocol error is
667                                  generated and no child is produced. Values
668                                  returned by OpenSectionStreamEx.
669 
670 **/
671 EFI_STATUS
CreateChildNode(IN CORE_SECTION_STREAM_NODE * Stream,IN UINT32 ChildOffset,OUT CORE_SECTION_CHILD_NODE ** ChildNode)672 CreateChildNode (
673   IN     CORE_SECTION_STREAM_NODE              *Stream,
674   IN     UINT32                                ChildOffset,
675   OUT    CORE_SECTION_CHILD_NODE               **ChildNode
676   )
677 {
678   EFI_STATUS                                   Status;
679   EFI_COMMON_SECTION_HEADER                    *SectionHeader;
680   EFI_COMPRESSION_SECTION                      *CompressionHeader;
681   EFI_GUID_DEFINED_SECTION                     *GuidedHeader;
682   EFI_DECOMPRESS_PROTOCOL                      *Decompress;
683   EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL       *GuidedExtraction;
684   VOID                                         *NewStreamBuffer;
685   VOID                                         *ScratchBuffer;
686   UINT32                                       ScratchSize;
687   UINTN                                        NewStreamBufferSize;
688   UINT32                                       AuthenticationStatus;
689   VOID                                         *CompressionSource;
690   UINT32                                       CompressionSourceSize;
691   UINT32                                       UncompressedLength;
692   UINT8                                        CompressionType;
693   UINT16                                       GuidedSectionAttributes;
694 
695   CORE_SECTION_CHILD_NODE                      *Node;
696 
697   SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
698 
699   //
700   // Allocate a new node
701   //
702   *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));
703   Node = *ChildNode;
704   if (Node == NULL) {
705     return EFI_OUT_OF_RESOURCES;
706   }
707 
708   //
709   // Now initialize it
710   //
711   Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
712   Node->Type = SectionHeader->Type;
713   if (IS_SECTION2 (SectionHeader)) {
714     Node->Size = SECTION2_SIZE (SectionHeader);
715   } else {
716     Node->Size = SECTION_SIZE (SectionHeader);
717   }
718   Node->OffsetInStream = ChildOffset;
719   Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
720   Node->EncapsulationGuid = NULL;
721 
722   //
723   // If it's an encapsulating section, then create the new section stream also
724   //
725   switch (Node->Type) {
726     case EFI_SECTION_COMPRESSION:
727       //
728       // Get the CompressionSectionHeader
729       //
730       if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {
731         CoreFreePool (Node);
732         return EFI_NOT_FOUND;
733       }
734 
735       CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;
736 
737       if (IS_SECTION2 (CompressionHeader)) {
738         CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
739         CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
740         UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->UncompressedLength;
741         CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->CompressionType;
742       } else {
743         CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
744         CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
745         UncompressedLength = CompressionHeader->UncompressedLength;
746         CompressionType = CompressionHeader->CompressionType;
747       }
748 
749       //
750       // Allocate space for the new stream
751       //
752       if (UncompressedLength > 0) {
753         NewStreamBufferSize = UncompressedLength;
754         NewStreamBuffer = AllocatePool (NewStreamBufferSize);
755         if (NewStreamBuffer == NULL) {
756           CoreFreePool (Node);
757           return EFI_OUT_OF_RESOURCES;
758         }
759 
760         if (CompressionType == EFI_NOT_COMPRESSED) {
761           //
762           // stream is not actually compressed, just encapsulated.  So just copy it.
763           //
764           CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
765         } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
766           //
767           // Only support the EFI_SATNDARD_COMPRESSION algorithm.
768           //
769 
770           //
771           // Decompress the stream
772           //
773           Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
774           ASSERT_EFI_ERROR (Status);
775           ASSERT (Decompress != NULL);
776 
777           Status = Decompress->GetInfo (
778                                  Decompress,
779                                  CompressionSource,
780                                  CompressionSourceSize,
781                                  (UINT32 *)&NewStreamBufferSize,
782                                  &ScratchSize
783                                  );
784           if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
785             CoreFreePool (Node);
786             CoreFreePool (NewStreamBuffer);
787             if (!EFI_ERROR (Status)) {
788               Status = EFI_BAD_BUFFER_SIZE;
789             }
790             return Status;
791           }
792 
793           ScratchBuffer = AllocatePool (ScratchSize);
794           if (ScratchBuffer == NULL) {
795             CoreFreePool (Node);
796             CoreFreePool (NewStreamBuffer);
797             return EFI_OUT_OF_RESOURCES;
798           }
799 
800           Status = Decompress->Decompress (
801                                  Decompress,
802                                  CompressionSource,
803                                  CompressionSourceSize,
804                                  NewStreamBuffer,
805                                  (UINT32)NewStreamBufferSize,
806                                  ScratchBuffer,
807                                  ScratchSize
808                                  );
809           CoreFreePool (ScratchBuffer);
810           if (EFI_ERROR (Status)) {
811             CoreFreePool (Node);
812             CoreFreePool (NewStreamBuffer);
813             return Status;
814           }
815         }
816       } else {
817         NewStreamBuffer = NULL;
818         NewStreamBufferSize = 0;
819       }
820 
821       Status = OpenSectionStreamEx (
822                  NewStreamBufferSize,
823                  NewStreamBuffer,
824                  FALSE,
825                  Stream->AuthenticationStatus,
826                  &Node->EncapsulatedStreamHandle
827                  );
828       if (EFI_ERROR (Status)) {
829         CoreFreePool (Node);
830         CoreFreePool (NewStreamBuffer);
831         return Status;
832       }
833       break;
834 
835     case EFI_SECTION_GUID_DEFINED:
836       GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;
837       if (IS_SECTION2 (GuidedHeader)) {
838         Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->SectionDefinitionGuid);
839         GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->Attributes;
840       } else {
841         Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
842         GuidedSectionAttributes = GuidedHeader->Attributes;
843       }
844       if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {
845         //
846         // NewStreamBuffer is always allocated by ExtractSection... No caller
847         // allocation here.
848         //
849         Status = GuidedExtraction->ExtractSection (
850                                      GuidedExtraction,
851                                      GuidedHeader,
852                                      &NewStreamBuffer,
853                                      &NewStreamBufferSize,
854                                      &AuthenticationStatus
855                                      );
856         if (EFI_ERROR (Status)) {
857           CoreFreePool (*ChildNode);
858           return EFI_PROTOCOL_ERROR;
859         }
860 
861         //
862         // Make sure we initialize the new stream with the correct
863         // authentication status for both aggregate and local status fields.
864         //
865         if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
866           //
867           // OR in the parent stream's aggregate status.
868           //
869           AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
870         } else {
871           //
872           // since there's no authentication data contributed by the section,
873           // just inherit the full value from our immediate parent.
874           //
875           AuthenticationStatus = Stream->AuthenticationStatus;
876         }
877 
878         Status = OpenSectionStreamEx (
879                    NewStreamBufferSize,
880                    NewStreamBuffer,
881                    FALSE,
882                    AuthenticationStatus,
883                    &Node->EncapsulatedStreamHandle
884                    );
885         if (EFI_ERROR (Status)) {
886           CoreFreePool (*ChildNode);
887           CoreFreePool (NewStreamBuffer);
888           return Status;
889         }
890       } else {
891         //
892         // There's no GUIDed section extraction protocol available.
893         //
894         if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
895           //
896           // If the section REQUIRES an extraction protocol, register for RPN
897           // when the required GUIDed extraction protocol becomes available.
898           //
899           CreateGuidedExtractionRpnEvent (Stream, Node);
900         } else {
901           //
902           // Figure out the proper authentication status
903           //
904           AuthenticationStatus = Stream->AuthenticationStatus;
905 
906           if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
907             AuthenticationStatus |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
908           }
909 
910           if (IS_SECTION2 (GuidedHeader)) {
911             Status = OpenSectionStreamEx (
912                        SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
913                        (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
914                        TRUE,
915                        AuthenticationStatus,
916                        &Node->EncapsulatedStreamHandle
917                        );
918           } else {
919             Status = OpenSectionStreamEx (
920                        SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
921                        (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
922                        TRUE,
923                        AuthenticationStatus,
924                        &Node->EncapsulatedStreamHandle
925                        );
926           }
927           if (EFI_ERROR (Status)) {
928             CoreFreePool (Node);
929             return Status;
930           }
931         }
932       }
933 
934       break;
935 
936     default:
937 
938       //
939       // Nothing to do if it's a leaf
940       //
941       break;
942   }
943 
944   //
945   // Last, add the new child node to the stream
946   //
947   InsertTailList (&Stream->Children, &Node->Link);
948 
949   return EFI_SUCCESS;
950 }
951 
952 
953 /**
954   Worker function  Recursively searches / builds section stream database
955   looking for requested section.
956 
957   @param  SourceStream           Indicates the section stream in which to do the
958                                  search.
959   @param  SearchType             Indicates the type of section to search for.
960   @param  SectionInstance        Indicates which instance of section to find.
961                                  This is an in/out parameter to deal with
962                                  recursions.
963   @param  SectionDefinitionGuid  Guid of section definition
964   @param  FoundChild             Output indicating the child node that is found.
965   @param  FoundStream            Output indicating which section stream the child
966                                  was found in.  If this stream was generated as a
967                                  result of an encapsulation section, the
968                                  streamhandle is visible within the SEP driver
969                                  only.
970   @param  AuthenticationStatus   Indicates the authentication status of the found section.
971 
972   @retval EFI_SUCCESS            Child node was found and returned.
973                                  EFI_OUT_OF_RESOURCES- Memory allocation failed.
974   @retval EFI_NOT_FOUND          Requested child node does not exist.
975   @retval EFI_PROTOCOL_ERROR     a required GUIDED section extraction protocol
976                                  does not exist
977 
978 **/
979 EFI_STATUS
FindChildNode(IN CORE_SECTION_STREAM_NODE * SourceStream,IN EFI_SECTION_TYPE SearchType,IN OUT UINTN * SectionInstance,IN EFI_GUID * SectionDefinitionGuid,OUT CORE_SECTION_CHILD_NODE ** FoundChild,OUT CORE_SECTION_STREAM_NODE ** FoundStream,OUT UINT32 * AuthenticationStatus)980 FindChildNode (
981   IN     CORE_SECTION_STREAM_NODE                   *SourceStream,
982   IN     EFI_SECTION_TYPE                           SearchType,
983   IN OUT UINTN                                      *SectionInstance,
984   IN     EFI_GUID                                   *SectionDefinitionGuid,
985   OUT    CORE_SECTION_CHILD_NODE                    **FoundChild,
986   OUT    CORE_SECTION_STREAM_NODE                   **FoundStream,
987   OUT    UINT32                                     *AuthenticationStatus
988   )
989 {
990   CORE_SECTION_CHILD_NODE                       *CurrentChildNode;
991   CORE_SECTION_CHILD_NODE                       *RecursedChildNode;
992   CORE_SECTION_STREAM_NODE                      *RecursedFoundStream;
993   UINT32                                        NextChildOffset;
994   EFI_STATUS                                    ErrorStatus;
995   EFI_STATUS                                    Status;
996 
997   CurrentChildNode = NULL;
998   ErrorStatus = EFI_NOT_FOUND;
999 
1000   if (SourceStream->StreamLength == 0) {
1001     return EFI_NOT_FOUND;
1002   }
1003 
1004   if (IsListEmpty (&SourceStream->Children) &&
1005       SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) {
1006     //
1007     // This occurs when a section stream exists, but no child sections
1008     // have been parsed out yet.  Therefore, extract the first child and add it
1009     // to the list of children so we can get started.
1010     // Section stream may contain an array of zero or more bytes.
1011     // So, its size should be >= the size of commen section header.
1012     //
1013     Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
1014     if (EFI_ERROR (Status)) {
1015       return Status;
1016     }
1017   }
1018 
1019   //
1020   // At least one child has been parsed out of the section stream.  So, walk
1021   // through the sections that have already been parsed out looking for the
1022   // requested section, if necessary, continue parsing section stream and
1023   // adding children until either the requested section is found, or we run
1024   // out of data
1025   //
1026   CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));
1027 
1028   for (;;) {
1029     ASSERT (CurrentChildNode != NULL);
1030     if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
1031       //
1032       // The type matches, so check the instance count to see if it's the one we want
1033       //
1034       (*SectionInstance)--;
1035       if (*SectionInstance == 0) {
1036         //
1037         // Got it!
1038         //
1039         *FoundChild = CurrentChildNode;
1040         *FoundStream = SourceStream;
1041         *AuthenticationStatus = SourceStream->AuthenticationStatus;
1042         return EFI_SUCCESS;
1043       }
1044     }
1045 
1046     if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
1047       //
1048       // If the current node is an encapsulating node, recurse into it...
1049       //
1050       Status = FindChildNode (
1051                 (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
1052                 SearchType,
1053                 SectionInstance,
1054                 SectionDefinitionGuid,
1055                 &RecursedChildNode,
1056                 &RecursedFoundStream,
1057                 AuthenticationStatus
1058                 );
1059       //
1060       // If the status is not EFI_SUCCESS, just save the error code and continue
1061       // to find the request child node in the rest stream.
1062       //
1063       if (*SectionInstance == 0) {
1064         ASSERT_EFI_ERROR (Status);
1065         *FoundChild = RecursedChildNode;
1066         *FoundStream = RecursedFoundStream;
1067         return EFI_SUCCESS;
1068       } else {
1069         ErrorStatus = Status;
1070       }
1071     } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
1072       //
1073       // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
1074       // because a required GUIDED section extraction protocol does not exist.
1075       // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
1076       //
1077       ErrorStatus = EFI_PROTOCOL_ERROR;
1078     }
1079 
1080     if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
1081       //
1082       // We haven't found the child node we're interested in yet, but there's
1083       // still more nodes that have already been parsed so get the next one
1084       // and continue searching..
1085       //
1086       CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
1087     } else {
1088       //
1089       // We've exhausted children that have already been parsed, so see if
1090       // there's any more data and continue parsing out more children if there
1091       // is.
1092       //
1093       NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
1094       //
1095       // Round up to 4 byte boundary
1096       //
1097       NextChildOffset += 3;
1098       NextChildOffset &= ~(UINTN) 3;
1099       if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
1100         //
1101         // There's an unparsed child remaining in the stream, so create a new child node
1102         //
1103         Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
1104         if (EFI_ERROR (Status)) {
1105           return Status;
1106         }
1107       } else {
1108         ASSERT (EFI_ERROR (ErrorStatus));
1109         return ErrorStatus;
1110       }
1111     }
1112   }
1113 }
1114 
1115 
1116 /**
1117   Worker function.  Search stream database for requested stream handle.
1118 
1119   @param  SearchHandle           Indicates which stream to look for.
1120   @param  FoundStream            Output pointer to the found stream.
1121 
1122   @retval EFI_SUCCESS            StreamHandle was found and *FoundStream contains
1123                                  the stream node.
1124   @retval EFI_NOT_FOUND          SearchHandle was not found in the stream
1125                                  database.
1126 
1127 **/
1128 EFI_STATUS
FindStreamNode(IN UINTN SearchHandle,OUT CORE_SECTION_STREAM_NODE ** FoundStream)1129 FindStreamNode (
1130   IN  UINTN                                     SearchHandle,
1131   OUT CORE_SECTION_STREAM_NODE                  **FoundStream
1132   )
1133 {
1134   CORE_SECTION_STREAM_NODE                      *StreamNode;
1135 
1136   if (!IsListEmpty (&mStreamRoot)) {
1137     StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
1138     for (;;) {
1139       if (StreamNode->StreamHandle == SearchHandle) {
1140         *FoundStream = StreamNode;
1141         return EFI_SUCCESS;
1142       } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
1143         break;
1144       } else {
1145         StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
1146       }
1147     }
1148   }
1149 
1150   return EFI_NOT_FOUND;
1151 }
1152 
1153 
1154 /**
1155   SEP member function.  Retrieves requested section from section stream.
1156 
1157   @param  SectionStreamHandle   The section stream from which to extract the
1158                                 requested section.
1159   @param  SectionType           A pointer to the type of section to search for.
1160   @param  SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
1161                                 then SectionDefinitionGuid indicates which of
1162                                 these types of sections to search for.
1163   @param  SectionInstance       Indicates which instance of the requested
1164                                 section to return.
1165   @param  Buffer                Double indirection to buffer.  If *Buffer is
1166                                 non-null on input, then the buffer is caller
1167                                 allocated.  If Buffer is NULL, then the buffer
1168                                 is callee allocated.  In either case, the
1169                                 required buffer size is returned in *BufferSize.
1170   @param  BufferSize            On input, indicates the size of *Buffer if
1171                                 *Buffer is non-null on input.  On output,
1172                                 indicates the required size (allocated size if
1173                                 callee allocated) of *Buffer.
1174   @param  AuthenticationStatus  A pointer to a caller-allocated UINT32 that
1175                                 indicates the authentication status of the
1176                                 output buffer. If the input section's
1177                                 GuidedSectionHeader.Attributes field
1178                                 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
1179                                 bit as clear, AuthenticationStatus must return
1180                                 zero. Both local bits (19:16) and aggregate
1181                                 bits (3:0) in AuthenticationStatus are returned
1182                                 by ExtractSection(). These bits reflect the
1183                                 status of the extraction operation. The bit
1184                                 pattern in both regions must be the same, as
1185                                 the local and aggregate authentication statuses
1186                                 have equivalent meaning at this level. If the
1187                                 function returns anything other than
1188                                 EFI_SUCCESS, the value of *AuthenticationStatus
1189                                 is undefined.
1190   @param  IsFfs3Fv              Indicates the FV format.
1191 
1192   @retval EFI_SUCCESS           Section was retrieved successfully
1193   @retval EFI_PROTOCOL_ERROR    A GUID defined section was encountered in the
1194                                 section stream with its
1195                                 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
1196                                 but there was no corresponding GUIDed Section
1197                                 Extraction Protocol in the handle database.
1198                                 *Buffer is unmodified.
1199   @retval EFI_NOT_FOUND         An error was encountered when parsing the
1200                                 SectionStream.  This indicates the SectionStream
1201                                 is not correctly formatted.
1202   @retval EFI_NOT_FOUND         The requested section does not exist.
1203   @retval EFI_OUT_OF_RESOURCES  The system has insufficient resources to process
1204                                 the request.
1205   @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1206   @retval EFI_WARN_TOO_SMALL    The size of the caller allocated input buffer is
1207                                 insufficient to contain the requested section.
1208                                 The input buffer is filled and section contents
1209                                 are truncated.
1210 
1211 **/
1212 EFI_STATUS
1213 EFIAPI
GetSection(IN UINTN SectionStreamHandle,IN EFI_SECTION_TYPE * SectionType,IN EFI_GUID * SectionDefinitionGuid,IN UINTN SectionInstance,IN VOID ** Buffer,IN OUT UINTN * BufferSize,OUT UINT32 * AuthenticationStatus,IN BOOLEAN IsFfs3Fv)1214 GetSection (
1215   IN UINTN                                              SectionStreamHandle,
1216   IN EFI_SECTION_TYPE                                   *SectionType,
1217   IN EFI_GUID                                           *SectionDefinitionGuid,
1218   IN UINTN                                              SectionInstance,
1219   IN VOID                                               **Buffer,
1220   IN OUT UINTN                                          *BufferSize,
1221   OUT UINT32                                            *AuthenticationStatus,
1222   IN BOOLEAN                                            IsFfs3Fv
1223   )
1224 {
1225   CORE_SECTION_STREAM_NODE                              *StreamNode;
1226   EFI_TPL                                               OldTpl;
1227   EFI_STATUS                                            Status;
1228   CORE_SECTION_CHILD_NODE                               *ChildNode;
1229   CORE_SECTION_STREAM_NODE                              *ChildStreamNode;
1230   UINTN                                                 CopySize;
1231   UINT32                                                ExtractedAuthenticationStatus;
1232   UINTN                                                 Instance;
1233   UINT8                                                 *CopyBuffer;
1234   UINTN                                                 SectionSize;
1235   EFI_COMMON_SECTION_HEADER                             *Section;
1236 
1237 
1238   ChildStreamNode = NULL;
1239   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1240   Instance = SectionInstance + 1;
1241 
1242   //
1243   // Locate target stream
1244   //
1245   Status = FindStreamNode (SectionStreamHandle, &StreamNode);
1246   if (EFI_ERROR (Status)) {
1247     Status = EFI_INVALID_PARAMETER;
1248     goto GetSection_Done;
1249   }
1250 
1251   //
1252   // Found the stream, now locate and return the appropriate section
1253   //
1254   if (SectionType == NULL) {
1255     //
1256     // SectionType == NULL means return the WHOLE section stream...
1257     //
1258     CopySize = StreamNode->StreamLength;
1259     CopyBuffer = StreamNode->StreamBuffer;
1260     *AuthenticationStatus = StreamNode->AuthenticationStatus;
1261   } else {
1262     //
1263     // There's a requested section type, so go find it and return it...
1264     //
1265     Status = FindChildNode (
1266                StreamNode,
1267                *SectionType,
1268                &Instance,
1269                SectionDefinitionGuid,
1270                &ChildNode,
1271                &ChildStreamNode,
1272                &ExtractedAuthenticationStatus
1273                );
1274     if (EFI_ERROR (Status)) {
1275       goto GetSection_Done;
1276     }
1277 
1278     Section = (EFI_COMMON_SECTION_HEADER *) (ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
1279 
1280     if (IS_SECTION2 (Section)) {
1281       ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
1282       if (!IsFfs3Fv) {
1283         DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
1284         Status = EFI_NOT_FOUND;
1285         goto GetSection_Done;
1286       }
1287       CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
1288       CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2);
1289     } else {
1290       CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
1291       CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER);
1292     }
1293     *AuthenticationStatus = ExtractedAuthenticationStatus;
1294   }
1295 
1296   SectionSize = CopySize;
1297   if (*Buffer != NULL) {
1298     //
1299     // Caller allocated buffer.  Fill to size and return required size...
1300     //
1301     if (*BufferSize < CopySize) {
1302       Status = EFI_WARN_BUFFER_TOO_SMALL;
1303       CopySize = *BufferSize;
1304     }
1305   } else {
1306     //
1307     // Callee allocated buffer.  Allocate buffer and return size.
1308     //
1309     *Buffer = AllocatePool (CopySize);
1310     if (*Buffer == NULL) {
1311       Status = EFI_OUT_OF_RESOURCES;
1312       goto GetSection_Done;
1313     }
1314   }
1315   CopyMem (*Buffer, CopyBuffer, CopySize);
1316   *BufferSize = SectionSize;
1317 
1318 GetSection_Done:
1319   CoreRestoreTpl (OldTpl);
1320 
1321   return Status;
1322 }
1323 
1324 
1325 /**
1326   Worker function.  Destructor for child nodes.
1327 
1328   @param  ChildNode              Indicates the node to destroy
1329 
1330 **/
1331 VOID
FreeChildNode(IN CORE_SECTION_CHILD_NODE * ChildNode)1332 FreeChildNode (
1333   IN  CORE_SECTION_CHILD_NODE                   *ChildNode
1334   )
1335 {
1336   ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
1337   //
1338   // Remove the child from it's list
1339   //
1340   RemoveEntryList (&ChildNode->Link);
1341 
1342   if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
1343     //
1344     // If it's an encapsulating section, we close the resulting section stream.
1345     // CloseSectionStream will free all memory associated with the stream.
1346     //
1347     CloseSectionStream (ChildNode->EncapsulatedStreamHandle, TRUE);
1348   }
1349 
1350   if (ChildNode->Event != NULL) {
1351     gBS->CloseEvent (ChildNode->Event);
1352   }
1353 
1354   //
1355   // Last, free the child node itself
1356   //
1357   CoreFreePool (ChildNode);
1358 }
1359 
1360 
1361 /**
1362   SEP member function.  Deletes an existing section stream
1363 
1364   @param  StreamHandleToClose    Indicates the stream to close
1365   @param  FreeStreamBuffer       TRUE - Need to free stream buffer;
1366                                  FALSE - No need to free stream buffer.
1367 
1368   @retval EFI_SUCCESS            The section stream is closed sucessfully.
1369   @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
1370   @retval EFI_INVALID_PARAMETER  Section stream does not end concident with end
1371                                  of last section.
1372 
1373 **/
1374 EFI_STATUS
1375 EFIAPI
CloseSectionStream(IN UINTN StreamHandleToClose,IN BOOLEAN FreeStreamBuffer)1376 CloseSectionStream (
1377   IN  UINTN                                     StreamHandleToClose,
1378   IN  BOOLEAN                                   FreeStreamBuffer
1379   )
1380 {
1381   CORE_SECTION_STREAM_NODE                      *StreamNode;
1382   EFI_TPL                                       OldTpl;
1383   EFI_STATUS                                    Status;
1384   LIST_ENTRY                                    *Link;
1385   CORE_SECTION_CHILD_NODE                       *ChildNode;
1386 
1387   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1388 
1389   //
1390   // Locate target stream
1391   //
1392   Status = FindStreamNode (StreamHandleToClose, &StreamNode);
1393   if (!EFI_ERROR (Status)) {
1394     //
1395     // Found the stream, so close it
1396     //
1397     RemoveEntryList (&StreamNode->Link);
1398     while (!IsListEmpty (&StreamNode->Children)) {
1399       Link = GetFirstNode (&StreamNode->Children);
1400       ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
1401       FreeChildNode (ChildNode);
1402     }
1403     if (FreeStreamBuffer) {
1404       CoreFreePool (StreamNode->StreamBuffer);
1405     }
1406     CoreFreePool (StreamNode);
1407     Status = EFI_SUCCESS;
1408   } else {
1409     Status = EFI_INVALID_PARAMETER;
1410   }
1411 
1412   CoreRestoreTpl (OldTpl);
1413   return Status;
1414 }
1415 
1416 
1417 /**
1418   The ExtractSection() function processes the input section and
1419   allocates a buffer from the pool in which it returns the section
1420   contents. If the section being extracted contains
1421   authentication information (the section's
1422   GuidedSectionHeader.Attributes field has the
1423   EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1424   returned in AuthenticationStatus must reflect the results of
1425   the authentication operation. Depending on the algorithm and
1426   size of the encapsulated data, the time that is required to do
1427   a full authentication may be prohibitively long for some
1428   classes of systems. To indicate this, use
1429   EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1430   the security policy driver (see the Platform Initialization
1431   Driver Execution Environment Core Interface Specification for
1432   more details and the GUID definition). If the
1433   EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1434   database, then, if possible, full authentication should be
1435   skipped and the section contents simply returned in the
1436   OutputBuffer. In this case, the
1437   EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1438   must be set on return. ExtractSection() is callable only from
1439   TPL_NOTIFY and below. Behavior of ExtractSection() at any
1440   EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1441   defined in RaiseTPL() in the UEFI 2.0 specification.
1442 
1443 
1444   @param This         Indicates the
1445                       EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1446   @param InputSection Buffer containing the input GUIDed section
1447                       to be processed. OutputBuffer OutputBuffer
1448                       is allocated from boot services pool
1449                       memory and contains the new section
1450                       stream. The caller is responsible for
1451                       freeing this buffer.
1452   @param OutputBuffer *OutputBuffer is allocated from boot services
1453                       pool memory and contains the new section stream.
1454                       The caller is responsible for freeing this buffer.
1455   @param OutputSize   A pointer to a caller-allocated UINTN in
1456                       which the size of OutputBuffer allocation
1457                       is stored. If the function returns
1458                       anything other than EFI_SUCCESS, the value
1459                       of OutputSize is undefined.
1460 
1461   @param AuthenticationStatus A pointer to a caller-allocated
1462                               UINT32 that indicates the
1463                               authentication status of the
1464                               output buffer. If the input
1465                               section's
1466                               GuidedSectionHeader.Attributes
1467                               field has the
1468                               EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1469                               bit as clear, AuthenticationStatus
1470                               must return zero. Both local bits
1471                               (19:16) and aggregate bits (3:0)
1472                               in AuthenticationStatus are
1473                               returned by ExtractSection().
1474                               These bits reflect the status of
1475                               the extraction operation. The bit
1476                               pattern in both regions must be
1477                               the same, as the local and
1478                               aggregate authentication statuses
1479                               have equivalent meaning at this
1480                               level. If the function returns
1481                               anything other than EFI_SUCCESS,
1482                               the value of AuthenticationStatus
1483                               is undefined.
1484 
1485 
1486   @retval EFI_SUCCESS          The InputSection was successfully
1487                                processed and the section contents were
1488                                returned.
1489 
1490   @retval EFI_OUT_OF_RESOURCES The system has insufficient
1491                                resources to process the
1492                                request.
1493 
1494   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1495                                 not match this instance of the
1496                                 GUIDed Section Extraction
1497                                 Protocol.
1498 
1499 **/
1500 EFI_STATUS
1501 EFIAPI
CustomGuidedSectionExtract(IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL * This,IN CONST VOID * InputSection,OUT VOID ** OutputBuffer,OUT UINTN * OutputSize,OUT UINT32 * AuthenticationStatus)1502 CustomGuidedSectionExtract (
1503   IN CONST  EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
1504   IN CONST  VOID                                   *InputSection,
1505   OUT       VOID                                   **OutputBuffer,
1506   OUT       UINTN                                  *OutputSize,
1507   OUT       UINT32                                 *AuthenticationStatus
1508   )
1509 {
1510   EFI_STATUS      Status;
1511   VOID            *ScratchBuffer;
1512   VOID            *AllocatedOutputBuffer;
1513   UINT32          OutputBufferSize;
1514   UINT32          ScratchBufferSize;
1515   UINT16          SectionAttribute;
1516 
1517   //
1518   // Init local variable
1519   //
1520   ScratchBuffer         = NULL;
1521   AllocatedOutputBuffer = NULL;
1522 
1523   //
1524   // Call GetInfo to get the size and attribute of input guided section data.
1525   //
1526   Status = ExtractGuidedSectionGetInfo (
1527              InputSection,
1528              &OutputBufferSize,
1529              &ScratchBufferSize,
1530              &SectionAttribute
1531              );
1532 
1533   if (EFI_ERROR (Status)) {
1534     DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
1535     return Status;
1536   }
1537 
1538   if (ScratchBufferSize > 0) {
1539     //
1540     // Allocate scratch buffer
1541     //
1542     ScratchBuffer = AllocatePool (ScratchBufferSize);
1543     if (ScratchBuffer == NULL) {
1544       return EFI_OUT_OF_RESOURCES;
1545     }
1546   }
1547 
1548   if (OutputBufferSize > 0) {
1549     //
1550     // Allocate output buffer
1551     //
1552     AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
1553     if (AllocatedOutputBuffer == NULL) {
1554       FreePool (ScratchBuffer);
1555       return EFI_OUT_OF_RESOURCES;
1556     }
1557     *OutputBuffer = AllocatedOutputBuffer;
1558   }
1559 
1560   //
1561   // Call decode function to extract raw data from the guided section.
1562   //
1563   Status = ExtractGuidedSectionDecode (
1564              InputSection,
1565              OutputBuffer,
1566              ScratchBuffer,
1567              AuthenticationStatus
1568              );
1569   if (EFI_ERROR (Status)) {
1570     //
1571     // Decode failed
1572     //
1573     if (AllocatedOutputBuffer != NULL) {
1574       CoreFreePool (AllocatedOutputBuffer);
1575     }
1576     if (ScratchBuffer != NULL) {
1577       CoreFreePool (ScratchBuffer);
1578     }
1579     DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
1580     return Status;
1581   }
1582 
1583   if (*OutputBuffer != AllocatedOutputBuffer) {
1584     //
1585     // OutputBuffer was returned as a different value,
1586     // so copy section contents to the allocated memory buffer.
1587     //
1588     CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
1589     *OutputBuffer = AllocatedOutputBuffer;
1590   }
1591 
1592   //
1593   // Set real size of output buffer.
1594   //
1595   *OutputSize = (UINTN) OutputBufferSize;
1596 
1597   //
1598   // Free unused scratch buffer.
1599   //
1600   if (ScratchBuffer != NULL) {
1601     CoreFreePool (ScratchBuffer);
1602   }
1603 
1604   return EFI_SUCCESS;
1605 }
1606