Rework Buildtime Random Stack Cookie Values to Improve Incremental Build Times and Ensure Binary Reproducibility (#773)
## Description 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 PR 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. - [x] Impacts functionality? - **Functionality** - Does the change ultimately impact how firmware functions? - Examples: Add a new library, publish a new PPI, update an algorithm, ... - [x] Impacts security? - **Security** - Does the change have a direct security impact on an application, flow, or firmware? - Examples: Crypto algorithm change, buffer overflow fix, parameter validation improvement, ... - [ ] Breaking change? - **Breaking change** - Will anyone consuming this change experience a break in build or boot behavior? - Examples: Add a new library class, move a module to a different repo, call a function in a new library class in a pre-existing module, ... - [ ] Includes tests? - **Tests** - Does the change include any explicit test code? - Examples: Unit tests, integration tests, robot tests, ... - [ ] Includes documentation? - **Documentation** - Does the change contain explicit documentation additions outside direct code modifications (and comments)? - Examples: Update readme file, add feature readme file, link to documentation on an a separate Web page, ... ## How This Was Tested Tested by building and confirming the reduced build time for debug builds after the initial build. ## Integration Instructions N/A
This commit is contained in:
Родитель
8af8b99933
Коммит
6e8e740d17
|
@ -21,7 +21,10 @@ from .StrGather import *
|
|||
from .GenPcdDb import CreatePcdDatabaseCode
|
||||
from .IdfClassObject import *
|
||||
|
||||
import secrets # MU_CHANGE: Add Stack Cookie Support
|
||||
# MU_CHANGE [BEGIN]: Add build-time random stack cookie support
|
||||
import json
|
||||
import secrets
|
||||
# MU_CHANGE [END]
|
||||
|
||||
## PCD type string
|
||||
gItemTypeStringDatabase = {
|
||||
|
@ -2047,21 +2050,38 @@ def CreateFooterCode(Info, AutoGenC, AutoGenH):
|
|||
def CreateCode(Info, AutoGenC, AutoGenH, StringH, UniGenCFlag, UniGenBinBuffer, StringIdf, IdfGenCFlag, IdfGenBinBuffer):
|
||||
CreateHeaderCode(Info, AutoGenC, AutoGenH)
|
||||
|
||||
# MU_CHANGE [START]: Add Stack Cookie Support
|
||||
# MU_CHANGE [BEGIN]: Add build-time random stack cookie support
|
||||
if Info.ModuleType != SUP_MODULE_HOST_APPLICATION:
|
||||
if Info.Arch not in ['X64', 'IA32', 'ARM', 'AARCH64']:
|
||||
EdkLogger.error("build", AUTOGEN_ERROR, "Unsupported Arch %s" % Info.Arch, ExtraData="[%s]" % str(Info))
|
||||
else:
|
||||
Bitwidth = 64 if Info.Arch == 'X64' or Info.Arch == 'AARCH64' else 32
|
||||
|
||||
CookieValue = secrets.randbelow(0xFFFFFFFFFFFFFFFF if Bitwidth == 64 else 0xFFFFFFFF)
|
||||
if GlobalData.gStackCookieValues64 == [] and os.path.exists(os.path.join(Info.PlatformInfo.BuildDir, "StackCookieValues64.json")):
|
||||
with open (os.path.join(Info.PlatformInfo.BuildDir, "StackCookieValues64.json"), "r") as file:
|
||||
GlobalData.gStackCookieValues64 = json.load(file)
|
||||
if GlobalData.gStackCookieValues32 == [] and os.path.exists(os.path.join(Info.PlatformInfo.BuildDir, "StackCookieValues32.json")):
|
||||
with open (os.path.join(Info.PlatformInfo.BuildDir, "StackCookieValues32.json"), "r") as file:
|
||||
GlobalData.gStackCookieValues32 = json.load(file)
|
||||
|
||||
try:
|
||||
if Bitwidth == 32:
|
||||
CookieValue = int(GlobalData.gStackCookieValues32[hash(Info.Guid) % len(GlobalData.gStackCookieValues32)])
|
||||
else:
|
||||
CookieValue = int(GlobalData.gStackCookieValues64[hash(Info.Guid) % len(GlobalData.gStackCookieValues64)])
|
||||
except:
|
||||
EdkLogger.error("build", AUTOGEN_ERROR, "Failed to get Stack Cookie Value List! Generating random value.", ExtraData="[%s]" % str(Info))
|
||||
if Bitwidth == 32:
|
||||
CookieValue = secrets.randbelow (0xFFFFFFFF)
|
||||
else:
|
||||
CookieValue = secrets.randbelow (0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
AutoGenH.Append((
|
||||
'#define STACK_COOKIE_VALUE 0x%XULL\n' % CookieValue
|
||||
if Bitwidth == 64 else
|
||||
'#define STACK_COOKIE_VALUE 0x%X\n' % CookieValue
|
||||
))
|
||||
# MU_CHANGE [END]: Add Stack Cookie Support
|
||||
# MU_CHANGE [END]
|
||||
|
||||
CreateGuidDefinitionCode(Info, AutoGenC, AutoGenH)
|
||||
CreateProtocolDefinitionCode(Info, AutoGenC, AutoGenH)
|
||||
|
|
|
@ -123,3 +123,7 @@ gSikpAutoGenCache = set()
|
|||
# Common lock for the file access in multiple process AutoGens
|
||||
file_lock = None
|
||||
gLogLibraryMismatch = True # MU_CHANGE
|
||||
# MU_CHANGE [BEGIN]: Add build-time random stack cookie support
|
||||
gStackCookieValues32 = []
|
||||
gStackCookieValues64 = []
|
||||
# MU_CHANGE [END]
|
||||
|
|
|
@ -29,6 +29,10 @@ from linecache import getlines
|
|||
from subprocess import Popen,PIPE, STDOUT
|
||||
from collections import OrderedDict, defaultdict
|
||||
import pathlib
|
||||
# MU_CHANGE [BEGIN]: Add build-time random stack cookie support
|
||||
import json
|
||||
import secrets
|
||||
# MU_CHANGE [END]
|
||||
|
||||
from AutoGen.PlatformAutoGen import PlatformAutoGen
|
||||
from AutoGen.ModuleAutoGen import ModuleAutoGen
|
||||
|
@ -307,6 +311,24 @@ def LaunchCommand(Command, WorkingDir,ModuleAuto = None):
|
|||
iau.CreateDepsTarget()
|
||||
return "%dms" % (int(round((time.time() - BeginTime) * 1000)))
|
||||
|
||||
# MU_CHANGE [BEGIN]: Add build-time random stack cookie support
|
||||
def GenerateStackCookieValues():
|
||||
if GlobalData.gBuildDirectory == "":
|
||||
return
|
||||
|
||||
# Check if the 32 bit values array needs to be created
|
||||
if not os.path.exists(os.path.join(GlobalData.gBuildDirectory, "StackCookieValues32.json")):
|
||||
StackCookieValues32 = [secrets.randbelow(0xFFFFFFFF) for _ in range(0, 100)]
|
||||
with open (os.path.join(GlobalData.gBuildDirectory, "StackCookieValues32.json"), "w") as file:
|
||||
json.dump(StackCookieValues32, file)
|
||||
|
||||
# Check if the 64 bit values array needs to be created
|
||||
if not os.path.exists(os.path.join(GlobalData.gBuildDirectory, "StackCookieValues64.json")):
|
||||
StackCookieValues64 = [secrets.randbelow(0xFFFFFFFFFFFFFFFF) for _ in range(0, 100)]
|
||||
with open (os.path.join(GlobalData.gBuildDirectory, "StackCookieValues64.json"), "w") as file:
|
||||
json.dump(StackCookieValues64, file)
|
||||
# MU_CHANGE [END]
|
||||
|
||||
## The smallest unit that can be built in multi-thread build mode
|
||||
#
|
||||
# This is the base class of build unit. The "Obj" parameter must provide
|
||||
|
@ -1848,6 +1870,7 @@ class Build():
|
|||
self.UniFlag,
|
||||
self.Progress
|
||||
)
|
||||
GenerateStackCookieValues() # MU_CHANGE [BEGIN]: Add build-time random stack cookie support
|
||||
self.Fdf = Wa.FdfFile
|
||||
self.LoadFixAddress = Wa.Platform.LoadFixAddress
|
||||
self.BuildReport.AddPlatformReport(Wa)
|
||||
|
@ -2200,7 +2223,8 @@ class Build():
|
|||
self.SkuId,
|
||||
self.UniFlag,
|
||||
self.Progress
|
||||
)
|
||||
)
|
||||
GenerateStackCookieValues() # MU_CHANGE [BEGIN]: Add build-time random stack cookie support
|
||||
self.Fdf = Wa.FdfFile
|
||||
self.LoadFixAddress = Wa.Platform.LoadFixAddress
|
||||
self.BuildReport.AddPlatformReport(Wa)
|
||||
|
|
Загрузка…
Ссылка в новой задаче