MeasureBootPeCoff.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /** @file
  2. This module implements measuring PeCoff image for Tcg2 Protocol.
  3. Caution: This file requires additional review when modified.
  4. This driver will have external input - PE/COFF image.
  5. This external input must be validated carefully to avoid security issue like
  6. buffer overflow, integer overflow.
  7. Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
  8. SPDX-License-Identifier: BSD-2-Clause-Patent
  9. **/
  10. #include <PiDxe.h>
  11. #include <Library/BaseLib.h>
  12. #include <Library/DebugLib.h>
  13. #include <Library/BaseMemoryLib.h>
  14. #include <Library/MemoryAllocationLib.h>
  15. #include <Library/DevicePathLib.h>
  16. #include <Library/UefiBootServicesTableLib.h>
  17. #include <Library/PeCoffLib.h>
  18. #include <Library/Tpm2CommandLib.h>
  19. #include <Library/HashLib.h>
  20. UINTN mTcg2DxeImageSize = 0;
  21. /**
  22. Reads contents of a PE/COFF image in memory buffer.
  23. Caution: This function may receive untrusted input.
  24. PE/COFF image is external input, so this function will make sure the PE/COFF image content
  25. read is within the image buffer.
  26. @param FileHandle Pointer to the file handle to read the PE/COFF image.
  27. @param FileOffset Offset into the PE/COFF image to begin the read operation.
  28. @param ReadSize On input, the size in bytes of the requested read operation.
  29. On output, the number of bytes actually read.
  30. @param Buffer Output buffer that contains the data read from the PE/COFF image.
  31. @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
  32. **/
  33. EFI_STATUS
  34. EFIAPI
  35. Tcg2DxeImageRead (
  36. IN VOID *FileHandle,
  37. IN UINTN FileOffset,
  38. IN OUT UINTN *ReadSize,
  39. OUT VOID *Buffer
  40. )
  41. {
  42. UINTN EndPosition;
  43. if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
  44. return EFI_INVALID_PARAMETER;
  45. }
  46. if (MAX_ADDRESS - FileOffset < *ReadSize) {
  47. return EFI_INVALID_PARAMETER;
  48. }
  49. EndPosition = FileOffset + *ReadSize;
  50. if (EndPosition > mTcg2DxeImageSize) {
  51. *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset);
  52. }
  53. if (FileOffset >= mTcg2DxeImageSize) {
  54. *ReadSize = 0;
  55. }
  56. CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
  57. return EFI_SUCCESS;
  58. }
  59. /**
  60. Measure PE image into TPM log based on the authenticode image hashing in
  61. PE/COFF Specification 8.0 Appendix A.
  62. Caution: This function may receive untrusted input.
  63. PE/COFF image is external input, so this function will validate its data structure
  64. within this image buffer before use.
  65. Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
  66. @param[in] PCRIndex TPM PCR index
  67. @param[in] ImageAddress Start address of image buffer.
  68. @param[in] ImageSize Image size
  69. @param[out] DigestList Digest list of this image.
  70. @retval EFI_SUCCESS Successfully measure image.
  71. @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
  72. @retval other error value
  73. **/
  74. EFI_STATUS
  75. MeasurePeImageAndExtend (
  76. IN UINT32 PCRIndex,
  77. IN EFI_PHYSICAL_ADDRESS ImageAddress,
  78. IN UINTN ImageSize,
  79. OUT TPML_DIGEST_VALUES *DigestList
  80. )
  81. {
  82. EFI_STATUS Status;
  83. EFI_IMAGE_DOS_HEADER *DosHdr;
  84. UINT32 PeCoffHeaderOffset;
  85. EFI_IMAGE_SECTION_HEADER *Section;
  86. UINT8 *HashBase;
  87. UINTN HashSize;
  88. UINTN SumOfBytesHashed;
  89. EFI_IMAGE_SECTION_HEADER *SectionHeader;
  90. UINTN Index;
  91. UINTN Pos;
  92. EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
  93. UINT32 NumberOfRvaAndSizes;
  94. UINT32 CertSize;
  95. HASH_HANDLE HashHandle;
  96. PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
  97. HashHandle = 0xFFFFFFFF; // Know bad value
  98. Status = EFI_UNSUPPORTED;
  99. SectionHeader = NULL;
  100. //
  101. // Check PE/COFF image
  102. //
  103. ZeroMem (&ImageContext, sizeof (ImageContext));
  104. ImageContext.Handle = (VOID *) (UINTN) ImageAddress;
  105. mTcg2DxeImageSize = ImageSize;
  106. ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) Tcg2DxeImageRead;
  107. //
  108. // Get information about the image being loaded
  109. //
  110. Status = PeCoffLoaderGetImageInfo (&ImageContext);
  111. if (EFI_ERROR (Status)) {
  112. //
  113. // The information can't be got from the invalid PeImage
  114. //
  115. DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n"));
  116. goto Finish;
  117. }
  118. DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
  119. PeCoffHeaderOffset = 0;
  120. if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
  121. PeCoffHeaderOffset = DosHdr->e_lfanew;
  122. }
  123. Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
  124. if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
  125. Status = EFI_UNSUPPORTED;
  126. goto Finish;
  127. }
  128. //
  129. // PE/COFF Image Measurement
  130. //
  131. // NOTE: The following codes/steps are based upon the authenticode image hashing in
  132. // PE/COFF Specification 8.0 Appendix A.
  133. //
  134. //
  135. // 1. Load the image header into memory.
  136. // 2. Initialize a SHA hash context.
  137. Status = HashStart (&HashHandle);
  138. if (EFI_ERROR (Status)) {
  139. goto Finish;
  140. }
  141. //
  142. // Measuring PE/COFF Image Header;
  143. // But CheckSum field and SECURITY data directory (certificate) are excluded
  144. //
  145. //
  146. // 3. Calculate the distance from the base of the image header to the image checksum address.
  147. // 4. Hash the image header from its base to beginning of the image checksum.
  148. //
  149. HashBase = (UINT8 *) (UINTN) ImageAddress;
  150. if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  151. //
  152. // Use PE32 offset
  153. //
  154. NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
  155. HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
  156. } else {
  157. //
  158. // Use PE32+ offset
  159. //
  160. NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
  161. HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
  162. }
  163. Status = HashUpdate (HashHandle, HashBase, HashSize);
  164. if (EFI_ERROR (Status)) {
  165. goto Finish;
  166. }
  167. //
  168. // 5. Skip over the image checksum (it occupies a single ULONG).
  169. //
  170. if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
  171. //
  172. // 6. Since there is no Cert Directory in optional header, hash everything
  173. // from the end of the checksum to the end of image header.
  174. //
  175. if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  176. //
  177. // Use PE32 offset.
  178. //
  179. HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
  180. HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
  181. } else {
  182. //
  183. // Use PE32+ offset.
  184. //
  185. HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
  186. HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
  187. }
  188. if (HashSize != 0) {
  189. Status = HashUpdate (HashHandle, HashBase, HashSize);
  190. if (EFI_ERROR (Status)) {
  191. goto Finish;
  192. }
  193. }
  194. } else {
  195. //
  196. // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
  197. //
  198. if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  199. //
  200. // Use PE32 offset
  201. //
  202. HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
  203. HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
  204. } else {
  205. //
  206. // Use PE32+ offset
  207. //
  208. HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
  209. HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
  210. }
  211. if (HashSize != 0) {
  212. Status = HashUpdate (HashHandle, HashBase, HashSize);
  213. if (EFI_ERROR (Status)) {
  214. goto Finish;
  215. }
  216. }
  217. //
  218. // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
  219. // 9. Hash everything from the end of the Cert Directory to the end of image header.
  220. //
  221. if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  222. //
  223. // Use PE32 offset
  224. //
  225. HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
  226. HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
  227. } else {
  228. //
  229. // Use PE32+ offset
  230. //
  231. HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
  232. HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
  233. }
  234. if (HashSize != 0) {
  235. Status = HashUpdate (HashHandle, HashBase, HashSize);
  236. if (EFI_ERROR (Status)) {
  237. goto Finish;
  238. }
  239. }
  240. }
  241. //
  242. // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
  243. //
  244. if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  245. //
  246. // Use PE32 offset
  247. //
  248. SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
  249. } else {
  250. //
  251. // Use PE32+ offset
  252. //
  253. SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
  254. }
  255. //
  256. // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
  257. // structures in the image. The 'NumberOfSections' field of the image
  258. // header indicates how big the table should be. Do not include any
  259. // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
  260. //
  261. SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
  262. if (SectionHeader == NULL) {
  263. Status = EFI_OUT_OF_RESOURCES;
  264. goto Finish;
  265. }
  266. //
  267. // 12. Using the 'PointerToRawData' in the referenced section headers as
  268. // a key, arrange the elements in the table in ascending order. In other
  269. // words, sort the section headers according to the disk-file offset of
  270. // the section.
  271. //
  272. Section = (EFI_IMAGE_SECTION_HEADER *) (
  273. (UINT8 *) (UINTN) ImageAddress +
  274. PeCoffHeaderOffset +
  275. sizeof(UINT32) +
  276. sizeof(EFI_IMAGE_FILE_HEADER) +
  277. Hdr.Pe32->FileHeader.SizeOfOptionalHeader
  278. );
  279. for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
  280. Pos = Index;
  281. while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
  282. CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
  283. Pos--;
  284. }
  285. CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
  286. Section += 1;
  287. }
  288. //
  289. // 13. Walk through the sorted table, bring the corresponding section
  290. // into memory, and hash the entire section (using the 'SizeOfRawData'
  291. // field in the section header to determine the amount of data to hash).
  292. // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
  293. // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
  294. //
  295. for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
  296. Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
  297. if (Section->SizeOfRawData == 0) {
  298. continue;
  299. }
  300. HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
  301. HashSize = (UINTN) Section->SizeOfRawData;
  302. Status = HashUpdate (HashHandle, HashBase, HashSize);
  303. if (EFI_ERROR (Status)) {
  304. goto Finish;
  305. }
  306. SumOfBytesHashed += HashSize;
  307. }
  308. //
  309. // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
  310. // data in the file that needs to be added to the hash. This data begins
  311. // at file offset SUM_OF_BYTES_HASHED and its length is:
  312. // FileSize - (CertDirectory->Size)
  313. //
  314. if (ImageSize > SumOfBytesHashed) {
  315. HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
  316. if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
  317. CertSize = 0;
  318. } else {
  319. if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  320. //
  321. // Use PE32 offset.
  322. //
  323. CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
  324. } else {
  325. //
  326. // Use PE32+ offset.
  327. //
  328. CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
  329. }
  330. }
  331. if (ImageSize > CertSize + SumOfBytesHashed) {
  332. HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
  333. Status = HashUpdate (HashHandle, HashBase, HashSize);
  334. if (EFI_ERROR (Status)) {
  335. goto Finish;
  336. }
  337. } else if (ImageSize < CertSize + SumOfBytesHashed) {
  338. Status = EFI_UNSUPPORTED;
  339. goto Finish;
  340. }
  341. }
  342. //
  343. // 17. Finalize the SHA hash.
  344. //
  345. Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);
  346. if (EFI_ERROR (Status)) {
  347. goto Finish;
  348. }
  349. Finish:
  350. if (SectionHeader != NULL) {
  351. FreePool (SectionHeader);
  352. }
  353. return Status;
  354. }