• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
3   only supports relocating IA32, x64, IPF, and EBC images.
4 
5   Caution: This file requires additional review when modified.
6   This library will have external input - PE/COFF image.
7   This external input must be validated carefully to avoid security issue like
8   buffer overflow, integer overflow.
9 
10   The basic guideline is that caller need provide ImageContext->ImageRead () with the
11   necessary data range check, to make sure when this library reads PE/COFF image, the
12   PE image buffer is always in valid range.
13   This library will also do some additional check for PE header fields.
14 
15   PeCoffLoaderGetPeHeader() routine will do basic check for PE/COFF header.
16   PeCoffLoaderGetImageInfo() routine will do basic check for whole PE/COFF image.
17 
18   Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
19   Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
20   This program and the accompanying materials
21   are licensed and made available under the terms and conditions of the BSD License
22   which accompanies this distribution.  The full text of the license may be found at
23   http://opensource.org/licenses/bsd-license.php.
24 
25   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
26   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
27 
28 **/
29 
30 #include "BasePeCoffLibInternals.h"
31 
32 /**
33   Adjust some fields in section header for TE image.
34 
35   @param  SectionHeader             Pointer to the section header.
36   @param  TeStrippedOffset          Size adjust for the TE image.
37 
38 **/
39 VOID
PeCoffLoaderAdjustOffsetForTeImage(EFI_IMAGE_SECTION_HEADER * SectionHeader,UINT32 TeStrippedOffset)40 PeCoffLoaderAdjustOffsetForTeImage (
41   EFI_IMAGE_SECTION_HEADER              *SectionHeader,
42   UINT32                                TeStrippedOffset
43   )
44 {
45   SectionHeader->VirtualAddress   -= TeStrippedOffset;
46   SectionHeader->PointerToRawData -= TeStrippedOffset;
47 }
48 
49 /**
50   Retrieves the magic value from the PE/COFF header.
51 
52   @param  Hdr             The buffer in which to return the PE32, PE32+, or TE header.
53 
54   @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
55   @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
56 
57 **/
58 UINT16
PeCoffLoaderGetPeHeaderMagicValue(IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr)59 PeCoffLoaderGetPeHeaderMagicValue (
60   IN  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
61   )
62 {
63   //
64   // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
65   //       in the PE/COFF Header.  If the MachineType is Itanium(IA64) and the
66   //       Magic value in the OptionalHeader is  EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
67   //       then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
68   //
69   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
70     return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
71   }
72   //
73   // Return the magic value from the PC/COFF Optional Header
74   //
75   return Hdr.Pe32->OptionalHeader.Magic;
76 }
77 
78 
79 /**
80   Retrieves the PE or TE Header from a PE/COFF or TE image.
81 
82   Caution: This function may receive untrusted input.
83   PE/COFF image is external input, so this routine will
84   also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
85   SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
86 
87   @param  ImageContext    The context of the image being loaded.
88   @param  Hdr             The buffer in which to return the PE32, PE32+, or TE header.
89 
90   @retval RETURN_SUCCESS  The PE or TE Header is read.
91   @retval Other           The error status from reading the PE/COFF or TE image using the ImageRead function.
92 
93 **/
94 RETURN_STATUS
PeCoffLoaderGetPeHeader(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext,OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr)95 PeCoffLoaderGetPeHeader (
96   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext,
97   OUT    EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
98   )
99 {
100   RETURN_STATUS         Status;
101   EFI_IMAGE_DOS_HEADER  DosHdr;
102   UINTN                 Size;
103   UINTN                 ReadSize;
104   UINT16                Magic;
105   UINT32                SectionHeaderOffset;
106   UINT32                Index;
107   UINT32                HeaderWithoutDataDir;
108   CHAR8                 BufferData;
109   UINTN                 NumberOfSections;
110   EFI_IMAGE_SECTION_HEADER  SectionHeader;
111 
112   //
113   // Read the DOS image header to check for its existence
114   //
115   Size = sizeof (EFI_IMAGE_DOS_HEADER);
116   ReadSize = Size;
117   Status = ImageContext->ImageRead (
118                            ImageContext->Handle,
119                            0,
120                            &Size,
121                            &DosHdr
122                            );
123   if (RETURN_ERROR (Status) || (Size != ReadSize)) {
124     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
125     if (Size != ReadSize) {
126       Status = RETURN_UNSUPPORTED;
127     }
128     return Status;
129   }
130 
131   ImageContext->PeCoffHeaderOffset = 0;
132   if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
133     //
134     // DOS image header is present, so read the PE header after the DOS image
135     // header
136     //
137     ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
138   }
139 
140   //
141   // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
142   // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
143   // determines if this is a PE32 or PE32+ image. The magic is in the same
144   // location in both images.
145   //
146   Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
147   ReadSize = Size;
148   Status = ImageContext->ImageRead (
149                            ImageContext->Handle,
150                            ImageContext->PeCoffHeaderOffset,
151                            &Size,
152                            Hdr.Pe32
153                            );
154   if (RETURN_ERROR (Status) || (Size != ReadSize)) {
155     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
156     if (Size != ReadSize) {
157       Status = RETURN_UNSUPPORTED;
158     }
159     return Status;
160   }
161 
162   //
163   // Use Signature to figure out if we understand the image format
164   //
165   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
166     ImageContext->IsTeImage         = TRUE;
167     ImageContext->Machine           = Hdr.Te->Machine;
168     ImageContext->ImageType         = (UINT16)(Hdr.Te->Subsystem);
169     //
170     // For TeImage, SectionAlignment is undefined to be set to Zero
171     // ImageSize can be calculated.
172     //
173     ImageContext->ImageSize         = 0;
174     ImageContext->SectionAlignment  = 0;
175     ImageContext->SizeOfHeaders     = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
176 
177     //
178     // Check the StrippedSize.
179     //
180     if (sizeof (EFI_TE_IMAGE_HEADER) >= (UINT32)Hdr.Te->StrippedSize) {
181       ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
182       return RETURN_UNSUPPORTED;
183     }
184 
185     //
186     // Check the SizeOfHeaders field.
187     //
188     if (Hdr.Te->BaseOfCode <= Hdr.Te->StrippedSize) {
189       ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
190       return RETURN_UNSUPPORTED;
191     }
192 
193     //
194     // Read last byte of Hdr.Te->SizeOfHeaders from the file.
195     //
196     Size = 1;
197     ReadSize = Size;
198     Status = ImageContext->ImageRead (
199                              ImageContext->Handle,
200                              ImageContext->SizeOfHeaders - 1,
201                              &Size,
202                              &BufferData
203                              );
204     if (RETURN_ERROR (Status) || (Size != ReadSize)) {
205       ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
206       if (Size != ReadSize) {
207         Status = RETURN_UNSUPPORTED;
208       }
209       return Status;
210     }
211 
212     //
213     // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.
214     // This case is not a valid TE image.
215     //
216     if ((Hdr.Te->DataDirectory[0].Size != 0 && Hdr.Te->DataDirectory[0].VirtualAddress == 0) ||
217         (Hdr.Te->DataDirectory[1].Size != 0 && Hdr.Te->DataDirectory[1].VirtualAddress == 0)) {
218       ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
219       return RETURN_UNSUPPORTED;
220     }
221   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
222     ImageContext->IsTeImage = FALSE;
223     ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;
224 
225     Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
226 
227     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
228       //
229       // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
230       //
231       if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
232         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
233         return RETURN_UNSUPPORTED;
234       }
235 
236       //
237       // 2. Check the FileHeader.SizeOfOptionalHeader field.
238       // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
239       // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
240       //
241       HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER32) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
242       if (((UINT32)Hdr.Pe32->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
243           Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
244         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
245         return RETURN_UNSUPPORTED;
246       }
247 
248       SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
249       //
250       // 3. Check the FileHeader.NumberOfSections field.
251       //
252       if (Hdr.Pe32->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {
253         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
254         return RETURN_UNSUPPORTED;
255       }
256       if ((Hdr.Pe32->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32->FileHeader.NumberOfSections) {
257         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
258         return RETURN_UNSUPPORTED;
259       }
260 
261       //
262       // 4. Check the OptionalHeader.SizeOfHeaders field.
263       //
264       if (Hdr.Pe32->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {
265         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
266         return RETURN_UNSUPPORTED;
267       }
268       if (Hdr.Pe32->OptionalHeader.SizeOfHeaders >= Hdr.Pe32->OptionalHeader.SizeOfImage) {
269         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
270         return RETURN_UNSUPPORTED;
271       }
272       if ((Hdr.Pe32->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32->FileHeader.NumberOfSections) {
273         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
274         return RETURN_UNSUPPORTED;
275       }
276 
277       //
278       // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
279       //
280       Size = 1;
281       ReadSize = Size;
282       Status = ImageContext->ImageRead (
283                                ImageContext->Handle,
284                                Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,
285                                &Size,
286                                &BufferData
287                                );
288       if (RETURN_ERROR (Status) || (Size != ReadSize)) {
289         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
290         if (Size != ReadSize) {
291           Status = RETURN_UNSUPPORTED;
292         }
293         return Status;
294       }
295 
296       //
297       // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
298       // Read the last byte to make sure the data is in the image region.
299       // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
300       //
301       if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
302         if (Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
303           //
304           // Check the member data to avoid overflow.
305           //
306           if ((UINT32) (~0) - Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
307               Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
308             ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
309             return RETURN_UNSUPPORTED;
310           }
311 
312           //
313           // Read last byte of section header from file
314           //
315           Size = 1;
316           ReadSize = Size;
317           Status = ImageContext->ImageRead (
318                                    ImageContext->Handle,
319                                    Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
320                                     Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
321                                    &Size,
322                                    &BufferData
323                                    );
324           if (RETURN_ERROR (Status) || (Size != ReadSize)) {
325             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
326             if (Size != ReadSize) {
327               Status = RETURN_UNSUPPORTED;
328             }
329             return Status;
330           }
331         }
332       }
333 
334       //
335       // Use PE32 offset
336       //
337       ImageContext->ImageType         = Hdr.Pe32->OptionalHeader.Subsystem;
338       ImageContext->ImageSize         = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;
339       ImageContext->SectionAlignment  = Hdr.Pe32->OptionalHeader.SectionAlignment;
340       ImageContext->SizeOfHeaders     = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
341 
342     } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
343       //
344       // 1. Check FileHeader.NumberOfRvaAndSizes filed.
345       //
346       if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
347         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
348         return RETURN_UNSUPPORTED;
349       }
350       //
351       // 2. Check the FileHeader.SizeOfOptionalHeader field.
352       // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
353       // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
354       //
355       HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER64) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
356       if (((UINT32)Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
357           Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
358         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
359         return RETURN_UNSUPPORTED;
360       }
361 
362       SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
363       //
364       // 3. Check the FileHeader.NumberOfSections field.
365       //
366       if (Hdr.Pe32Plus->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {
367         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
368         return RETURN_UNSUPPORTED;
369       }
370       if ((Hdr.Pe32Plus->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32Plus->FileHeader.NumberOfSections) {
371         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
372         return RETURN_UNSUPPORTED;
373       }
374 
375       //
376       // 4. Check the OptionalHeader.SizeOfHeaders field.
377       //
378       if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {
379         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
380         return RETURN_UNSUPPORTED;
381       }
382       if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders >= Hdr.Pe32Plus->OptionalHeader.SizeOfImage) {
383         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
384         return RETURN_UNSUPPORTED;
385       }
386       if ((Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32Plus->FileHeader.NumberOfSections) {
387         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
388         return RETURN_UNSUPPORTED;
389       }
390 
391       //
392       // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
393       //
394       Size = 1;
395       ReadSize = Size;
396       Status = ImageContext->ImageRead (
397                                ImageContext->Handle,
398                                Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,
399                                &Size,
400                                &BufferData
401                                );
402       if (RETURN_ERROR (Status) || (Size != ReadSize)) {
403         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
404         if (Size != ReadSize) {
405           Status = RETURN_UNSUPPORTED;
406         }
407         return Status;
408       }
409 
410       //
411       // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
412       // Read the last byte to make sure the data is in the image region.
413       // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
414       //
415       if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
416         if (Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
417           //
418           // Check the member data to avoid overflow.
419           //
420           if ((UINT32) (~0) - Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
421               Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
422             ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
423             return RETURN_UNSUPPORTED;
424           }
425 
426           //
427           // Read last byte of section header from file
428           //
429           Size = 1;
430           ReadSize = Size;
431           Status = ImageContext->ImageRead (
432                                    ImageContext->Handle,
433                                    Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
434                                     Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
435                                    &Size,
436                                    &BufferData
437                                    );
438           if (RETURN_ERROR (Status) || (Size != ReadSize)) {
439             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
440             if (Size != ReadSize) {
441               Status = RETURN_UNSUPPORTED;
442             }
443             return Status;
444           }
445         }
446       }
447 
448       //
449       // Use PE32+ offset
450       //
451       ImageContext->ImageType         = Hdr.Pe32Plus->OptionalHeader.Subsystem;
452       ImageContext->ImageSize         = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
453       ImageContext->SectionAlignment  = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
454       ImageContext->SizeOfHeaders     = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
455     } else {
456       ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
457       return RETURN_UNSUPPORTED;
458     }
459   } else {
460     ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
461     return RETURN_UNSUPPORTED;
462   }
463 
464   if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {
465     //
466     // If the PE/COFF loader does not support the image type return
467     // unsupported. This library can support lots of types of images
468     // this does not mean the user of this library can call the entry
469     // point of the image.
470     //
471     return RETURN_UNSUPPORTED;
472   }
473 
474   //
475   // Check each section field.
476   //
477   if (ImageContext->IsTeImage) {
478     SectionHeaderOffset = sizeof(EFI_TE_IMAGE_HEADER);
479     NumberOfSections    = (UINTN) (Hdr.Te->NumberOfSections);
480   } else {
481     SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
482     NumberOfSections    = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
483   }
484 
485   for (Index = 0; Index < NumberOfSections; Index++) {
486     //
487     // Read section header from file
488     //
489     Size = sizeof (EFI_IMAGE_SECTION_HEADER);
490     ReadSize = Size;
491     Status = ImageContext->ImageRead (
492                              ImageContext->Handle,
493                              SectionHeaderOffset,
494                              &Size,
495                              &SectionHeader
496                              );
497     if (RETURN_ERROR (Status) || (Size != ReadSize)) {
498       ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
499       if (Size != ReadSize) {
500         Status = RETURN_UNSUPPORTED;
501       }
502       return Status;
503     }
504 
505     //
506     // Adjust some field in Section Header for TE image.
507     //
508     if (ImageContext->IsTeImage) {
509       PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader, (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
510     }
511 
512     if (SectionHeader.SizeOfRawData > 0) {
513       //
514       // Section data should bigger than the Pe header.
515       //
516       if (SectionHeader.VirtualAddress < ImageContext->SizeOfHeaders ||
517           SectionHeader.PointerToRawData < ImageContext->SizeOfHeaders) {
518         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
519         return RETURN_UNSUPPORTED;
520       }
521 
522       //
523       // Check the member data to avoid overflow.
524       //
525       if ((UINT32) (~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {
526         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
527         return RETURN_UNSUPPORTED;
528       }
529 
530       //
531       // Base on the ImageRead function to check the section data field.
532       // Read the last byte to make sure the data is in the image region.
533       //
534       Size = 1;
535       ReadSize = Size;
536       Status = ImageContext->ImageRead (
537                                ImageContext->Handle,
538                                SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,
539                                &Size,
540                                &BufferData
541                                );
542       if (RETURN_ERROR (Status) || (Size != ReadSize)) {
543         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
544         if (Size != ReadSize) {
545           Status = RETURN_UNSUPPORTED;
546         }
547         return Status;
548       }
549     }
550 
551     //
552     // Check next section.
553     //
554     SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
555   }
556 
557   return RETURN_SUCCESS;
558 }
559 
560 
561 /**
562   Retrieves information about a PE/COFF image.
563 
564   Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
565   DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
566   DebugDirectoryEntryRva fields of the ImageContext structure.
567   If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
568   If the PE/COFF image accessed through the ImageRead service in the ImageContext
569   structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
570   If any errors occur while computing the fields of ImageContext,
571   then the error status is returned in the ImageError field of ImageContext.
572   If the image is a TE image, then SectionAlignment is set to 0.
573   The ImageRead and Handle fields of ImageContext structure must be valid prior
574   to invoking this service.
575 
576   Caution: This function may receive untrusted input.
577   PE/COFF image is external input, so this routine will
578   also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
579   SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
580 
581   @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
582                                     image that needs to be examined by this function.
583 
584   @retval RETURN_SUCCESS            The information on the PE/COFF image was collected.
585   @retval RETURN_INVALID_PARAMETER  ImageContext is NULL.
586   @retval RETURN_UNSUPPORTED        The PE/COFF image is not supported.
587 
588 **/
589 RETURN_STATUS
590 EFIAPI
PeCoffLoaderGetImageInfo(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)591 PeCoffLoaderGetImageInfo (
592   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
593   )
594 {
595   RETURN_STATUS                         Status;
596   EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;
597   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
598   EFI_IMAGE_DATA_DIRECTORY              *DebugDirectoryEntry;
599   UINTN                                 Size;
600   UINTN                                 ReadSize;
601   UINTN                                 Index;
602   UINTN                                 DebugDirectoryEntryRva;
603   UINTN                                 DebugDirectoryEntryFileOffset;
604   UINTN                                 SectionHeaderOffset;
605   EFI_IMAGE_SECTION_HEADER              SectionHeader;
606   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       DebugEntry;
607   UINT32                                NumberOfRvaAndSizes;
608   UINT16                                Magic;
609   UINT32                                TeStrippedOffset;
610 
611   if (ImageContext == NULL) {
612     return RETURN_INVALID_PARAMETER;
613   }
614   //
615   // Assume success
616   //
617   ImageContext->ImageError  = IMAGE_ERROR_SUCCESS;
618 
619   Hdr.Union = &HdrData;
620   Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);
621   if (RETURN_ERROR (Status)) {
622     return Status;
623   }
624 
625   Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
626 
627   //
628   // Retrieve the base address of the image
629   //
630   if (!(ImageContext->IsTeImage)) {
631     TeStrippedOffset = 0;
632     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
633       //
634       // Use PE32 offset
635       //
636       ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;
637     } else {
638       //
639       // Use PE32+ offset
640       //
641       ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;
642     }
643   } else {
644     TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
645     ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + TeStrippedOffset);
646   }
647 
648   //
649   // Initialize the alternate destination address to 0 indicating that it
650   // should not be used.
651   //
652   ImageContext->DestinationAddress = 0;
653 
654   //
655   // Initialize the debug codeview pointer.
656   //
657   ImageContext->DebugDirectoryEntryRva = 0;
658   ImageContext->CodeView               = NULL;
659   ImageContext->PdbPointer             = NULL;
660 
661   //
662   // Three cases with regards to relocations:
663   // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable
664   // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
665   // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
666   //   has no base relocs to apply
667   // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
668   //
669   // Look at the file header to determine if relocations have been stripped, and
670   // save this information in the image context for later use.
671   //
672   if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
673     ImageContext->RelocationsStripped = TRUE;
674   } else if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
675     ImageContext->RelocationsStripped = TRUE;
676   } else {
677     ImageContext->RelocationsStripped = FALSE;
678   }
679 
680   if (!(ImageContext->IsTeImage)) {
681     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
682       //
683       // Use PE32 offset
684       //
685       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
686       DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
687     } else {
688       //
689       // Use PE32+ offset
690       //
691       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
692       DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
693     }
694 
695     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
696 
697       DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
698 
699       //
700       // Determine the file offset of the debug directory...  This means we walk
701       // the sections to find which section contains the RVA of the debug
702       // directory
703       //
704       DebugDirectoryEntryFileOffset = 0;
705 
706       SectionHeaderOffset = (UINTN)(
707                                ImageContext->PeCoffHeaderOffset +
708                                sizeof (UINT32) +
709                                sizeof (EFI_IMAGE_FILE_HEADER) +
710                                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
711                                );
712 
713       for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
714         //
715         // Read section header from file
716         //
717         Size = sizeof (EFI_IMAGE_SECTION_HEADER);
718         ReadSize = Size;
719         Status = ImageContext->ImageRead (
720                                  ImageContext->Handle,
721                                  SectionHeaderOffset,
722                                  &Size,
723                                  &SectionHeader
724                                  );
725         if (RETURN_ERROR (Status) || (Size != ReadSize)) {
726           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
727           if (Size != ReadSize) {
728             Status = RETURN_UNSUPPORTED;
729           }
730           return Status;
731         }
732 
733         if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
734             DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
735 
736           DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
737           break;
738         }
739 
740         SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
741       }
742 
743       if (DebugDirectoryEntryFileOffset != 0) {
744         for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
745           //
746           // Read next debug directory entry
747           //
748           Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
749           ReadSize = Size;
750           Status = ImageContext->ImageRead (
751                                    ImageContext->Handle,
752                                    DebugDirectoryEntryFileOffset + Index,
753                                    &Size,
754                                    &DebugEntry
755                                    );
756           if (RETURN_ERROR (Status) || (Size != ReadSize)) {
757             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
758             if (Size != ReadSize) {
759               Status = RETURN_UNSUPPORTED;
760             }
761             return Status;
762           }
763 
764           //
765           // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
766           // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
767           // ImageContext->ImageSize when DebugEntry.RVA == 0.
768           //
769           if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
770             ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
771             if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
772               ImageContext->ImageSize += DebugEntry.SizeOfData;
773             }
774 
775             return RETURN_SUCCESS;
776           }
777         }
778       }
779     }
780   } else {
781 
782     DebugDirectoryEntry             = &Hdr.Te->DataDirectory[1];
783     DebugDirectoryEntryRva          = DebugDirectoryEntry->VirtualAddress;
784     SectionHeaderOffset             = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
785 
786     DebugDirectoryEntryFileOffset   = 0;
787 
788     for (Index = 0; Index < Hdr.Te->NumberOfSections;) {
789       //
790       // Read section header from file
791       //
792       Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
793       ReadSize = Size;
794       Status = ImageContext->ImageRead (
795                                ImageContext->Handle,
796                                SectionHeaderOffset,
797                                &Size,
798                                &SectionHeader
799                                );
800       if (RETURN_ERROR (Status) || (Size != ReadSize)) {
801         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
802         if (Size != ReadSize) {
803           Status = RETURN_UNSUPPORTED;
804         }
805         return Status;
806       }
807 
808       if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
809           DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
810         DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
811                                         SectionHeader.VirtualAddress +
812                                         SectionHeader.PointerToRawData -
813                                         TeStrippedOffset;
814 
815         //
816         // File offset of the debug directory was found, if this is not the last
817         // section, then skip to the last section for calculating the image size.
818         //
819         if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {
820           SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
821           Index = Hdr.Te->NumberOfSections - 1;
822           continue;
823         }
824       }
825 
826       //
827       // In Te image header there is not a field to describe the ImageSize.
828       // Actually, the ImageSize equals the RVA plus the VirtualSize of
829       // the last section mapped into memory (Must be rounded up to
830       // a multiple of Section Alignment). Per the PE/COFF specification, the
831       // section headers in the Section Table must appear in order of the RVA
832       // values for the corresponding sections. So the ImageSize can be determined
833       // by the RVA and the VirtualSize of the last section header in the
834       // Section Table.
835       //
836       if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {
837         ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) - TeStrippedOffset;
838       }
839 
840       SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
841     }
842 
843     if (DebugDirectoryEntryFileOffset != 0) {
844       for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
845         //
846         // Read next debug directory entry
847         //
848         Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
849         ReadSize = Size;
850         Status = ImageContext->ImageRead (
851                                  ImageContext->Handle,
852                                  DebugDirectoryEntryFileOffset + Index,
853                                  &Size,
854                                  &DebugEntry
855                                  );
856         if (RETURN_ERROR (Status) || (Size != ReadSize)) {
857           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
858           if (Size != ReadSize) {
859             Status = RETURN_UNSUPPORTED;
860           }
861           return Status;
862         }
863 
864         if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
865           ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
866           return RETURN_SUCCESS;
867         }
868       }
869     }
870   }
871 
872   return RETURN_SUCCESS;
873 }
874 
875 
876 /**
877   Converts an image address to the loaded address.
878 
879   @param  ImageContext      The context of the image being loaded.
880   @param  Address           The address to be converted to the loaded address.
881   @param  TeStrippedOffset  Stripped offset for TE image.
882 
883   @return The converted address or NULL if the address can not be converted.
884 
885 **/
886 VOID *
PeCoffLoaderImageAddress(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext,IN UINTN Address,IN UINTN TeStrippedOffset)887 PeCoffLoaderImageAddress (
888   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT          *ImageContext,
889   IN     UINTN                                 Address,
890   IN     UINTN                                 TeStrippedOffset
891   )
892 {
893   //
894   // Make sure that Address and ImageSize is correct for the loaded image.
895   //
896   if (Address >= ImageContext->ImageSize + TeStrippedOffset) {
897     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
898     return NULL;
899   }
900 
901   return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address - TeStrippedOffset);
902 }
903 
904 /**
905   Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
906 
907   If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
908   ImageContext as the relocation base address.  Otherwise, use the DestinationAddress field
909   of ImageContext as the relocation base address.  The caller must allocate the relocation
910   fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
911 
912   The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage, Machine, ImageType, ImageAddress,
913   ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
914   DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
915   the ImageContext structure must be valid prior to invoking this service.
916 
917   If ImageContext is NULL, then ASSERT().
918 
919   Note that if the platform does not maintain coherency between the instruction cache(s) and the data
920   cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
921   prior to transferring control to a PE/COFF image that is loaded using this library.
922 
923   @param  ImageContext        The pointer to the image context structure that describes the PE/COFF
924                               image that is being relocated.
925 
926   @retval RETURN_SUCCESS      The PE/COFF image was relocated.
927                               Extended status information is in the ImageError field of ImageContext.
928   @retval RETURN_LOAD_ERROR   The image in not a valid PE/COFF image.
929                               Extended status information is in the ImageError field of ImageContext.
930   @retval RETURN_UNSUPPORTED  A relocation record type is not supported.
931                               Extended status information is in the ImageError field of ImageContext.
932 
933 **/
934 RETURN_STATUS
935 EFIAPI
PeCoffLoaderRelocateImage(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)936 PeCoffLoaderRelocateImage (
937   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
938   )
939 {
940   RETURN_STATUS                         Status;
941   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
942   EFI_IMAGE_DATA_DIRECTORY              *RelocDir;
943   UINT64                                Adjust;
944   EFI_IMAGE_BASE_RELOCATION             *RelocBaseOrg;
945   EFI_IMAGE_BASE_RELOCATION             *RelocBase;
946   EFI_IMAGE_BASE_RELOCATION             *RelocBaseEnd;
947   UINT16                                *Reloc;
948   UINT16                                *RelocEnd;
949   CHAR8                                 *Fixup;
950   CHAR8                                 *FixupBase;
951   UINT16                                *Fixup16;
952   UINT32                                *Fixup32;
953   UINT64                                *Fixup64;
954   CHAR8                                 *FixupData;
955   PHYSICAL_ADDRESS                      BaseAddress;
956   UINT32                                NumberOfRvaAndSizes;
957   UINT16                                Magic;
958   UINT32                                TeStrippedOffset;
959 
960   ASSERT (ImageContext != NULL);
961 
962   //
963   // Assume success
964   //
965   ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
966 
967   //
968   // If there are no relocation entries, then we are done
969   //
970   if (ImageContext->RelocationsStripped) {
971     // Applies additional environment specific actions to relocate fixups
972     // to a PE/COFF image if needed
973     PeCoffLoaderRelocateImageExtraAction (ImageContext);
974     return RETURN_SUCCESS;
975   }
976 
977   //
978   // If the destination address is not 0, use that rather than the
979   // image address as the relocation target.
980   //
981   if (ImageContext->DestinationAddress != 0) {
982     BaseAddress = ImageContext->DestinationAddress;
983   } else {
984     BaseAddress = ImageContext->ImageAddress;
985   }
986 
987   if (!(ImageContext->IsTeImage)) {
988     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
989     TeStrippedOffset = 0;
990     Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
991 
992     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
993       //
994       // Use PE32 offset
995       //
996       Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
997       if (Adjust != 0) {
998         Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
999       }
1000 
1001       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1002       RelocDir  = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1003     } else {
1004       //
1005       // Use PE32+ offset
1006       //
1007       Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
1008       if (Adjust != 0) {
1009         Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
1010       }
1011 
1012       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1013       RelocDir  = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1014     }
1015 
1016     //
1017     // Find the relocation block
1018     // Per the PE/COFF spec, you can't assume that a given data directory
1019     // is present in the image. You have to check the NumberOfRvaAndSizes in
1020     // the optional header to verify a desired directory entry is there.
1021     //
1022     if ((NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)) {
1023       RelocDir = NULL;
1024     }
1025   } else {
1026     Hdr.Te             = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
1027     TeStrippedOffset   = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
1028     Adjust             = (UINT64) (BaseAddress - (Hdr.Te->ImageBase + TeStrippedOffset));
1029     if (Adjust != 0) {
1030       Hdr.Te->ImageBase  = (UINT64) (BaseAddress - TeStrippedOffset);
1031     }
1032 
1033     //
1034     // Find the relocation block
1035     //
1036     RelocDir = &Hdr.Te->DataDirectory[0];
1037   }
1038 
1039   if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
1040     RelocBase = (EFI_IMAGE_BASE_RELOCATION *) PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress, TeStrippedOffset);
1041     RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) PeCoffLoaderImageAddress (ImageContext,
1042                                                                             RelocDir->VirtualAddress + RelocDir->Size - 1,
1043                                                                             TeStrippedOffset
1044                                                                             );
1045     if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
1046       ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1047       return RETURN_LOAD_ERROR;
1048     }
1049   } else {
1050     //
1051     // Set base and end to bypass processing below.
1052     //
1053     RelocBase = RelocBaseEnd = NULL;
1054   }
1055   RelocBaseOrg = RelocBase;
1056 
1057   //
1058   // If Adjust is not zero, then apply fix ups to the image
1059   //
1060   if (Adjust != 0) {
1061     //
1062     // Run the relocation information and apply the fixups
1063     //
1064     FixupData = ImageContext->FixupData;
1065     while (RelocBase < RelocBaseEnd) {
1066 
1067       Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1068       //
1069       // Add check for RelocBase->SizeOfBlock field.
1070       //
1071       if (RelocBase->SizeOfBlock == 0) {
1072         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1073         return RETURN_LOAD_ERROR;
1074       }
1075       if ((UINTN)RelocBase > MAX_ADDRESS - RelocBase->SizeOfBlock) {
1076         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1077         return RETURN_LOAD_ERROR;
1078       }
1079 
1080       RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
1081       if ((UINTN)RelocEnd > (UINTN)RelocBaseOrg + RelocDir->Size) {
1082         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1083         return RETURN_LOAD_ERROR;
1084       }
1085       FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress, TeStrippedOffset);
1086       if (FixupBase == NULL) {
1087         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1088         return RETURN_LOAD_ERROR;
1089       }
1090 
1091       //
1092       // Run this relocation record
1093       //
1094       while (Reloc < RelocEnd) {
1095         Fixup = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset);
1096         if (Fixup == NULL) {
1097           ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1098           return RETURN_LOAD_ERROR;
1099         }
1100         switch ((*Reloc) >> 12) {
1101         case EFI_IMAGE_REL_BASED_ABSOLUTE:
1102           break;
1103 
1104         case EFI_IMAGE_REL_BASED_HIGH:
1105           Fixup16   = (UINT16 *) Fixup;
1106           *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
1107           if (FixupData != NULL) {
1108             *(UINT16 *) FixupData = *Fixup16;
1109             FixupData             = FixupData + sizeof (UINT16);
1110           }
1111           break;
1112 
1113         case EFI_IMAGE_REL_BASED_LOW:
1114           Fixup16   = (UINT16 *) Fixup;
1115           *Fixup16  = (UINT16) (*Fixup16 + (UINT16) Adjust);
1116           if (FixupData != NULL) {
1117             *(UINT16 *) FixupData = *Fixup16;
1118             FixupData             = FixupData + sizeof (UINT16);
1119           }
1120           break;
1121 
1122         case EFI_IMAGE_REL_BASED_HIGHLOW:
1123           Fixup32   = (UINT32 *) Fixup;
1124           *Fixup32  = *Fixup32 + (UINT32) Adjust;
1125           if (FixupData != NULL) {
1126             FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT32));
1127             *(UINT32 *)FixupData  = *Fixup32;
1128             FixupData             = FixupData + sizeof (UINT32);
1129           }
1130           break;
1131 
1132         case EFI_IMAGE_REL_BASED_DIR64:
1133           Fixup64 = (UINT64 *) Fixup;
1134           *Fixup64 = *Fixup64 + (UINT64) Adjust;
1135           if (FixupData != NULL) {
1136             FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
1137             *(UINT64 *)(FixupData) = *Fixup64;
1138             FixupData = FixupData + sizeof(UINT64);
1139           }
1140           break;
1141 
1142         default:
1143           //
1144           // The common code does not handle some of the stranger IPF relocations
1145           // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1146           // on IPF and is a No-Op on other architectures.
1147           //
1148           Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1149           if (RETURN_ERROR (Status)) {
1150             ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1151             return Status;
1152           }
1153         }
1154 
1155         //
1156         // Next relocation record
1157         //
1158         Reloc += 1;
1159       }
1160 
1161       //
1162       // Next reloc block
1163       //
1164       RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
1165     }
1166     ASSERT ((UINTN)FixupData <= (UINTN)ImageContext->FixupData + ImageContext->FixupDataSize);
1167 
1168     //
1169     // Adjust the EntryPoint to match the linked-to address
1170     //
1171     if (ImageContext->DestinationAddress != 0) {
1172        ImageContext->EntryPoint -= (UINT64) ImageContext->ImageAddress;
1173        ImageContext->EntryPoint += (UINT64) ImageContext->DestinationAddress;
1174     }
1175   }
1176 
1177   // Applies additional environment specific actions to relocate fixups
1178   // to a PE/COFF image if needed
1179   PeCoffLoaderRelocateImageExtraAction (ImageContext);
1180 
1181   return RETURN_SUCCESS;
1182 }
1183 
1184 /**
1185   Loads a PE/COFF image into memory.
1186 
1187   Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1188   specified by the ImageAddress and ImageSize fields of ImageContext.  The caller must allocate
1189   the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1190   The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1191   The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage,  Machine, ImageType, ImageAddress, ImageSize,
1192   DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1193   fields of the ImageContext structure must be valid prior to invoking this service.
1194 
1195   If ImageContext is NULL, then ASSERT().
1196 
1197   Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1198   cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1199   prior to transferring control to a PE/COFF image that is loaded using this library.
1200 
1201   @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
1202                                     image that is being loaded.
1203 
1204   @retval RETURN_SUCCESS            The PE/COFF image was loaded into the buffer specified by
1205                                     the ImageAddress and ImageSize fields of ImageContext.
1206                                     Extended status information is in the ImageError field of ImageContext.
1207   @retval RETURN_BUFFER_TOO_SMALL   The caller did not provide a large enough buffer.
1208                                     Extended status information is in the ImageError field of ImageContext.
1209   @retval RETURN_LOAD_ERROR         The PE/COFF image is an EFI Runtime image with no relocations.
1210                                     Extended status information is in the ImageError field of ImageContext.
1211   @retval RETURN_INVALID_PARAMETER  The image address is invalid.
1212                                     Extended status information is in the ImageError field of ImageContext.
1213 
1214 **/
1215 RETURN_STATUS
1216 EFIAPI
PeCoffLoaderLoadImage(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1217 PeCoffLoaderLoadImage (
1218   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
1219   )
1220 {
1221   RETURN_STATUS                         Status;
1222   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
1223   PE_COFF_LOADER_IMAGE_CONTEXT          CheckContext;
1224   EFI_IMAGE_SECTION_HEADER              *FirstSection;
1225   EFI_IMAGE_SECTION_HEADER              *Section;
1226   UINTN                                 NumberOfSections;
1227   UINTN                                 Index;
1228   CHAR8                                 *Base;
1229   CHAR8                                 *End;
1230   EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
1231   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
1232   UINTN                                 Size;
1233   UINT32                                TempDebugEntryRva;
1234   UINT32                                NumberOfRvaAndSizes;
1235   UINT16                                Magic;
1236   EFI_IMAGE_RESOURCE_DIRECTORY          *ResourceDirectory;
1237   EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY    *ResourceDirectoryEntry;
1238   EFI_IMAGE_RESOURCE_DIRECTORY_STRING   *ResourceDirectoryString;
1239   EFI_IMAGE_RESOURCE_DATA_ENTRY         *ResourceDataEntry;
1240   CHAR16                                *String;
1241   UINT32                                Offset;
1242   UINT32                                TeStrippedOffset;
1243 
1244   ASSERT (ImageContext != NULL);
1245 
1246   //
1247   // Assume success
1248   //
1249   ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
1250 
1251   //
1252   // Copy the provided context information into our local version, get what we
1253   // can from the original image, and then use that to make sure everything
1254   // is legit.
1255   //
1256   CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
1257 
1258   Status = PeCoffLoaderGetImageInfo (&CheckContext);
1259   if (RETURN_ERROR (Status)) {
1260     return Status;
1261   }
1262 
1263   //
1264   // Make sure there is enough allocated space for the image being loaded
1265   //
1266   if (ImageContext->ImageSize < CheckContext.ImageSize) {
1267     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
1268     return RETURN_BUFFER_TOO_SMALL;
1269   }
1270   if (ImageContext->ImageAddress == 0) {
1271     //
1272     // Image cannot be loaded into 0 address.
1273     //
1274     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
1275     return RETURN_INVALID_PARAMETER;
1276   }
1277   //
1278   // If there's no relocations, then make sure it's not a runtime driver,
1279   // and that it's being loaded at the linked address.
1280   //
1281   if (CheckContext.RelocationsStripped) {
1282     //
1283     // If the image does not contain relocations and it is a runtime driver
1284     // then return an error.
1285     //
1286     if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
1287       ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
1288       return RETURN_LOAD_ERROR;
1289     }
1290     //
1291     // If the image does not contain relocations, and the requested load address
1292     // is not the linked address, then return an error.
1293     //
1294     if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
1295       ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
1296       return RETURN_INVALID_PARAMETER;
1297     }
1298   }
1299   //
1300   // Make sure the allocated space has the proper section alignment
1301   //
1302   if (!(ImageContext->IsTeImage)) {
1303     if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
1304       ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
1305       return RETURN_INVALID_PARAMETER;
1306     }
1307   }
1308   //
1309   // Read the entire PE/COFF or TE header into memory
1310   //
1311   if (!(ImageContext->IsTeImage)) {
1312     Status = ImageContext->ImageRead (
1313                             ImageContext->Handle,
1314                             0,
1315                             &ImageContext->SizeOfHeaders,
1316                             (VOID *) (UINTN) ImageContext->ImageAddress
1317                             );
1318 
1319     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
1320 
1321     FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
1322                       (UINTN)ImageContext->ImageAddress +
1323                       ImageContext->PeCoffHeaderOffset +
1324                       sizeof(UINT32) +
1325                       sizeof(EFI_IMAGE_FILE_HEADER) +
1326                       Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1327       );
1328     NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
1329     TeStrippedOffset = 0;
1330   } else {
1331     Status = ImageContext->ImageRead (
1332                             ImageContext->Handle,
1333                             0,
1334                             &ImageContext->SizeOfHeaders,
1335                             (void *)(UINTN)ImageContext->ImageAddress
1336                             );
1337 
1338     Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
1339     FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
1340                       (UINTN)ImageContext->ImageAddress +
1341                       sizeof(EFI_TE_IMAGE_HEADER)
1342                       );
1343     NumberOfSections  = (UINTN) (Hdr.Te->NumberOfSections);
1344     TeStrippedOffset  = (UINT32) Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
1345   }
1346 
1347   if (RETURN_ERROR (Status)) {
1348     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1349     return RETURN_LOAD_ERROR;
1350   }
1351 
1352   //
1353   // Load each section of the image
1354   //
1355   Section = FirstSection;
1356   for (Index = 0; Index < NumberOfSections; Index++) {
1357     //
1358     // Read the section
1359     //
1360     Size = (UINTN) Section->Misc.VirtualSize;
1361     if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1362       Size = (UINTN) Section->SizeOfRawData;
1363     }
1364 
1365     //
1366     // Compute sections address
1367     //
1368     Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress, TeStrippedOffset);
1369     End  = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress + Section->Misc.VirtualSize - 1, TeStrippedOffset);
1370 
1371     //
1372     // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1373     //
1374     if ((Size > 0) && ((Base == NULL) || (End == NULL))) {
1375       ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
1376       return RETURN_LOAD_ERROR;
1377     }
1378 
1379     if (Section->SizeOfRawData > 0) {
1380       Status = ImageContext->ImageRead (
1381                               ImageContext->Handle,
1382                               Section->PointerToRawData - TeStrippedOffset,
1383                               &Size,
1384                               Base
1385                               );
1386       if (RETURN_ERROR (Status)) {
1387         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1388         return Status;
1389       }
1390     }
1391 
1392     //
1393     // If raw size is less then virtual size, zero fill the remaining
1394     //
1395 
1396     if (Size < Section->Misc.VirtualSize) {
1397       ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1398     }
1399 
1400     //
1401     // Next Section
1402     //
1403     Section += 1;
1404   }
1405 
1406   //
1407   // Get image's entry point
1408   //
1409   Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
1410   if (!(ImageContext->IsTeImage)) {
1411     //
1412     // Sizes of AddressOfEntryPoint are different so we need to do this safely
1413     //
1414     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1415       //
1416       // Use PE32 offset
1417       //
1418       ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1419                                                             ImageContext,
1420                                                             (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint,
1421                                                             0
1422                                                             );
1423     } else {
1424       //
1425       // Use PE32+ offset
1426       //
1427       ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1428                                                             ImageContext,
1429                                                             (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint,
1430                                                             0
1431                                                             );
1432     }
1433   } else {
1434     ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1435                                                           ImageContext,
1436                                                           (UINTN)Hdr.Te->AddressOfEntryPoint,
1437                                                           TeStrippedOffset
1438                                                           );
1439   }
1440 
1441   //
1442   // Determine the size of the fixup data
1443   //
1444   // Per the PE/COFF spec, you can't assume that a given data directory
1445   // is present in the image. You have to check the NumberOfRvaAndSizes in
1446   // the optional header to verify a desired directory entry is there.
1447   //
1448   if (!(ImageContext->IsTeImage)) {
1449     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1450       //
1451       // Use PE32 offset
1452       //
1453       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1454       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1455     } else {
1456       //
1457       // Use PE32+ offset
1458       //
1459       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1460       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1461     }
1462 
1463     //
1464     // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
1465     //
1466     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1467       ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
1468     } else {
1469       ImageContext->FixupDataSize = 0;
1470     }
1471   } else {
1472     DirectoryEntry              = &Hdr.Te->DataDirectory[0];
1473     ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
1474   }
1475   //
1476   // Consumer must allocate a buffer for the relocation fixup log.
1477   // Only used for runtime drivers.
1478   //
1479   ImageContext->FixupData = NULL;
1480 
1481   //
1482   // Load the Codeview information if present
1483   //
1484   if (ImageContext->DebugDirectoryEntryRva != 0) {
1485     DebugEntry = PeCoffLoaderImageAddress (
1486                 ImageContext,
1487                 ImageContext->DebugDirectoryEntryRva,
1488                 TeStrippedOffset
1489                 );
1490     if (DebugEntry == NULL) {
1491       ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1492       return RETURN_LOAD_ERROR;
1493     }
1494 
1495     TempDebugEntryRva = DebugEntry->RVA;
1496     if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1497       Section--;
1498       if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
1499         TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1500       } else {
1501         TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1502       }
1503     }
1504 
1505     if (TempDebugEntryRva != 0) {
1506       ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva, TeStrippedOffset);
1507       if (ImageContext->CodeView == NULL) {
1508         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1509         return RETURN_LOAD_ERROR;
1510       }
1511 
1512       if (DebugEntry->RVA == 0) {
1513         Size = DebugEntry->SizeOfData;
1514         Status = ImageContext->ImageRead (
1515                                 ImageContext->Handle,
1516                                 DebugEntry->FileOffset - TeStrippedOffset,
1517                                 &Size,
1518                                 ImageContext->CodeView
1519                                 );
1520         //
1521         // Should we apply fix up to this field according to the size difference between PE and TE?
1522         // Because now we maintain TE header fields unfixed, this field will also remain as they are
1523         // in original PE image.
1524         //
1525 
1526         if (RETURN_ERROR (Status)) {
1527           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1528           return RETURN_LOAD_ERROR;
1529         }
1530 
1531         DebugEntry->RVA = TempDebugEntryRva;
1532       }
1533 
1534       switch (*(UINT32 *) ImageContext->CodeView) {
1535       case CODEVIEW_SIGNATURE_NB10:
1536         if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {
1537           ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1538           return RETURN_UNSUPPORTED;
1539         }
1540         ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1541         break;
1542 
1543       case CODEVIEW_SIGNATURE_RSDS:
1544         if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {
1545           ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1546           return RETURN_UNSUPPORTED;
1547         }
1548         ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1549         break;
1550 
1551       case CODEVIEW_SIGNATURE_MTOC:
1552         if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {
1553           ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1554           return RETURN_UNSUPPORTED;
1555         }
1556         ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
1557         break;
1558 
1559       default:
1560         break;
1561       }
1562     }
1563   }
1564 
1565   //
1566   // Get Image's HII resource section
1567   //
1568   ImageContext->HiiResourceData = 0;
1569   if (!(ImageContext->IsTeImage)) {
1570     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1571       //
1572       // Use PE32 offset
1573       //
1574       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1575       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
1576     } else {
1577       //
1578       // Use PE32+ offset
1579       //
1580       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1581       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
1582     }
1583 
1584     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && DirectoryEntry->Size != 0) {
1585       Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress, 0);
1586       if (Base != NULL) {
1587         ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;
1588         Offset = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) *
1589                (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1590         if (Offset > DirectoryEntry->Size) {
1591           ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1592           return RETURN_UNSUPPORTED;
1593         }
1594         ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1595 
1596         for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
1597           if (ResourceDirectoryEntry->u1.s.NameIsString) {
1598             //
1599             // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1600             //
1601             if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {
1602               ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1603               return RETURN_UNSUPPORTED;
1604             }
1605             ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);
1606             String = &ResourceDirectoryString->String[0];
1607 
1608             if (ResourceDirectoryString->Length == 3 &&
1609                 String[0] == L'H' &&
1610                 String[1] == L'I' &&
1611                 String[2] == L'I') {
1612               //
1613               // Resource Type "HII" found
1614               //
1615               if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1616                 //
1617                 // Move to next level - resource Name
1618                 //
1619                 if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
1620                   ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1621                   return RETURN_UNSUPPORTED;
1622                 }
1623                 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
1624                 Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
1625                          sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1626                 if (Offset > DirectoryEntry->Size) {
1627                   ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1628                   return RETURN_UNSUPPORTED;
1629                 }
1630                 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1631 
1632                 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1633                   //
1634                   // Move to next level - resource Language
1635                   //
1636                   if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
1637                     ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1638                     return RETURN_UNSUPPORTED;
1639                   }
1640                   ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
1641                   Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
1642                            sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1643                   if (Offset > DirectoryEntry->Size) {
1644                     ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1645                     return RETURN_UNSUPPORTED;
1646                   }
1647                   ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1648                 }
1649               }
1650 
1651               //
1652               // Now it ought to be resource Data
1653               //
1654               if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1655                 if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {
1656                   ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1657                   return RETURN_UNSUPPORTED;
1658                 }
1659                 ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);
1660                 ImageContext->HiiResourceData = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData, 0);
1661                 break;
1662               }
1663             }
1664           }
1665           ResourceDirectoryEntry++;
1666         }
1667       }
1668     }
1669   }
1670 
1671   return Status;
1672 }
1673 
1674 
1675 /**
1676   Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1677   runtime.
1678 
1679   This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1680   and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1681   to the address specified by VirtualImageBase.  RelocationData must be identical
1682   to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1683   after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1684 
1685   Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1686   cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1687   prior to transferring control to a PE/COFF image that is loaded using this library.
1688 
1689   @param  ImageBase          The base address of a PE/COFF image that has been loaded
1690                              and relocated into system memory.
1691   @param  VirtImageBase      The request virtual address that the PE/COFF image is to
1692                              be fixed up for.
1693   @param  ImageSize          The size, in bytes, of the PE/COFF image.
1694   @param  RelocationData     A pointer to the relocation data that was collected when the PE/COFF
1695                              image was relocated using PeCoffLoaderRelocateImage().
1696 
1697 **/
1698 VOID
1699 EFIAPI
PeCoffLoaderRelocateImageForRuntime(IN PHYSICAL_ADDRESS ImageBase,IN PHYSICAL_ADDRESS VirtImageBase,IN UINTN ImageSize,IN VOID * RelocationData)1700 PeCoffLoaderRelocateImageForRuntime (
1701   IN  PHYSICAL_ADDRESS        ImageBase,
1702   IN  PHYSICAL_ADDRESS        VirtImageBase,
1703   IN  UINTN                   ImageSize,
1704   IN  VOID                    *RelocationData
1705   )
1706 {
1707   CHAR8                               *OldBase;
1708   CHAR8                               *NewBase;
1709   EFI_IMAGE_DOS_HEADER                *DosHdr;
1710   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1711   UINT32                              NumberOfRvaAndSizes;
1712   EFI_IMAGE_DATA_DIRECTORY            *DataDirectory;
1713   EFI_IMAGE_DATA_DIRECTORY            *RelocDir;
1714   EFI_IMAGE_BASE_RELOCATION           *RelocBase;
1715   EFI_IMAGE_BASE_RELOCATION           *RelocBaseEnd;
1716   UINT16                              *Reloc;
1717   UINT16                              *RelocEnd;
1718   CHAR8                               *Fixup;
1719   CHAR8                               *FixupBase;
1720   UINT16                              *Fixup16;
1721   UINT32                              *Fixup32;
1722   UINT64                              *Fixup64;
1723   CHAR8                               *FixupData;
1724   UINTN                               Adjust;
1725   RETURN_STATUS                       Status;
1726   UINT16                              Magic;
1727 
1728   OldBase = (CHAR8 *)((UINTN)ImageBase);
1729   NewBase = (CHAR8 *)((UINTN)VirtImageBase);
1730   Adjust = (UINTN) NewBase - (UINTN) OldBase;
1731 
1732   //
1733   // Find the image's relocate dir info
1734   //
1735   DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;
1736   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1737     //
1738     // Valid DOS header so get address of PE header
1739     //
1740     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
1741   } else {
1742     //
1743     // No Dos header so assume image starts with PE header.
1744     //
1745     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
1746   }
1747 
1748   if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1749     //
1750     // Not a valid PE image so Exit
1751     //
1752     return ;
1753   }
1754 
1755   Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
1756 
1757   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1758     //
1759     // Use PE32 offset
1760     //
1761     NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1762     DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);
1763   } else {
1764     //
1765     // Use PE32+ offset
1766     //
1767     NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1768     DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);
1769   }
1770 
1771   //
1772   // Find the relocation block
1773   //
1774   // Per the PE/COFF spec, you can't assume that a given data directory
1775   // is present in the image. You have to check the NumberOfRvaAndSizes in
1776   // the optional header to verify a desired directory entry is there.
1777   //
1778   if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1779     RelocDir      = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
1780     RelocBase     = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);
1781     RelocBaseEnd  = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);
1782   } else {
1783     //
1784     // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1785     //
1786     ASSERT (FALSE);
1787     return ;
1788   }
1789 
1790   //
1791   // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1792   //
1793   ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
1794 
1795   //
1796   // Run the whole relocation block. And re-fixup data that has not been
1797   // modified. The FixupData is used to see if the image has been modified
1798   // since it was relocated. This is so data sections that have been updated
1799   // by code will not be fixed up, since that would set them back to
1800   // defaults.
1801   //
1802   FixupData = RelocationData;
1803   while (RelocBase < RelocBaseEnd) {
1804     //
1805     // Add check for RelocBase->SizeOfBlock field.
1806     //
1807     if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {
1808       //
1809       // Data invalid, cannot continue to relocate the image, just return.
1810       //
1811       return;
1812     }
1813 
1814     Reloc     = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1815     RelocEnd  = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
1816     FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;
1817 
1818     //
1819     // Run this relocation record
1820     //
1821     while (Reloc < RelocEnd) {
1822 
1823       Fixup = FixupBase + (*Reloc & 0xFFF);
1824       switch ((*Reloc) >> 12) {
1825 
1826       case EFI_IMAGE_REL_BASED_ABSOLUTE:
1827         break;
1828 
1829       case EFI_IMAGE_REL_BASED_HIGH:
1830         Fixup16 = (UINT16 *) Fixup;
1831         if (*(UINT16 *) FixupData == *Fixup16) {
1832           *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
1833         }
1834 
1835         FixupData = FixupData + sizeof (UINT16);
1836         break;
1837 
1838       case EFI_IMAGE_REL_BASED_LOW:
1839         Fixup16 = (UINT16 *) Fixup;
1840         if (*(UINT16 *) FixupData == *Fixup16) {
1841           *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) Adjust & 0xffff));
1842         }
1843 
1844         FixupData = FixupData + sizeof (UINT16);
1845         break;
1846 
1847       case EFI_IMAGE_REL_BASED_HIGHLOW:
1848         Fixup32       = (UINT32 *) Fixup;
1849         FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
1850         if (*(UINT32 *) FixupData == *Fixup32) {
1851           *Fixup32 = *Fixup32 + (UINT32) Adjust;
1852         }
1853 
1854         FixupData = FixupData + sizeof (UINT32);
1855         break;
1856 
1857       case EFI_IMAGE_REL_BASED_DIR64:
1858         Fixup64       = (UINT64 *)Fixup;
1859         FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
1860         if (*(UINT64 *) FixupData == *Fixup64) {
1861           *Fixup64 = *Fixup64 + (UINT64)Adjust;
1862         }
1863 
1864         FixupData = FixupData + sizeof (UINT64);
1865         break;
1866 
1867       default:
1868         //
1869         // Only Itanium requires ConvertPeImage_Ex
1870         //
1871         Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1872         if (RETURN_ERROR (Status)) {
1873           return ;
1874         }
1875       }
1876       //
1877       // Next relocation record
1878       //
1879       Reloc += 1;
1880     }
1881     //
1882     // next reloc block
1883     //
1884     RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
1885   }
1886 }
1887 
1888 
1889 /**
1890   Reads contents of a PE/COFF image from a buffer in system memory.
1891 
1892   This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1893   that assumes FileHandle pointer to the beginning of a PE/COFF image.
1894   This function reads contents of the PE/COFF image that starts at the system memory
1895   address specified by FileHandle.  The read operation copies ReadSize bytes from the
1896   PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1897   The size of the buffer actually read is returned in ReadSize.
1898 
1899   The caller must make sure the FileOffset and ReadSize within the file scope.
1900 
1901   If FileHandle is NULL, then ASSERT().
1902   If ReadSize is NULL, then ASSERT().
1903   If Buffer is NULL, then ASSERT().
1904 
1905   @param  FileHandle        The pointer to base of the input stream
1906   @param  FileOffset        Offset into the PE/COFF image to begin the read operation.
1907   @param  ReadSize          On input, the size in bytes of the requested read operation.
1908                             On output, the number of bytes actually read.
1909   @param  Buffer            Output buffer that contains the data read from the PE/COFF image.
1910 
1911   @retval RETURN_SUCCESS    Data is read from FileOffset from the Handle into
1912                             the buffer.
1913 **/
1914 RETURN_STATUS
1915 EFIAPI
PeCoffLoaderImageReadFromMemory(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINTN * ReadSize,OUT VOID * Buffer)1916 PeCoffLoaderImageReadFromMemory (
1917   IN     VOID    *FileHandle,
1918   IN     UINTN   FileOffset,
1919   IN OUT UINTN   *ReadSize,
1920   OUT    VOID    *Buffer
1921   )
1922 {
1923   ASSERT (ReadSize != NULL);
1924   ASSERT (FileHandle != NULL);
1925   ASSERT (Buffer != NULL);
1926 
1927   CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);
1928   return RETURN_SUCCESS;
1929 }
1930 
1931 /**
1932   Unloads a loaded PE/COFF image from memory and releases its taken resource.
1933   Releases any environment specific resources that were allocated when the image
1934   specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1935 
1936   For NT32 emulator, the PE/COFF image loaded by system needs to release.
1937   For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1938   this function can simply return RETURN_SUCCESS.
1939 
1940   If ImageContext is NULL, then ASSERT().
1941 
1942   @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
1943                                     image to be unloaded.
1944 
1945   @retval RETURN_SUCCESS            The PE/COFF image was unloaded successfully.
1946 **/
1947 RETURN_STATUS
1948 EFIAPI
PeCoffLoaderUnloadImage(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1949 PeCoffLoaderUnloadImage (
1950   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
1951   )
1952 {
1953   //
1954   // Applies additional environment specific actions to unload a
1955   // PE/COFF image if needed
1956   //
1957   PeCoffLoaderUnloadImageExtraAction (ImageContext);
1958   return RETURN_SUCCESS;
1959 }
1960