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