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