From 6460d06c6f028154088ea7db4a44821ffabfe9e6 Mon Sep 17 00:00:00 2001
From: hy <941973499@qq.com>
Date: Sat, 26 Apr 2025 23:38:23 +0800
Subject: [PATCH] SecurityPkg: Out of bound read in HashPeImageByType() In
 HashPeImageByType(), the hash of PE/COFF image is calculated. This function
 may get untrusted input.

Inside this function, the following code verifies the loaded image has
the correct format, by reading the second byte of the buffer.

```c
  if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
  	...
  }
```

The input image is not trusted and that may not have the second byte to
read. So this poses an out of bound read error.

With below fix we are assuring that we don't do out of bound read. i.e,
we make sure that AuthDataSize is greater than 1.

```c
  if (AuthDataSize > 1
      && (*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE){
    ...
  }
```

AuthDataSize size is verified before reading the second byte.
So if AuthDataSize is less than 2, the second byte will not be read, and
the out of bound read situation won't occur.

Tested the patch on real platform with and without TPM connected and
verified image is booting fine.

Authored-by: Raj AlwinX Selvaraj <Alw...@intel.com>
Signed-off-by: Doug Flick <DougFlick@microsoft.com>
---
 .../DxeImageVerificationLib.c                 | 37 ++++++++++---------
 SecurityPkg/SecurityFixes.yaml                | 15 ++++++++
 .../SecureBootConfigImpl.c                    | 37 +++++++++++--------
 3 files changed, 55 insertions(+), 34 deletions(-)

diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
index 5d8dbd54..157318b1 100644
--- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -618,6 +618,7 @@ Done:
   @param[in]  AuthDataSize        Size of the Authenticode Signature in bytes.
 
   @retval EFI_UNSUPPORTED             Hash algorithm is not supported.
+  @retval EFI_BAD_BUFFER_SIZE         AuthData provided is invalid size.
   @retval EFI_SUCCESS                 Hash successfully.
 
 **/
@@ -629,28 +630,28 @@ HashPeImageByType (
 {
   UINT8  Index;
 
-  for (Index = 0; Index < HASHALG_MAX; Index++) {
+  //
+  // Check the Hash algorithm in PE/COFF Authenticode.
+  //    According to PKCS#7 Definition:
+  //        SignedData ::= SEQUENCE {
+  //            version Version,
+  //            digestAlgorithms DigestAlgorithmIdentifiers,
+  //            contentInfo ContentInfo,
+  //            .... }
+  //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
+  //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.
+  //    Fixed offset (+32) is calculated based on two bytes of length encoding.
+  //
+  if ((AuthDataSize > 1) && ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE)) {
     //
-    // Check the Hash algorithm in PE/COFF Authenticode.
-    //    According to PKCS#7 Definition:
-    //        SignedData ::= SEQUENCE {
-    //            version Version,
-    //            digestAlgorithms DigestAlgorithmIdentifiers,
-    //            contentInfo ContentInfo,
-    //            .... }
-    //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
-    //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.
-    //    Fixed offset (+32) is calculated based on two bytes of length encoding.
+    // Only support two bytes of Long Form of Length Encoding.
     //
-    if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
-      //
-      // Only support two bytes of Long Form of Length Encoding.
-      //
-      continue;
-    }
+    return EFI_BAD_BUFFER_SIZE;
+  }
 
+  for (Index = 0; Index < HASHALG_MAX; Index++) {
     if (AuthDataSize < 32 + mHash[Index].OidLength) {
-      return EFI_UNSUPPORTED;
+      continue;
     }
 
     if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml
index ceaaa256..0b24844d 100644
--- a/SecurityPkg/SecurityFixes.yaml
+++ b/SecurityPkg/SecurityFixes.yaml
@@ -34,3 +34,18 @@ CVE_2022_36764:
   - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c
   links:
   - https://bugzilla.tianocore.org/show_bug.cgi?id=4118
+CVE_2024_38797:
+  commit-titles:
+    - "SecurityPkg: Out of bound read in HashPeImageByType()"
+    - "SecurityPkg: Improving HashPeImageByType () logic"
+    - "SecurityPkg: Improving SecureBootConfigImpl:HashPeImageByType () logic"
+  cve: CVE-2024-38797
+  date_reported: 2024-06-04 12:00 UTC
+  description: Out of bound read in HashPeImageByType()
+  note:
+  files_impacted:
+    - SecurityPkg\Library\DxeImageVerificationLib\DxeImageVerificationLib.c
+    - SecurityPkg\VariableAuthenticated\SecureBootConfigDxe\SecureBootConfigImpl.c
+  links:
+    - https://bugzilla.tianocore.org/show_bug.cgi?id=2214
+    - https://github.com/tianocore/edk2/security/advisories/GHSA-4wjw-6xmf-44xf
diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
index 0e31502b..02aa142b 100644
--- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
+++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
@@ -2079,30 +2079,35 @@ HashPeImageByType (
 {
   UINT8                     Index;
   WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;
+  UINT32                    PkcsCertSize;
 
   PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *)(mImageBase + mSecDataDir->Offset);
+  PkcsCertSize = mSecDataDir->SizeOfCert;
 
-  for (Index = 0; Index < HASHALG_MAX; Index++) {
+  //
+  // Check the Hash algorithm in PE/COFF Authenticode.
+  //    According to PKCS#7 Definition:
+  //        SignedData ::= SEQUENCE {
+  //            version Version,
+  //            digestAlgorithms DigestAlgorithmIdentifiers,
+  //            contentInfo ContentInfo,
+  //            .... }
+  //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
+  //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.
+  //    Fixed offset (+32) is calculated based on two bytes of length encoding.
+  //
+  if ((PkcsCertSize > 1) && ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE)) {
     //
-    // Check the Hash algorithm in PE/COFF Authenticode.
-    //    According to PKCS#7 Definition:
-    //        SignedData ::= SEQUENCE {
-    //            version Version,
-    //            digestAlgorithms DigestAlgorithmIdentifiers,
-    //            contentInfo ContentInfo,
-    //            .... }
-    //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
-    //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.
-    //    Fixed offset (+32) is calculated based on two bytes of length encoding.
+    // Only support two bytes of Long Form of Length Encoding.
     //
-    if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
-      //
-      // Only support two bytes of Long Form of Length Encoding.
-      //
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  for (Index = 0; Index < HASHALG_MAX; Index++) {
+    if (PkcsCertSize < 32 + mHash[Index].OidLength) {
       continue;
     }
 
-    //
     if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
       break;
     }
-- 
2.33.0

