SetPermissions.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /** @file
  2. Locate, get and update PE/COFF permissions during Standalone MM
  3. Foundation Entry point on ARM platforms.
  4. Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <PiMm.h>
  8. #include <PiPei.h>
  9. #include <Guid/MmramMemoryReserve.h>
  10. #include <Guid/MpInformation.h>
  11. #include <Library/Arm/StandaloneMmCoreEntryPoint.h>
  12. #include <Library/ArmMmuLib.h>
  13. #include <Library/ArmSvcLib.h>
  14. #include <Library/DebugLib.h>
  15. #include <Library/HobLib.h>
  16. #include <Library/BaseLib.h>
  17. #include <Library/BaseMemoryLib.h>
  18. #include <Library/SerialPortLib.h>
  19. #include <IndustryStandard/ArmStdSmc.h>
  20. /**
  21. Privileged firmware assigns RO & Executable attributes to all memory occupied
  22. by the Boot Firmware Volume. This function sets the correct permissions of
  23. sections in the Standalone MM Core module to be able to access RO and RW data
  24. and make further progress in the boot process.
  25. @param [in] ImageContext Pointer to PE/COFF image context
  26. @param [in] ImageBase Base of image in memory
  27. @param [in] SectionHeaderOffset Offset of PE/COFF image section header
  28. @param [in] NumberOfSections Number of Sections
  29. @param [in] TextUpdater Function to change code permissions
  30. @param [in] ReadOnlyUpdater Function to change RO permissions
  31. @param [in] ReadWriteUpdater Function to change RW permissions
  32. **/
  33. EFI_STATUS
  34. EFIAPI
  35. UpdateMmFoundationPeCoffPermissions (
  36. IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
  37. IN EFI_PHYSICAL_ADDRESS ImageBase,
  38. IN UINT32 SectionHeaderOffset,
  39. IN CONST UINT16 NumberOfSections,
  40. IN REGION_PERMISSION_UPDATE_FUNC TextUpdater,
  41. IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater,
  42. IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater
  43. )
  44. {
  45. EFI_IMAGE_SECTION_HEADER SectionHeader;
  46. RETURN_STATUS Status;
  47. EFI_PHYSICAL_ADDRESS Base;
  48. UINTN Size;
  49. UINTN ReadSize;
  50. UINTN Index;
  51. ASSERT (ImageContext != NULL);
  52. //
  53. // Iterate over the sections
  54. //
  55. for (Index = 0; Index < NumberOfSections; Index++) {
  56. //
  57. // Read section header from file
  58. //
  59. Size = sizeof (EFI_IMAGE_SECTION_HEADER);
  60. ReadSize = Size;
  61. Status = ImageContext->ImageRead (
  62. ImageContext->Handle,
  63. SectionHeaderOffset,
  64. &Size,
  65. &SectionHeader
  66. );
  67. if (RETURN_ERROR (Status) || (Size != ReadSize)) {
  68. DEBUG ((DEBUG_ERROR,
  69. "%a: ImageContext->ImageRead () failed (Status = %r)\n",
  70. __FUNCTION__, Status));
  71. return Status;
  72. }
  73. DEBUG ((DEBUG_INFO,
  74. "%a: Section %d of image at 0x%lx has 0x%x permissions\n",
  75. __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics));
  76. DEBUG ((DEBUG_INFO,
  77. "%a: Section %d of image at 0x%lx has %a name\n",
  78. __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Name));
  79. DEBUG ((DEBUG_INFO,
  80. "%a: Section %d of image at 0x%lx has 0x%x address\n",
  81. __FUNCTION__, Index, ImageContext->ImageAddress,
  82. ImageContext->ImageAddress + SectionHeader.VirtualAddress));
  83. DEBUG ((DEBUG_INFO,
  84. "%a: Section %d of image at 0x%lx has 0x%x data\n",
  85. __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.PointerToRawData));
  86. //
  87. // If the section is marked as XN then remove the X attribute. Furthermore,
  88. // if it is a writeable section then mark it appropriately as well.
  89. //
  90. if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
  91. Base = ImageBase + SectionHeader.VirtualAddress;
  92. TextUpdater (Base, SectionHeader.Misc.VirtualSize);
  93. if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) {
  94. ReadWriteUpdater (Base, SectionHeader.Misc.VirtualSize);
  95. DEBUG ((DEBUG_INFO,
  96. "%a: Mapping section %d of image at 0x%lx with RW-XN permissions\n",
  97. __FUNCTION__, Index, ImageContext->ImageAddress));
  98. } else {
  99. DEBUG ((DEBUG_INFO,
  100. "%a: Mapping section %d of image at 0x%lx with RO-XN permissions\n",
  101. __FUNCTION__, Index, ImageContext->ImageAddress));
  102. }
  103. } else {
  104. DEBUG ((DEBUG_INFO,
  105. "%a: Ignoring section %d of image at 0x%lx with 0x%x permissions\n",
  106. __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics));
  107. }
  108. SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
  109. }
  110. return RETURN_SUCCESS;
  111. }
  112. /**
  113. Privileged firmware assigns RO & Executable attributes to all memory occupied
  114. by the Boot Firmware Volume. This function locates the Standalone MM Core
  115. module PE/COFF image in the BFV and returns this information.
  116. @param [in] BfvAddress Base Address of Boot Firmware Volume
  117. @param [in, out] TeData Pointer to address for allocating memory
  118. for PE/COFF image data
  119. @param [in, out] TeDataSize Pointer to size of PE/COFF image data
  120. **/
  121. EFI_STATUS
  122. EFIAPI
  123. LocateStandaloneMmCorePeCoffData (
  124. IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress,
  125. IN OUT VOID **TeData,
  126. IN OUT UINTN *TeDataSize
  127. )
  128. {
  129. EFI_FFS_FILE_HEADER *FileHeader;
  130. EFI_STATUS Status;
  131. FileHeader = NULL;
  132. Status = FfsFindNextFile (
  133. EFI_FV_FILETYPE_SECURITY_CORE,
  134. BfvAddress,
  135. &FileHeader
  136. );
  137. if (EFI_ERROR (Status)) {
  138. DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM FFS file - 0x%x\n",
  139. Status));
  140. return Status;
  141. }
  142. Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, TeData, TeDataSize);
  143. if (EFI_ERROR (Status)) {
  144. Status = FfsFindSectionData (EFI_SECTION_TE, FileHeader, TeData, TeDataSize);
  145. if (EFI_ERROR (Status)) {
  146. DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Section data - %r\n",
  147. Status));
  148. return Status;
  149. }
  150. }
  151. DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *TeData));
  152. return Status;
  153. }
  154. /**
  155. Returns the PC COFF section information.
  156. @param [in, out] ImageContext Pointer to PE/COFF image context
  157. @param [out] ImageBase Base of image in memory
  158. @param [out] SectionHeaderOffset Offset of PE/COFF image section header
  159. @param [out] NumberOfSections Number of Sections
  160. **/
  161. STATIC
  162. EFI_STATUS
  163. GetPeCoffSectionInformation (
  164. IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
  165. OUT EFI_PHYSICAL_ADDRESS *ImageBase,
  166. OUT UINT32 *SectionHeaderOffset,
  167. OUT UINT16 *NumberOfSections
  168. )
  169. {
  170. RETURN_STATUS Status;
  171. EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
  172. EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
  173. UINTN Size;
  174. UINTN ReadSize;
  175. ASSERT (ImageContext != NULL);
  176. ASSERT (SectionHeaderOffset != NULL);
  177. ASSERT (NumberOfSections != NULL);
  178. Status = PeCoffLoaderGetImageInfo (ImageContext);
  179. if (RETURN_ERROR (Status)) {
  180. DEBUG ((DEBUG_ERROR,
  181. "%a: PeCoffLoaderGetImageInfo () failed (Status == %r)\n",
  182. __FUNCTION__, Status));
  183. return Status;
  184. }
  185. if (ImageContext->SectionAlignment < EFI_PAGE_SIZE) {
  186. //
  187. // The sections need to be at least 4 KB aligned, since that is the
  188. // granularity at which we can tighten permissions.
  189. //
  190. if (!ImageContext->IsTeImage) {
  191. DEBUG ((DEBUG_WARN,
  192. "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
  193. __FUNCTION__, ImageContext->ImageAddress, ImageContext->SectionAlignment));
  194. return RETURN_UNSUPPORTED;
  195. }
  196. ImageContext->SectionAlignment = EFI_PAGE_SIZE;
  197. }
  198. //
  199. // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
  200. // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
  201. // determines if this is a PE32 or PE32+ image. The magic is in the same
  202. // location in both images.
  203. //
  204. Hdr.Union = &HdrData;
  205. Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
  206. ReadSize = Size;
  207. Status = ImageContext->ImageRead (
  208. ImageContext->Handle,
  209. ImageContext->PeCoffHeaderOffset,
  210. &Size,
  211. Hdr.Pe32
  212. );
  213. if (RETURN_ERROR (Status) || (Size != ReadSize)) {
  214. DEBUG ((DEBUG_ERROR,
  215. "%a: TmpContext->ImageRead () failed (Status = %r)\n",
  216. __FUNCTION__, Status));
  217. return Status;
  218. }
  219. *ImageBase = ImageContext->ImageAddress;
  220. if (!ImageContext->IsTeImage) {
  221. ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
  222. *SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) +
  223. sizeof (EFI_IMAGE_FILE_HEADER);
  224. *NumberOfSections = Hdr.Pe32->FileHeader.NumberOfSections;
  225. switch (Hdr.Pe32->OptionalHeader.Magic) {
  226. case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  227. *SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
  228. break;
  229. case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  230. *SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
  231. break;
  232. default:
  233. ASSERT (FALSE);
  234. }
  235. } else {
  236. *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
  237. *NumberOfSections = Hdr.Te->NumberOfSections;
  238. *ImageBase -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
  239. }
  240. return RETURN_SUCCESS;
  241. }
  242. /**
  243. Privileged firmware assigns RO & Executable attributes to all memory occupied
  244. by the Boot Firmware Volume. This function locates the section information of
  245. the Standalone MM Core module to be able to change permissions of the
  246. individual sections later in the boot process.
  247. @param [in] TeData Pointer to PE/COFF image data
  248. @param [in, out] ImageContext Pointer to PE/COFF image context
  249. @param [out] ImageBase Pointer to ImageBase variable
  250. @param [in, out] SectionHeaderOffset Offset of PE/COFF image section header
  251. @param [in, out] NumberOfSections Number of Sections
  252. **/
  253. EFI_STATUS
  254. EFIAPI
  255. GetStandaloneMmCorePeCoffSections (
  256. IN VOID *TeData,
  257. IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
  258. OUT EFI_PHYSICAL_ADDRESS *ImageBase,
  259. IN OUT UINT32 *SectionHeaderOffset,
  260. IN OUT UINT16 *NumberOfSections
  261. )
  262. {
  263. EFI_STATUS Status;
  264. // Initialize the Image Context
  265. ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
  266. ImageContext->Handle = TeData;
  267. ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory;
  268. DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData));
  269. Status = GetPeCoffSectionInformation (ImageContext, ImageBase,
  270. SectionHeaderOffset, NumberOfSections);
  271. if (EFI_ERROR (Status)) {
  272. DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status));
  273. return Status;
  274. }
  275. DEBUG ((DEBUG_INFO, "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n",
  276. *SectionHeaderOffset, *NumberOfSections));
  277. return Status;
  278. }