]> xenbits.xensource.com Git - ovmf.git/commitdiff
UefiCpuPkg/CpuPageTableLib:Modify RandomTest to check Mask/Attr
authorDun Tan <dun.tan@intel.com>
Fri, 17 Mar 2023 07:06:48 +0000 (15:06 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 27 Mar 2023 08:21:58 +0000 (08:21 +0000)
Modify RandomTest to check invalid input. When creating new page
table or updating exsiting page table:
1.If set [LinearAddress, LinearAddress+Length] to non-present, all
  other attributes should not be provided.
2.If [LinearAddress, LinearAddress+Length] contain non-present range,
  the Returnstatus of PageTableMap() should be InvalidParameter when:
2.1Some of attributes are not provided when mapping non-present range
   to present.
2.2Set any other attribute without setting the non-present range to
   Present.

Signed-off-by: Dun Tan <dun.tan@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Tested-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/RandomTest.c
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/TestHelper.c

index 612fddcee0c5fd04b0fbd54c67d56d17d37bf638..121cc4f2b2e2c16342bd17d6fadc3f1ef00a1bfe 100644 (file)
@@ -273,6 +273,27 @@ ValidateAndRandomeModifyPageTable (
   return Status;\r
 }\r
 \r
+/**\r
+  Remove the last MAP_ENTRY in MapEntrys.\r
+\r
+  @param MapEntrys   Pointer to MapEntrys buffer\r
+**/\r
+VOID\r
+RemoveLastMapEntry (\r
+  IN OUT MAP_ENTRYS  *MapEntrys\r
+  )\r
+{\r
+  UINTN  MapsIndex;\r
+\r
+  if (MapEntrys->Count == 0) {\r
+    return;\r
+  }\r
+\r
+  MapsIndex = MapEntrys->Count - 1;\r
+  ZeroMem (&(MapEntrys->Maps[MapsIndex]), sizeof (MAP_ENTRY));\r
+  MapEntrys->Count = MapsIndex;\r
+}\r
+\r
 /**\r
   Generate single random map entry.\r
   The map entry can be the input of function PageTableMap\r
@@ -327,7 +348,16 @@ GenerateSingleRandomMapEntry (
     MapEntrys->Maps[MapsIndex].Mask.Uint64      = MapEntrys->Maps[Random32 (0, (UINT32)MapsIndex-1)].Mask.Uint64;\r
   } else {\r
     MapEntrys->Maps[MapsIndex].Attribute.Uint64 = Random64 (0, MAX_UINT64) & mSupportedBit.Uint64;\r
-    MapEntrys->Maps[MapsIndex].Mask.Uint64      = Random64 (0, MAX_UINT64) & mSupportedBit.Uint64;\r
+    if (RandomBoolean (5)) {\r
+      //\r
+      // The probability to get random Mask should be small since all bits of a random number\r
+      // have a high probability of containing 0, which may be a invalid input.\r
+      //\r
+      MapEntrys->Maps[MapsIndex].Mask.Uint64 = Random64 (0, MAX_UINT64) & mSupportedBit.Uint64;\r
+    } else {\r
+      MapEntrys->Maps[MapsIndex].Mask.Uint64 = MAX_UINT64;\r
+    }\r
+\r
     if (MapEntrys->Maps[MapsIndex].Mask.Bits.ProtectionKey != 0) {\r
       MapEntrys->Maps[MapsIndex].Mask.Bits.ProtectionKey = 0xF;\r
     }\r
@@ -337,15 +367,7 @@ GenerateSingleRandomMapEntry (
     MapEntrys->Maps[MapsIndex].Attribute.Bits.PageTableBaseAddress = MapEntrys->Maps[MapsIndex].LinearAddress >> 12;\r
     MapEntrys->Maps[MapsIndex].Mask.Bits.PageTableBaseAddress      = 0xFFFFFFFFFF;\r
   } else {\r
-    //\r
-    // Todo: If the mask bit for base address is zero, when dump the pagetable, every entry mapping to physical address zeor.\r
-    //       This means the map count will be a large number, and impossible to finish in proper time.\r
-    //       Need to avoid such case when remove the Random option ONLY_ONE_ONE_MAPPING\r
-    //\r
     MapEntrys->Maps[MapsIndex].Attribute.Bits.PageTableBaseAddress = (Random64 (0, (((UINT64)1)<<52) - 1) & AlignedTable[Random32 (0, ARRAY_SIZE (AlignedTable) -1)])>> 12;\r
-    if (RandomBoolean (50)) {\r
-      MapEntrys->Maps[MapsIndex].Mask.Bits.PageTableBaseAddress = 0;\r
-    }\r
   }\r
 \r
   MapEntrys->Count += 1;\r
@@ -608,25 +630,65 @@ SingleMapEntryTest (
   IN     UINTN                  InitMapCount\r
   )\r
 {\r
-  UINTN             MapsIndex;\r
-  RETURN_STATUS     Status;\r
-  UINTN             PageTableBufferSize;\r
-  VOID              *Buffer;\r
-  IA32_MAP_ENTRY    *Map;\r
-  UINTN             MapCount;\r
-  UINTN             Index;\r
-  UINTN             KeyPointCount;\r
-  UINTN             NewKeyPointCount;\r
-  UINT64            *KeyPointBuffer;\r
-  UINTN             Level;\r
-  UINT64            Value;\r
-  UNIT_TEST_STATUS  TestStatus;\r
-  MAP_ENTRY         *LastMapEntry;\r
-\r
-  MapsIndex = MapEntrys->Count;\r
+  UINTN               MapsIndex;\r
+  RETURN_STATUS       Status;\r
+  UINTN               PageTableBufferSize;\r
+  VOID                *Buffer;\r
+  IA32_MAP_ENTRY      *Map;\r
+  UINTN               MapCount;\r
+  UINTN               Index;\r
+  UINTN               KeyPointCount;\r
+  UINTN               NewKeyPointCount;\r
+  UINT64              *KeyPointBuffer;\r
+  UINTN               Level;\r
+  UINT64              Value;\r
+  UNIT_TEST_STATUS    TestStatus;\r
+  MAP_ENTRY           *LastMapEntry;\r
+  IA32_MAP_ATTRIBUTE  *Mask;\r
+  IA32_MAP_ATTRIBUTE  *Attribute;\r
+  UINT64              LastNotPresentRegionStart;\r
+  BOOLEAN             IsNotPresent;\r
+\r
+  MapsIndex                 = MapEntrys->Count;\r
+  MapCount                  = 0;\r
+  LastNotPresentRegionStart = 0;\r
+  IsNotPresent              = FALSE;\r
 \r
   GenerateSingleRandomMapEntry (MaxAddress, MapEntrys);\r
   LastMapEntry = &MapEntrys->Maps[MapsIndex];\r
+  Status       = PageTableParse (*PageTable, PagingMode, NULL, &MapCount);\r
+\r
+  if (MapCount != 0) {\r
+    UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);\r
+    Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount * sizeof (IA32_MAP_ENTRY)));\r
+    ASSERT (Map != NULL);\r
+    Status = PageTableParse (*PageTable, PagingMode, Map, &MapCount);\r
+  }\r
+\r
+  //\r
+  // Check if the generated MapEntrys->Maps[MapsIndex] contains not-present range.\r
+  //\r
+  if (LastMapEntry->Length > 0) {\r
+    for (Index = 0; Index < MapCount; Index++) {\r
+      if ((LastNotPresentRegionStart < Map[Index].LinearAddress) &&\r
+          (LastMapEntry->LinearAddress < Map[Index].LinearAddress) && (LastMapEntry->LinearAddress + LastMapEntry->Length > LastNotPresentRegionStart))\r
+      {\r
+        //\r
+        // MapEntrys->Maps[MapsIndex] contains not-present range in exsiting page table.\r
+        //\r
+        break;\r
+      }\r
+\r
+      LastNotPresentRegionStart = Map[Index].LinearAddress + Map[Index].Length;\r
+    }\r
+\r
+    //\r
+    // Either LastMapEntry overlaps with the not-present region in the very end\r
+    // Or it overlaps with one in the middle\r
+    if (LastNotPresentRegionStart < LastMapEntry->LinearAddress + LastMapEntry->Length) {\r
+      IsNotPresent = TRUE;\r
+    }\r
+  }\r
 \r
   PageTableBufferSize = 0;\r
   Status              = PageTableMap (\r
@@ -639,6 +701,47 @@ SingleMapEntryTest (
                           &LastMapEntry->Attribute,\r
                           &LastMapEntry->Mask\r
                           );\r
+\r
+  Attribute = &LastMapEntry->Attribute;\r
+  Mask      = &LastMapEntry->Mask;\r
+  //\r
+  // If set [LinearAddress, LinearAddress+Attribute] to not preset, all\r
+  // other attributes should not be provided.\r
+  //\r
+  if ((LastMapEntry->Length > 0) && (Attribute->Bits.Present == 0) && (Mask->Bits.Present == 1) && (Mask->Uint64 > 1)) {\r
+    RemoveLastMapEntry (MapEntrys);\r
+    UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);\r
+    return UNIT_TEST_PASSED;\r
+  }\r
+\r
+  //\r
+  // Return Status for non-present range also should be InvalidParameter when:\r
+  // 1. Some of attributes are not provided when mapping non-present range to present.\r
+  // 2. Set any other attribute without setting the non-present range to Present.\r
+  //\r
+  if (IsNotPresent) {\r
+    if ((Mask->Bits.Present == 1) && (Attribute->Bits.Present == 1)) {\r
+      //\r
+      // Creating new page table or remapping non-present range to present.\r
+      //\r
+      if ((Mask->Bits.ReadWrite == 0) || (Mask->Bits.UserSupervisor == 0) || (Mask->Bits.WriteThrough == 0) || (Mask->Bits.CacheDisabled == 0) ||\r
+          (Mask->Bits.Accessed == 0) || (Mask->Bits.Dirty == 0) || (Mask->Bits.Pat == 0) || (Mask->Bits.Global == 0) ||\r
+          (Mask->Bits.PageTableBaseAddress == 0) || (Mask->Bits.ProtectionKey == 0) || (Mask->Bits.Nx == 0))\r
+      {\r
+        RemoveLastMapEntry (MapEntrys);\r
+        UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);\r
+        return UNIT_TEST_PASSED;\r
+      }\r
+    } else if ((Mask->Bits.Present == 0) && (Mask->Uint64 > 1)) {\r
+      //\r
+      // Only change other attributes for non-present range is not permitted.\r
+      //\r
+      RemoveLastMapEntry (MapEntrys);\r
+      UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);\r
+      return UNIT_TEST_PASSED;\r
+    }\r
+  }\r
+\r
   if (PageTableBufferSize != 0) {\r
     UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);\r
 \r
index 5bd70c0f657fa00eff0976ace3bac3e9d9119cef..10fdee2f946f470db988b6fb3e15852324caef94 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   helper file for Unit tests of the CpuPageTableLib instance of the CpuPageTableLib class\r
 \r
-  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>\r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
@@ -171,6 +171,10 @@ IsPageTableValid (
   UNIT_TEST_STATUS   Status;\r
   IA32_PAGING_ENTRY  *PagingEntry;\r
 \r
+  if (PageTable == 0) {\r
+    return UNIT_TEST_PASSED;\r
+  }\r
+\r
   if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {\r
     //\r
     // 32bit paging is never supported.\r