]> xenbits.xensource.com Git - people/aperard/ovmf.git/commitdiff
BaseTools: Update Stack Cookie Logic
authorTaylor Beebe <taylor.d.beebe@gmail.com>
Fri, 14 Jun 2024 21:07:33 +0000 (14:07 -0700)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Fri, 13 Sep 2024 03:58:46 +0000 (03:58 +0000)
This patch updates the GenC logic to generate a random stack cookie value
for the stack check libraries. These random values improve security
for modules which cannot update the global intrinsics.

If the stack cookie value is randomized in the AutoGen.h file each
build, the build system will determine the module/library must be
rebuilt causing effectively a clean build every time. This also makes
binary reproducibility impossible.

This patch updates the early build scripts to create 32 and 64-bit JSON
files in the build output directory which each contain 100 randomized
stack cookie values for each bitwidth. If the JSON files are already
present, then they are not recreated which allows them to be stored and
moved to other builds for binary reproducibility. Because they are in
the build directory, a clean build will cause the values to be
regenerated.

The logic which creates AutoGen.h will read these JSON files and use a
hash of the module GUID (the hash seed is fixed in Basetools) to index
into the array of stack cookie values for the module bitwidth. This
model is necessary because there isn't thread-consistent data so we
cannot use a locking mechanism to ensure only one thread is writing to
the stack cookie files at a time. With this model, the build threads
only need to read from the files.

Signed-off-by: Oliver Smith-Denny <osde@linux.microsoft.com>
BaseTools/Source/Python/AutoGen/GenC.py
BaseTools/Source/Python/Common/GlobalData.py
BaseTools/Source/Python/build/build.py

index 5ad10cee2898a193d0ec25be9211d68f67da1c05..86991e7675de7e280647f39f32672ff7681ed46c 100755 (executable)
@@ -21,6 +21,9 @@ from .StrGather import *
 from .GenPcdDb import CreatePcdDatabaseCode\r
 from .IdfClassObject import *\r
 \r
+import json\r
+import secrets\r
+\r
 ## PCD type string\r
 gItemTypeStringDatabase  = {\r
     TAB_PCDS_FEATURE_FLAG       :   TAB_PCDS_FIXED_AT_BUILD,\r
@@ -2039,6 +2042,34 @@ def CreateFooterCode(Info, AutoGenC, AutoGenH):
 def CreateCode(Info, AutoGenC, AutoGenH, StringH, UniGenCFlag, UniGenBinBuffer, StringIdf, IdfGenCFlag, IdfGenBinBuffer):\r
     CreateHeaderCode(Info, AutoGenC, AutoGenH)\r
 \r
+    # The only 32 bit archs we have are IA32 and ARM, everything else is 64 bit\r
+    Bitwidth = 32 if Info.Arch == 'IA32' or Info.Arch == 'ARM' else 64\r
+\r
+    if GlobalData.gStackCookieValues64 == [] and os.path.exists(os.path.join(Info.PlatformInfo.BuildDir, "StackCookieValues64.json")):\r
+        with open (os.path.join(Info.PlatformInfo.BuildDir, "StackCookieValues64.json"), "r") as file:\r
+            GlobalData.gStackCookieValues64 = json.load(file)\r
+    if GlobalData.gStackCookieValues32 == [] and os.path.exists(os.path.join(Info.PlatformInfo.BuildDir, "StackCookieValues32.json")):\r
+        with open (os.path.join(Info.PlatformInfo.BuildDir, "StackCookieValues32.json"), "r") as file:\r
+            GlobalData.gStackCookieValues32 = json.load(file)\r
+\r
+    try:\r
+        if Bitwidth == 32:\r
+            CookieValue = int(GlobalData.gStackCookieValues32[hash(Info.Guid) % len(GlobalData.gStackCookieValues32)])\r
+        else:\r
+            CookieValue = int(GlobalData.gStackCookieValues64[hash(Info.Guid) % len(GlobalData.gStackCookieValues64)])\r
+    except:\r
+        EdkLogger.warn("build", "Failed to get Stack Cookie Value List! Generating random value.", ExtraData="[%s]" % str(Info))\r
+        if Bitwidth == 32:\r
+            CookieValue = secrets.randbelow (0xFFFFFFFF)\r
+        else:\r
+            CookieValue = secrets.randbelow (0xFFFFFFFFFFFFFFFF)\r
+\r
+    AutoGenH.Append((\r
+        '#define STACK_COOKIE_VALUE 0x%XULL\n' % CookieValue\r
+        if Bitwidth == 64 else\r
+        '#define STACK_COOKIE_VALUE 0x%X\n' % CookieValue\r
+    ))\r
+\r
     CreateGuidDefinitionCode(Info, AutoGenC, AutoGenH)\r
     CreateProtocolDefinitionCode(Info, AutoGenC, AutoGenH)\r
     CreatePpiDefinitionCode(Info, AutoGenC, AutoGenH)\r
index 11849e863f535f5cd0552dfa917def4bd804576f..dd5316d2831e7e1b67599e9146d4152e8808c8fb 100755 (executable)
@@ -122,4 +122,5 @@ gEnableGenfdsMultiThread = True
 gSikpAutoGenCache = set()\r
 # Common lock for the file access in multiple process AutoGens\r
 file_lock = None\r
-\r
+gStackCookieValues32 = []\r
+gStackCookieValues64 = []\r
index 51fb1f433eb7878d3721e882a7ff8e19cfee4297..ce1bb871269378e8e9161859c6cf32bd00fe9fa6 100755 (executable)
@@ -28,6 +28,8 @@ import threading
 from linecache import getlines\r
 from subprocess import Popen,PIPE, STDOUT\r
 from collections import OrderedDict, defaultdict\r
+import json\r
+import secrets\r
 \r
 from AutoGen.PlatformAutoGen import PlatformAutoGen\r
 from AutoGen.ModuleAutoGen import ModuleAutoGen\r
@@ -282,6 +284,22 @@ def LaunchCommand(Command, WorkingDir,ModuleAuto = None):
         iau.CreateDepsTarget()\r
     return "%dms" % (int(round((time.time() - BeginTime) * 1000)))\r
 \r
+def GenerateStackCookieValues():\r
+    if GlobalData.gBuildDirectory == "":\r
+        return\r
+\r
+    # Check if the 32 bit values array needs to be created\r
+    if not os.path.exists(os.path.join(GlobalData.gBuildDirectory, "StackCookieValues32.json")):\r
+        StackCookieValues32 = [secrets.randbelow(0xFFFFFFFF) for _ in range(0, 100)]\r
+        with open (os.path.join(GlobalData.gBuildDirectory, "StackCookieValues32.json"), "w") as file:\r
+            json.dump(StackCookieValues32, file)\r
+\r
+    # Check if the 64 bit values array needs to be created\r
+    if not os.path.exists(os.path.join(GlobalData.gBuildDirectory, "StackCookieValues64.json")):\r
+        StackCookieValues64 = [secrets.randbelow(0xFFFFFFFFFFFFFFFF) for _ in range(0, 100)]\r
+        with open (os.path.join(GlobalData.gBuildDirectory, "StackCookieValues64.json"), "w") as file:\r
+            json.dump(StackCookieValues64, file)\r
+\r
 ## The smallest unit that can be built in multi-thread build mode\r
 #\r
 # This is the base class of build unit. The "Obj" parameter must provide\r
@@ -1794,6 +1812,7 @@ class Build():
                         self.UniFlag,\r
                         self.Progress\r
                         )\r
+                GenerateStackCookieValues()\r
                 self.Fdf = Wa.FdfFile\r
                 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
                 self.BuildReport.AddPlatformReport(Wa)\r
@@ -1897,6 +1916,7 @@ class Build():
                         self.Progress,\r
                         self.ModuleFile\r
                         )\r
+                GenerateStackCookieValues()\r
                 self.Fdf = Wa.FdfFile\r
                 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
                 Wa.CreateMakeFile(False)\r
@@ -2147,6 +2167,7 @@ class Build():
                 self.UniFlag,\r
                 self.Progress\r
                 )\r
+        GenerateStackCookieValues()\r
         self.Fdf = Wa.FdfFile\r
         self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
         self.BuildReport.AddPlatformReport(Wa)\r