public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Krzysztof Koch" <krzysztof.koch@arm.com>
To: <devel@edk2.groups.io>
Cc: <jaben.carsey@intel.com>, <ray.ni@intel.com>,
	<zhichao.gao@intel.com>, <Sami.Mujawar@arm.com>,
	<Matteo.Carlini@arm.com>, <nd@arm.com>
Subject: [PATCH v1 10/11] ShellPkg: acpiview: GTDT: Add error-checking in the parsing logic
Date: Fri, 12 Jul 2019 07:52:42 +0100	[thread overview]
Message-ID: <20190712065243.3812-11-krzysztof.koch@arm.com> (raw)
In-Reply-To: <20190712065243.3812-1-krzysztof.koch@arm.com>

1. Check if the global pointers (in the scope of this ACPI table parser)
have been successfully updated before they are later used to control
the parsing logic.

2. Test against buffer overruns.

3. Allow silencing ACPI table content validation errors which do not
cause table parsing to fail.

4. Remove redundant forward function declarations by repositioning
blocks of code.

5. Convert a 'do-while' loop for parsing GTDT table body into a 'while'
block for consistency with other table parsers.

Signed-off-by: Krzysztof Koch <krzysztof.koch@arm.com>
---

Changes can be seen at: https://github.com/KrzysztofKoch1/edk2/commit/8c2ed18c7f1c44620eb86e1c9117cbccee8938ce

Notes:
    v1:
    - improve the logic in the GTDT parser [Krzysztof]

 ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c | 294 +++++++++++---------
 1 file changed, 170 insertions(+), 124 deletions(-)

diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c
index 3b05ff3015d4a3af62dd9fab057c32369a456267..4e8e6f3eb50596823827d20dbb72314a583d0931 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c
@@ -12,6 +12,10 @@
 #include <Library/UefiLib.h>
 #include "AcpiParser.h"
 #include "AcpiTableParser.h"
+#include "AcpiView.h"
+
+// "The number of GT Block Timers must be less than or equal to 8"
+#define GT_BLOCK_TIMER_COUNT_MAX 8
 
 // Local variables
 STATIC CONST UINT32* GtdtPlatformTimerCount;
@@ -20,7 +24,6 @@ STATIC CONST UINT8*  PlatformTimerType;
 STATIC CONST UINT16* PlatformTimerLength;
 STATIC CONST UINT32* GtBlockTimerCount;
 STATIC CONST UINT32* GtBlockTimerOffset;
-STATIC CONST UINT16* GtBlockLength;
 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
 
 /**
@@ -36,7 +39,21 @@ EFIAPI
 ValidateGtBlockTimerCount (
   IN UINT8* Ptr,
   IN VOID*  Context
-  );
+  )
+{
+  UINT32 BlockTimerCount;
+
+  BlockTimerCount = *(UINT32*)Ptr;
+
+  if (BlockTimerCount > GT_BLOCK_TIMER_COUNT_MAX) {
+    IncrementErrorCount ();
+    Print (
+      L"\nERROR: Timer Count = %d. Max Timer Count is %d.",
+      BlockTimerCount,
+      GT_BLOCK_TIMER_COUNT_MAX
+      );
+  }
+}
 
 /**
   This function validates the GT Frame Number.
@@ -51,7 +68,21 @@ EFIAPI
 ValidateGtFrameNumber (
   IN UINT8* Ptr,
   IN VOID*  Context
-  );
+  )
+{
+  UINT8 FrameNumber;
+
+  FrameNumber = *(UINT8*)Ptr;
+
+  if (FrameNumber >= GT_BLOCK_TIMER_COUNT_MAX) {
+    IncrementErrorCount ();
+    Print (
+      L"\nERROR: GT Frame Number = %d. GT Frame Number must be in range 0-%d.",
+      FrameNumber,
+      GT_BLOCK_TIMER_COUNT_MAX - 1
+      );
+  }
+}
 
 /**
   An ACPI_PARSER array describing the ACPI GTDT Table.
@@ -96,7 +127,7 @@ STATIC CONST ACPI_PARSER GtPlatformTimerHeaderParser[] = {
 **/
 STATIC CONST ACPI_PARSER GtBlockParser[] = {
   {L"Type", 1, 0, L"%d", NULL, NULL, NULL, NULL},
-  {L"Length", 2, 1, L"%d", NULL, (VOID**)&GtBlockLength, NULL, NULL},
+  {L"Length", 2, 1, L"%d", NULL, NULL, NULL, NULL},
   {L"Reserved", 1, 3, L"%x", NULL, NULL, NULL, NULL},
   {L"Physical address (CntCtlBase)", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL},
   {L"Timer Count", 4, 12, L"%d", NULL, (VOID**)&GtBlockTimerCount,
@@ -134,115 +165,71 @@ STATIC CONST ACPI_PARSER SBSAGenericWatchdogParser[] = {
   {L"Watchdog Timer Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}
 };
 
-/**
-  This function validates the GT Block timer count.
-
-  @param [in] Ptr     Pointer to the start of the field data.
-  @param [in] Context Pointer to context specific information e.g. this
-                      could be a pointer to the ACPI table header.
-**/
-STATIC
-VOID
-EFIAPI
-ValidateGtBlockTimerCount (
-  IN UINT8* Ptr,
-  IN VOID*  Context
-  )
-{
-  UINT32 BlockTimerCount;
-
-  BlockTimerCount = *(UINT32*)Ptr;
-
-  if (BlockTimerCount > 8) {
-    IncrementErrorCount ();
-    Print (
-      L"\nERROR: Timer Count = %d. Max Timer Count is 8.",
-      BlockTimerCount
-      );
-  }
-}
-
-/**
-  This function validates the GT Frame Number.
-
-  @param [in] Ptr     Pointer to the start of the field data.
-  @param [in] Context Pointer to context specific information e.g. this
-                      could be a pointer to the ACPI table header.
-**/
-STATIC
-VOID
-EFIAPI
-ValidateGtFrameNumber (
-  IN UINT8* Ptr,
-  IN VOID*  Context
-  )
-{
-  UINT8 FrameNumber;
-
-  FrameNumber = *(UINT8*)Ptr;
-
-  if (FrameNumber > 7) {
-    IncrementErrorCount ();
-    Print (
-      L"\nERROR: GT Frame Number = %d. GT Frame Number must be in range 0-7.",
-      FrameNumber
-      );
-  }
-}
-
 /**
   This function parses the Platform GT Block.
 
-  @param [in] Ptr     Pointer to the start of the GT Block data.
-  @param [in] Length  Length of the GT Block structure.
+  @param [in] Ptr       Pointer to the start of the GT Block data.
+  @param [in] Length    Length of the GT Block structure.
 **/
 STATIC
 VOID
 DumpGTBlock (
   IN UINT8* Ptr,
-  IN UINT32 Length
+  IN UINT16 Length
   )
 {
   UINT32 Index;
   UINT32 Offset;
-  UINT32 GTBlockTimerLength;
 
-  Offset = ParseAcpi (
-             TRUE,
-             2,
-             "GT Block",
-             Ptr,
-             Length,
-             PARSER_PARAMS (GtBlockParser)
-             );
-  GTBlockTimerLength = (*GtBlockLength - Offset) / (*GtBlockTimerCount);
-  Length -= Offset;
+  ParseAcpi (
+    TRUE,
+    2,
+    "GT Block",
+    Ptr,
+    Length,
+    PARSER_PARAMS (GtBlockParser)
+    );
 
-  if (*GtBlockTimerCount != 0) {
-    Ptr += (*GtBlockTimerOffset);
-    Index = 0;
-    while ((Index < (*GtBlockTimerCount)) && (Length >= GTBlockTimerLength)) {
-      Offset = ParseAcpi (
-                 TRUE,
-                 2,
-                 "GT Block Timer",
-                 Ptr,
-                 GTBlockTimerLength,
-                 PARSER_PARAMS (GtBlockTimerParser)
-                 );
-      // Increment by GT Block Timer structure size
-      Ptr += Offset;
-      Length -= Offset;
-      Index++;
-    }
+  // Check if the values used to control the parsing logic have been
+  // successfully read.
+  if ((GtBlockTimerCount == NULL) ||
+      (GtBlockTimerOffset == NULL)) {
+    IncrementErrorCount ();
+    Print (
+      L"ERROR: Insufficient GT Block Structure length. Length = %d.\n",
+      Length
+      );
+    return;
+  }
 
-    if (Length != 0) {
-      IncrementErrorCount ();
-      Print (
-        L"ERROR:GT Block Timer length mismatch. Unparsed %d bytes.\n",
-        Length
-        );
-    }
+  Offset = *GtBlockTimerOffset;
+  Index = 0;
+
+  // Parse the specified number of GT Block Timer Structures or the GT Block
+  // Structure buffer length. Whichever is minimum.
+  while ((Index++ < *GtBlockTimerCount) &&
+         (Offset < Length)) {
+    Offset += ParseAcpi (
+                TRUE,
+                2,
+                "GT Block Timer",
+                Ptr + Offset,
+                Length - Offset,
+                PARSER_PARAMS (GtBlockTimerParser)
+                );
+  }
+
+  // Cross-check the substructure count with the length of the encapsulating
+  // buffer
+  if (GetConsistencyChecking () &&
+      (Index < *GtBlockTimerCount)) {
+    IncrementErrorCount ();
+    Print (
+      L"ERROR: Invalid GT Block Timer count. GtBlockTimerCount = %d. " \
+        L"GtBlockBufferSize = %d.\n",
+      *GtBlockTimerCount,
+      Length
+      );
   }
 }
 
@@ -295,6 +282,7 @@ ParseAcpiGtdt (
   )
 {
   UINT32 Index;
+  UINT32 Offset;
   UINT8* TimerPtr;
 
   if (!Trace) {
@@ -310,36 +298,94 @@ ParseAcpiGtdt (
     PARSER_PARAMS (GtdtParser)
     );
 
-  if (*GtdtPlatformTimerCount != 0) {
-    TimerPtr = Ptr + (*GtdtPlatformTimerOffset);
-    Index = 0;
-    do {
-      // Parse the Platform Timer Header
-      ParseAcpi (
-        FALSE,
-        0,
-        NULL,
-        TimerPtr,
-        4,  // GT Platform Timer structure header length.
-        PARSER_PARAMS (GtPlatformTimerHeaderParser)
+  // Check if the values used to control the parsing logic have been
+  // successfully read.
+  if ((GtdtPlatformTimerCount == NULL) ||
+      (GtdtPlatformTimerOffset == NULL)) {
+    IncrementErrorCount ();
+    Print (
+      L"ERROR: Insufficient table length. AcpiTableLength = %d.\n",
+      AcpiTableLength
+      );
+    return;
+  }
+
+  TimerPtr = Ptr + *GtdtPlatformTimerOffset;
+  Offset = *GtdtPlatformTimerOffset;
+  Index = 0;
+
+  // Parse the specified number of Platform Timer Structures or the GTDT
+  // buffer length. Whichever is minimum.
+  while ((Index++ < *GtdtPlatformTimerCount) &&
+         (Offset < AcpiTableLength)) {
+    // Parse the Platform Timer Header to obtain Length and Type
+    ParseAcpi (
+      FALSE,
+      0,
+      NULL,
+      TimerPtr,
+      AcpiTableLength - Offset,
+      PARSER_PARAMS (GtPlatformTimerHeaderParser)
+      );
+
+    // Check if the values used to control the parsing logic have been
+    // successfully read.
+    if ((PlatformTimerType == NULL) ||
+        (PlatformTimerLength == NULL)) {
+      IncrementErrorCount ();
+      Print (
+        L"ERROR: Insufficient remaining table buffer length to read the " \
+          L"Platform Timer Structure header. Length = %d.\n",
+        AcpiTableLength - Offset
         );
-      switch (*PlatformTimerType) {
-        case EFI_ACPI_6_2_GTDT_GT_BLOCK:
-          DumpGTBlock (TimerPtr, *PlatformTimerLength);
-          break;
-        case EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG:
-          DumpWatchdogTimer (TimerPtr, *PlatformTimerLength);
-          break;
-        default:
+      return;
+    }
+
+    // Make sure the Platform Timer is inside the table.
+    if ((Offset + *PlatformTimerLength) > AcpiTableLength) {
+      IncrementErrorCount ();
+      Print (
+        L"ERROR: Invalid Platform Timer Structure length. " \
+          L"PlatformTimerLength = %d. RemainingTableBufferLength = %d. " \
+          L"GTDT parsing aborted.\n",
+        *PlatformTimerLength,
+        AcpiTableLength - Offset
+        );
+      return;
+    }
+
+    switch (*PlatformTimerType) {
+      case EFI_ACPI_6_3_GTDT_GT_BLOCK:
+        DumpGTBlock (TimerPtr, *PlatformTimerLength);
+        break;
+      case EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG:
+        DumpWatchdogTimer (TimerPtr, *PlatformTimerLength);
+        break;
+      default:
+        if (GetConsistencyChecking ()) {
           IncrementErrorCount ();
           Print (
-            L"ERROR: INVALID Platform Timer Type = %d\n",
+            L"ERROR: Invalid Platform Timer Type = %d\n",
             *PlatformTimerType
             );
-          break;
-      } // switch
-      TimerPtr += (*PlatformTimerLength);
-      Index++;
-    } while (Index < *GtdtPlatformTimerCount);
+        }
+        break;
+    } // switch
+
+    TimerPtr += *PlatformTimerLength;
+    Offset += *PlatformTimerLength;
+  } // while
+
+  // Cross-check the substructure count with the length of the encapsulating
+  // buffer
+  if (GetConsistencyChecking () &&
+      (Index < *GtdtPlatformTimerCount)) {
+    IncrementErrorCount ();
+    Print (
+      L"ERROR: Invalid Platform Timer Structure count. " \
+        L"GtdtPlatformTimerCount = %d. AcpiTableLength = %d.\n",
+      *GtdtPlatformTimerCount,
+      AcpiTableLength
+      );
   }
 }
--
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'



  parent reply	other threads:[~2019-07-12  6:55 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-12  6:52 [PATCH v1 00/11] Add security checks in the Acpiview table parsers Krzysztof Koch
2019-07-12  6:52 ` [PATCH v1 01/11] ShellPkg: acpiview: FADT: Validate global pointers before use Krzysztof Koch
2019-07-12 14:26   ` Carsey, Jaben
2019-07-17 13:38     ` [edk2-devel] " Krzysztof Koch
2019-07-19  1:21   ` Gao, Zhichao
2019-07-12  6:52 ` [PATCH v1 02/11] ShellPkg: acpiview: SPCR: Remove redundant forward declaration Krzysztof Koch
2019-07-17  9:42   ` [edk2-devel] " Alexei Fedorov
2019-07-12  6:52 ` [PATCH v1 03/11] ShellPkg: acpiview: RSDP: Make printing table checksum optional Krzysztof Koch
2019-07-17  9:41   ` [edk2-devel] " Alexei Fedorov
2019-07-12  6:52 ` [PATCH v1 04/11] ShellPkg: acpiview: XSDT: Remove redundant ParseAcpi() call Krzysztof Koch
2019-07-17  9:41   ` [edk2-devel] " Alexei Fedorov
2019-07-12  6:52 ` [PATCH v1 05/11] ShellPkg: acpiview: SLIT: Add error-checking in the parsing logic Krzysztof Koch
2019-07-17  9:42   ` [edk2-devel] " Alexei Fedorov
2019-07-12  6:52 ` [PATCH v1 06/11] ShellPkg: acpiview: SRAT: " Krzysztof Koch
2019-07-17  9:41   ` [edk2-devel] " Alexei Fedorov
2019-07-12  6:52 ` [PATCH v1 07/11] ShellPkg: acpiview: MADT: " Krzysztof Koch
2019-07-17  9:40   ` [edk2-devel] " Alexei Fedorov
2019-07-12  6:52 ` [PATCH v1 08/11] ShellPkg: acpiview: PPTT: " Krzysztof Koch
2019-07-17  9:40   ` [edk2-devel] " Alexei Fedorov
2019-07-12  6:52 ` [PATCH v1 09/11] ShellPkg: acpiview: IORT: " Krzysztof Koch
2019-07-17  9:40   ` [edk2-devel] " Alexei Fedorov
2019-07-12  6:52 ` Krzysztof Koch [this message]
2019-07-17  9:39   ` [edk2-devel] [PATCH v1 10/11] ShellPkg: acpiview: GTDT: " Alexei Fedorov
2019-07-12  6:52 ` [PATCH v1 11/11] ShellPkg: acpiview: DBG2: " Krzysztof Koch
2019-07-17  9:39   ` [edk2-devel] " Alexei Fedorov
2019-07-19  5:39   ` Gao, Zhichao
2019-07-17  9:42 ` [edk2-devel] [PATCH v1 00/11] Add security checks in the Acpiview table parsers Alexei Fedorov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190712065243.3812-11-krzysztof.koch@arm.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox