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 - 2014, 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 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 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 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 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 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 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 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 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 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 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 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 requried 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 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 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 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 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