https://bugzilla.tianocore.org/show_bug.cgi?id=4018 Coverity report FORWARD_NULL and OVERFLOW_BEFORE_WIDEN potential defect in UefiPayloadPkg. Signed-off-by: Gregx Yeh <gregx.yeh@intel.com> Reviewed-by: Guo Dong <guo.dong@intel.com> Reviewed-by: James Lu <james.lu@intel.com>
		
			
				
	
	
		
			482 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			482 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   ELF library
 | |
| 
 | |
|   Copyright (c) 2019 - 2021, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "ElfLibInternal.h"
 | |
| 
 | |
| /**
 | |
|   Check if the ELF image is valid.
 | |
| 
 | |
|   @param[in]  ImageBase       Memory address of an image.
 | |
| 
 | |
|   @retval     TRUE if valid.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsElfFormat (
 | |
|   IN  CONST UINT8  *ImageBase
 | |
|   )
 | |
| {
 | |
|   Elf32_Ehdr  *Elf32Hdr;
 | |
|   Elf64_Ehdr  *Elf64Hdr;
 | |
| 
 | |
|   ASSERT (ImageBase != NULL);
 | |
| 
 | |
|   Elf32Hdr = (Elf32_Ehdr *)ImageBase;
 | |
| 
 | |
|   //
 | |
|   // Start with correct signature "\7fELF"
 | |
|   //
 | |
|   if ((Elf32Hdr->e_ident[EI_MAG0] != ELFMAG0) ||
 | |
|       (Elf32Hdr->e_ident[EI_MAG1] != ELFMAG1) ||
 | |
|       (Elf32Hdr->e_ident[EI_MAG1] != ELFMAG1) ||
 | |
|       (Elf32Hdr->e_ident[EI_MAG2] != ELFMAG2)
 | |
|       )
 | |
|   {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Support little-endian only
 | |
|   //
 | |
|   if (Elf32Hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check 32/64-bit architecture
 | |
|   //
 | |
|   if (Elf32Hdr->e_ident[EI_CLASS] == ELFCLASS64) {
 | |
|     Elf64Hdr = (Elf64_Ehdr *)Elf32Hdr;
 | |
|     Elf32Hdr = NULL;
 | |
|   } else if (Elf32Hdr->e_ident[EI_CLASS] == ELFCLASS32) {
 | |
|     Elf64Hdr = NULL;
 | |
|   } else {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (Elf64Hdr != NULL) {
 | |
|     //
 | |
|     // Support intel architecture only for now
 | |
|     //
 | |
|     if (Elf64Hdr->e_machine != EM_X86_64) {
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     //  Support ELF types: EXEC (Executable file), DYN (Shared object file)
 | |
|     //
 | |
|     if ((Elf64Hdr->e_type != ET_EXEC) && (Elf64Hdr->e_type != ET_DYN)) {
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Support current ELF version only
 | |
|     //
 | |
|     if (Elf64Hdr->e_version != EV_CURRENT) {
 | |
|       return FALSE;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Support intel architecture only for now
 | |
|     //
 | |
|     if (Elf32Hdr->e_machine != EM_386) {
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     //  Support ELF types: EXEC (Executable file), DYN (Shared object file)
 | |
|     //
 | |
|     if ((Elf32Hdr->e_type != ET_EXEC) && (Elf32Hdr->e_type != ET_DYN)) {
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Support current ELF version only
 | |
|     //
 | |
|     if (Elf32Hdr->e_version != EV_CURRENT) {
 | |
|       return FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Calculate a ELF file size.
 | |
| 
 | |
|   @param[in]  ElfCt               ELF image context pointer.
 | |
|   @param[out] FileSize            Return the file size.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER   ElfCt or SecPos is NULL.
 | |
|   @retval EFI_NOT_FOUND           Could not find the section.
 | |
|   @retval EFI_SUCCESS             Section posistion was filled successfully.
 | |
| **/
 | |
| EFI_STATUS
 | |
| CalculateElfFileSize (
 | |
|   IN  ELF_IMAGE_CONTEXT  *ElfCt,
 | |
|   OUT UINTN              *FileSize
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       FileSize1;
 | |
|   UINTN       FileSize2;
 | |
|   Elf32_Ehdr  *Elf32Hdr;
 | |
|   Elf64_Ehdr  *Elf64Hdr;
 | |
|   UINTN       Offset;
 | |
|   UINTN       Size;
 | |
| 
 | |
|   if ((ElfCt == NULL) || (FileSize == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Use last section as end of file
 | |
|   Status = GetElfSectionPos (ElfCt, ElfCt->ShNum - 1, &Offset, &Size);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   FileSize1 = Offset + Size;
 | |
| 
 | |
|   // Use end of section header as end of file
 | |
|   FileSize2 = 0;
 | |
|   if (ElfCt->EiClass == ELFCLASS32) {
 | |
|     Elf32Hdr  = (Elf32_Ehdr *)ElfCt->FileBase;
 | |
|     FileSize2 = Elf32Hdr->e_shoff + Elf32Hdr->e_shentsize * Elf32Hdr->e_shnum;
 | |
|   } else if (ElfCt->EiClass == ELFCLASS64) {
 | |
|     Elf64Hdr  = (Elf64_Ehdr *)ElfCt->FileBase;
 | |
|     FileSize2 = ((UINTN)Elf64Hdr->e_shoff + (UINTN)(Elf64Hdr->e_shentsize * Elf64Hdr->e_shnum));
 | |
|   }
 | |
| 
 | |
|   *FileSize = MAX (FileSize1, FileSize2);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get a ELF program segment loading info.
 | |
| 
 | |
|   @param[in]  ImageBase           Image base.
 | |
|   @param[in]  EiClass             ELF class.
 | |
|   @param[in]  Index               ELF segment index.
 | |
|   @param[out] SegInfo             The pointer to the segment info.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER   ElfCt or SecPos is NULL.
 | |
|   @retval EFI_NOT_FOUND           Could not find the section.
 | |
|   @retval EFI_SUCCESS             Section posistion was filled successfully.
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetElfSegmentInfo (
 | |
|   IN  UINT8         *ImageBase,
 | |
|   IN  UINT32        EiClass,
 | |
|   IN  UINT32        Index,
 | |
|   OUT SEGMENT_INFO  *SegInfo
 | |
|   )
 | |
| {
 | |
|   Elf32_Phdr  *Elf32Phdr;
 | |
|   Elf64_Phdr  *Elf64Phdr;
 | |
| 
 | |
|   if ((ImageBase == NULL) || (SegInfo == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (EiClass == ELFCLASS32) {
 | |
|     Elf32Phdr = GetElf32SegmentByIndex (ImageBase, Index);
 | |
|     if (Elf32Phdr != NULL) {
 | |
|       SegInfo->PtType    = Elf32Phdr->p_type;
 | |
|       SegInfo->Offset    = Elf32Phdr->p_offset;
 | |
|       SegInfo->Length    = Elf32Phdr->p_filesz;
 | |
|       SegInfo->MemLen    = Elf32Phdr->p_memsz;
 | |
|       SegInfo->MemAddr   = Elf32Phdr->p_paddr;
 | |
|       SegInfo->Alignment = Elf32Phdr->p_align;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   } else if (EiClass == ELFCLASS64) {
 | |
|     Elf64Phdr = GetElf64SegmentByIndex (ImageBase, Index);
 | |
|     if (Elf64Phdr != NULL) {
 | |
|       SegInfo->PtType    = Elf64Phdr->p_type;
 | |
|       SegInfo->Offset    = (UINTN)Elf64Phdr->p_offset;
 | |
|       SegInfo->Length    = (UINTN)Elf64Phdr->p_filesz;
 | |
|       SegInfo->MemLen    = (UINTN)Elf64Phdr->p_memsz;
 | |
|       SegInfo->MemAddr   = (UINTN)Elf64Phdr->p_paddr;
 | |
|       SegInfo->Alignment = (UINTN)Elf64Phdr->p_align;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Parse the ELF image info.
 | |
| 
 | |
|   On return, all fields in ElfCt are updated except ImageAddress.
 | |
| 
 | |
|   @param[in]  ImageBase      Memory address of an image.
 | |
|   @param[out] ElfCt          The EFL image context pointer.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER   Input parameters are not valid.
 | |
|   @retval EFI_UNSUPPORTED         Unsupported binary type.
 | |
|   @retval EFI_LOAD_ERROR          ELF binary loading error.
 | |
|   @retval EFI_SUCCESS             ELF binary is loaded successfully.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ParseElfImage (
 | |
|   IN  VOID               *ImageBase,
 | |
|   OUT ELF_IMAGE_CONTEXT  *ElfCt
 | |
|   )
 | |
| {
 | |
|   Elf32_Ehdr    *Elf32Hdr;
 | |
|   Elf64_Ehdr    *Elf64Hdr;
 | |
|   Elf32_Shdr    *Elf32Shdr;
 | |
|   Elf64_Shdr    *Elf64Shdr;
 | |
|   EFI_STATUS    Status;
 | |
|   UINT32        Index;
 | |
|   SEGMENT_INFO  SegInfo;
 | |
|   UINTN         End;
 | |
|   UINTN         Base;
 | |
| 
 | |
|   if (ElfCt == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (ElfCt, sizeof (ELF_IMAGE_CONTEXT));
 | |
| 
 | |
|   if (ImageBase == NULL) {
 | |
|     return (ElfCt->ParseStatus = EFI_INVALID_PARAMETER);
 | |
|   }
 | |
| 
 | |
|   ElfCt->FileBase = (UINT8 *)ImageBase;
 | |
|   if (!IsElfFormat (ElfCt->FileBase)) {
 | |
|     return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
 | |
|   }
 | |
| 
 | |
|   Elf32Hdr       = (Elf32_Ehdr *)ElfCt->FileBase;
 | |
|   ElfCt->EiClass = Elf32Hdr->e_ident[EI_CLASS];
 | |
|   if (ElfCt->EiClass == ELFCLASS32) {
 | |
|     if ((Elf32Hdr->e_type != ET_EXEC) && (Elf32Hdr->e_type != ET_DYN)) {
 | |
|       return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
 | |
|     }
 | |
| 
 | |
|     Elf32Shdr = (Elf32_Shdr *)GetElf32SectionByIndex (ElfCt->FileBase, Elf32Hdr->e_shstrndx);
 | |
|     if (Elf32Shdr == NULL) {
 | |
|       return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
 | |
|     }
 | |
| 
 | |
|     ElfCt->EntryPoint = (UINTN)Elf32Hdr->e_entry;
 | |
|     ElfCt->ShNum      = Elf32Hdr->e_shnum;
 | |
|     ElfCt->PhNum      = Elf32Hdr->e_phnum;
 | |
|     ElfCt->ShStrLen   = Elf32Shdr->sh_size;
 | |
|     ElfCt->ShStrOff   = Elf32Shdr->sh_offset;
 | |
|   } else {
 | |
|     Elf64Hdr = (Elf64_Ehdr *)Elf32Hdr;
 | |
|     if ((Elf64Hdr->e_type != ET_EXEC) && (Elf64Hdr->e_type != ET_DYN)) {
 | |
|       return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
 | |
|     }
 | |
| 
 | |
|     Elf64Shdr = (Elf64_Shdr *)GetElf64SectionByIndex (ElfCt->FileBase, Elf64Hdr->e_shstrndx);
 | |
|     if (Elf64Shdr == NULL) {
 | |
|       return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
 | |
|     }
 | |
| 
 | |
|     ElfCt->EntryPoint = (UINTN)Elf64Hdr->e_entry;
 | |
|     ElfCt->ShNum      = Elf64Hdr->e_shnum;
 | |
|     ElfCt->PhNum      = Elf64Hdr->e_phnum;
 | |
|     ElfCt->ShStrLen   = (UINT32)Elf64Shdr->sh_size;
 | |
|     ElfCt->ShStrOff   = (UINT32)Elf64Shdr->sh_offset;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the preferred image base and required memory size when loaded to new location.
 | |
|   //
 | |
|   End                   = 0;
 | |
|   Base                  = MAX_UINT32;
 | |
|   ElfCt->ReloadRequired = FALSE;
 | |
|   for (Index = 0; Index < ElfCt->PhNum; Index++) {
 | |
|     Status = GetElfSegmentInfo (ElfCt->FileBase, ElfCt->EiClass, Index, &SegInfo);
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     if (SegInfo.PtType != PT_LOAD) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (SegInfo.MemLen != SegInfo.Length) {
 | |
|       //
 | |
|       // Not enough space to execute at current location.
 | |
|       //
 | |
|       ElfCt->ReloadRequired = TRUE;
 | |
|     }
 | |
| 
 | |
|     if (Base > (SegInfo.MemAddr & ~(EFI_PAGE_SIZE - 1))) {
 | |
|       Base = SegInfo.MemAddr & ~(EFI_PAGE_SIZE - 1);
 | |
|     }
 | |
| 
 | |
|     if (End < ALIGN_VALUE (SegInfo.MemAddr + SegInfo.MemLen, EFI_PAGE_SIZE) - 1) {
 | |
|       End = ALIGN_VALUE (SegInfo.MemAddr + SegInfo.MemLen, EFI_PAGE_SIZE) - 1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 0 - MAX_UINT32  + 1 equals to 0.
 | |
|   //
 | |
|   ElfCt->ImageSize             = End - Base + 1;
 | |
|   ElfCt->PreferredImageAddress = (VOID *)Base;
 | |
| 
 | |
|   CalculateElfFileSize (ElfCt, &ElfCt->FileSize);
 | |
|   return (ElfCt->ParseStatus = EFI_SUCCESS);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Load the ELF image to Context.ImageAddress.
 | |
| 
 | |
|   Context should be initialized by ParseElfImage().
 | |
|   Caller should set Context.ImageAddress to a proper value, either pointing to
 | |
|   a new allocated memory whose size equal to Context.ImageSize, or pointing
 | |
|   to Context.PreferredImageAddress.
 | |
| 
 | |
|   @param[in]  ElfCt               ELF image context pointer.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER   Input parameters are not valid.
 | |
|   @retval EFI_UNSUPPORTED         Unsupported binary type.
 | |
|   @retval EFI_LOAD_ERROR          ELF binary loading error.
 | |
|   @retval EFI_SUCCESS             ELF binary is loaded successfully.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LoadElfImage (
 | |
|   IN  ELF_IMAGE_CONTEXT  *ElfCt
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   if (ElfCt == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (ElfCt->ParseStatus)) {
 | |
|     return ElfCt->ParseStatus;
 | |
|   }
 | |
| 
 | |
|   if (ElfCt->ImageAddress == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_UNSUPPORTED;
 | |
|   if (ElfCt->EiClass == ELFCLASS32) {
 | |
|     Status = LoadElf32Image (ElfCt);
 | |
|   } else if (ElfCt->EiClass == ELFCLASS64) {
 | |
|     Status = LoadElf64Image (ElfCt);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get a ELF section name from its index.
 | |
| 
 | |
|   @param[in]  ElfCt               ELF image context pointer.
 | |
|   @param[in]  SectionIndex        ELF section index.
 | |
|   @param[out] SectionName         The pointer to the section name.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER   ElfCt or SecName is NULL.
 | |
|   @retval EFI_NOT_FOUND           Could not find the section.
 | |
|   @retval EFI_SUCCESS             Section name was filled successfully.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetElfSectionName (
 | |
|   IN  ELF_IMAGE_CONTEXT  *ElfCt,
 | |
|   IN  UINT32             SectionIndex,
 | |
|   OUT CHAR8              **SectionName
 | |
|   )
 | |
| {
 | |
|   Elf32_Shdr  *Elf32Shdr;
 | |
|   Elf64_Shdr  *Elf64Shdr;
 | |
|   CHAR8       *Name;
 | |
| 
 | |
|   if ((ElfCt == NULL) || (SectionName == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (ElfCt->ParseStatus)) {
 | |
|     return ElfCt->ParseStatus;
 | |
|   }
 | |
| 
 | |
|   Name = NULL;
 | |
|   if (ElfCt->EiClass == ELFCLASS32) {
 | |
|     Elf32Shdr = GetElf32SectionByIndex (ElfCt->FileBase, SectionIndex);
 | |
|     if ((Elf32Shdr != NULL) && (Elf32Shdr->sh_name < ElfCt->ShStrLen)) {
 | |
|       Name = (CHAR8 *)(ElfCt->FileBase + ElfCt->ShStrOff + Elf32Shdr->sh_name);
 | |
|     }
 | |
|   } else if (ElfCt->EiClass == ELFCLASS64) {
 | |
|     Elf64Shdr = GetElf64SectionByIndex (ElfCt->FileBase, SectionIndex);
 | |
|     if ((Elf64Shdr != NULL) && (Elf64Shdr->sh_name < ElfCt->ShStrLen)) {
 | |
|       Name = (CHAR8 *)(ElfCt->FileBase + ElfCt->ShStrOff + Elf64Shdr->sh_name);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Name == NULL) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *SectionName = Name;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the offset and size of x-th ELF section.
 | |
| 
 | |
|   @param[in]  ElfCt               ELF image context pointer.
 | |
|   @param[in]  Index               ELF section index.
 | |
|   @param[out] Offset              Return the offset of the specific section.
 | |
|   @param[out] Size                Return the size of the specific section.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER   ImageBase, Offset or Size is NULL.
 | |
|   @retval EFI_INVALID_PARAMETER   EiClass doesn't equal to ELFCLASS32 or ELFCLASS64.
 | |
|   @retval EFI_NOT_FOUND           Could not find the section.
 | |
|   @retval EFI_SUCCESS             Offset and Size are returned.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetElfSectionPos (
 | |
|   IN  ELF_IMAGE_CONTEXT  *ElfCt,
 | |
|   IN  UINT32             Index,
 | |
|   OUT UINTN              *Offset,
 | |
|   OUT UINTN              *Size
 | |
|   )
 | |
| {
 | |
|   Elf32_Shdr  *Elf32Shdr;
 | |
|   Elf64_Shdr  *Elf64Shdr;
 | |
| 
 | |
|   if ((ElfCt == NULL) || (Offset == NULL) || (Size == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (ElfCt->ParseStatus)) {
 | |
|     return ElfCt->ParseStatus;
 | |
|   }
 | |
| 
 | |
|   if (ElfCt->EiClass == ELFCLASS32) {
 | |
|     Elf32Shdr = GetElf32SectionByIndex (ElfCt->FileBase, Index);
 | |
|     if (Elf32Shdr != NULL) {
 | |
|       *Offset = (UINTN)Elf32Shdr->sh_offset;
 | |
|       *Size   = (UINTN)Elf32Shdr->sh_size;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   } else if (ElfCt->EiClass == ELFCLASS64) {
 | |
|     Elf64Shdr = GetElf64SectionByIndex (ElfCt->FileBase, Index);
 | |
|     if (Elf64Shdr != NULL) {
 | |
|       *Offset = (UINTN)Elf64Shdr->sh_offset;
 | |
|       *Size   = (UINTN)Elf64Shdr->sh_size;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 |