]> git.proxmox.com Git - efi-boot-shim.git/commitdiff
New upstream version 15.5
authorSteve McIntyre <steve@einval.com>
Wed, 27 Apr 2022 21:41:59 +0000 (22:41 +0100)
committerSteve McIntyre <steve@einval.com>
Wed, 27 Apr 2022 21:41:59 +0000 (22:41 +0100)
179 files changed:
.gitignore
.gitmodules
BUILDING
Cryptlib/Hash/CryptMd5.c
Cryptlib/Hash/CryptSha1.c
Cryptlib/Hash/CryptSha256.c
Cryptlib/Hash/CryptSha512.c
Cryptlib/Include/OpenSslSupport.h
Cryptlib/Pk/CryptPkcs7Verify.c
Make.defaults
Makefile
MokManager.c
MokVars.txt
SBAT.example.md
SBAT.md
commit
csv.c
elf_aarch64_efi.lds
elf_arm_efi.lds
elf_ia32_efi.lds
fallback.c
globals.c [new file with mode: 0644]
gnu-efi/Make.defaults
gnu-efi/inc/efiapi.h
gnu-efi/inc/efilib.h
gnu-efi/lib/misc.c
gnu-efi/lib/str.c
httpboot.c
include/asm.h
include/console.h
include/efiauthenticated.h
include/hexdump.h
include/load-options.h [new file with mode: 0644]
include/mock-variables.h [new file with mode: 0644]
include/mok.h [new file with mode: 0644]
include/pe.h
include/str.h
include/system/stdarg.h
include/test-data-efivars-0.h [new file with mode: 0644]
include/test-data-efivars-1.h [new file with mode: 0644]
include/test.h
include/test.mk
include/ucs2.h
lib/console.c
lib/execute.c
lib/security_policy.c
lib/shell.c
lib/simple_file.c
lib/variables.c
load-options.c [new file with mode: 0644]
mock-variables.c [new file with mode: 0644]
mok.c
netboot.c
pe.c
post-process-pe.c [new file with mode: 0644]
replacements.c
shim.c
shim.h
test-csv.c
test-data/efivars-0/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 [new file with mode: 0644]
test-data/efivars-0/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 [new file with mode: 0644]
test-data/efivars-0/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e [new file with mode: 0644]
test-data/efivars-0/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-0/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f [new file with mode: 0644]
test-data/efivars-0/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-0/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f [new file with mode: 0644]
test-data/efivars-0/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 [new file with mode: 0644]
test-data/efivars-1/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 [new file with mode: 0644]
test-data/efivars-1/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e [new file with mode: 0644]
test-data/efivars-1/AMITSESetup-c811fa38-42c8-4579-a9bb-60e94eddfb34 [new file with mode: 0644]
test-data/efivars-1/AOD_SETUP-5ed15dc0-edef-4161-9151-6014c4cc630c [new file with mode: 0644]
test-data/efivars-1/AmdAcpiVar-79941ecd-ed36-49d0-8124-e4c31ac75cd4 [new file with mode: 0644]
test-data/efivars-1/AmdSetup-3a997502-647a-4c82-998e-52ef9486a247 [new file with mode: 0644]
test-data/efivars-1/AmiHardwareSignatureSetupUpdateCountVar-81c76078-bfde-4368-9790-570914c01a65 [new file with mode: 0644]
test-data/efivars-1/ApSyncFlagNv-ad3f6761-f0a3-46c8-a4cb-19b70ffdb305 [new file with mode: 0644]
test-data/efivars-1/AsbkpInfo-cb825795-feb1-4c0b-894f-cc70f8064395 [new file with mode: 0644]
test-data/efivars-1/AsusExtFancard-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/AsusFanSetupFeatures-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/AsusHwmSetupOneof-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/AsusNodePsu-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/AsusQFanSetupData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/AsusRomLayout-7186d975-2dba-4413-81a8-9f1538faef5e [new file with mode: 0644]
test-data/efivars-1/AsusSetupDataBackup-1111b056-c5e9-40ca-aba3-ec172533d814 [new file with mode: 0644]
test-data/efivars-1/AutoDetectData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/BiosEventLog-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 [new file with mode: 0644]
test-data/efivars-1/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/Boot0004-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/Boot0005-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/Boot0006-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/BootFromUSB-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/CMOSfailflag-c89dc9c7-5105-472c-a743-b1621e142b41 [new file with mode: 0644]
test-data/efivars-1/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/CurrentPolicy-77fa9abd-0359-4d32-bd60-28f4e78f784b [new file with mode: 0644]
test-data/efivars-1/DefaultBootOrder-45cf35f6-0d6e-4d04-856a-0370a5b16f53 [new file with mode: 0644]
test-data/efivars-1/DeploymentModeNv-97e8965f-c761-4f48-b6e4-9ffa9cb2a2d6 [new file with mode: 0644]
test-data/efivars-1/DownCoreStatus-29749bad-401b-4f6d-b124-cece8c590c48 [new file with mode: 0644]
test-data/efivars-1/EnWpData-cbab171f-f356-4009-baaa-6628353a0a29 [new file with mode: 0644]
test-data/efivars-1/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/FPLayoutOrder-4db88a62-6721-47a0-9082-280b00323594 [new file with mode: 0644]
test-data/efivars-1/FTMActiveFlag-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 [new file with mode: 0644]
test-data/efivars-1/FastBootOption-b540a530-6978-4da7-91cb-7207d764d262 [new file with mode: 0644]
test-data/efivars-1/FirstBootFlag-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/HddSmartInfo-a6f44860-b2e8-4fda-bd45-78368994b6ae [new file with mode: 0644]
test-data/efivars-1/HiiDB-1b838190-4625-4ead-abc9-cd5e6af18fe0 [new file with mode: 0644]
test-data/efivars-1/HwErrRecSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/KEKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/Kernel_ATPSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b [new file with mode: 0644]
test-data/efivars-1/Kernel_DriverSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b [new file with mode: 0644]
test-data/efivars-1/Kernel_RvkSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b [new file with mode: 0644]
test-data/efivars-1/Kernel_SiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b [new file with mode: 0644]
test-data/efivars-1/Kernel_SkuSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b [new file with mode: 0644]
test-data/efivars-1/Kernel_WinSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b [new file with mode: 0644]
test-data/efivars-1/LastBoot-b540a530-6978-4da7-91cb-7207d764d262 [new file with mode: 0644]
test-data/efivars-1/MaximumTableSize-4b3082a3-80c6-4d7e-9cd0-583917265df1 [new file with mode: 0644]
test-data/efivars-1/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829 [new file with mode: 0644]
test-data/efivars-1/MemoryOverwriteRequestControlLock-bb983ccf-151d-40e1-a07b-4a17be168292 [new file with mode: 0644]
test-data/efivars-1/MokList-605dab50-e046-4300-abb6-3dd810dd8b23 [new file with mode: 0644]
test-data/efivars-1/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23 [new file with mode: 0644]
test-data/efivars-1/MokListX-605dab50-e046-4300-abb6-3dd810dd8b23 [new file with mode: 0644]
test-data/efivars-1/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23 [new file with mode: 0644]
test-data/efivars-1/MonotonicCounter-01368881-c4ad-4b1d-b631-d57a8ec8db6b [new file with mode: 0644]
test-data/efivars-1/MyFav-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 [new file with mode: 0644]
test-data/efivars-1/NVRAM_Verify-15a9dd61-e4f8-4a99-80db-353b13d76490 [new file with mode: 0644]
test-data/efivars-1/NetworkStackVar-d1405d16-7afc-4695-bb12-41459d3695a2 [new file with mode: 0644]
test-data/efivars-1/NvHdd0-e57abcbd-9456-4639-8f65-06aab41d840f [new file with mode: 0644]
test-data/efivars-1/NvHdd8-e57abcbd-9456-4639-8f65-06aab41d840f [new file with mode: 0644]
test-data/efivars-1/OsIndications-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/PCI_COMMON-aca9f304-21e2-4852-9875-7ff4881d67a5 [new file with mode: 0644]
test-data/efivars-1/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/PcieSataModVar-5e9a565f-cdc0-413b-ad13-1fe8713ffdcd [new file with mode: 0644]
test-data/efivars-1/PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/PreVgaInfo-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/RsdpAddr-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/SIDSUPPORT-7d3dceee-cbce-4ea7-8709-6e552f1edbde [new file with mode: 0644]
test-data/efivars-1/SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23 [new file with mode: 0644]
test-data/efivars-1/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23 [new file with mode: 0644]
test-data/efivars-1/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/SecureBootSetup-7b59104a-c00d-4158-87ff-f04d6396a915 [new file with mode: 0644]
test-data/efivars-1/Setup-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/SetupLedData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/SmbiosEntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 [new file with mode: 0644]
test-data/efivars-1/SmbiosScratchBuffer-4b3082a3-80c6-4d7e-9cd0-583917265df1 [new file with mode: 0644]
test-data/efivars-1/SmbiosV3EntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 [new file with mode: 0644]
test-data/efivars-1/StdDefaults-4599d26f-1a11-49b8-b91f-858745cff824 [new file with mode: 0644]
test-data/efivars-1/TPMPERBIOSFLAGS-7d3dceee-cbce-4ea7-8709-6e552f1edbde [new file with mode: 0644]
test-data/efivars-1/Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/TotalNumberOfRootBridges-fb5703f5-f8a7-f401-18b4-3f108deb2612 [new file with mode: 0644]
test-data/efivars-1/TpmServFlags-7d3dceee-cbce-4ea7-8709-6e552f1edbde [new file with mode: 0644]
test-data/efivars-1/UsbSupport-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 [new file with mode: 0644]
test-data/efivars-1/VARSTORE_OCMR_SETTINGS_NAME-c05fba7d-7a92-49e0-bcee-233b14dca803 [new file with mode: 0644]
test-data/efivars-1/VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/WpBufAddr-cba83c4a-a5fc-48a8-b3a6-d33636166544 [new file with mode: 0644]
test-data/efivars-1/WriteOnceStatus-4b3082a3-80c6-4d7e-9cd0-583917265df1 [new file with mode: 0644]
test-data/efivars-1/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f [new file with mode: 0644]
test-data/efivars-1/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-data/efivars-1/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f [new file with mode: 0644]
test-data/efivars-1/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c [new file with mode: 0644]
test-load-options.c [new file with mode: 0644]
test-mock-variables.c [new file with mode: 0644]
test-mok-mirror.c [new file with mode: 0644]
test-str.c
test.c
tpm.c

index 832c0cd77e21a161b37cee9004e5f32a4e67342c..7fc55bce57d7f36b034ed8940b6f9882ab1016a1 100644 (file)
@@ -14,7 +14,10 @@ Make.local
 *.efi.debug
 *.efi.signed
 *.esl
-*.gdbinit
+*.gdb*
+*.gcda
+*.gcno
+*.gcov
 *.hash
 *.key
 *.key
@@ -27,8 +30,11 @@ Make.local
 *.sw?
 *.tar.*
 /build*/
+/.cache/
 /certdb/
+/compile_commands.json
 /cov-int/
+/post-process-pe
 /random.bin
 /sbat.*.csv
 /scan-results/
@@ -36,5 +42,6 @@ Make.local
 shim_cert.h
 /test-*
 !/test-*.c
+!/test-data/
 /test-random.h
 version.c
index 2ad8bb84e95af2a7cd0c7f35d58b0c914b56a6ef..1029752d340dbd5d1204efe7081baac1962f0fd8 100644 (file)
@@ -1,4 +1,4 @@
 [submodule "gnu-efi"]
        path = gnu-efi
        url = https://github.com/rhboot/gnu-efi.git
-       branch = shim-15.3
+       branch = shim-15.5
index ff1390fa991789fe32175ce1e3c76b0b7d733627..2da9b5f045326ef4e8aaf33cca6c93e70151af5b 100644 (file)
--- a/BUILDING
+++ b/BUILDING
@@ -45,6 +45,12 @@ Variables you could set to customize the build:
   shim has already verified the kernel when shim loaded the kernel as the
   second stage loader.  In such a case, and only in this case, you should
   use DISABLE_EBS_PROTECTION=y to build.
+- DISABLE_REMOVABLE_LOAD_OPTIONS
+  Do not parse load options when invoked as boot*.efi. This prevents boot
+  failures because of unexpected data in boot entries automatically generated
+  by firmware. It breaks loading non-default second-stage loaders when invoked
+  via that path, and requires using a binary named shim*.efi (or really anything
+  else).
 - REQUIRE_TPM
   if tpm logging or extends return an error code, treat that as a fatal error.
 - ARCH
index ccf6ad0017783be78c8ae1320c5d29bc38d93b44..b389f0e1b3b8a9891aca3792701f1cd70624ed67 100644 (file)
@@ -93,7 +93,7 @@ Md5Duplicate (
     return FALSE;\r
   }\r
 \r
-  CopyMem (NewMd5Context, Md5Context, sizeof (MD5_CTX));\r
+  CopyMem (NewMd5Context, (void *)Md5Context, sizeof (MD5_CTX));\r
 \r
   return TRUE;\r
 }\r
index 42cfd08a28c934df3691d888f3efb3eaef72acc2..3e67a80549cee394161e06d246dad2f435366253 100644 (file)
@@ -92,7 +92,7 @@ Sha1Duplicate (
     return FALSE;\r
   }\r
 \r
-  CopyMem (NewSha1Context, Sha1Context, sizeof (SHA_CTX));\r
+  CopyMem (NewSha1Context, (void *)Sha1Context, sizeof (SHA_CTX));\r
 \r
   return TRUE;\r
 }\r
index 06ecb2e98098f00fa7402a84472ededb8751a327..05bc6b0ae897ec8d01d3f9b336bfdc12a81ec357 100644 (file)
@@ -91,7 +91,7 @@ Sha256Duplicate (
     return FALSE;\r
   }\r
 \r
-  CopyMem (NewSha256Context, Sha256Context, sizeof (SHA256_CTX));\r
+  CopyMem (NewSha256Context, (void *)Sha256Context, sizeof (SHA256_CTX));\r
 \r
   return TRUE;\r
 }\r
index 3ce372a066d67f08ac558048f1ac0278225540cb..16063b23593fdceba3c1e49a2d8884979d58c209 100644 (file)
@@ -93,7 +93,7 @@ Sha384Duplicate (
     return FALSE;\r
   }\r
 \r
-  CopyMem (NewSha384Context, Sha384Context, sizeof (SHA512_CTX));\r
+  CopyMem (NewSha384Context, (void *)Sha384Context, sizeof (SHA512_CTX));\r
 \r
   return TRUE;\r
 }\r
@@ -308,7 +308,7 @@ Sha512Duplicate (
     return FALSE;\r
   }\r
 \r
-  CopyMem (NewSha512Context, Sha512Context, sizeof (SHA512_CTX));\r
+  CopyMem (NewSha512Context, (void *)Sha512Context, sizeof (SHA512_CTX));\r
 \r
   return TRUE;\r
 }\r
index b97149e27dd61ad70cb83ed153e4982519ae3aa2..0c2fb8b0cb56507be67235999532186a4d81aaed 100644 (file)
@@ -262,11 +262,11 @@ extern FILE  *stdout;
 //\r
 // Macros that directly map functions to BaseLib, BaseMemoryLib, and DebugLib functions\r
 //\r
-#define memcpy(dest,source,count)         ( {CopyMem(dest,source,(UINTN)(count)); dest; })\r
+#define memcpy(dest,source,count)         ( {CopyMem(dest,(void *)source,(UINTN)(count)); dest; })\r
 #define memset(dest,ch,count)             SetMem(dest,(UINTN)(count),(UINT8)(ch))\r
 #define memchr(buf,ch,count)              ScanMem8((CHAR8 *)buf,(UINTN)(count),ch)\r
 #define memcmp(buf1,buf2,count)           (int)(CompareMem(buf1,buf2,(UINTN)(count)))\r
-#define memmove(dest,source,count)        CopyMem(dest,source,(UINTN)(count))\r
+#define memmove(dest,source,count)        CopyMem(dest,(void *)source,(UINTN)(count))\r
 #define localtime(timer)                  NULL\r
 #define assert(expression)\r
 #define atoi(nptr)                        AsciiStrDecimalToUintn((const CHAR8 *)nptr)\r
index 09895d8c66a4a2ca98e65727a14eaa920c7bdbaf..c1893848f6424ddf6a17e961a1b601e0651dedf4 100644 (file)
@@ -216,7 +216,7 @@ WrapPkcs7Data (
     //\r
     // Part7: P7Data.\r
     //\r
-    CopyMem (SignedData + 19, P7Data, P7Length);\r
+    CopyMem (SignedData + 19, (void *)P7Data, P7Length);\r
   }\r
 \r
   *WrapFlag = Wrapped;\r
index a775083ee0b60c49c9b1f014618af349ba68798c..18677daad5d31f8dfcc4abd7c82834d9f4313f06 100644 (file)
@@ -52,7 +52,11 @@ override EFI_INCLUDES := $(EFI_INCLUDES)
 EFI_CRT_OBJS   = $(LOCAL_EFI_PATH)/crt0-efi-$(ARCH_GNUEFI).o
 EFI_LDS                = $(TOPDIR)/elf_$(ARCH)_efi.lds
 
-CLANG_BUGS     = $(if $(findstring gcc,$(CC)),-maccumulate-outgoing-args,)
+CLANG_WARNINGS = -Wno-pointer-bool-conversion \
+                -Wno-unknown-attributes
+
+CLANG_BUGS     = $(if $(findstring gcc,$(CC)),-maccumulate-outgoing-args,) \
+                 $(if $(findstring clang,$(CC)),$(CLANG_WARNINGS))
 
 COMMIT_ID ?= $(shell if [ -e .git ] ; then git log -1 --pretty=format:%H ; elif [ -f commit ]; then cat commit ; else echo master; fi)
 
@@ -64,7 +68,6 @@ ifeq ($(ARCH),x86_64)
        ARCH_SUFFIX             ?= x64
        ARCH_SUFFIX_UPPER       ?= X64
        ARCH_LDFLAGS            ?=
-       TIMESTAMP_LOCATION      := 136
 endif
 ifeq ($(ARCH),ia32)
        ARCH_CFLAGS             ?= -mno-mmx -mno-sse -mno-red-zone -nostdinc \
@@ -75,7 +78,6 @@ ifeq ($(ARCH),ia32)
        ARCH_SUFFIX_UPPER       ?= IA32
        ARCH_LDFLAGS            ?=
        ARCH_CFLAGS             ?= -m32
-       TIMESTAMP_LOCATION      := 136
 endif
 ifeq ($(ARCH),aarch64)
        ARCH_CFLAGS             ?= -DMDE_CPU_AARCH64 -DPAGE_SIZE=4096 -mstrict-align
@@ -86,7 +88,6 @@ ifeq ($(ARCH),aarch64)
        SUBSYSTEM               := 0xa
        ARCH_LDFLAGS            += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
        ARCH_CFLAGS             ?=
-       TIMESTAMP_LOCATION      := 72
 endif
 ifeq ($(ARCH),arm)
        ARCH_CFLAGS             ?= -DMDE_CPU_ARM -DPAGE_SIZE=4096 -mno-unaligned-access
@@ -96,7 +97,6 @@ ifeq ($(ARCH),arm)
        FORMAT                  := -O binary
        SUBSYSTEM               := 0xa
        ARCH_LDFLAGS            += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
-       TIMESTAMP_LOCATION      := 72
 endif
 
 DEFINES                = -DDEFAULT_LOADER='L"$(DEFAULT_LOADER)"' \
@@ -135,6 +135,7 @@ $(call update-variable,WERRFLAGS)
 CFLAGS         = $(FEATUREFLAGS) \
                  $(OPTIMIZATIONS) \
                  $(WARNFLAGS) \
+                 $(if $(findstring clang,$(CC)),$(CLANG_WARNINGS)) \
                  $(ARCH_CFLAGS) \
                  $(WERRFLAGS) \
                  $(INCLUDES) \
@@ -152,6 +153,10 @@ ifneq ($(origin DISABLE_EBS_PROTECTION), undefined)
        DEFINES  += -DDISABLE_EBS_PROTECTION
 endif
 
+ifneq ($(origin DISABLE_REMOVABLE_LOAD_OPTIONS), undefined)
+       DEFINES  += -DDISABLE_REMOVABLE_LOAD_OPTIONS
+endif
+
 LIB_GCC                = $(shell $(CC) $(ARCH_CFLAGS) -print-libgcc-file-name)
 EFI_LIBS       = -lefi -lgnuefi --start-group Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a --end-group $(LIB_GCC)
 FORMAT         ?= --target efi-app-$(ARCH)
index 8c66459c4f33932173865fdc0a0a644360f0467e..6b50b8fea0ce72207a1da817e02bd7183980bfd6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 default : all
 
 NAME           = shim
-VERSION                = 15.4
+VERSION                = 15.5
 ifneq ($(origin RELEASE),undefined)
 DASHRELEASE    ?= -$(RELEASE)
 else
@@ -38,12 +38,12 @@ CFLAGS += -DENABLE_SHIM_CERT
 else
 TARGETS += $(MMNAME) $(FBNAME)
 endif
-OBJS   = shim.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o sbat.o sbat_data.o pe.o httpboot.o csv.o
+OBJS   = shim.o globals.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o sbat.o sbat_data.o pe.o httpboot.o csv.o load-options.o
 KEYS   = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
-ORIG_SOURCES   = shim.c mok.c netboot.c replacements.c tpm.c errlog.c sbat.c pe.c httpboot.c shim.h version.h $(wildcard include/*.h)
-MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o errlog.o sbat_data.o
+ORIG_SOURCES   = shim.c globals.c mok.c netboot.c replacements.c tpm.c errlog.c sbat.c pe.c httpboot.c shim.h version.h $(wildcard include/*.h)
+MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o errlog.o sbat_data.o globals.o
 ORIG_MOK_SOURCES = MokManager.c PasswordCrypt.c crypt_blowfish.c shim.h $(wildcard include/*.h)
-FALLBACK_OBJS = fallback.o tpm.o errlog.o sbat_data.o
+FALLBACK_OBJS = fallback.o tpm.o errlog.o sbat_data.o globals.o
 ORIG_FALLBACK_SRCS = fallback.c
 SBATPATH = $(TOPDIR)/data/sbat.csv
 
@@ -61,6 +61,10 @@ ifneq ($(origin FALLBACK_VERBOSE), undefined)
        CFLAGS += -DFALLBACK_VERBOSE
 endif
 
+ifneq ($(origin FALLBACK_NONINTERACTIVE), undefined)
+       CFLAGS += -DFALLBACK_NONINTERACTIVE
+endif
+
 ifneq ($(origin FALLBACK_VERBOSE_WAIT), undefined)
        CFLAGS += -DFALLBACK_VERBOSE_WAIT=$(FALLBACK_VERBOSE_WAIT)
 endif
@@ -121,9 +125,10 @@ sbat_data.o : /dev/null
                $@
        $(foreach vs,$(VENDOR_SBATS),$(call add-vendor-sbat,$(vs),$@))
 
-$(SHIMNAME) : $(SHIMSONAME)
-$(MMNAME) : $(MMSONAME)
-$(FBNAME) : $(FBSONAME)
+$(SHIMNAME) : $(SHIMSONAME) post-process-pe
+$(MMNAME) : $(MMSONAME) post-process-pe
+$(FBNAME) : $(FBSONAME) post-process-pe
+$(SHIMNAME) $(MMNAME) $(FBNAME) : | post-process-pe
 
 LIBS = Cryptlib/libcryptlib.a \
        Cryptlib/OpenSSL/libopenssl.a \
@@ -148,7 +153,10 @@ gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a: C
 gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a:
        mkdir -p gnu-efi/lib gnu-efi/gnuefi
        $(MAKE) -C gnu-efi \
-               ARCH=$(ARCH_GNUEFI) TOPDIR=$(TOPDIR)/gnu-efi \
+               COMPILER="$(COMPILER)" \
+               CC="$(CC)" \
+               ARCH=$(ARCH_GNUEFI) \
+               TOPDIR=$(TOPDIR)/gnu-efi \
                -f $(TOPDIR)/gnu-efi/Makefile \
                lib gnuefi inc
 
@@ -164,6 +172,9 @@ lib/lib.a: | $(TOPDIR)/lib/Makefile $(wildcard $(TOPDIR)/include/*.[ch])
        mkdir -p lib
        $(MAKE) VPATH=$(TOPDIR)/lib TOPDIR=$(TOPDIR) -C lib -f $(TOPDIR)/lib/Makefile
 
+post-process-pe : $(TOPDIR)/post-process-pe.c
+       $(HOSTCC) -std=gnu11 -Og -g3 -Wall -Wextra -Wno-missing-field-initializers -Werror -o $@ $<
+
 buildid : $(TOPDIR)/buildid.c
        $(HOSTCC) -I/usr/include -Og -g3 -Wall -Werror -Wextra -o $@ $< -lelf
 
@@ -243,11 +254,10 @@ ifneq ($(OBJCOPY_GTE224),1)
 endif
        $(OBJCOPY) -D -j .text -j .sdata -j .data -j .data.ident \
                -j .dynamic -j .rodata -j .rel* \
-               -j .rela* -j .reloc -j .eh_frame \
+               -j .rela* -j .dyn -j .reloc -j .eh_frame \
                -j .vendor_cert -j .sbat \
                $(FORMAT) $< $@
-       # I am tired of wasting my time fighting binutils timestamp code.
-       dd conv=notrunc bs=1 count=4 seek=$(TIMESTAMP_LOCATION) if=/dev/zero of=$@
+       ./post-process-pe -vv $@
 
 ifneq ($(origin ENABLE_SHIM_HASH),undefined)
 %.hash : %.efi
@@ -260,7 +270,7 @@ ifneq ($(OBJCOPY_GTE224),1)
 endif
        $(OBJCOPY) -D -j .text -j .sdata -j .data \
                -j .dynamic -j .rodata -j .rel* \
-               -j .rela* -j .reloc -j .eh_frame -j .sbat \
+               -j .rela* -j .dyn -j .reloc -j .eh_frame -j .sbat \
                -j .debug_info -j .debug_abbrev -j .debug_aranges \
                -j .debug_line -j .debug_str -j .debug_ranges \
                -j .note.gnu.build-id \
@@ -277,8 +287,14 @@ else
        $(PESIGN) -n certdb -i $< -c "shim" -s -o $@ -f
 endif
 
-test :
-       @make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" all
+test test-clean test-coverage test-lto :
+       @make -f $(TOPDIR)/include/test.mk \
+               COMPILER="$(COMPILER)" \
+               CROSS_COMPILE="$(CROSS_COMPILE)" \
+               CLANG_WARNINGS="$(CLANG_WARNINGS)" \
+               ARCH_DEFINES="$(ARCH_DEFINES)" \
+               EFI_INCLUDES="$(EFI_INCLUDES)" \
+               test-clean $@
 
 $(patsubst %.c,%,$(wildcard test-*.c)) :
        @make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" $@
@@ -291,7 +307,11 @@ clean-test-objs:
 clean-gnu-efi:
        @if [ -d gnu-efi ] ; then \
                $(MAKE) -C gnu-efi \
-                       ARCH=$(ARCH_GNUEFI) TOPDIR=$(TOPDIR)/gnu-efi \
+                       CC="$(CC)" \
+                       HOSTCC="$(HOSTCC)" \
+                       COMPILER="$(COMPILER)" \
+                       ARCH=$(ARCH_GNUEFI) \
+                       TOPDIR=$(TOPDIR)/gnu-efi \
                        -f $(TOPDIR)/gnu-efi/Makefile \
                        clean ; \
        fi
@@ -303,7 +323,7 @@ clean-lib-objs:
 
 clean-shim-objs:
        @rm -rvf $(TARGET) *.o $(SHIM_OBJS) $(MOK_OBJS) $(FALLBACK_OBJS) $(KEYS) certdb $(BOOTCSVNAME)
-       @rm -vf *.debug *.so *.efi *.efi.* *.tar.* version.c buildid
+       @rm -vf *.debug *.so *.efi *.efi.* *.tar.* version.c buildid post-process-pe
        @rm -vf Cryptlib/*.[oa] Cryptlib/*/*.[oa]
        @if [ -d .git ] ; then git clean -f -d -e 'Cryptlib/OpenSSL/*'; fi
 
index cd1492f8ba12e0278a033e53df1f4bce860345f0..1359af83705512312f19a13612deaf49c339c043 100644 (file)
@@ -40,6 +40,12 @@ typedef struct {
        CHAR16 Password[SB_PASSWORD_LEN];
 } __attribute__ ((packed)) MokDBvar;
 
+typedef struct {
+       UINT32 MokTMLState;
+       UINT32 PWLen;
+       CHAR16 Password[SB_PASSWORD_LEN];
+} __attribute__ ((packed)) MokTMLvar;
+
 typedef struct {
        INT32 Timeout;
 } __attribute__ ((packed)) MokTimeoutvar;
@@ -333,6 +339,7 @@ static void show_x509_info(X509 * X509Cert, UINT8 * hash)
                for (i = 0; i < n; i++) {
                        CatPrint(&serial_string, L"%02x:", hexbuf[i]);
                }
+               BN_free(bnser);
        }
 
        if (serial_string.str)
@@ -735,7 +742,7 @@ done:
 
 static INTN reset_system()
 {
-       gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
+       RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
        console_notify(L"Failed to reboot\n");
        return -1;
 }
@@ -883,10 +890,10 @@ static EFI_STATUS write_db(CHAR16 * db_name, void *MokNew, UINTN MokNewSize)
        CopyMem(new_data, old_data, old_size);
        CopyMem(new_data + old_size, MokNew, MokNewSize);
 
-       efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
-                                     EFI_VARIABLE_NON_VOLATILE |
-                                     EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                                     new_size, new_data);
+       efi_status = RT->SetVariable(db_name, &SHIM_LOCK_GUID,
+                                    EFI_VARIABLE_NON_VOLATILE |
+                                    EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                    new_size, new_data);
 out:
        if (old_size > 0) {
                FreePool(old_data);
@@ -918,8 +925,8 @@ static EFI_STATUS store_keys(void *MokNew, UINTN MokNewSize, int authenticate,
        }
 
        if (authenticate) {
-               efi_status = gRT->GetVariable(auth_name, &SHIM_LOCK_GUID,
-                                             &attributes, &auth_size, auth);
+               efi_status = RT->GetVariable(auth_name, &SHIM_LOCK_GUID,
+                                            &attributes, &auth_size, auth);
                if (EFI_ERROR(efi_status) ||
                    (auth_size != SHA256_DIGEST_SIZE &&
                     auth_size != PASSWORD_CRYPT_SIZE)) {
@@ -945,10 +952,10 @@ static EFI_STATUS store_keys(void *MokNew, UINTN MokNewSize, int authenticate,
 
        if (!MokNewSize) {
                /* Delete MOK */
-               efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
-                                             EFI_VARIABLE_NON_VOLATILE |
-                                             EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                                             0, NULL);
+               efi_status = RT->SetVariable(db_name, &SHIM_LOCK_GUID,
+                                            EFI_VARIABLE_NON_VOLATILE |
+                                            EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                            0, NULL);
        } else {
                /* Write new MOK */
                efi_status = write_db(db_name, MokNew, MokNewSize);
@@ -1005,7 +1012,7 @@ static EFI_STATUS mok_reset_prompt(BOOLEAN MokX)
        EFI_STATUS efi_status;
        CHAR16 *prompt[] = { NULL, NULL };
 
-       ST->ConOut->ClearScreen(ST->ConOut);
+       clear_screen();
 
        if (MokX)
                prompt[0] = L"Erase all stored keys in MokListX?";
@@ -1064,10 +1071,10 @@ static EFI_STATUS write_back_mok_list(MokListNode * list, INTN key_num,
        }
        if (DataSize == 0) {
                dprint(L"DataSize = 0; deleting variable %s\n", db_name);
-               efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
-                                             EFI_VARIABLE_NON_VOLATILE |
-                                             EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                                             DataSize, Data);
+               efi_status = RT->SetVariable(db_name, &SHIM_LOCK_GUID,
+                                            EFI_VARIABLE_NON_VOLATILE |
+                                            EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                            DataSize, Data);
                dprint(L"efi_status:%llu\n", efi_status);
                return EFI_SUCCESS;
        }
@@ -1109,10 +1116,10 @@ static EFI_STATUS write_back_mok_list(MokListNode * list, INTN key_num,
                ptr = (uint8_t *) ptr + CertList->SignatureListSize;
        }
 
-       efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
-                                     EFI_VARIABLE_NON_VOLATILE |
-                                     EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                                     DataSize, Data);
+       efi_status = RT->SetVariable(db_name, &SHIM_LOCK_GUID,
+                                    EFI_VARIABLE_NON_VOLATILE |
+                                    EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                    DataSize, Data);
        if (Data)
                FreePool(Data);
 
@@ -1262,8 +1269,8 @@ static EFI_STATUS delete_keys(void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
                auth_name = L"MokDelAuth";
        }
 
-       efi_status = gRT->GetVariable(auth_name, &SHIM_LOCK_GUID, &attributes,
-                                     &auth_size, auth);
+       efi_status = RT->GetVariable(auth_name, &SHIM_LOCK_GUID, &attributes,
+                                    &auth_size, auth);
        if (EFI_ERROR(efi_status) ||
            (auth_size != SHA256_DIGEST_SIZE
             && auth_size != PASSWORD_CRYPT_SIZE)) {
@@ -1305,9 +1312,9 @@ static EFI_STATUS delete_keys(void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
                        err_strs[1] = L"Erase all keys in MokList!";
                }
                console_alertbox(err_strs);
-               gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
-                                EFI_VARIABLE_NON_VOLATILE |
-                                EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
+               RT->SetVariable(db_name, &SHIM_LOCK_GUID,
+                               EFI_VARIABLE_NON_VOLATILE |
+                               EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
                efi_status = EFI_ACCESS_DENIED;
                goto error;
        }
@@ -1327,9 +1334,9 @@ static EFI_STATUS delete_keys(void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
                        err_strs[1] = L"Reset MokList!";
                }
                console_alertbox(err_strs);
-               gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
-                                EFI_VARIABLE_NON_VOLATILE |
-                                EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
+               RT->SetVariable(db_name, &SHIM_LOCK_GUID,
+                               EFI_VARIABLE_NON_VOLATILE |
+                               EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
                efi_status = EFI_ABORTED;
                goto error;
        }
@@ -1468,7 +1475,7 @@ static EFI_STATUS mok_sb_prompt(void *MokSB, UINTN MokSBSize)
                return EFI_INVALID_PARAMETER;
        }
 
-       ST->ConOut->ClearScreen(ST->ConOut);
+       clear_screen();
 
        message[0] = L"Change Secure Boot state";
        message[1] = NULL;
@@ -1541,19 +1548,19 @@ static EFI_STATUS mok_sb_prompt(void *MokSB, UINTN MokSBSize)
        }
 
        if (var->MokSBState == 0) {
-               efi_status = gRT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
-                                             EFI_VARIABLE_NON_VOLATILE |
-                                             EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                                             1, &sbval);
+               efi_status = RT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
+                                            EFI_VARIABLE_NON_VOLATILE |
+                                            EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                            1, &sbval);
                if (EFI_ERROR(efi_status)) {
                        console_notify(L"Failed to set Secure Boot state");
                        return efi_status;
                }
        } else {
-               efi_status = gRT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
-                                             EFI_VARIABLE_NON_VOLATILE |
-                                             EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                                             0, NULL);
+               efi_status = RT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
+                                            EFI_VARIABLE_NON_VOLATILE |
+                                            EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                            0, NULL);
                if (EFI_ERROR(efi_status)) {
                        console_notify(L"Failed to delete Secure Boot state");
                        return efi_status;
@@ -1583,7 +1590,7 @@ static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize)
                return EFI_INVALID_PARAMETER;
        }
 
-       ST->ConOut->ClearScreen(ST->ConOut);
+       clear_screen();
 
        message[0] = L"Change DB state";
        message[1] = NULL;
@@ -1656,21 +1663,136 @@ static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize)
        }
 
        if (var->MokDBState == 0) {
-               efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
+               efi_status = RT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
+                                            EFI_VARIABLE_NON_VOLATILE |
+                                            EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                            1, &dbval);
+               if (EFI_ERROR(efi_status)) {
+                       console_notify(L"Failed to set DB state");
+                       return efi_status;
+               }
+       } else {
+               efi_status = RT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
+                                            EFI_VARIABLE_NON_VOLATILE |
+                                            EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                            0, NULL);
+               if (EFI_ERROR(efi_status)) {
+                       console_notify(L"Failed to delete DB state");
+                       return efi_status;
+               }
+       }
+
+       return EFI_SUCCESS;
+}
+
+static EFI_STATUS mok_tml_prompt(void *MokTML, UINTN MokTMLSize)
+{
+       EFI_STATUS efi_status;
+       SIMPLE_TEXT_OUTPUT_MODE SavedMode;
+       MokTMLvar *var = MokTML;
+       CHAR16 *message[4];
+       CHAR16 pass1, pass2, pass3;
+       CHAR16 *str;
+       UINT8 fail_count = 0;
+       UINT8 dbval = 1;
+       UINT8 pos1, pos2, pos3;
+       int ret;
+       CHAR16 *untrust_tml[] = { L"Do not trust the MOK list", NULL };
+       CHAR16 *trust_tml[] = { L"Trust the MOK list", NULL };
+
+       if (MokTMLSize != sizeof(MokTMLvar)) {
+               console_notify(L"Invalid MokTML variable contents");
+               return EFI_INVALID_PARAMETER;
+       }
+
+       clear_screen();
+
+       message[0] = L"Change Trusted MOK List Keyring state";
+       message[1] = NULL;
+
+       console_save_and_set_mode(&SavedMode);
+       console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
+       console_restore_mode(&SavedMode);
+
+       while (fail_count < 3) {
+               RandomBytes(&pos1, sizeof(pos1));
+               pos1 = (pos1 % var->PWLen);
+
+               do {
+                       RandomBytes(&pos2, sizeof(pos2));
+                       pos2 = (pos2 % var->PWLen);
+               } while (pos2 == pos1);
+
+               do {
+                       RandomBytes(&pos3, sizeof(pos3));
+                       pos3 = (pos3 % var->PWLen);
+               } while (pos3 == pos2 || pos3 == pos1);
+
+               str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
+               if (!str) {
+                       console_errorbox(L"Failed to allocate buffer");
+                       return EFI_OUT_OF_RESOURCES;
+               }
+               pass1 = get_password_charater(str);
+               FreePool(str);
+
+               str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
+               if (!str) {
+                       console_errorbox(L"Failed to allocate buffer");
+                       return EFI_OUT_OF_RESOURCES;
+               }
+               pass2 = get_password_charater(str);
+               FreePool(str);
+
+               str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
+               if (!str) {
+                       console_errorbox(L"Failed to allocate buffer");
+                       return EFI_OUT_OF_RESOURCES;
+               }
+               pass3 = get_password_charater(str);
+               FreePool(str);
+
+               if (pass1 != var->Password[pos1] ||
+                   pass2 != var->Password[pos2] ||
+                   pass3 != var->Password[pos3]) {
+                       console_print(L"Invalid character\n");
+                       fail_count++;
+               } else {
+                       break;
+               }
+       }
+
+       if (fail_count >= 3) {
+               console_notify(L"Password limit reached");
+               return EFI_ACCESS_DENIED;
+       }
+
+       if (var->MokTMLState == 0)
+               ret = console_yes_no(trust_tml);
+       else
+               ret = console_yes_no(untrust_tml);
+
+       if (ret == 0) {
+               LibDeleteVariable(L"MokListTrustedNew", &SHIM_LOCK_GUID);
+               return EFI_ABORTED;
+       }
+
+       if (var->MokTMLState == 0) {
+               efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
                                              EFI_VARIABLE_NON_VOLATILE |
                                              EFI_VARIABLE_BOOTSERVICE_ACCESS,
                                              1, &dbval);
                if (EFI_ERROR(efi_status)) {
-                       console_notify(L"Failed to set DB state");
+                       console_notify(L"Failed to set MokListTrusted state");
                        return efi_status;
                }
        } else {
-               efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
+               efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
                                              EFI_VARIABLE_NON_VOLATILE |
                                              EFI_VARIABLE_BOOTSERVICE_ACCESS,
                                              0, NULL);
                if (EFI_ERROR(efi_status)) {
-                       console_notify(L"Failed to delete DB state");
+                       console_notify(L"Failed to delete MokListTrusted state");
                        return efi_status;
                }
        }
@@ -1691,7 +1813,7 @@ static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
                return EFI_INVALID_PARAMETER;
        }
 
-       ST->ConOut->ClearScreen(ST->ConOut);
+       clear_screen();
 
        SetMem(hash, PASSWORD_CRYPT_SIZE, 0);
 
@@ -1707,9 +1829,9 @@ static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
                if (console_yes_no(clear_p) == 0)
                        return EFI_ABORTED;
 
-               gRT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
-                                EFI_VARIABLE_NON_VOLATILE |
-                                EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
+               RT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
+                               EFI_VARIABLE_NON_VOLATILE |
+                               EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
                goto mokpw_done;
        }
 
@@ -1729,10 +1851,10 @@ static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
        if (console_yes_no(set_p) == 0)
                return EFI_ABORTED;
 
-       efi_status = gRT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
-                                     EFI_VARIABLE_NON_VOLATILE |
-                                     EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                                     MokPWSize, MokPW);
+       efi_status = RT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
+                                    EFI_VARIABLE_NON_VOLATILE |
+                                    EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                    MokPWSize, MokPW);
        if (EFI_ERROR(efi_status)) {
                console_notify(L"Failed to set MOK password");
                return efi_status;
@@ -1994,8 +2116,8 @@ static BOOLEAN verify_pw(BOOLEAN * protected)
 
        *protected = FALSE;
 
-       efi_status = gRT->GetVariable(L"MokPWStore", &SHIM_LOCK_GUID, &attributes,
-                                     &size, pwhash);
+       efi_status = RT->GetVariable(L"MokPWStore", &SHIM_LOCK_GUID, &attributes,
+                                    &size, pwhash);
        /*
         * If anything can attack the password it could just set it to a
         * known value, so there's no safety advantage in failing to validate
@@ -2008,7 +2130,7 @@ static BOOLEAN verify_pw(BOOLEAN * protected)
        if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
                return TRUE;
 
-       ST->ConOut->ClearScreen(ST->ConOut);
+       clear_screen();
 
        /* Draw the background */
        console_save_and_set_mode(&SavedMode);
@@ -2076,7 +2198,8 @@ typedef enum {
        MOK_SET_PW,
        MOK_CHANGE_DB,
        MOK_KEY_ENROLL,
-       MOK_HASH_ENROLL
+       MOK_HASH_ENROLL,
+       MOK_CHANGE_TML
 } mok_menu_item;
 
 static void free_menu(mok_menu_item * menu_item, CHAR16 ** menu_strings)
@@ -2095,7 +2218,8 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
                                 void *MokPW, UINTN MokPWSize,
                                 void *MokDB, UINTN MokDBSize,
                                 void *MokXNew, UINTN MokXNewSize,
-                                void *MokXDel, UINTN MokXDelSize)
+                                void *MokXDel, UINTN MokXDelSize,
+                                void *MokTML, UINTN MokTMLSize)
 {
        CHAR16 **menu_strings = NULL;
        mok_menu_item *menu_item = NULL;
@@ -2122,29 +2246,29 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
                UINT32 MokXAuth = 0;
                UINT32 MokXDelAuth = 0;
 
-               efi_status = gRT->GetVariable(L"MokAuth", &SHIM_LOCK_GUID,
-                                             &attributes, &auth_size, auth);
+               efi_status = RT->GetVariable(L"MokAuth", &SHIM_LOCK_GUID,
+                                            &attributes, &auth_size, auth);
                if (!EFI_ERROR(efi_status) &&
                    (auth_size == SHA256_DIGEST_SIZE ||
                     auth_size == PASSWORD_CRYPT_SIZE))
                        MokAuth = 1;
 
-               efi_status = gRT->GetVariable(L"MokDelAuth", &SHIM_LOCK_GUID,
-                                             &attributes, &auth_size, auth);
+               efi_status = RT->GetVariable(L"MokDelAuth", &SHIM_LOCK_GUID,
+                                            &attributes, &auth_size, auth);
                if (!EFI_ERROR(efi_status) &&
                    (auth_size == SHA256_DIGEST_SIZE ||
                     auth_size == PASSWORD_CRYPT_SIZE))
                        MokDelAuth = 1;
 
-               efi_status = gRT->GetVariable(L"MokXAuth", &SHIM_LOCK_GUID,
-                                             &attributes, &auth_size, auth);
+               efi_status = RT->GetVariable(L"MokXAuth", &SHIM_LOCK_GUID,
+                                            &attributes, &auth_size, auth);
                if (!EFI_ERROR(efi_status) &&
                    (auth_size == SHA256_DIGEST_SIZE ||
                     auth_size == PASSWORD_CRYPT_SIZE))
                        MokXAuth = 1;
 
-               efi_status = gRT->GetVariable(L"MokXDelAuth", &SHIM_LOCK_GUID,
-                                             &attributes, &auth_size, auth);
+               efi_status = RT->GetVariable(L"MokXDelAuth", &SHIM_LOCK_GUID,
+                                            &attributes, &auth_size, auth);
                if (!EFI_ERROR(efi_status) &&
                    (auth_size == SHA256_DIGEST_SIZE ||
                     auth_size == PASSWORD_CRYPT_SIZE))
@@ -2171,6 +2295,9 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
                if (MokDB)
                        menucount++;
 
+               if (MokTML)
+                       menucount++;
+
                menu_strings = AllocateZeroPool(sizeof(CHAR16 *) *
                                                (menucount + 1));
                if (!menu_strings)
@@ -2242,6 +2369,12 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
                        i++;
                }
 
+               if (MokTML) {
+                       menu_strings[i] = L"Change MOK List Trusted State";
+                       menu_item[i] = MOK_CHANGE_TML;
+                       i++;
+               }
+
                menu_strings[i] = L"Enroll key from disk";
                menu_item[i] = MOK_KEY_ENROLL;
                i++;
@@ -2352,6 +2485,17 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
                case MOK_HASH_ENROLL:
                        efi_status = mok_hash_enroll();
                        break;
+               case MOK_CHANGE_TML:
+                       if (!MokTML) {
+                               console_print(L"MokManager: internal error: %s",
+                                       L"MokListTrusted was ! NULL bs is now NULL\n");
+                               ret = EFI_ABORTED;
+                               goto out;
+                       }
+                       efi_status = mok_tml_prompt(MokTML, MokTMLSize);
+                       if (!EFI_ERROR(efi_status))
+                               MokTML = NULL;
+                       break;
                }
 
                if (!EFI_ERROR(efi_status))
@@ -2376,7 +2520,7 @@ out:
 static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
 {
        UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
-       UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0;
+       UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0, MokTMLSize = 0;
        void *MokNew = NULL;
        void *MokDel = NULL;
        void *MokSB = NULL;
@@ -2384,6 +2528,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
        void *MokDB = NULL;
        void *MokXNew = NULL;
        void *MokXDel = NULL;
+       void *MokTML = NULL;
        EFI_STATUS efi_status;
 
        efi_status = get_variable(L"MokNew", (UINT8 **) & MokNew, &MokNewSize,
@@ -2436,6 +2581,18 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
                console_error(L"Could not retrieve MokDB", efi_status);
        }
 
+       efi_status = get_variable(L"MokListTrustedNew", (UINT8 **) & MokTML,
+                                 &MokTMLSize, SHIM_LOCK_GUID);
+       if (!EFI_ERROR(efi_status)) {
+               efi_status = LibDeleteVariable(L"MokListTrustedNew",
+                                              &SHIM_LOCK_GUID);
+               if (EFI_ERROR(efi_status))
+                       console_notify(L"Failed to delete MokListTrustedNew");
+       } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
+               console_error(L"Could not retrieve MokListTrustedNew",
+                             efi_status);
+       }
+
        efi_status = get_variable(L"MokXNew", (UINT8 **) & MokXNew,
                                  &MokXNewSize, SHIM_LOCK_GUID);
        if (!EFI_ERROR(efi_status)) {
@@ -2458,7 +2615,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
 
        enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
                       MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize,
-                      MokXNew, MokXNewSize, MokXDel, MokXDelSize);
+                      MokXNew, MokXNewSize, MokXDel, MokXDelSize, MokTML, MokTMLSize);
 
        if (MokNew)
                FreePool(MokNew);
@@ -2481,6 +2638,9 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
        if (MokXDel)
                FreePool(MokXDel);
 
+       if (MokTML)
+               FreePool(MokTML);
+
        LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
        LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID);
        LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
@@ -2496,7 +2656,7 @@ static EFI_STATUS setup_rand(void)
        UINT64 seed;
        BOOLEAN status;
 
-       efi_status = gRT->GetTime(&time, NULL);
+       efi_status = RT->GetTime(&time, NULL);
        if (EFI_ERROR(efi_status))
                return efi_status;
 
index 4b80a4134876649e6496bedaba51e56179deeba7..cdfec2c8eb8427ff52f5b934dec81bb536052e87 100644 (file)
@@ -77,3 +77,9 @@ or not to import DB certs for its own verification purposes.
 MokPWStore: A SHA-256 representation of the password set by the user
 via MokPW. The user will be prompted to enter this password in order
 to interact with MokManager.
+
+MokListTrusted: An 8-bit unsigned integer.  If 1, it signifies to Linux
+to trust CA keys in the MokList. BS,NV
+
+MokListTrustedRT: A copy of MokListTrusted made available to the kernel
+at runtime. RT
index 400765b196c26a49719497afa17a17df8803ec5c..930f71a129c5a4516dfc4d0e02514c6e0ddd9424 100644 (file)
@@ -16,7 +16,7 @@ the `.sbat` section has the following fields:
 
 `SBAT` EFI variable
 -----------------
-The SBAT EFI variable (`SBAT-605dab50-e046-4300-abb6-3dd810dd8b23`) is structured as a series ASCII CSV records:
+The SBAT EFI variable (`SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23`) is structured as a series ASCII CSV records:
 
 ```
 sbat,1
@@ -192,7 +192,7 @@ Debian discovers that they actually shipped bug 0 as well (woops).  They
 produce a new build which fixes it and has the following in `.sbat`:
 ```
 sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
-grub,1,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
+grub,2,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
 grub.debian,2,Debian,grub2,2.04-13,https://packages.debian.org/source/sid/grub2
 ```
 
diff --git a/SBAT.md b/SBAT.md
index 1a5ecad9b2b71aa3514cd466afd0918b22a8489a..d44789289c3a2aa21d1f8711b02b3d2a52a5be79 100644 (file)
--- a/SBAT.md
+++ b/SBAT.md
@@ -6,7 +6,7 @@ In the PC ecosystem, [UEFI Secure Boot](https://docs.microsoft.com/en-us/windows
 is typically configured to trust 2 authorities for signing UEFI boot code, the
 Microsoft UEFI Certificate Authority (CA) and Windows CA. When malicious or
 security compromised code is detected, 2 revocation mechanisms are provided by
-compatible UEFI implementations, signing certificate or image hash. The UEFI
+compatible UEFI implementations: signing certificate or image hash. The UEFI
 Specification does not provides any well tested additional revocation
 mechanisms.
 
@@ -140,21 +140,29 @@ value associated with the data currently stored in that variable.
 
 #### Generation-Based Revocation Scenarios
 
-Products (**not** vendors, a vendor can have multiple products or even pass a
+**Products** (**not** vendors, a vendor can have multiple products or even pass a
 product from one vendor to another over time) are assigned a name. Product
 names can specify a specific version or refer to the entire product family. For
 example mydistro and mydistro,12.
 
-Components that are used as a link in the UEFI Secure Boot chain of trust are
+**Components** that are used as a link in the UEFI Secure Boot chain of trust are
 assigned names. Examples of components are shim, GRUB, kernel, hypervisors, etc.
 
+Below is an example of a product and component, both in the same `sbat.csv` file. `sbat`
+defines the version of the format of the revocation metadata itself.
+`grub.acme` is an example of a product name.
+```
+sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
+grub.acme,1,Acme Corporation,grub,1.96-8191,https://acme.arpa/packages/grub
+```
+
 We could conceivably support sub-components, but it's hard to conceive of a
 scenario that would trigger a UEFI variable update that wouldn't justify a
 hypervisor or kernel re-release to enforce that sub-component level from there.
 Something like a "level 1.5 hypervisor" that can exist between different kernel
 generations can be considered its own component.
 
-Each component is assigned a minimum global generation number. Vendors signing
+Each component is assigned a **minimum global generation number**. Vendors signing
 component binary artifacts with a specific global generation number are
 required to include fixes for any public or pre-disclosed issue required for
 that generation. Additionally, in the event that a bypass only manifests in a
@@ -162,7 +170,9 @@ specific product's component, vendors may ask for a product-specific generation
 number to be published for one of their product's components. This avoids
 triggering an industry wide re-publishing of otherwise safe components.
 
-A product-specific minimum generation number only applies to the instance of
+In the example above, 1 is sbat's minimum global generation number.
+
+A **product-specific minimum generation number** only applies to the instance of
 that component that is signed with that product name. Another product's
 instance of the same component may be installed on the same system and would
 not be subject to the other product's product-specific minimum generation
@@ -174,6 +184,8 @@ entire industry that uses that component re-release, just that product's
 minimum generation number would be incremented and that product's component
 re-released along with a UEFI variable update specifying that requirement.
 
+In the example above, 1 is grub.acme's product-specific minimum generation number.
+
 The global and product-specific generation number name spaces are not tied to
 each other. The global number is managed externally, and the vast majority of
 products will never publish a minimum product-specific generation number for
@@ -232,8 +244,8 @@ number, this product-specific number can be dropped from the UEFI revocation
 variable.
 
 If this same Vendor C has a similar event after the global number is
-incremented, they would again set their product-specific or version-specific
-number to 1. If they have a second event on with the same component, they would
+incremented, they would again set their product-specific or **version-specific
+number** to 1. If they have a second event on the same component, they would
 set their product-specific or version-specific number to 2.
 
 In such an event, a vendor would set the product-specific or version-specific
@@ -242,15 +254,17 @@ branches or in just a subset of them. The goal is generally to limit end
 customer impact with as few re-releases as possible, while not creating an
 unnecessarily large UEFI revocation variable payload.
 
-|                                                                                      | prior to<br>disclosure | after<br>disclosure | after Vendor C's<br>first update | after Vendor C's<br>second update | after next global<br>disclosure |
+|                                                                                      | prior to<br>disclosure\* | after<br>disclosure | after Vendor C's<br>first update | after Vendor C's<br>second update | after next global<br>disclosure |
 |--------------------------------------------------------------------------------------|------------------------|---------------------|----------------------------------|----------------------------------|---------------------------------|
 | GRUB global<br>generation number in<br>artifacts .sbat section                       | 3                      | 4                   | 4                                | 4                                | 5                               |
-| Vendor C's product-specific<br>generation number in artifact's<br>.sbat section      | 1                      | 1                   | 5                                | 6                                | 1                               |
+| Vendor C's product-specific<br>generation number in artifact's<br>.sbat section      | 1                      | 1                   | 2                                | 3                                | 1                               |
 | GRUB global<br>generation number in<br>UEFI SBAT revocation variable                 | 3                      | 4                   | 4                                | 4                                | 5                               |
-| Vendor C's product-specific<br>generation number in<br>UEFI SBAT revocation variable | not set                | not set             | 5                                | 6                                | not set                         |
+| Vendor C's product-specific<br>generation number in<br>UEFI SBAT revocation variable | not set                | not set             | 2                                | 3                                | not set                         |
+
+\* A disclosure is the event/date where a CVE and fixes for it are made public.
 
 The product-specific generation number does not reset and continues to
-monotonically increase over the course of these events.        Continuity of more
+monotonically increase over the course of these non-global events. Continuity of more
 specific generation numbers must be maintained in this way in order to satisfy
 checks against older revocation data.
 
@@ -258,6 +272,10 @@ The variable payload will be stored publicly in the shim source base and
 identify the global generation associated with a product or version-specific
 one. The payload is also built into shim to additionally limit exposure.
 
+At this time of writing, all version-numbers are set to 1. Presumably at some point,
+updated numbers will be published on the respective websites of the associated vendors
+and components.
+
 #### Retiring Signed Releases
 
 Products that have reached the end of their support life by definition no
@@ -269,7 +287,7 @@ that the global generation numbers will eventually move forward and exclude
 those products from booting on a UEFI Secure Boot enabled system. However a
 product made up of GRUB and a closed source kernel is just as conceivable. In
 that case the kernel version may never move forward once the product reaches
-its end of support. Therefor it is recommended that the product-specific
+its end of support. Therefore it is recommended that the product-specific
 generation number be incremented past the latest one shown in any binary for
 that product, effectively disabling that product on UEFI Secure Boot enabled
 systems.
@@ -309,8 +327,8 @@ compromise.
 
 The initial SBAT implementation will add SBAT metadata to Shim and GRUB and
 enforce SBAT on all components labeled with it. Until a component (e.g. the
-Linux kernel gains SBAT metadata) it can not be revoked via SBAT, but only by
-revoking the keys signing that component. These keys will should live in
+Linux kernel) gains SBAT metadata it can not be revoked via SBAT, but only by
+revoking the keys signing that component. These keys will live in
 separate, product-specific signed PE files that contain **only** the
 certificate and SBAT metadata for the key files. These key files can then be
 revoked via SBAT in order to invalidate and replace a specific key. While
@@ -346,7 +364,7 @@ Adding a .sbat section containing the SBAT metadata structure to PE images.
 | vendor_url | url to look stuff up, contact, whatever.
 
 The format of this .sbat section is comma separated values, or more
-specifically UTF-8 encoded strings.
+specifically ASCII encoded strings.
 
 ## Example sbat sections
 
diff --git a/commit b/commit
index 6ab67e7e26da01b0d8aee456b83bdf83dc46cd1d..ef9904932131d845e335a29f88c6fe9594c1bd7d 100644 (file)
--- a/commit
+++ b/commit
@@ -1 +1 @@
-20e4d9486fcae54ee44d2323ae342ffe68c920e6
\ No newline at end of file
+f2c598bb2218da966872ba3e0c6e7e830dca6ef0
\ No newline at end of file
diff --git a/csv.c b/csv.c
index f6b37f150f09eaaccd352d1b2df60fbc83b45521..18460cd7be863f85b369cd85f55219e1092145f9 100644 (file)
--- a/csv.c
+++ b/csv.c
@@ -15,6 +15,7 @@ parse_csv_line(char * line, size_t max, size_t *n_columns, const char *columns[]
        char *token = NULL;
 
        bool valid = true;
+
        for (n = 0; n < *n_columns; n++) {
 
                if (valid) {
@@ -62,19 +63,21 @@ parse_csv_data(char *data, char *data_end, size_t n_columns, list_t *list)
        }
 
        max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
+       if (is_utf8_bom(line, max))
 
-       if (line && is_utf8_bom(line, max))
                line += UTF8_BOM_SIZE;
 
-       while (line && line <= data_end) {
+       while (line <= data_end && *line) {
                size_t entrysz = sizeof(char *) * n_columns + sizeof(struct csv_row);
                struct csv_row *entry;
                size_t m_columns = n_columns;
                char *delim;
                bool found = true;
+               bool eof = false;
 
                end = data_end;
                max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
+               /* Skip the delimiter(s) of the previous line */
                while (max && found) {
                        found = false;
                        for (delim = &delims[0]; max && *delim; delim++) {
@@ -85,12 +88,16 @@ parse_csv_data(char *data, char *data_end, size_t n_columns, list_t *list)
                                }
                        }
                }
+               /* Find the first delimiter of the current line */
                for (delim = &delims[0]; *delim; delim++) {
                        char *tmp = strnchrnul(line, max, *delim);
                        if (tmp < end)
                                end = tmp;
                }
                max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
+
+               if (!*end)
+                       eof = true;
                *end = '\0';
 
                if (line == data_end || max == 0) {
@@ -115,6 +122,9 @@ parse_csv_data(char *data, char *data_end, size_t n_columns, list_t *list)
 
                parse_csv_line(line, max, &m_columns, (const char **)entry->columns);
                entry->n_columns = m_columns;
+               if (eof)
+                       break;
+
                line = end + 1;
        }
 
index 353b24a0533995eaac1b180d681ed6a581569d15..42825fd939de03ef3cb03c5b6bece9b891544f1e 100644 (file)
@@ -70,21 +70,29 @@ SECTIONS
   .rodata :
   {
     _rodata = .;
-    *(.rela.dyn)
-    *(.rela.plt)
-    *(.rela.got)
-    *(.rela.data)
-    *(.rela.data*)
-
     *(.rodata*)
     *(.srodata)
-    *(.dynsym)
-    *(.dynstr)
     . = ALIGN(16);
     *(.note.gnu.build-id)
     . = ALIGN(4096);
     *(.vendor_cert)
     *(.data.ident)
+    . = ALIGN(4096);
+  }
+  . = ALIGN(4096);
+  .rela :
+  {
+    *(.rela.dyn)
+    *(.rela.plt)
+    *(.rela.got)
+    *(.rela.data)
+    *(.rela.data*)
+  }
+  . = ALIGN(4096);
+  .dyn :
+  {
+    *(.dynsym)
+    *(.dynstr)
     _evrodata = .;
     . = ALIGN(4096);
   }
index e4e29bdf3b15c3507b265a246575e171592ed399..5334621930da4512ee3382cafc67bf4ea4e71df8 100644 (file)
@@ -70,21 +70,29 @@ SECTIONS
   .rodata :
   {
     _rodata = .;
-    *(.rel.dyn)
-    *(.rel.plt)
-    *(.rel.got)
-    *(.rel.data)
-    *(.rel.data*)
-
     *(.rodata*)
     *(.srodata)
-    *(.dynsym)
-    *(.dynstr)
     . = ALIGN(16);
     *(.note.gnu.build-id)
     . = ALIGN(4096);
     *(.vendor_cert)
     *(.data.ident)
+    . = ALIGN(4096);
+  }
+  . = ALIGN(4096);
+  .rela :
+  {
+    *(.rela.dyn)
+    *(.rela.plt)
+    *(.rela.got)
+    *(.rela.data)
+    *(.rela.data*)
+  }
+  . = ALIGN(4096);
+  .dyn :
+  {
+    *(.dynsym)
+    *(.dynstr)
     _evrodata = .;
     . = ALIGN(4096);
   }
index 742e0a47a732c210fba0eeaaa8c99fa493c6d931..497a3a1526549b7b3faf138ac4c9757e9e5e7a5d 100644 (file)
@@ -15,6 +15,7 @@ SECTIONS
    *(.gnu.linkonce.t.*)
    _etext = .;
   }
+  . = ALIGN(4096);
   .reloc :
   {
    *(.reloc)
index 8d89917a5cbc845d3c4b99580c77babbf45d4bf9..8e6327be8bb983574c2b7c5773838adcfc7f2eae 100644 (file)
@@ -158,7 +158,7 @@ read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
        }
 
        b = AllocateZeroPool(len + 2);
-       if (!buffer) {
+       if (!b) {
                console_print(L"Could not allocate memory\n");
                fh2->Close(fh2);
                return EFI_OUT_OF_RESOURCES;
@@ -166,7 +166,7 @@ read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
 
        efi_status = fh->Read(fh, &len, b);
        if (EFI_ERROR(efi_status)) {
-               FreePool(buffer);
+               FreePool(b);
                fh2->Close(fh2);
                console_print(L"Could not read file: %r\n", efi_status);
                return efi_status;
@@ -230,8 +230,11 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
                                StrLen(label)*2 + 2 + DevicePathSize(hddp) +
                                StrLen(arguments) * 2;
 
-                       CHAR8 *data = AllocateZeroPool(size + 2);
-                       CHAR8 *cursor = data;
+                       CHAR8 *data, *cursor;
+                       cursor = data = AllocateZeroPool(size + 2);
+                       if (!data)
+                               return EFI_OUT_OF_RESOURCES;
+
                        *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
                        cursor += sizeof (UINT32);
                        *(UINT16 *)cursor = DevicePathSize(hddp);
@@ -248,11 +251,11 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
 
                        if (!first_new_option) {
                                first_new_option = DuplicateDevicePath(fulldp);
-                               first_new_option_args = arguments;
+                               first_new_option_args = StrDuplicate(arguments);
                                first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
                        }
 
-                       efi_status = gRT->SetVariable(varname, &GV_GUID,
+                       efi_status = RT->SetVariable(varname, &GV_GUID,
                                                EFI_VARIABLE_NON_VOLATILE |
                                                EFI_VARIABLE_BOOTSERVICE_ACCESS |
                                                EFI_VARIABLE_RUNTIME_ACCESS,
@@ -415,9 +418,12 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
        cursor += DevicePathSize(dp);
        StrCpy((CHAR16 *)cursor, arguments);
 
-       CHAR16 varname[256];
        EFI_STATUS efi_status;
        EFI_GUID vendor_guid = NullGuid;
+       UINTN buffer_size = 256 * sizeof(CHAR16);
+       CHAR16 *varname = AllocateZeroPool(buffer_size);
+       if (!varname)
+               return EFI_OUT_OF_RESOURCES;
 
        UINTN max_candidate_size = calc_masked_boot_option_size(size);
        CHAR8 *candidate = AllocateZeroPool(max_candidate_size);
@@ -426,13 +432,34 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
                return EFI_OUT_OF_RESOURCES;
        }
 
-       varname[0] = 0;
        while (1) {
-               UINTN varname_size = sizeof(varname);
-               efi_status = gRT->GetNextVariableName(&varname_size, varname,
-                                                     &vendor_guid);
-               if (EFI_ERROR(efi_status))
+               UINTN varname_size = buffer_size;
+               efi_status = RT->GetNextVariableName(&varname_size, varname,
+                                                    &vendor_guid);
+               if (EFI_ERROR(efi_status)) {
+                       if (efi_status == EFI_BUFFER_TOO_SMALL) {
+                               VerbosePrint(L"Buffer too small for next variable name, re-allocating it to be %d bytes and retrying\n",
+                                            varname_size);
+                               varname = ReallocatePool(varname,
+                                                        buffer_size,
+                                                        varname_size);
+                               if (!varname)
+                                       return EFI_OUT_OF_RESOURCES;
+                               buffer_size = varname_size;
+                               continue;
+                       }
+
+                       if (efi_status == EFI_DEVICE_ERROR)
+                               VerbosePrint(L"The next variable name could not be retrieved due to a hardware error\n");
+
+                       if (efi_status == EFI_INVALID_PARAMETER)
+                               VerbosePrint(L"Invalid parameter to GetNextVariableName: varname_size=%d, varname=%s\n",
+                                            varname_size, varname);
+
+                       /* EFI_NOT_FOUND means we listed all variables */
+                       VerbosePrint(L"Checked all boot entries\n");
                        break;
+               }
 
                if (StrLen(varname) != 8 || StrnCmp(varname, L"Boot", 4) ||
                    !isxdigit(varname[4]) || !isxdigit(varname[5]) ||
@@ -440,8 +467,8 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
                        continue;
 
                UINTN candidate_size = max_candidate_size;
-               efi_status = gRT->GetVariable(varname, &GV_GUID, NULL,
-                                             &candidate_size, candidate);
+               efi_status = RT->GetVariable(varname, &GV_GUID, NULL,
+                                            &candidate_size, candidate);
                if (EFI_ERROR(efi_status))
                        continue;
 
@@ -458,7 +485,7 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
                /* at this point, we have duplicate data. */
                if (!first_new_option) {
                        first_new_option = DuplicateDevicePath(fulldp);
-                       first_new_option_args = arguments;
+                       first_new_option_args = StrDuplicate(arguments);
                        first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
                }
 
@@ -469,7 +496,8 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
        }
        FreePool(candidate);
        FreePool(data);
-       return EFI_NOT_FOUND;
+       FreePool(varname);
+       return efi_status;
 }
 
 EFI_STATUS
@@ -513,15 +541,15 @@ update_boot_order(void)
        for (j = 0 ; j < size / sizeof (CHAR16); j++)
                VerbosePrintUnprefixed(L"%04x ", newbootorder[j]);
        VerbosePrintUnprefixed(L"\n");
-       efi_status = gRT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL);
+       efi_status = RT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL);
        if (efi_status == EFI_BUFFER_TOO_SMALL)
                LibDeleteVariable(L"BootOrder", &GV_GUID);
 
-       efi_status = gRT->SetVariable(L"BootOrder", &GV_GUID,
-                                     EFI_VARIABLE_NON_VOLATILE |
-                                     EFI_VARIABLE_BOOTSERVICE_ACCESS |
-                                     EFI_VARIABLE_RUNTIME_ACCESS,
-                                     size, newbootorder);
+       efi_status = RT->SetVariable(L"BootOrder", &GV_GUID,
+                                    EFI_VARIABLE_NON_VOLATILE |
+                                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                    EFI_VARIABLE_RUNTIME_ACCESS,
+                                    size, newbootorder);
        FreePool(newbootorder);
        return efi_status;
 }
@@ -544,7 +572,7 @@ add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *argum
        full_device_path = FileDevicePath(this_image->DeviceHandle, fullpath);
        if (!full_device_path) {
                efi_status = EFI_OUT_OF_RESOURCES;
-               goto err;
+               goto done;
        }
        dps = DevicePathToStr(full_device_path);
        VerbosePrint(L"file DP: %s\n", dps);
@@ -558,7 +586,7 @@ add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *argum
                        dp = full_device_path;
                } else {
                        efi_status = EFI_OUT_OF_RESOURCES;
-                       goto err;
+                       goto done;
                }
        }
 
@@ -587,21 +615,53 @@ add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *argum
        if (EFI_ERROR(efi_status)) {
                add_boot_option(dp, full_device_path, fullpath, label,
                                arguments);
-       } else if (option != 0) {
-               CHAR16 *newbootorder;
-               newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder);
-               if (!newbootorder)
-                       return EFI_OUT_OF_RESOURCES;
+               goto done;
+       }
 
-               newbootorder[0] = bootorder[option];
-               CopyMem(newbootorder + 1, bootorder, sizeof (CHAR16) * option);
-               CopyMem(newbootorder + option + 1, bootorder + option + 1,
-                       sizeof (CHAR16) * (nbootorder - option - 1));
+       UINT16 bootnum;
+       CHAR16 *newbootorder;
+       /* Search for the option in the current bootorder */
+       for (bootnum = 0; bootnum < nbootorder; bootnum++)
+               if (bootorder[bootnum] == option)
+                       break;
+       if (bootnum == nbootorder) {
+               /* Option not found, prepend option and copy the rest */
+               newbootorder = AllocateZeroPool(sizeof(CHAR16)
+                                               * (nbootorder + 1));
+               if (!newbootorder) {
+                       efi_status = EFI_OUT_OF_RESOURCES;
+                       goto done;
+               }
+               newbootorder[0] = option;
+               CopyMem(newbootorder + 1, bootorder,
+                       sizeof(CHAR16) * nbootorder);
+               FreePool(bootorder);
+               bootorder = newbootorder;
+               nbootorder += 1;
+       } else {
+               /* Option found, put first and slice the rest */
+               newbootorder = AllocateZeroPool(
+                       sizeof(CHAR16) * nbootorder);
+               if (!newbootorder) {
+                       efi_status = EFI_OUT_OF_RESOURCES;
+                       goto done;
+               }
+               newbootorder[0] = option;
+               CopyMem(newbootorder + 1, bootorder,
+                       sizeof(CHAR16) * bootnum);
+               CopyMem(newbootorder + 1 + bootnum,
+                       bootorder + bootnum + 1,
+                       sizeof(CHAR16) * (nbootorder - bootnum - 1));
                FreePool(bootorder);
                bootorder = newbootorder;
        }
+       VerbosePrint(L"New nbootorder: %d\nBootOrder: ",
+                     nbootorder);
+       for (int i = 0 ; i < nbootorder ; i++)
+               VerbosePrintUnprefixed(L"%04x ", bootorder[i]);
+       VerbosePrintUnprefixed(L"\n");
 
-err:
+done:
        if (full_device_path)
                FreePool(full_device_path);
        if (dp && dp != full_device_path)
@@ -832,8 +892,8 @@ find_boot_options(EFI_HANDLE device)
        EFI_STATUS efi_status;
        EFI_FILE_IO_INTERFACE *fio = NULL;
 
-       efi_status = gBS->HandleProtocol(device, &FileSystemProtocol,
-                                        (void **) &fio);
+       efi_status = BS->HandleProtocol(device, &FileSystemProtocol,
+                                       (void **) &fio);
        if (EFI_ERROR(efi_status)) {
                console_print(L"Couldn't find file system: %r\n", efi_status);
                return efi_status;
@@ -960,8 +1020,8 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
                return EFI_SUCCESS;
        }
 
-       efi_status = gBS->LoadImage(0, parent_image_handle, first_new_option,
-                                   NULL, 0, &image_handle);
+       efi_status = BS->LoadImage(0, parent_image_handle, first_new_option,
+                                  NULL, 0, &image_handle);
        if (EFI_ERROR(efi_status)) {
                CHAR16 *dps = DevicePathToStr(first_new_option);
                UINTN s = DevicePathSize(first_new_option);
@@ -981,14 +1041,14 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
        }
 
        EFI_LOADED_IMAGE *image;
-       efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol,
-                                        (void *) &image);
+       efi_status = BS->HandleProtocol(image_handle, &LoadedImageProtocol,
+                                       (void *) &image);
        if (!EFI_ERROR(efi_status)) {
                image->LoadOptions = first_new_option_args;
                image->LoadOptionsSize = first_new_option_size;
        }
 
-       efi_status = gBS->StartImage(image_handle, NULL, NULL);
+       efi_status = BS->StartImage(image_handle, NULL, NULL);
        if (EFI_ERROR(efi_status)) {
                console_print(L"StartImage failed: %r\n", efi_status);
                msleep(500000000);
@@ -1003,24 +1063,25 @@ get_fallback_no_reboot(void)
        UINT32 no_reboot;
        UINTN size = sizeof(UINT32);
 
-       efi_status = gRT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
-                                     NULL, &size, &no_reboot);
+       efi_status = RT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
+                                    NULL, &size, &no_reboot);
        if (!EFI_ERROR(efi_status)) {
                return no_reboot;
        }
        return 0;
 }
 
+#ifndef FALLBACK_NONINTERACTIVE
 static EFI_STATUS
 set_fallback_no_reboot(void)
 {
        EFI_STATUS efi_status;
        UINT32 no_reboot = 1;
-       efi_status = gRT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
-                                     EFI_VARIABLE_NON_VOLATILE
-                                     | EFI_VARIABLE_BOOTSERVICE_ACCESS
-                                     | EFI_VARIABLE_RUNTIME_ACCESS,
-                                     sizeof(UINT32), &no_reboot);
+       efi_status = RT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
+                                    EFI_VARIABLE_NON_VOLATILE |
+                                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                    EFI_VARIABLE_RUNTIME_ACCESS,
+                                    sizeof(UINT32), &no_reboot);
        return efi_status;
 }
 
@@ -1054,6 +1115,7 @@ get_user_choice(void)
 
        return choice;
 }
+#endif
 
 extern EFI_STATUS
 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
@@ -1097,8 +1159,8 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
         */
        debug_hook();
 
-       efi_status = gBS->HandleProtocol(image, &LoadedImageProtocol,
-                                        (void *) &this_image);
+       efi_status = BS->HandleProtocol(image, &LoadedImageProtocol,
+                                       (void *) &this_image);
        if (EFI_ERROR(efi_status)) {
                console_print(L"Error: could not find loaded image: %r\n",
                              efi_status);
@@ -1126,6 +1188,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
                        try_start_first_option(image);
                }
 
+#ifndef FALLBACK_NONINTERACTIVE
                int timeout = draw_countdown();
                if (timeout == 0)
                        goto reset;
@@ -1141,6 +1204,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
                VerbosePrint(L"tpm present, starting the first image\n");
                try_start_first_option(image);
 reset:
+#endif
                VerbosePrint(L"tpm present, resetting system\n");
        }
 
@@ -1157,7 +1221,7 @@ reset:
                msleep(fallback_verbose_wait);
        }
 
-       gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
+       RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
 
        return EFI_SUCCESS;
 }
diff --git a/globals.c b/globals.c
new file mode 100644 (file)
index 0000000..4a1f432
--- /dev/null
+++ b/globals.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * globals.c - global shim state
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#include "shim.h"
+
+UINT32 vendor_authorized_size = 0;
+UINT8 *vendor_authorized = NULL;
+
+UINT32 vendor_deauthorized_size = 0;
+UINT8 *vendor_deauthorized = NULL;
+
+#if defined(ENABLE_SHIM_CERT)
+UINT32 build_cert_size;
+UINT8 *build_cert;
+#endif /* defined(ENABLE_SHIM_CERT) */
+
+/*
+ * indicator of how an image has been verified
+ */
+verification_method_t verification_method;
+int loader_is_participating;
+
+UINT8 user_insecure_mode;
+UINT8 ignore_db;
+UINT8 trust_mok_list;
+
+UINT32 verbose = 0;
+
+// vim:fenc=utf-8:tw=75:noet
index fd1d123d85144b30ff12501eeba99c54b0f07a20..5ce8f7cbf0e9b4d29d4a7c79ff6a1b63b6d15c96 100755 (executable)
@@ -124,10 +124,10 @@ ifeq ($(ARCH),x86_64)
                             || ( [ $(GCCVERSION) -eq "4" ]      \
                                  && [ $(GCCMINOR) -ge "7" ] ) ) \
                           && echo 1)
-  ifeq ($(GCCNEWENOUGH),1)
-    CPPFLAGS += -DGNU_EFI_USE_MS_ABI -DGNU_EFI_USE_EXTERNAL_STDARG -maccumulate-outgoing-args --std=c11
-  else ifeq ($(USING_CLANG),clang)
+  ifeq ($(USING_CLANG),clang)
     CPPFLAGS += -DGNU_EFI_USE_MS_ABI -DGNU_EFI_USE_EXTERNAL_STDARG --std=c11
+  else ifeq ($(GCCNEWENOUGH),1)
+    CPPFLAGS += -DGNU_EFI_USE_MS_ABI -DGNU_EFI_USE_EXTERNAL_STDARG -maccumulate-outgoing-args --std=c11
   endif
 
   CFLAGS += -mno-red-zone
@@ -193,6 +193,7 @@ CFLAGS  += $(ARCH3264) $(OPTIMIZATIONS) \
            -fshort-wchar -fno-strict-aliasing \
           -ffreestanding -fno-stack-protector \
            -fno-stack-check -nostdinc \
+          $(CFLAGS_LTO) $(CFLAGS_GCOV) \
           -isystem $(TOPDIR)/../include/system \
           -isystem $(shell $(CC) $(ARCH3264) -print-file-name=include) \
            $(if $(findstring gcc,$(CC)),-fno-merge-all-constants,)
index bdf5de26a3fd9f9d43b45f5fd4e1d182d4a538d7..96e9e4a011ee37c0d2ab550b361cfdfe09b5a049 100644 (file)
@@ -229,6 +229,7 @@ VOID
 #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS            0x00000010
 #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
 #define EFI_VARIABLE_APPEND_WRITE                          0x00000040
+#define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS        0x00000080
 
 // Variable size limitation
 #define EFI_MAXIMUM_VARIABLE_SIZE           1024
@@ -751,6 +752,8 @@ typedef struct _EFI_TABLE_HEADER {
 //
 
 #define EFI_RUNTIME_SERVICES_SIGNATURE  0x56524553544e5552
+#define EFI_1_10_RUNTIME_SERVICES_REVISION ((1<<16) | (10))
+#define EFI_2_00_RUNTIME_SERVICES_REVISION ((2<<16) | (0))
 #define EFI_RUNTIME_SERVICES_REVISION   (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)
 
 typedef struct  {
@@ -798,6 +801,8 @@ typedef struct  {
 //
 
 #define EFI_BOOT_SERVICES_SIGNATURE     0x56524553544f4f42
+#define EFI_1_10_BOOT_SERVICES_REVISION ((1<<16) | (10))
+#define EFI_2_00_BOOT_SERVICES_REVISION ((2<<16) | (0))
 #define EFI_BOOT_SERVICES_REVISION      (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)
 
 typedef struct _EFI_BOOT_SERVICES {
@@ -938,6 +943,9 @@ typedef struct _EFI_CONFIGURATION_TABLE {
 
 
 #define EFI_SYSTEM_TABLE_SIGNATURE      0x5453595320494249
+#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | (02))
+#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | (10))
+#define EFI_2_00_SYSTEM_TABLE_REVISION ((2<<16) | (0))
 #define EFI_SYSTEM_TABLE_REVISION      (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)
 
 typedef struct _EFI_SYSTEM_TABLE {
index 91b511844288135705810338b3530a062c4c570e..af4701915b63b3487b2511498080e8d31844b896 100644 (file)
@@ -272,17 +272,17 @@ ZeroMem (
     IN UINTN     Size
     );
 
-VOID
+VOID EFIAPI
 SetMem (
     IN VOID     *Buffer,
     IN UINTN    Size,
     IN UINT8    Value
     );
 
-VOID
+VOID EFIAPI
 CopyMem (
     IN VOID     *Dest,
-    IN CONST VOID     *Src,
+    IN VOID     *Src,
     IN UINTN    len
     );
 
index 47331d0749c7a9da9d7178d5a3d67a97f7c6b4d8..c9a4b0bafd5f4c612be4de2ade42beec1c1a5914 100644 (file)
@@ -98,7 +98,7 @@ ZeroMem (
     RtZeroMem (Buffer, Size);
 }
 
-VOID
+VOID EFIAPI
 SetMem (
     IN VOID     *Buffer,
     IN UINTN    Size,
@@ -108,10 +108,10 @@ SetMem (
     RtSetMem (Buffer, Size, Value);
 }
 
-VOID
+VOID EFIAPI
 CopyMem (
     IN VOID     *Dest,
-    IN CONST VOID     *Src,
+    IN VOID     *Src,
     IN UINTN    len
     )
 {
index cf5c7246d8e40c7e9913dec65d46ddb29361cea4..b78bf8621c1f2c0a34d39389c6ff42403a6f37b3 100644 (file)
@@ -211,7 +211,7 @@ StrDuplicate (
     Size = StrSize(Src);
     Dest = AllocatePool (Size);
     if (Dest) {
-        CopyMem (Dest, Src, Size);
+        CopyMem (Dest, (void *)Src, Size);
     }
     return Dest;
 }
index 93d88931569fe2c83cdcd82344b3c6fd02ea79e4..dfa493bf52f0638d971cecadfafe9f5c9c454b6a 100644 (file)
@@ -179,8 +179,8 @@ generate_next_uri (CONST CHAR8 *current_uri, CONST CHAR8 *next_loader,
        if (!*uri)
                return EFI_OUT_OF_RESOURCES;
 
-       CopyMem(*uri, current_uri, path_len);
-       CopyMem(*uri + path_len, next_loader, next_len);
+       CopyMem(*uri, (void *)current_uri, path_len);
+       CopyMem(*uri + path_len, (void *)next_loader, next_len);
        (*uri)[path_len + next_len] = '\0';
 
        return EFI_SUCCESS;
@@ -209,7 +209,7 @@ extract_hostname (CONST CHAR8 *url, CHAR8 **hostname)
        if (!*hostname)
                return EFI_OUT_OF_RESOURCES;
 
-       CopyMem(*hostname, start, host_len);
+       CopyMem(*hostname, (void *)start, host_len);
        (*hostname)[host_len] = '\0';
 
        return EFI_SUCCESS;
@@ -232,9 +232,9 @@ get_nic_handle (EFI_MAC_ADDRESS *mac)
 
        /* Get the list of handles that support the HTTP service binding
           protocol */
-       efi_status = gBS->LocateHandleBuffer(ByProtocol,
-                                            &EFI_HTTP_BINDING_GUID,
-                                            NULL, &NoHandles, &buffer);
+       efi_status = BS->LocateHandleBuffer(ByProtocol,
+                                           &EFI_HTTP_BINDING_GUID,
+                                           NULL, &NoHandles, &buffer);
        if (EFI_ERROR(efi_status))
                return NULL;
 
@@ -306,8 +306,8 @@ set_ip6(EFI_HANDLE *nic, IPv6_DEVICE_PATH *ip6node)
        EFI_IPv6_ADDRESS gateway;
        EFI_STATUS efi_status;
 
-       efi_status = gBS->HandleProtocol(nic, &EFI_IP6_CONFIG_GUID,
-                                        (VOID **)&ip6cfg);
+       efi_status = BS->HandleProtocol(nic, &EFI_IP6_CONFIG_GUID,
+                                       (VOID **)&ip6cfg);
        if (EFI_ERROR(efi_status))
                return efi_status;
 
@@ -367,8 +367,8 @@ set_ip4(EFI_HANDLE *nic, IPv4_DEVICE_PATH *ip4node)
        EFI_IPv4_ADDRESS gateway;
        EFI_STATUS efi_status;
 
-       efi_status = gBS->HandleProtocol(nic, &EFI_IP4_CONFIG2_GUID,
-                                        (VOID **)&ip4cfg2);
+       efi_status = BS->HandleProtocol(nic, &EFI_IP4_CONFIG2_GUID,
+                                       (VOID **)&ip4cfg2);
        if (EFI_ERROR(efi_status))
                return efi_status;
 
@@ -470,9 +470,9 @@ send_http_request (EFI_HTTP_PROTOCOL *http, CHAR8 *hostname, CHAR8 *uri)
        tx_token.Message = &tx_message;
        tx_token.Event = NULL;
        request_done = FALSE;
-       efi_status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
-                                     httpnotify, &request_done,
-                                     &tx_token.Event);
+       efi_status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
+                                    httpnotify, &request_done,
+                                    &tx_token.Event);
        if (EFI_ERROR(efi_status)) {
                perror(L"Failed to Create Event for HTTP request: %r\n",
                       efi_status);
@@ -496,7 +496,7 @@ send_http_request (EFI_HTTP_PROTOCOL *http, CHAR8 *hostname, CHAR8 *uri)
        }
 
 error:
-       event_status = gBS->CloseEvent(tx_token.Event);
+       event_status = BS->CloseEvent(tx_token.Event);
        if (EFI_ERROR(event_status)) {
                perror(L"Failed to close Event for HTTP request: %r\n",
                       event_status);
@@ -534,9 +534,9 @@ receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINT64 *buf_size)
        rx_token.Message = &rx_message;
        rx_token.Event = NULL;
        response_done = FALSE;
-       efi_status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
-                                     httpnotify, &response_done,
-                                     &rx_token.Event);
+       efi_status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
+                                    httpnotify, &response_done,
+                                    &rx_token.Event);
        if (EFI_ERROR(efi_status)) {
                perror(L"Failed to Create Event for HTTP response: %r\n",
                       efi_status);
@@ -571,7 +571,8 @@ receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINT64 *buf_size)
 
        /* Check the length of the file */
        for (i = 0; i < rx_message.HeaderCount; i++) {
-               if (!strcmp(rx_message.Headers[i].FieldName, (CHAR8 *)"Content-Length")) {
+               if (!strcasecmp(rx_message.Headers[i].FieldName,
+                               (CHAR8 *)"Content-Length")) {
                        *buf_size = ascii_to_int(rx_message.Headers[i].FieldValue);
                }
        }
@@ -631,7 +632,7 @@ receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINT64 *buf_size)
        }
 
 error:
-       event_status = gBS->CloseEvent(rx_token.Event);
+       event_status = BS->CloseEvent(rx_token.Event);
        if (EFI_ERROR(event_status)) {
                perror(L"Failed to close Event for HTTP response: %r\n",
                       event_status);
@@ -659,9 +660,9 @@ http_fetch (EFI_HANDLE image, EFI_HANDLE device,
        *buf_size = 0;
 
        /* Open HTTP Service Binding Protocol */
-       efi_status = gBS->OpenProtocol(device, &EFI_HTTP_BINDING_GUID,
-                                      (VOID **) &service, image, NULL,
-                                      EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+       efi_status = BS->OpenProtocol(device, &EFI_HTTP_BINDING_GUID,
+                                     (VOID **) &service, image, NULL,
+                                     EFI_OPEN_PROTOCOL_GET_PROTOCOL);
        if (EFI_ERROR(efi_status))
                return efi_status;
 
@@ -675,8 +676,8 @@ http_fetch (EFI_HANDLE image, EFI_HANDLE device,
        }
 
        /* Get the http protocol */
-       efi_status = gBS->HandleProtocol(http_handle, &EFI_HTTP_PROTOCOL_GUID,
-                                        (VOID **) &http);
+       efi_status = BS->HandleProtocol(http_handle, &EFI_HTTP_PROTOCOL_GUID,
+                                       (VOID **) &http);
        if (EFI_ERROR(efi_status)) {
                perror(L"Failed to get http\n");
                goto error;
index 8458d5d22f84e5f4e15c92477447aeac5635f648..03b06557e0bc05af3cbd96237a2016f78e59d885 100644 (file)
@@ -26,17 +26,17 @@ static inline uint64_t read_counter(void)
 }
 
 #if defined(__x86_64__) || defined(__i386__) || defined(__i686__)
-static inline void pause(void)
+static inline void wait_for_debug(void)
 {
        __asm__ __volatile__("pause");
 }
 #elif defined(__aarch64__)
-static inline void pause(void)
+static inline void wait_for_debug(void)
 {
                __asm__ __volatile__("wfi");
 }
 #else
-static inline void pause(void)
+static inline void wait_for_debug(void)
 {
         uint64_t a, b;
         int x;
index f56b1231a9fdd71a9d0fb4ba2646acfb53cc779d..0c4a5137e3207b8048e5e8c3ec9f84f948b7240e 100644 (file)
@@ -50,6 +50,9 @@ void
 console_reset(void);
 void
 console_mode_handle(void);
+void
+clear_screen(void);
+
 #define NOSEL 0x7fffffff
 
 typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL   EFI_CONSOLE_CONTROL_PROTOCOL;
@@ -109,8 +112,12 @@ extern UINT32 verbose;
 
 extern EFI_STATUS EFIAPI vdprint_(const CHAR16 *fmt, const char *file, int line,
                                   const char *func, ms_va_list args);
+#if defined(SHIM_UNIT_TEST)
+#define vdprint(fmt, ...)
+#else
 #define vdprint(fmt, ...) \
        vdprint_(fmt, __FILE__, __LINE__ - 1, __func__, ##__VA_ARGS__)
+#endif
 
 extern EFI_STATUS print_crypto_errors(EFI_STATUS rc, char *file, const char *func, int line);
 #define crypterr(rc) print_crypto_errors((rc), __FILE__, __func__, __LINE__)
index f2bcefdb190ac5045da0916587def99fbf883dd7..d5c3204f3b5af4638e6113e769ffd18530c39e8c 100644 (file)
@@ -124,9 +124,15 @@ typedef struct {
 /*
  * Attributes of Authenticated Variable
  */
+#ifndef EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
 #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS              0x00000010
+#endif
+#ifndef EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
 #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS   0x00000020
+#endif
+#ifndef EFI_VARIABLE_APPEND_WRITE
 #define EFI_VARIABLE_APPEND_WRITE                            0x00000040
+#endif
 
 /*
  * AuthInfo is a WIN_CERTIFICATE using the wCertificateType
index 381e1a685e20c51f8829cfda40b82e6928d24033..e8f4fe1acbdf777bffead9a6c3386c815ddbd429 100644 (file)
@@ -71,7 +71,7 @@ prepare_text(const void *data, size_t size, char *buf, unsigned int position)
                else
                        buf[offset++] = '.';
        }
-       buf[offset++] = size > 0 ? '|' : 'X';
+       buf[offset++] = '|';
        buf[offset] = '\0';
 }
 
@@ -89,6 +89,11 @@ vhexdumpf(const char *file, int line, const char *func, const CHAR16 *const fmt,
        if (verbose == 0)
                return;
 
+       if (!data || !size) {
+               dprint(L"hexdump of a NULL pointer!\n");
+               return;
+       }
+
        while (offset < size) {
                char hexbuf[49];
                char txtbuf[19];
@@ -137,12 +142,19 @@ hexdumpat(const char *file, int line, const char *func, const void *data, unsign
        hexdumpf(file, line, func, L"", data, size, at);
 }
 
+#if defined(SHIM_UNIT_TEST)
+#define LogHexDump(data, ...)
+#define dhexdump(data, ...)
+#define dhexdumpat(data, ...)
+#define dhexdumpf(fmt, ...)
+#else
 #define LogHexdump(data, sz) LogHexdump_(__FILE__, __LINE__, __func__, data, sz)
 #define dhexdump(data, sz)   hexdump(__FILE__, __LINE__, __func__, data, sz)
 #define dhexdumpat(data, sz, at) \
        hexdumpat(__FILE__, __LINE__ - 1, __func__, data, sz, at)
 #define dhexdumpf(fmt, data, sz, at, ...) \
        hexdumpf(__FILE__, __LINE__ - 1, __func__, fmt, data, sz, at, ##__VA_ARGS__)
+#endif
 
 #endif /* STATIC_HEXDUMP_H */
 // vim:fenc=utf-8:tw=75:noet
diff --git a/include/load-options.h b/include/load-options.h
new file mode 100644 (file)
index 0000000..d2bee3b
--- /dev/null
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * load-options.h - all the stuff we need to parse the load options
+ */
+
+#ifndef SHIM_ARGV_H_
+#define SHIM_ARGV_H_
+
+EFI_STATUS generate_path_from_image_path(EFI_LOADED_IMAGE *li,
+                                        CHAR16 *ImagePath,
+                                        CHAR16 **PathName);
+
+EFI_STATUS parse_load_options(EFI_LOADED_IMAGE *li);
+
+extern CHAR16 *second_stage;
+extern void *load_options;
+extern UINT32 load_options_size;
+
+#endif /* !SHIM_ARGV_H_ */
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/mock-variables.h b/include/mock-variables.h
new file mode 100644 (file)
index 0000000..9f276e6
--- /dev/null
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * mock-variables.h - a mock GetVariable/SetVariable/GNVN/etc
+ *                    implementation for testing.
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#ifndef SHIM_MOCK_VARIABLES_H_
+#define SHIM_MOCK_VARIABLES_H_
+
+#include "test.h"
+
+EFI_STATUS EFIAPI mock_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs,
+                                    UINTN *size, VOID *data);
+EFI_STATUS EFIAPI mock_get_next_variable_name(UINTN *size, CHAR16 *name,
+                                              EFI_GUID *guid);
+EFI_STATUS EFIAPI mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
+                                    UINTN size, VOID *data);
+EFI_STATUS EFIAPI mock_query_variable_info(UINT32 attrs,
+                                           UINT64 *max_var_storage,
+                                           UINT64 *remaining_var_storage,
+                                           UINT64 *max_var_size);
+
+EFI_STATUS EFIAPI mock_install_configuration_table(EFI_GUID *guid, VOID *table);
+
+struct mock_variable_limits {
+       UINT32 attrs;
+       UINT64 *max_var_storage;
+       UINT64 *remaining_var_storage;
+       UINT64 *max_var_size;
+       EFI_STATUS status;
+
+       list_t list;
+};
+
+typedef enum {
+       MOCK_SORT_DESCENDING,
+       MOCK_SORT_PREPEND,
+       MOCK_SORT_APPEND,
+       MOCK_SORT_ASCENDING,
+       MOCK_SORT_MAX_SENTINEL
+} mock_sort_policy_t;
+
+extern mock_sort_policy_t mock_variable_sort_policy;
+extern mock_sort_policy_t mock_config_table_sort_policy;
+
+#define MOCK_VAR_DELETE_ATTR_ALLOW_ZERO                0x01
+#define MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH     0x02
+
+extern UINT32 mock_variable_delete_attr_policy;
+
+extern list_t mock_default_variable_limits;
+extern list_t *mock_qvi_limits;
+extern list_t *mock_sv_limits;
+
+struct mock_variable {
+       CHAR16 *name;
+       EFI_GUID guid;
+       void *data;
+       size_t size;
+       uint32_t attrs;
+
+       list_t list;
+};
+
+extern list_t mock_variables;
+
+static inline void
+dump_mock_variables(const char * const file,
+                   const int line,
+                   const char * const func)
+{
+       list_t *pos = NULL;
+       printf("%s:%d:%s(): dumping variables\n", file, line, func);
+       list_for_each(pos, &mock_variables) {
+               struct mock_variable *var;
+
+               var = list_entry(pos, struct mock_variable, list);
+               printf("%s:%d:%s():  "GUID_FMT"-%s\n", file, line, func,
+                      GUID_ARGS(var->guid), Str2str(var->name));
+       }
+}
+
+static inline void
+dump_mock_variables_if_wrong(const char * const file,
+                            const int line,
+                            const char * const func,
+                            EFI_GUID *guid, CHAR16 *first)
+{
+       UINTN size = 0;
+       CHAR16 buf[8192] = { 0, };
+       EFI_STATUS status;
+
+       size = sizeof(buf);
+       buf[0] = L'\0';
+       status = RT->GetNextVariableName(&size, buf, guid);
+       if (EFI_ERROR(status)) {
+               printf("%s:%d:%s() Can't dump variables: %lx\n",
+                      __FILE__, __LINE__, __func__,
+                      (unsigned long)status);
+               return;
+       }
+       buf[size] = L'\0';
+       if (StrCmp(buf, first) == 0)
+               return;
+       printf("%s:%d:%s():expected \"%s\" but got \"%s\".  Variables:\n",
+              file, line, func, Str2str(first), Str2str(buf));
+       dump_mock_variables(file, line, func);
+}
+
+void mock_load_variables(const char *const dirname, const char *filters[],
+                         bool filter_out);
+void mock_install_query_variable_info(void);
+void mock_uninstall_query_variable_info(void);
+void mock_reset_variables(void);
+void mock_reset_config_table(void);
+void mock_finalize_vars_and_configs(void);
+
+typedef enum {
+       NONE = 0,
+       CREATE,
+       DELETE,
+       APPEND,
+       REPLACE,
+       GET,
+} mock_variable_op_t;
+
+static inline const char *
+format_var_op(mock_variable_op_t op)
+{
+       static const char *var_op_names[] = {
+               "NONE",
+               "CREATE",
+               "DELETE",
+               "APPEND",
+               "REPLACE",
+               "GET",
+               NULL
+       };
+
+       return var_op_names[op];
+}
+
+typedef EFI_STATUS (mock_set_variable_pre_hook_t)(CHAR16 *name, EFI_GUID *guid,
+                                                 UINT32 attrs, UINTN size,
+                                                 VOID *data);
+extern mock_set_variable_pre_hook_t *mock_set_variable_pre_hook;
+
+typedef void (mock_set_variable_post_hook_t)(CHAR16 *name, EFI_GUID *guid,
+                                            UINT32 attrs, UINTN size,
+                                            VOID *data, EFI_STATUS *status,
+                                            mock_variable_op_t op,
+                                            const char * const file,
+                                            const int line,
+                                            const char * const func);
+extern mock_set_variable_post_hook_t *mock_set_variable_post_hook;
+
+typedef EFI_STATUS (mock_get_variable_pre_hook_t)(CHAR16 *name, EFI_GUID *guid,
+                                                 UINT32 *attrs, UINTN *size,
+                                                 VOID *data);
+extern mock_get_variable_pre_hook_t *mock_get_variable_pre_hook;
+
+typedef void (mock_get_variable_post_hook_t)(CHAR16 *name, EFI_GUID *guid,
+                                            UINT32 *attrs, UINTN *size,
+                                            VOID *data, EFI_STATUS *status,
+                                            const char * const file,
+                                            const int line,
+                                            const char * const func);
+extern mock_get_variable_post_hook_t *mock_get_variable_post_hook;
+
+typedef EFI_STATUS (mock_get_next_variable_name_pre_hook_t)(UINTN *size,
+                                                           CHAR16 *name,
+                                                           EFI_GUID *guid);
+extern mock_get_next_variable_name_pre_hook_t
+       *mock_get_next_variable_name_pre_hook;
+
+typedef void (mock_get_next_variable_name_post_hook_t)(
+                       UINTN *size, CHAR16 *name, EFI_GUID *guid,
+                       EFI_STATUS *status, const char * const file,
+                       const int line, const char * const func);
+extern mock_get_next_variable_name_post_hook_t
+       *mock_get_next_variable_name_post_hook;
+
+typedef EFI_STATUS (mock_query_variable_info_pre_hook_t)(
+                       UINT32 attrs, UINT64 *max_var_storage,
+                       UINT64 *remaining_var_storage, UINT64 *max_var_size);
+extern mock_query_variable_info_pre_hook_t *mock_query_variable_info_pre_hook;
+
+typedef void (mock_query_variable_info_post_hook_t)(
+       UINT32 attrs, UINT64 *max_var_storage, UINT64 *remaining_var_storage,
+       UINT64 *max_var_size, EFI_STATUS *status, const char * const file,
+       const int line, const char * const func);
+extern mock_query_variable_info_post_hook_t *mock_query_variable_info_post_hook;
+
+#define MOCK_CONFIG_TABLE_ENTRIES 1024
+extern EFI_CONFIGURATION_TABLE mock_config_table[MOCK_CONFIG_TABLE_ENTRIES];
+
+#endif /* !SHIM_MOCK_VARIABLES_H_ */
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/mok.h b/include/mok.h
new file mode 100644 (file)
index 0000000..96da397
--- /dev/null
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * mok.h - structs for MoK data
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#ifndef SHIM_MOK_H_
+#define SHIM_MOK_H_
+
+#include "shim.h"
+
+typedef enum {
+       VENDOR_ADDEND_DB,
+       VENDOR_ADDEND_X509,
+       VENDOR_ADDEND_NONE,
+} vendor_addend_category_t;
+
+struct mok_state_variable;
+typedef vendor_addend_category_t (vendor_addend_categorizer_t)(struct mok_state_variable *);
+
+/*
+ * MoK variables that need to have their storage validated.
+ *
+ * The order here is important, since this is where we measure for the
+ * tpm as well.
+ */
+struct mok_state_variable {
+       CHAR16 *name;   /* UCS-2 BS|NV variable name */
+       char *name8;    /* UTF-8 BS|NV variable name */
+       CHAR16 *rtname; /* UCS-2 RT variable name */
+       char *rtname8;  /* UTF-8 RT variable name */
+       EFI_GUID *guid; /* variable GUID */
+
+       /*
+        * these are used during processing, they shouldn't be filled out
+        * in the static table below.
+        */
+       UINT8 *data;
+       UINTN data_size;
+
+       /*
+        * addend are added to the input variable, as part of the runtime
+        * variable, so that they're visible to the kernel.  These are
+        * where we put vendor_cert / vendor_db / vendor_dbx
+        *
+        * These are indirect pointers just to make initialization saner...
+        */
+       vendor_addend_categorizer_t *categorize_addend; /* determines format */
+       /*
+        * we call categorize_addend() and it determines what kind of thing
+        * this is.  That is, if this shim was built with VENDOR_CERT, for
+        * the DB entry it'll return VENDOR_ADDEND_X509; if you used
+        * VENDOR_DB instead, it'll return VENDOR_ADDEND_DB.  If you used
+        * neither, it'll do VENDOR_ADDEND_NONE.
+        *
+        * The existing categorizers are for db and dbx; they differ
+        * because we don't currently support a CERT for dbx.
+        */
+       UINT8 **addend;
+       UINT32 *addend_size;
+
+       /*
+        * build_cert is our build-time cert.  Like addend, this is added
+        * to the input variable, as part of the runtime variable, so that
+        * they're visible to the kernel.  This is the ephemeral cert used
+        * for signing MokManager.efi and fallback.efi.
+        *
+        * These are indirect pointers just to make initialization saner...
+        */
+       UINT8 **build_cert;
+       UINT32 *build_cert_size;
+
+       UINT32 yes_attr;        /* var attrs that must be set */
+       UINT32 no_attr;         /* var attrs that must not be set */
+       UINT32 flags;           /* flags on what and how to mirror */
+       /*
+        * MOK_MIRROR_KEYDB         mirror this as a key database
+        * MOK_MIRROR_DELETE_FIRST  delete any existing variable first
+        * MOK_VARIABLE_MEASURE     extend PCR 7 and log the hash change
+        * MOK_VARIABLE_LOG         measure into whatever .pcr says and log
+        */
+       UINTN pcr;              /* PCR to measure and hash to */
+
+       /*
+        * if this is a state value, a pointer to our internal state to be
+        * mirrored.
+        */
+       UINT8 *state;
+};
+
+extern size_t n_mok_state_variables;
+extern struct mok_state_variable *mok_state_variables;
+
+struct mok_variable_config_entry {
+       CHAR8 name[256];
+       UINT64 data_size;
+       UINT8 data[];
+};
+
+#endif /* !SHIM_MOK_H_ */
+// vim:fenc=utf-8:tw=75:noet
index 79bf440cfd06788f962002c3435d73064a3e5c00..43727f5e933821fc22ab7a938598ff7d0c62bb8c 100644 (file)
@@ -25,7 +25,7 @@ handle_image (void *data, unsigned int datasize,
              UINTN *alloc_pages);
 
 EFI_STATUS
-generate_hash (char *data, unsigned int datasize_in,
+generate_hash (char *data, unsigned int datasize,
               PE_COFF_LOADER_IMAGE_CONTEXT *context,
               UINT8 *sha256hash, UINT8 *sha1hash);
 
index d433e6ecb57a3b35f623359c38b7e7798d912d6a..1d911e66cd255dd73472cf2b8ebe17d6dff5df05 100644 (file)
@@ -72,8 +72,6 @@ strntoken(char *str, size_t max, const char *delims, char **token, char *state)
                return 0;
 
        tokend = &str[max-1];
-       if (!str || max == 0 || !delims || !token)
-               return 0;
 
        /*
         * the very special case of "" with max=1, where we have no prior
index 4c956f708ac06ccb8f16c8c6c7bac392f7c8c1f7..68c171b8ff0e8e20d74b05402eab9d24448148f5 100644 (file)
@@ -24,7 +24,7 @@ typedef __builtin_va_list __builtin_sysv_va_list;
 #endif
 
 #if defined(__aarch64__) || defined(__arm__) || defined(__i386__) || \
-       defined(__i486__) || defined(__i686__)
+       defined(__i486__) || defined(__i686__) || defined(__COVERITY__)
 
 typedef __builtin_va_list ms_va_list;
 typedef __builtin_va_list __builtin_ms_va_list;
diff --git a/include/test-data-efivars-0.h b/include/test-data-efivars-0.h
new file mode 100644 (file)
index 0000000..b3e7c8c
--- /dev/null
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * test-data-efivars-0.h - test data
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#ifndef TEST_DATA_EFIVARS_0_H_
+#define TEST_DATA_EFIVARS_0_H_
+
+static const unsigned char test_data_efivars_0_Boot0000[] = {
+       0x01, 0x00, 0x00, 0x00, 0x62, 0x00, 0x46, 0x00, 0x65, 0x00, 0x64, 0x00,
+       0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x00, 0x00, 0x04, 0x01, 0x2a, 0x00,
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x58, 0x7f, 0x92,
+       0x54, 0xdc, 0xf4, 0x4f, 0x82, 0x1c, 0xd2, 0x9b, 0x59, 0xc4, 0x8a, 0xb1,
+       0x02, 0x02, 0x04, 0x04, 0x34, 0x00, 0x5c, 0x00, 0x45, 0x00, 0x46, 0x00,
+       0x49, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x45, 0x00, 0x44, 0x00, 0x4f, 0x00,
+       0x52, 0x00, 0x41, 0x00, 0x5c, 0x00, 0x53, 0x00, 0x48, 0x00, 0x49, 0x00,
+       0x4d, 0x00, 0x58, 0x00, 0x36, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x45, 0x00,
+       0x46, 0x00, 0x49, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x04, 0x00
+};
+
+static const unsigned char test_data_efivars_0_dbDefault[] = {
+       0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15,
+       0x5c, 0x2b, 0xf0, 0x72, 0x82, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x66, 0x03, 0x00, 0x00, 0x91, 0x30, 0x05, 0x3b, 0x9f, 0x6c, 0xcc, 0x04,
+       0xb1, 0xac, 0xe2, 0xa5, 0x1e, 0x3b, 0xe5, 0xf5, 0x30, 0x82, 0x03, 0x52,
+       0x30, 0x82, 0x02, 0x3a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xda,
+       0x83, 0xb9, 0x90, 0x42, 0x2e, 0xbc, 0x8c, 0x44, 0x1f, 0x8d, 0x8b, 0x03,
+       0x9a, 0x65, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+       0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d,
+       0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x41, 0x53, 0x55, 0x53, 0x54,
+       0x65, 0x4b, 0x20, 0x4d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x61,
+       0x72, 0x64, 0x20, 0x53, 0x57, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65,
+       0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x1e, 0x17,
+       0x0d, 0x31, 0x31, 0x31, 0x32, 0x32, 0x36, 0x32, 0x33, 0x33, 0x35, 0x30,
+       0x35, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x31, 0x32, 0x32, 0x36, 0x32, 0x33,
+       0x33, 0x35, 0x30, 0x34, 0x5a, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, 0x06,
+       0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65,
+       0x4b, 0x20, 0x4d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x61, 0x72,
+       0x64, 0x20, 0x53, 0x57, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65, 0x72,
+       0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x82, 0x01, 0x22,
+       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+       0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+       0x02, 0x82, 0x01, 0x01, 0x00, 0x8c, 0xf6, 0xa6, 0xeb, 0x77, 0xfc, 0x83,
+       0x8a, 0xa4, 0x9f, 0xd5, 0xf8, 0xcf, 0x3f, 0x37, 0xf2, 0x6e, 0x2d, 0x0a,
+       0x62, 0xc5, 0xd8, 0x9b, 0x1d, 0x16, 0x0b, 0x22, 0x7f, 0x29, 0x5f, 0x3a,
+       0x26, 0xdf, 0x53, 0x97, 0x8c, 0x78, 0x94, 0x19, 0x90, 0x42, 0x73, 0x0f,
+       0x85, 0xc2, 0xff, 0xa4, 0x85, 0x7c, 0x81, 0x2e, 0x0b, 0x51, 0xba, 0x56,
+       0x23, 0x27, 0x92, 0x3d, 0xa3, 0xf2, 0xdc, 0xe2, 0x77, 0x84, 0x9e, 0x50,
+       0xbe, 0x8a, 0xeb, 0x51, 0x34, 0xa4, 0xf8, 0xef, 0x5d, 0xd7, 0x51, 0xfe,
+       0x70, 0x42, 0x4c, 0x42, 0x06, 0xef, 0x69, 0x2c, 0xa2, 0xd3, 0x25, 0xe1,
+       0x26, 0x57, 0x23, 0x85, 0x6d, 0xd0, 0xa7, 0x7b, 0xc0, 0x45, 0x28, 0x7e,
+       0x89, 0xd5, 0xb4, 0x0a, 0xeb, 0xaf, 0x41, 0x79, 0x21, 0xd2, 0xd7, 0x00,
+       0xec, 0x48, 0xf9, 0x44, 0xf6, 0x5b, 0xbe, 0xb6, 0x25, 0x24, 0xf0, 0x8e,
+       0x2e, 0xb4, 0x52, 0x3e, 0xe1, 0x0e, 0xc1, 0xa4, 0x67, 0xea, 0xfe, 0xe5,
+       0x93, 0xcc, 0xb9, 0xc4, 0x36, 0x21, 0xcb, 0x54, 0xfa, 0xaf, 0x9d, 0x9c,
+       0x85, 0x78, 0xcc, 0xe5, 0x88, 0xf3, 0x84, 0x0c, 0x67, 0xdb, 0x26, 0x69,
+       0x58, 0xca, 0xde, 0x47, 0x34, 0xec, 0xcf, 0x2f, 0xb6, 0x49, 0x59, 0xb5,
+       0x56, 0xdb, 0x58, 0x45, 0x7b, 0x21, 0x9d, 0x99, 0x0b, 0x5f, 0xde, 0x57,
+       0x16, 0xa6, 0xab, 0xc8, 0x79, 0x3f, 0x9d, 0x76, 0x89, 0xe2, 0x09, 0xf9,
+       0x8d, 0xe2, 0x63, 0x37, 0xfc, 0x74, 0xea, 0x73, 0x7e, 0x70, 0xac, 0x15,
+       0x16, 0xa5, 0xed, 0x88, 0x60, 0x5f, 0x33, 0xed, 0x94, 0x9e, 0x0a, 0x05,
+       0xde, 0xc7, 0x85, 0xc3, 0xc1, 0x7a, 0x54, 0xfb, 0x4e, 0xcb, 0xcb, 0xe8,
+       0x5e, 0x44, 0x7c, 0x39, 0xdb, 0x2d, 0xb2, 0xb7, 0x6c, 0xce, 0xca, 0x2f,
+       0x63, 0x9d, 0x16, 0x4e, 0xa6, 0xe5, 0xef, 0xd6, 0xcf, 0x02, 0x03, 0x01,
+       0x00, 0x01, 0xa3, 0x66, 0x30, 0x64, 0x30, 0x62, 0x06, 0x03, 0x55, 0x1d,
+       0x01, 0x04, 0x5b, 0x30, 0x59, 0x80, 0x10, 0x56, 0xb0, 0x8b, 0x2a, 0xa7,
+       0xfe, 0xcc, 0xf1, 0x0c, 0xed, 0x87, 0x62, 0xdc, 0xd5, 0x1d, 0xc3, 0xa1,
+       0x33, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03,
+       0x13, 0x26, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65, 0x4b, 0x20, 0x4d, 0x6f,
+       0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x53, 0x57,
+       0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+       0x63, 0x61, 0x74, 0x65, 0x82, 0x10, 0xda, 0x83, 0xb9, 0x90, 0x42, 0x2e,
+       0xbc, 0x8c, 0x44, 0x1f, 0x8d, 0x8b, 0x03, 0x9a, 0x65, 0xa2, 0x30, 0x0d,
+       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+       0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x02, 0xcf, 0x52, 0x6f, 0x0b, 0x91,
+       0xeb, 0xe4, 0x3b, 0xb2, 0x70, 0x0c, 0x07, 0x2d, 0x79, 0x80, 0x01, 0x9e,
+       0x4b, 0x4d, 0x92, 0xbb, 0xdc, 0x9e, 0xe5, 0xe5, 0x31, 0x85, 0xe3, 0x9a,
+       0x75, 0xed, 0xca, 0xde, 0x8c, 0xee, 0x28, 0x34, 0x01, 0x83, 0x14, 0x47,
+       0x9e, 0x3a, 0xd4, 0x43, 0x5b, 0x2c, 0xc4, 0x41, 0xc8, 0x40, 0x7d, 0xb5,
+       0x08, 0x76, 0x86, 0x80, 0x2b, 0xa8, 0x00, 0x9f, 0xb7, 0xd3, 0xb1, 0xe6,
+       0x60, 0x5c, 0x32, 0xb0, 0xa0, 0x01, 0x0f, 0xba, 0x36, 0x8b, 0xb7, 0xb5,
+       0x4e, 0x87, 0xd5, 0xb7, 0x0a, 0x2c, 0xbd, 0xbc, 0x6a, 0x43, 0x3c, 0xee,
+       0x76, 0x7c, 0x76, 0x20, 0xed, 0x39, 0x91, 0xa8, 0xbf, 0x70, 0x1e, 0xd6,
+       0xa8, 0x1a, 0x3e, 0x81, 0x36, 0x6b, 0x7d, 0x1d, 0x8d, 0xf6, 0xf8, 0xaf,
+       0x5b, 0x38, 0x53, 0x6a, 0x04, 0x0d, 0x7e, 0xae, 0x4d, 0xee, 0xab, 0x02,
+       0xd4, 0xa4, 0xa2, 0xa9, 0xcf, 0xb6, 0xe3, 0x66, 0xa3, 0xca, 0x4d, 0x5d,
+       0xd4, 0x18, 0x61, 0x4d, 0xda, 0x83, 0x28, 0x4e, 0xaa, 0x2a, 0xaf, 0xda,
+       0xeb, 0xdf, 0x2a, 0x20, 0xbd, 0x78, 0x80, 0xef, 0xd1, 0xb0, 0xdd, 0x9b,
+       0x77, 0xdb, 0xc9, 0x25, 0x39, 0x4b, 0xcf, 0xa2, 0x86, 0x1a, 0xac, 0xcc,
+       0x32, 0xe7, 0x87, 0xd4, 0x59, 0xb2, 0x03, 0xc4, 0x69, 0x02, 0x8f, 0x17,
+       0xc9, 0xde, 0x52, 0xcb, 0xe7, 0xab, 0xb8, 0x35, 0xc5, 0xf8, 0x33, 0x06,
+       0x03, 0x93, 0x52, 0xcf, 0xb3, 0x68, 0xd2, 0xb3, 0x5c, 0x1c, 0xe8, 0x19,
+       0xfe, 0x75, 0x26, 0xed, 0xd1, 0x65, 0x72, 0x13, 0x4d, 0x69, 0x34, 0x5a,
+       0x9b, 0x0c, 0xb4, 0xe3, 0x56, 0x53, 0x3c, 0xb4, 0x67, 0x27, 0xf8, 0xfa,
+       0xd3, 0x20, 0xda, 0x37, 0x58, 0xf6, 0xad, 0xe2, 0x82, 0x59, 0xa2, 0xb8,
+       0x22, 0x2f, 0x9e, 0x56, 0xfe, 0xbc, 0x17, 0x49, 0x1d, 0xaf, 0xa1, 0x59,
+       0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b,
+       0xf0, 0x72, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x03,
+       0x00, 0x00, 0x91, 0x30, 0x05, 0x3b, 0x9f, 0x6c, 0xcc, 0x04, 0xb1, 0xac,
+       0xe2, 0xa5, 0x1e, 0x3b, 0xe5, 0xf5, 0x30, 0x82, 0x03, 0x49, 0x30, 0x82,
+       0x02, 0x31, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xb8, 0xe5, 0x81,
+       0xe4, 0xdf, 0x77, 0xa5, 0xbb, 0x42, 0x82, 0xd5, 0xcc, 0xfc, 0x00, 0xc0,
+       0x71, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+       0x01, 0x0b, 0x05, 0x00, 0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03,
+       0x55, 0x04, 0x03, 0x13, 0x23, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65, 0x4b,
+       0x20, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x20, 0x53, 0x57,
+       0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+       0x63, 0x61, 0x74, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x31, 0x32,
+       0x32, 0x37, 0x30, 0x30, 0x31, 0x38, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x33,
+       0x31, 0x31, 0x32, 0x32, 0x37, 0x30, 0x30, 0x31, 0x38, 0x35, 0x32, 0x5a,
+       0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+       0x23, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65, 0x4b, 0x20, 0x4e, 0x6f, 0x74,
+       0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x20, 0x53, 0x57, 0x20, 0x4b, 0x65, 0x79,
+       0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+       0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
+       0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9e, 0x61, 0xfa,
+       0x74, 0x2c, 0x2a, 0x88, 0x17, 0xc4, 0xbd, 0x77, 0x19, 0x0d, 0xb3, 0x33,
+       0x27, 0x0c, 0x0e, 0x94, 0xec, 0xb0, 0x8b, 0x71, 0xb3, 0x08, 0x77, 0xb7,
+       0xd2, 0x08, 0x9d, 0x32, 0x4f, 0x5c, 0xf7, 0x0c, 0xcf, 0xe0, 0x29, 0x53,
+       0x56, 0xed, 0x24, 0x91, 0xd8, 0xbd, 0x53, 0x2a, 0x89, 0x89, 0x8c, 0x74,
+       0x28, 0xab, 0x16, 0x2d, 0x4f, 0x9b, 0x65, 0xfc, 0x63, 0x7d, 0xed, 0x23,
+       0xb6, 0x97, 0x5c, 0x6d, 0x04, 0xe4, 0x15, 0x7f, 0xdc, 0xf8, 0xba, 0x6b,
+       0x08, 0xcc, 0xc9, 0x21, 0xe9, 0xb5, 0xde, 0x8e, 0x03, 0x28, 0x12, 0x63,
+       0xf0, 0x6a, 0xb6, 0xe5, 0xdf, 0x1d, 0x72, 0x28, 0xcc, 0x64, 0xd6, 0x63,
+       0x66, 0x2f, 0x04, 0x52, 0x6a, 0x1d, 0x25, 0x7d, 0xc7, 0xbd, 0xe0, 0x78,
+       0xfb, 0x0c, 0xb7, 0x37, 0xe5, 0xae, 0xf7, 0x0d, 0xd6, 0xb5, 0xb4, 0xbf,
+       0xf5, 0xf1, 0xc6, 0x82, 0x56, 0x78, 0x5c, 0xa8, 0xf3, 0x53, 0x2e, 0xf5,
+       0xec, 0x15, 0x3f, 0x12, 0x62, 0x2f, 0xeb, 0xb6, 0x79, 0x79, 0x86, 0xac,
+       0x76, 0xff, 0xb6, 0x66, 0x45, 0xf5, 0x33, 0xda, 0xdd, 0x25, 0xd6, 0xa7,
+       0xbf, 0xf8, 0xd9, 0xdb, 0xd3, 0xf1, 0xfa, 0xce, 0x0e, 0x22, 0x30, 0xd7,
+       0xd4, 0x80, 0x02, 0xbd, 0xd3, 0x2c, 0x1e, 0xec, 0x46, 0x2e, 0x2f, 0xca,
+       0x0f, 0x7a, 0xfa, 0xb9, 0x5c, 0xff, 0x2b, 0x16, 0xc6, 0x6a, 0x6b, 0x8d,
+       0x94, 0x64, 0x92, 0x7e, 0xf9, 0x55, 0xee, 0x96, 0x00, 0x4d, 0x04, 0x2e,
+       0x4b, 0x15, 0xed, 0xf1, 0x08, 0x49, 0x6a, 0x07, 0x86, 0x69, 0xc8, 0xc5,
+       0x64, 0xfa, 0xad, 0x2c, 0x4f, 0x02, 0x50, 0xe4, 0x1f, 0x83, 0xc7, 0x2f,
+       0x19, 0x9f, 0xe8, 0xa5, 0x62, 0xd9, 0x51, 0x32, 0x18, 0xb6, 0x83, 0xca,
+       0x08, 0x0a, 0xa1, 0xab, 0xa7, 0x65, 0x70, 0x9c, 0x1e, 0x48, 0xc3, 0x0f,
+       0x49, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x5f,
+       0x06, 0x03, 0x55, 0x1d, 0x01, 0x04, 0x58, 0x30, 0x56, 0x80, 0x10, 0x00,
+       0x65, 0x11, 0xe3, 0xca, 0x0f, 0x96, 0xe8, 0x8d, 0x5b, 0x04, 0xa4, 0xe7,
+       0xfe, 0xce, 0xaa, 0xa1, 0x30, 0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a, 0x06,
+       0x03, 0x55, 0x04, 0x03, 0x13, 0x23, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65,
+       0x4b, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x20, 0x53,
+       0x57, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+       0x69, 0x63, 0x61, 0x74, 0x65, 0x82, 0x10, 0xb8, 0xe5, 0x81, 0xe4, 0xdf,
+       0x77, 0xa5, 0xbb, 0x42, 0x82, 0xd5, 0xcc, 0xfc, 0x00, 0xc0, 0x71, 0x30,
+       0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+       0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x31, 0x18, 0xf4, 0xee, 0xe3,
+       0x72, 0xba, 0xbe, 0x33, 0x44, 0x61, 0x74, 0x19, 0x1f, 0x66, 0xac, 0x5c,
+       0xfd, 0x1d, 0x9a, 0x26, 0x75, 0xd0, 0x14, 0xcd, 0x68, 0x38, 0xb3, 0xa8,
+       0x3f, 0x4f, 0xb4, 0x4a, 0xe9, 0x1e, 0x21, 0xf2, 0xc9, 0xee, 0x37, 0x96,
+       0x26, 0xbe, 0x1d, 0x58, 0x9b, 0xad, 0x21, 0xce, 0x58, 0x79, 0x53, 0xd3,
+       0xff, 0x38, 0xef, 0x8f, 0x22, 0xcd, 0x90, 0x0e, 0xc6, 0x32, 0x21, 0x75,
+       0x9b, 0x5a, 0xab, 0xaf, 0x08, 0xff, 0x05, 0xcd, 0x2b, 0xf8, 0x8c, 0xe7,
+       0x97, 0x47, 0xbb, 0x78, 0xe4, 0x5f, 0x56, 0x47, 0xd2, 0xbc, 0xc8, 0xa5,
+       0x95, 0xcb, 0x76, 0x89, 0x5c, 0x65, 0x24, 0x02, 0x18, 0x06, 0x9c, 0x12,
+       0x5f, 0xef, 0xe0, 0x5c, 0x19, 0x45, 0x38, 0x96, 0xdf, 0x7a, 0x60, 0x5d,
+       0x61, 0xba, 0x4d, 0xc8, 0x7b, 0x6e, 0x8d, 0x8c, 0x6e, 0x1d, 0xa9, 0xe5,
+       0x92, 0x35, 0xa2, 0x4f, 0x36, 0xd3, 0x40, 0xad, 0xd7, 0x40, 0x12, 0xab,
+       0x6c, 0x48, 0x8d, 0x18, 0x92, 0xe4, 0x00, 0x52, 0x03, 0xdf, 0x14, 0xac,
+       0x66, 0x3f, 0x6a, 0xae, 0x42, 0x3a, 0x06, 0x50, 0xaa, 0xa5, 0x0d, 0x40,
+       0xa7, 0x7b, 0xeb, 0xfd, 0x41, 0x49, 0xff, 0xeb, 0xa3, 0xb4, 0x50, 0x4f,
+       0xf7, 0x54, 0x13, 0x3b, 0x1f, 0x8e, 0xb4, 0x45, 0x04, 0x20, 0x42, 0x74,
+       0xfe, 0x78, 0x3d, 0xbe, 0x7c, 0xdb, 0xa7, 0x2a, 0x2a, 0x9d, 0x06, 0x48,
+       0xc0, 0x9a, 0x02, 0x23, 0xaf, 0xf2, 0x98, 0x07, 0x95, 0xde, 0x3b, 0x30,
+       0x73, 0xec, 0x3e, 0x73, 0x58, 0x8f, 0x07, 0x53, 0x40, 0x96, 0xd8, 0x24,
+       0xd9, 0x66, 0x80, 0x7a, 0x75, 0x8d, 0xb7, 0x39, 0x27, 0x10, 0x89, 0x7a,
+       0xb4, 0x53, 0xbf, 0x3b, 0xc2, 0xe2, 0x97, 0x93, 0x37, 0x8a, 0x9d, 0x4d,
+       0x23, 0x6e, 0xac, 0xeb, 0x0d, 0x53, 0x21, 0x4d, 0x0b, 0x34, 0x13, 0xa1,
+       0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, 0x5c,
+       0x2b, 0xf0, 0x72, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
+       0x06, 0x00, 0x00, 0xbd, 0x9a, 0xfa, 0x77, 0x59, 0x03, 0x32, 0x4d, 0xbd,
+       0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b, 0x30, 0x82, 0x06, 0x10, 0x30,
+       0x82, 0x03, 0xf8, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x61, 0x08,
+       0xd3, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x30, 0x0d, 0x06, 0x09,
+       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+       0x81, 0x91, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+       0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+       0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e,
+       0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52,
+       0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03,
+       0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+       0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
+       0x6f, 0x6e, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+       0x32, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43,
+       0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x54,
+       0x68, 0x69, 0x72, 0x64, 0x20, 0x50, 0x61, 0x72, 0x74, 0x79, 0x20, 0x4d,
+       0x61, 0x72, 0x6b, 0x65, 0x74, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x52,
+       0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x36, 0x32,
+       0x37, 0x32, 0x31, 0x32, 0x32, 0x34, 0x35, 0x5a, 0x17, 0x0d, 0x32, 0x36,
+       0x30, 0x36, 0x32, 0x37, 0x32, 0x31, 0x33, 0x32, 0x34, 0x35, 0x5a, 0x30,
+       0x81, 0x81, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+       0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+       0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e,
+       0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52,
+       0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03,
+       0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+       0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
+       0x6f, 0x6e, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+       0x22, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43,
+       0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x55,
+       0x45, 0x46, 0x49, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x31, 0x30,
+       0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+       0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
+       0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x08, 0x6c, 0x4c,
+       0xc7, 0x45, 0x09, 0x6a, 0x4b, 0x0c, 0xa4, 0xc0, 0x87, 0x7f, 0x06, 0x75,
+       0x0c, 0x43, 0x01, 0x54, 0x64, 0xe0, 0x16, 0x7f, 0x07, 0xed, 0x92, 0x7d,
+       0x0b, 0xb2, 0x73, 0xbf, 0x0c, 0x0a, 0xc6, 0x4a, 0x45, 0x61, 0xa0, 0xc5,
+       0x16, 0x2d, 0x96, 0xd3, 0xf5, 0x2b, 0xa0, 0xfb, 0x4d, 0x49, 0x9b, 0x41,
+       0x80, 0x90, 0x3c, 0xb9, 0x54, 0xfd, 0xe6, 0xbc, 0xd1, 0x9d, 0xc4, 0xa4,
+       0x18, 0x8a, 0x7f, 0x41, 0x8a, 0x5c, 0x59, 0x83, 0x68, 0x32, 0xbb, 0x8c,
+       0x47, 0xc9, 0xee, 0x71, 0xbc, 0x21, 0x4f, 0x9a, 0x8a, 0x7c, 0xff, 0x44,
+       0x3f, 0x8d, 0x8f, 0x32, 0xb2, 0x26, 0x48, 0xae, 0x75, 0xb5, 0xee, 0xc9,
+       0x4c, 0x1e, 0x4a, 0x19, 0x7e, 0xe4, 0x82, 0x9a, 0x1d, 0x78, 0x77, 0x4d,
+       0x0c, 0xb0, 0xbd, 0xf6, 0x0f, 0xd3, 0x16, 0xd3, 0xbc, 0xfa, 0x2b, 0xa5,
+       0x51, 0x38, 0x5d, 0xf5, 0xfb, 0xba, 0xdb, 0x78, 0x02, 0xdb, 0xff, 0xec,
+       0x0a, 0x1b, 0x96, 0xd5, 0x83, 0xb8, 0x19, 0x13, 0xe9, 0xb6, 0xc0, 0x7b,
+       0x40, 0x7b, 0xe1, 0x1f, 0x28, 0x27, 0xc9, 0xfa, 0xef, 0x56, 0x5e, 0x1c,
+       0xe6, 0x7e, 0x94, 0x7e, 0xc0, 0xf0, 0x44, 0xb2, 0x79, 0x39, 0xe5, 0xda,
+       0xb2, 0x62, 0x8b, 0x4d, 0xbf, 0x38, 0x70, 0xe2, 0x68, 0x24, 0x14, 0xc9,
+       0x33, 0xa4, 0x08, 0x37, 0xd5, 0x58, 0x69, 0x5e, 0xd3, 0x7c, 0xed, 0xc1,
+       0x04, 0x53, 0x08, 0xe7, 0x4e, 0xb0, 0x2a, 0x87, 0x63, 0x08, 0x61, 0x6f,
+       0x63, 0x15, 0x59, 0xea, 0xb2, 0x2b, 0x79, 0xd7, 0x0c, 0x61, 0x67, 0x8a,
+       0x5b, 0xfd, 0x5e, 0xad, 0x87, 0x7f, 0xba, 0x86, 0x67, 0x4f, 0x71, 0x58,
+       0x12, 0x22, 0x04, 0x22, 0x22, 0xce, 0x8b, 0xef, 0x54, 0x71, 0x00, 0xce,
+       0x50, 0x35, 0x58, 0x76, 0x95, 0x08, 0xee, 0x6a, 0xb1, 0xa2, 0x01, 0xd5,
+       0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x76, 0x30, 0x82, 0x01,
+       0x72, 0x30, 0x12, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37,
+       0x15, 0x01, 0x04, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x23, 0x06,
+       0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x02, 0x04, 0x16,
+       0x04, 0x14, 0xf8, 0xc1, 0x6b, 0xb7, 0x7f, 0x77, 0x53, 0x4a, 0xf3, 0x25,
+       0x37, 0x1d, 0x4e, 0xa1, 0x26, 0x7b, 0x0f, 0x20, 0x70, 0x80, 0x30, 0x1d,
+       0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x13, 0xad, 0xbf,
+       0x43, 0x09, 0xbd, 0x82, 0x70, 0x9c, 0x8c, 0xd5, 0x4f, 0x31, 0x6e, 0xd5,
+       0x22, 0x98, 0x8a, 0x1b, 0xd4, 0x30, 0x19, 0x06, 0x09, 0x2b, 0x06, 0x01,
+       0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x04, 0x0c, 0x1e, 0x0a, 0x00, 0x53,
+       0x00, 0x75, 0x00, 0x62, 0x00, 0x43, 0x00, 0x41, 0x30, 0x0b, 0x06, 0x03,
+       0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06,
+       0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+       0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
+       0x16, 0x80, 0x14, 0x45, 0x66, 0x52, 0x43, 0xe1, 0x7e, 0x58, 0x11, 0xbf,
+       0xd6, 0x4e, 0x9e, 0x23, 0x55, 0x08, 0x3b, 0x3a, 0x22, 0x6a, 0xa8, 0x30,
+       0x5c, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x55, 0x30, 0x53, 0x30, 0x51,
+       0xa0, 0x4f, 0xa0, 0x4d, 0x86, 0x4b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+       0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+       0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x2f, 0x63,
+       0x72, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2f,
+       0x4d, 0x69, 0x63, 0x43, 0x6f, 0x72, 0x54, 0x68, 0x69, 0x50, 0x61, 0x72,
+       0x4d, 0x61, 0x72, 0x52, 0x6f, 0x6f, 0x5f, 0x32, 0x30, 0x31, 0x30, 0x2d,
+       0x31, 0x30, 0x2d, 0x30, 0x35, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x60, 0x06,
+       0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x54, 0x30,
+       0x52, 0x30, 0x50, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30,
+       0x02, 0x86, 0x44, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77,
+       0x77, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e,
+       0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x2f, 0x63, 0x65, 0x72, 0x74,
+       0x73, 0x2f, 0x4d, 0x69, 0x63, 0x43, 0x6f, 0x72, 0x54, 0x68, 0x69, 0x50,
+       0x61, 0x72, 0x4d, 0x61, 0x72, 0x52, 0x6f, 0x6f, 0x5f, 0x32, 0x30, 0x31,
+       0x30, 0x2d, 0x31, 0x30, 0x2d, 0x30, 0x35, 0x2e, 0x63, 0x72, 0x74, 0x30,
+       0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+       0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x35, 0x08, 0x42, 0xff, 0x30,
+       0xcc, 0xce, 0xf7, 0x76, 0x0c, 0xad, 0x10, 0x68, 0x58, 0x35, 0x29, 0x46,
+       0x32, 0x76, 0x27, 0x7c, 0xef, 0x12, 0x41, 0x27, 0x42, 0x1b, 0x4a, 0xaa,
+       0x6d, 0x81, 0x38, 0x48, 0x59, 0x13, 0x55, 0xf3, 0xe9, 0x58, 0x34, 0xa6,
+       0x16, 0x0b, 0x82, 0xaa, 0x5d, 0xad, 0x82, 0xda, 0x80, 0x83, 0x41, 0x06,
+       0x8f, 0xb4, 0x1d, 0xf2, 0x03, 0xb9, 0xf3, 0x1a, 0x5d, 0x1b, 0xf1, 0x50,
+       0x90, 0xf9, 0xb3, 0x55, 0x84, 0x42, 0x28, 0x1c, 0x20, 0xbd, 0xb2, 0xae,
+       0x51, 0x14, 0xc5, 0xc0, 0xac, 0x97, 0x95, 0x21, 0x1c, 0x90, 0xdb, 0x0f,
+       0xfc, 0x77, 0x9e, 0x95, 0x73, 0x91, 0x88, 0xca, 0xbd, 0xbd, 0x52, 0xb9,
+       0x05, 0x50, 0x0d, 0xdf, 0x57, 0x9e, 0xa0, 0x61, 0xed, 0x0d, 0xe5, 0x6d,
+       0x25, 0xd9, 0x40, 0x0f, 0x17, 0x40, 0xc8, 0xce, 0xa3, 0x4a, 0xc2, 0x4d,
+       0xaf, 0x9a, 0x12, 0x1d, 0x08, 0x54, 0x8f, 0xbd, 0xc7, 0xbc, 0xb9, 0x2b,
+       0x3d, 0x49, 0x2b, 0x1f, 0x32, 0xfc, 0x6a, 0x21, 0x69, 0x4f, 0x9b, 0xc8,
+       0x7e, 0x42, 0x34, 0xfc, 0x36, 0x06, 0x17, 0x8b, 0x8f, 0x20, 0x40, 0xc0,
+       0xb3, 0x9a, 0x25, 0x75, 0x27, 0xcd, 0xc9, 0x03, 0xa3, 0xf6, 0x5d, 0xd1,
+       0xe7, 0x36, 0x54, 0x7a, 0xb9, 0x50, 0xb5, 0xd3, 0x12, 0xd1, 0x07, 0xbf,
+       0xbb, 0x74, 0xdf, 0xdc, 0x1e, 0x8f, 0x80, 0xd5, 0xed, 0x18, 0xf4, 0x2f,
+       0x14, 0x16, 0x6b, 0x2f, 0xde, 0x66, 0x8c, 0xb0, 0x23, 0xe5, 0xc7, 0x84,
+       0xd8, 0xed, 0xea, 0xc1, 0x33, 0x82, 0xad, 0x56, 0x4b, 0x18, 0x2d, 0xf1,
+       0x68, 0x95, 0x07, 0xcd, 0xcf, 0xf0, 0x72, 0xf0, 0xae, 0xbb, 0xdd, 0x86,
+       0x85, 0x98, 0x2c, 0x21, 0x4c, 0x33, 0x2b, 0xf0, 0x0f, 0x4a, 0xf0, 0x68,
+       0x87, 0xb5, 0x92, 0x55, 0x32, 0x75, 0xa1, 0x6a, 0x82, 0x6a, 0x3c, 0xa3,
+       0x25, 0x11, 0xa4, 0xed, 0xad, 0xd7, 0x04, 0xae, 0xcb, 0xd8, 0x40, 0x59,
+       0xa0, 0x84, 0xd1, 0x95, 0x4c, 0x62, 0x91, 0x22, 0x1a, 0x74, 0x1d, 0x8c,
+       0x3d, 0x47, 0x0e, 0x44, 0xa6, 0xe4, 0xb0, 0x9b, 0x34, 0x35, 0xb1, 0xfa,
+       0xb6, 0x53, 0xa8, 0x2c, 0x81, 0xec, 0xa4, 0x05, 0x71, 0xc8, 0x9d, 0xb8,
+       0xba, 0xe8, 0x1b, 0x44, 0x66, 0xe4, 0x47, 0x54, 0x0e, 0x8e, 0x56, 0x7f,
+       0xb3, 0x9f, 0x16, 0x98, 0xb2, 0x86, 0xd0, 0x68, 0x3e, 0x90, 0x23, 0xb5,
+       0x2f, 0x5e, 0x8f, 0x50, 0x85, 0x8d, 0xc6, 0x8d, 0x82, 0x5f, 0x41, 0xa1,
+       0xf4, 0x2e, 0x0d, 0xe0, 0x99, 0xd2, 0x6c, 0x75, 0xe4, 0xb6, 0x69, 0xb5,
+       0x21, 0x86, 0xfa, 0x07, 0xd1, 0xf6, 0xe2, 0x4d, 0xd1, 0xda, 0xad, 0x2c,
+       0x77, 0x53, 0x1e, 0x25, 0x32, 0x37, 0xc7, 0x6c, 0x52, 0x72, 0x95, 0x86,
+       0xb0, 0xf1, 0x35, 0x61, 0x6a, 0x19, 0xf5, 0xb2, 0x3b, 0x81, 0x50, 0x56,
+       0xa6, 0x32, 0x2d, 0xfe, 0xa2, 0x89, 0xf9, 0x42, 0x86, 0x27, 0x18, 0x55,
+       0xa1, 0x82, 0xca, 0x5a, 0x9b, 0xf8, 0x30, 0x98, 0x54, 0x14, 0xa6, 0x47,
+       0x96, 0x25, 0x2f, 0xc8, 0x26, 0xe4, 0x41, 0x94, 0x1a, 0x5c, 0x02, 0x3f,
+       0xe5, 0x96, 0xe3, 0x85, 0x5b, 0x3c, 0x3e, 0x3f, 0xbb, 0x47, 0x16, 0x72,
+       0x55, 0xe2, 0x25, 0x22, 0xb1, 0xd9, 0x7b, 0xe7, 0x03, 0x06, 0x2a, 0xa3,
+       0xf7, 0x1e, 0x90, 0x46, 0xc3, 0x00, 0x0d, 0xd6, 0x19, 0x89, 0xe3, 0x0e,
+       0x35, 0x27, 0x62, 0x03, 0x71, 0x15, 0xa6, 0xef, 0xd0, 0x27, 0xa0, 0xa0,
+       0x59, 0x37, 0x60, 0xf8, 0x38, 0x94, 0xb8, 0xe0, 0x78, 0x70, 0xf8, 0xba,
+       0x4c, 0x86, 0x87, 0x94, 0xf6, 0xe0, 0xae, 0x02, 0x45, 0xee, 0x65, 0xc2,
+       0xb6, 0xa3, 0x7e, 0x69, 0x16, 0x75, 0x07, 0x92, 0x9b, 0xf5, 0xa6, 0xbc,
+       0x59, 0x83, 0x58, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87,
+       0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x07, 0x06, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0xeb, 0x05, 0x00, 0x00, 0xbd, 0x9a, 0xfa, 0x77, 0x59,
+       0x03, 0x32, 0x4d, 0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b, 0x30,
+       0x82, 0x05, 0xd7, 0x30, 0x82, 0x03, 0xbf, 0xa0, 0x03, 0x02, 0x01, 0x02,
+       0x02, 0x0a, 0x61, 0x07, 0x76, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+       0x0b, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+       0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
+       0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
+       0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
+       0x07, 0x13, 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e,
+       0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63,
+       0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f,
+       0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03,
+       0x55, 0x04, 0x03, 0x13, 0x29, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+       0x66, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+       0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+       0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x32, 0x30, 0x31, 0x30, 0x30, 0x1e,
+       0x17, 0x0d, 0x31, 0x31, 0x31, 0x30, 0x31, 0x39, 0x31, 0x38, 0x34, 0x31,
+       0x34, 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x31, 0x30, 0x31, 0x39, 0x31,
+       0x38, 0x35, 0x31, 0x34, 0x32, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30,
+       0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
+       0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73,
+       0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06,
+       0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e,
+       0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15,
+       0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f,
+       0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x2e, 0x30,
+       0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x4d, 0x69, 0x63, 0x72,
+       0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77,
+       0x73, 0x20, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+       0x20, 0x50, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x31, 0x30, 0x82, 0x01,
+       0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+       0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
+       0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdd, 0x0c, 0xbb, 0xa2, 0xe4, 0x2e,
+       0x09, 0xe3, 0xe7, 0xc5, 0xf7, 0x96, 0x69, 0xbc, 0x00, 0x21, 0xbd, 0x69,
+       0x33, 0x33, 0xef, 0xad, 0x04, 0xcb, 0x54, 0x80, 0xee, 0x06, 0x83, 0xbb,
+       0xc5, 0x20, 0x84, 0xd9, 0xf7, 0xd2, 0x8b, 0xf3, 0x38, 0xb0, 0xab, 0xa4,
+       0xad, 0x2d, 0x7c, 0x62, 0x79, 0x05, 0xff, 0xe3, 0x4a, 0x3f, 0x04, 0x35,
+       0x20, 0x70, 0xe3, 0xc4, 0xe7, 0x6b, 0xe0, 0x9c, 0xc0, 0x36, 0x75, 0xe9,
+       0x8a, 0x31, 0xdd, 0x8d, 0x70, 0xe5, 0xdc, 0x37, 0xb5, 0x74, 0x46, 0x96,
+       0x28, 0x5b, 0x87, 0x60, 0x23, 0x2c, 0xbf, 0xdc, 0x47, 0xa5, 0x67, 0xf7,
+       0x51, 0x27, 0x9e, 0x72, 0xeb, 0x07, 0xa6, 0xc9, 0xb9, 0x1e, 0x3b, 0x53,
+       0x35, 0x7c, 0xe5, 0xd3, 0xec, 0x27, 0xb9, 0x87, 0x1c, 0xfe, 0xb9, 0xc9,
+       0x23, 0x09, 0x6f, 0xa8, 0x46, 0x91, 0xc1, 0x6e, 0x96, 0x3c, 0x41, 0xd3,
+       0xcb, 0xa3, 0x3f, 0x5d, 0x02, 0x6a, 0x4d, 0xec, 0x69, 0x1f, 0x25, 0x28,
+       0x5c, 0x36, 0xff, 0xfd, 0x43, 0x15, 0x0a, 0x94, 0xe0, 0x19, 0xb4, 0xcf,
+       0xdf, 0xc2, 0x12, 0xe2, 0xc2, 0x5b, 0x27, 0xee, 0x27, 0x78, 0x30, 0x8b,
+       0x5b, 0x2a, 0x09, 0x6b, 0x22, 0x89, 0x53, 0x60, 0x16, 0x2c, 0xc0, 0x68,
+       0x1d, 0x53, 0xba, 0xec, 0x49, 0xf3, 0x9d, 0x61, 0x8c, 0x85, 0x68, 0x09,
+       0x73, 0x44, 0x5d, 0x7d, 0xa2, 0x54, 0x2b, 0xdd, 0x79, 0xf7, 0x15, 0xcf,
+       0x35, 0x5d, 0x6c, 0x1c, 0x2b, 0x5c, 0xce, 0xbc, 0x9c, 0x23, 0x8b, 0x6f,
+       0x6e, 0xb5, 0x26, 0xd9, 0x36, 0x13, 0xc3, 0x4f, 0xd6, 0x27, 0xae, 0xb9,
+       0x32, 0x3b, 0x41, 0x92, 0x2c, 0xe1, 0xc7, 0xcd, 0x77, 0xe8, 0xaa, 0x54,
+       0x4e, 0xf7, 0x5c, 0x0b, 0x04, 0x87, 0x65, 0xb4, 0x43, 0x18, 0xa8, 0xb2,
+       0xe0, 0x6d, 0x19, 0x77, 0xec, 0x5a, 0x24, 0xfa, 0x48, 0x03, 0x02, 0x03,
+       0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x43, 0x30, 0x82, 0x01, 0x3f, 0x30,
+       0x10, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01,
+       0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+       0x04, 0x16, 0x04, 0x14, 0xa9, 0x29, 0x02, 0x39, 0x8e, 0x16, 0xc4, 0x97,
+       0x78, 0xcd, 0x90, 0xf9, 0x9e, 0x4f, 0x9a, 0xe1, 0x7c, 0x55, 0xaf, 0x53,
+       0x30, 0x19, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14,
+       0x02, 0x04, 0x0c, 0x1e, 0x0a, 0x00, 0x53, 0x00, 0x75, 0x00, 0x62, 0x00,
+       0x43, 0x00, 0x41, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
+       0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+       0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06,
+       0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xd5, 0xf6,
+       0x56, 0xcb, 0x8f, 0xe8, 0xa2, 0x5c, 0x62, 0x68, 0xd1, 0x3d, 0x94, 0x90,
+       0x5b, 0xd7, 0xce, 0x9a, 0x18, 0xc4, 0x30, 0x56, 0x06, 0x03, 0x55, 0x1d,
+       0x1f, 0x04, 0x4f, 0x30, 0x4d, 0x30, 0x4b, 0xa0, 0x49, 0xa0, 0x47, 0x86,
+       0x45, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
+       0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f,
+       0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x70, 0x72,
+       0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2f, 0x4d, 0x69, 0x63, 0x52, 0x6f,
+       0x6f, 0x43, 0x65, 0x72, 0x41, 0x75, 0x74, 0x5f, 0x32, 0x30, 0x31, 0x30,
+       0x2d, 0x30, 0x36, 0x2d, 0x32, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x5a,
+       0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x4e,
+       0x30, 0x4c, 0x30, 0x4a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+       0x30, 0x02, 0x86, 0x3e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+       0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
+       0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x2f, 0x63, 0x65, 0x72,
+       0x74, 0x73, 0x2f, 0x4d, 0x69, 0x63, 0x52, 0x6f, 0x6f, 0x43, 0x65, 0x72,
+       0x41, 0x75, 0x74, 0x5f, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x30, 0x36, 0x2d,
+       0x32, 0x33, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
+       0x01, 0x00, 0x14, 0xfc, 0x7c, 0x71, 0x51, 0xa5, 0x79, 0xc2, 0x6e, 0xb2,
+       0xef, 0x39, 0x3e, 0xbc, 0x3c, 0x52, 0x0f, 0x6e, 0x2b, 0x3f, 0x10, 0x13,
+       0x73, 0xfe, 0xa8, 0x68, 0xd0, 0x48, 0xa6, 0x34, 0x4d, 0x8a, 0x96, 0x05,
+       0x26, 0xee, 0x31, 0x46, 0x90, 0x61, 0x79, 0xd6, 0xff, 0x38, 0x2e, 0x45,
+       0x6b, 0xf4, 0xc0, 0xe5, 0x28, 0xb8, 0xda, 0x1d, 0x8f, 0x8a, 0xdb, 0x09,
+       0xd7, 0x1a, 0xc7, 0x4c, 0x0a, 0x36, 0x66, 0x6a, 0x8c, 0xec, 0x1b, 0xd7,
+       0x04, 0x90, 0xa8, 0x18, 0x17, 0xa4, 0x9b, 0xb9, 0xe2, 0x40, 0x32, 0x36,
+       0x76, 0xc4, 0xc1, 0x5a, 0xc6, 0xbf, 0xe4, 0x04, 0xc0, 0xea, 0x16, 0xd3,
+       0xac, 0xc3, 0x68, 0xef, 0x62, 0xac, 0xdd, 0x54, 0x6c, 0x50, 0x30, 0x58,
+       0xa6, 0xeb, 0x7c, 0xfe, 0x94, 0xa7, 0x4e, 0x8e, 0xf4, 0xec, 0x7c, 0x86,
+       0x73, 0x57, 0xc2, 0x52, 0x21, 0x73, 0x34, 0x5a, 0xf3, 0xa3, 0x8a, 0x56,
+       0xc8, 0x04, 0xda, 0x07, 0x09, 0xed, 0xf8, 0x8b, 0xe3, 0xce, 0xf4, 0x7e,
+       0x8e, 0xae, 0xf0, 0xf6, 0x0b, 0x8a, 0x08, 0xfb, 0x3f, 0xc9, 0x1d, 0x72,
+       0x7f, 0x53, 0xb8, 0xeb, 0xbe, 0x63, 0xe0, 0xe3, 0x3d, 0x31, 0x65, 0xb0,
+       0x81, 0xe5, 0xf2, 0xac, 0xcd, 0x16, 0xa4, 0x9f, 0x3d, 0xa8, 0xb1, 0x9b,
+       0xc2, 0x42, 0xd0, 0x90, 0x84, 0x5f, 0x54, 0x1d, 0xff, 0x89, 0xea, 0xba,
+       0x1d, 0x47, 0x90, 0x6f, 0xb0, 0x73, 0x4e, 0x41, 0x9f, 0x40, 0x9f, 0x5f,
+       0xe5, 0xa1, 0x2a, 0xb2, 0x11, 0x91, 0x73, 0x8a, 0x21, 0x28, 0xf0, 0xce,
+       0xde, 0x73, 0x39, 0x5f, 0x3e, 0xab, 0x5c, 0x60, 0xec, 0xdf, 0x03, 0x10,
+       0xa8, 0xd3, 0x09, 0xe9, 0xf4, 0xf6, 0x96, 0x85, 0xb6, 0x7f, 0x51, 0x88,
+       0x66, 0x47, 0x19, 0x8d, 0xa2, 0xb0, 0x12, 0x3d, 0x81, 0x2a, 0x68, 0x05,
+       0x77, 0xbb, 0x91, 0x4c, 0x62, 0x7b, 0xb6, 0xc1, 0x07, 0xc7, 0xba, 0x7a,
+       0x87, 0x34, 0x03, 0x0e, 0x4b, 0x62, 0x7a, 0x99, 0xe9, 0xca, 0xfc, 0xce,
+       0x4a, 0x37, 0xc9, 0x2d, 0xa4, 0x57, 0x7c, 0x1c, 0xfe, 0x3d, 0xdc, 0xb8,
+       0x0f, 0x5a, 0xfa, 0xd6, 0xc4, 0xb3, 0x02, 0x85, 0x02, 0x3a, 0xea, 0xb3,
+       0xd9, 0x6e, 0xe4, 0x69, 0x21, 0x37, 0xde, 0x81, 0xd1, 0xf6, 0x75, 0x19,
+       0x05, 0x67, 0xd3, 0x93, 0x57, 0x5e, 0x29, 0x1b, 0x39, 0xc8, 0xee, 0x2d,
+       0xe1, 0xcd, 0xe4, 0x45, 0x73, 0x5b, 0xd0, 0xd2, 0xce, 0x7a, 0xab, 0x16,
+       0x19, 0x82, 0x46, 0x58, 0xd0, 0x5e, 0x9d, 0x81, 0xb3, 0x67, 0xaf, 0x6c,
+       0x35, 0xf2, 0xbc, 0xe5, 0x3f, 0x24, 0xe2, 0x35, 0xa2, 0x0a, 0x75, 0x06,
+       0xf6, 0x18, 0x56, 0x99, 0xd4, 0x78, 0x2c, 0xd1, 0x05, 0x1b, 0xeb, 0xd0,
+       0x88, 0x01, 0x9d, 0xaa, 0x10, 0xf1, 0x05, 0xdf, 0xba, 0x7e, 0x2c, 0x63,
+       0xb7, 0x06, 0x9b, 0x23, 0x21, 0xc4, 0xf9, 0x78, 0x6c, 0xe2, 0x58, 0x17,
+       0x06, 0x36, 0x2b, 0x91, 0x12, 0x03, 0xcc, 0xa4, 0xd9, 0xf2, 0x2d, 0xba,
+       0xf9, 0x94, 0x9d, 0x40, 0xed, 0x18, 0x45, 0xf1, 0xce, 0x8a, 0x5c, 0x6b,
+       0x3e, 0xab, 0x03, 0xd3, 0x70, 0x18, 0x2a, 0x0a, 0x6a, 0xe0, 0x5f, 0x47,
+       0xd1, 0xd5, 0x63, 0x0a, 0x32, 0xf2, 0xaf, 0xd7, 0x36, 0x1f, 0x2a, 0x70,
+       0x5a, 0xe5, 0x42, 0x59, 0x08, 0x71, 0x4b, 0x57, 0xba, 0x7e, 0x83, 0x81,
+       0xf0, 0x21, 0x3c, 0xf4, 0x1c, 0xc1, 0xc5, 0xb9, 0x90, 0x93, 0x0e, 0x88,
+       0x45, 0x93, 0x86, 0xe9, 0xb1, 0x20, 0x99, 0xbe, 0x98, 0xcb, 0xc5, 0x95,
+       0xa4, 0x5d, 0x62, 0xd6, 0xa0, 0x63, 0x08, 0x20, 0xbd, 0x75, 0x10, 0x77,
+       0x7d, 0x3d, 0xf3, 0x45, 0xb9, 0x9f, 0x97, 0x9f, 0xcb, 0x57, 0x80, 0x6f,
+       0x33, 0xa9, 0x04, 0xcf, 0x77, 0xa4, 0x62, 0x1c, 0x59, 0x7e, 0xa1, 0x59,
+       0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b,
+       0xf0, 0x72, 0x64, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x04,
+       0x00, 0x00, 0xe4, 0x0a, 0xc4, 0x6d, 0xe8, 0x2e, 0x4c, 0x9c, 0xa3, 0x14,
+       0x0f, 0xc7, 0xb2, 0x00, 0x87, 0x10, 0x30, 0x82, 0x04, 0x34, 0x30, 0x82,
+       0x03, 0x1c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xb9, 0x41,
+       0x24, 0xa0, 0x18, 0x2c, 0x92, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x84,
+       0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
+       0x42, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0b,
+       0x49, 0x73, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x4d, 0x61, 0x6e, 0x31,
+       0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x44, 0x6f,
+       0x75, 0x67, 0x6c, 0x61, 0x73, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
+       0x04, 0x0a, 0x0c, 0x0e, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61,
+       0x6c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x34, 0x30, 0x32, 0x06, 0x03,
+       0x55, 0x04, 0x03, 0x0c, 0x2b, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63,
+       0x61, 0x6c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x4d, 0x61, 0x73, 0x74,
+       0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+       0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+       0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x31, 0x32, 0x31, 0x31,
+       0x31, 0x32, 0x35, 0x31, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x34, 0x31,
+       0x31, 0x31, 0x31, 0x31, 0x32, 0x35, 0x31, 0x5a, 0x30, 0x81, 0x84, 0x31,
+       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42,
+       0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0b, 0x49,
+       0x73, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x4d, 0x61, 0x6e, 0x31, 0x10,
+       0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x44, 0x6f, 0x75,
+       0x67, 0x6c, 0x61, 0x73, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+       0x0a, 0x0c, 0x0e, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c,
+       0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x34, 0x30, 0x32, 0x06, 0x03, 0x55,
+       0x04, 0x03, 0x0c, 0x2b, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61,
+       0x6c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65,
+       0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+       0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30,
+       0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+       0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
+       0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, 0x5b, 0x3a, 0x16,
+       0x74, 0xee, 0x21, 0x5d, 0xae, 0x61, 0xed, 0x9d, 0x56, 0xac, 0xbd, 0xde,
+       0xde, 0x72, 0xf3, 0xdd, 0x7e, 0x2d, 0x4c, 0x62, 0x0f, 0xac, 0xc0, 0x6d,
+       0x48, 0x08, 0x11, 0xcf, 0x8d, 0x8b, 0xfb, 0x61, 0x1f, 0x27, 0xcc, 0x11,
+       0x6e, 0xd9, 0x55, 0x3d, 0x39, 0x54, 0xeb, 0x40, 0x3b, 0xb1, 0xbb, 0xe2,
+       0x85, 0x34, 0x79, 0xca, 0xf7, 0x7b, 0xbf, 0xba, 0x7a, 0xc8, 0x10, 0x2d,
+       0x19, 0x7d, 0xad, 0x59, 0xcf, 0xa6, 0xd4, 0xe9, 0x4e, 0x0f, 0xda, 0xae,
+       0x52, 0xea, 0x4c, 0x9e, 0x90, 0xce, 0xc6, 0x99, 0x0d, 0x4e, 0x67, 0x65,
+       0x78, 0x5d, 0xf9, 0xd1, 0xd5, 0x38, 0x4a, 0x4a, 0x7a, 0x8f, 0x93, 0x9c,
+       0x7f, 0x1a, 0xa3, 0x85, 0xdb, 0xce, 0xfa, 0x8b, 0xf7, 0xc2, 0xa2, 0x21,
+       0x2d, 0x9b, 0x54, 0x41, 0x35, 0x10, 0x57, 0x13, 0x8d, 0x6c, 0xbc, 0x29,
+       0x06, 0x50, 0x4a, 0x7e, 0xea, 0x99, 0xa9, 0x68, 0xa7, 0x3b, 0xc7, 0x07,
+       0x1b, 0x32, 0x9e, 0xa0, 0x19, 0x87, 0x0e, 0x79, 0xbb, 0x68, 0x99, 0x2d,
+       0x7e, 0x93, 0x52, 0xe5, 0xf6, 0xeb, 0xc9, 0x9b, 0xf9, 0x2b, 0xed, 0xb8,
+       0x68, 0x49, 0xbc, 0xd9, 0x95, 0x50, 0x40, 0x5b, 0xc5, 0xb2, 0x71, 0xaa,
+       0xeb, 0x5c, 0x57, 0xde, 0x71, 0xf9, 0x40, 0x0a, 0xdd, 0x5b, 0xac, 0x1e,
+       0x84, 0x2d, 0x50, 0x1a, 0x52, 0xd6, 0xe1, 0xf3, 0x6b, 0x6e, 0x90, 0x64,
+       0x4f, 0x5b, 0xb4, 0xeb, 0x20, 0xe4, 0x61, 0x10, 0xda, 0x5a, 0xf0, 0xea,
+       0xe4, 0x42, 0xd7, 0x01, 0xc4, 0xfe, 0x21, 0x1f, 0xd9, 0xb9, 0xc0, 0x54,
+       0x95, 0x42, 0x81, 0x52, 0x72, 0x1f, 0x49, 0x64, 0x7a, 0xc8, 0x6c, 0x24,
+       0xf1, 0x08, 0x70, 0x0b, 0x4d, 0xa5, 0xa0, 0x32, 0xd1, 0xa0, 0x1c, 0x57,
+       0xa8, 0x4d, 0xe3, 0xaf, 0xa5, 0x8e, 0x05, 0x05, 0x3e, 0x10, 0x43, 0xa1,
+       0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa6, 0x30, 0x81, 0xa3, 0x30,
+       0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xad, 0x91,
+       0x99, 0x0b, 0xc2, 0x2a, 0xb1, 0xf5, 0x17, 0x04, 0x8c, 0x23, 0xb6, 0x65,
+       0x5a, 0x26, 0x8e, 0x34, 0x5a, 0x63, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+       0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xad, 0x91, 0x99, 0x0b, 0xc2,
+       0x2a, 0xb1, 0xf5, 0x17, 0x04, 0x8c, 0x23, 0xb6, 0x65, 0x5a, 0x26, 0x8e,
+       0x34, 0x5a, 0x63, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+       0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03,
+       0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x43, 0x06,
+       0x03, 0x55, 0x1d, 0x1f, 0x04, 0x3c, 0x30, 0x3a, 0x30, 0x38, 0xa0, 0x36,
+       0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+       0x77, 0x77, 0x2e, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c,
+       0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2d,
+       0x62, 0x6f, 0x6f, 0x74, 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2d,
+       0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01,
+       0x01, 0x00, 0x3f, 0x7d, 0xf6, 0x76, 0xa5, 0xb3, 0x83, 0xb4, 0x2b, 0x7a,
+       0xd0, 0x6d, 0x52, 0x1a, 0x03, 0x83, 0xc4, 0x12, 0xa7, 0x50, 0x9c, 0x47,
+       0x92, 0xcc, 0xc0, 0x94, 0x77, 0x82, 0xd2, 0xae, 0x57, 0xb3, 0x99, 0x04,
+       0xf5, 0x32, 0x3a, 0xc6, 0x55, 0x1d, 0x07, 0xdb, 0x12, 0xa9, 0x56, 0xfa,
+       0xd8, 0xd4, 0x76, 0x20, 0xeb, 0xe4, 0xc3, 0x51, 0xdb, 0x9a, 0x5c, 0x9c,
+       0x92, 0x3f, 0x18, 0x73, 0xda, 0x94, 0x6a, 0xa1, 0x99, 0x38, 0x8c, 0xa4,
+       0x88, 0x6d, 0xc1, 0xfc, 0x39, 0x71, 0xd0, 0x74, 0x76, 0x16, 0x03, 0x3e,
+       0x56, 0x23, 0x35, 0xd5, 0x55, 0x47, 0x5b, 0x1a, 0x1d, 0x41, 0xc2, 0xd3,
+       0x12, 0x4c, 0xdc, 0xff, 0xae, 0x0a, 0x92, 0x9c, 0x62, 0x0a, 0x17, 0x01,
+       0x9c, 0x73, 0xe0, 0x5e, 0xb1, 0xfd, 0xbc, 0xd6, 0xb5, 0x19, 0x11, 0x7a,
+       0x7e, 0xcd, 0x3e, 0x03, 0x7e, 0x66, 0xdb, 0x5b, 0xa8, 0xc9, 0x39, 0x48,
+       0x51, 0xff, 0x53, 0xe1, 0x9c, 0x31, 0x53, 0x91, 0x1b, 0x3b, 0x10, 0x75,
+       0x03, 0x17, 0xba, 0xe6, 0x81, 0x02, 0x80, 0x94, 0x70, 0x4c, 0x46, 0xb7,
+       0x94, 0xb0, 0x3d, 0x15, 0xcd, 0x1f, 0x8e, 0x02, 0xe0, 0x68, 0x02, 0x8f,
+       0xfb, 0xf9, 0x47, 0x1d, 0x7d, 0xa2, 0x01, 0xc6, 0x07, 0x51, 0xc4, 0x9a,
+       0xcc, 0xed, 0xdd, 0xcf, 0xa3, 0x5d, 0xed, 0x92, 0xbb, 0xbe, 0xd1, 0xfd,
+       0xe6, 0xec, 0x1f, 0x33, 0x51, 0x73, 0x04, 0xbe, 0x3c, 0x72, 0xb0, 0x7d,
+       0x08, 0xf8, 0x01, 0xff, 0x98, 0x7d, 0xcb, 0x9c, 0xe0, 0x69, 0x39, 0x77,
+       0x25, 0x47, 0x71, 0x88, 0xb1, 0x8d, 0x27, 0xa5, 0x2e, 0xa8, 0xf7, 0x3f,
+       0x5f, 0x80, 0x69, 0x97, 0x3e, 0xa9, 0xf4, 0x99, 0x14, 0xdb, 0xce, 0x03,
+       0x0e, 0x0b, 0x66, 0xc4, 0x1c, 0x6d, 0xbd, 0xb8, 0x27, 0x77, 0xc1, 0x42,
+       0x94, 0xbd, 0xfc, 0x6a, 0x0a, 0xbc, 0x26, 0x16, 0xc4, 0xc1, 0x4c, 0x50,
+       0x92, 0x40, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28, 0x0c, 0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xf5, 0x8f, 0xbd, 0xf7, 0x1b, 0xe8, 0xc3, 0x7c, 0xbb, 0xd6,
+       0x94, 0x4e, 0x47, 0x2c, 0x45, 0x0b, 0x10, 0x43, 0x81, 0x7b, 0x97, 0x29,
+       0x14, 0x48, 0x7c, 0x22, 0x10, 0x33, 0xf3, 0x07, 0x9e, 0x43, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x04, 0x97, 0x01, 0x57, 0xde, 0x52, 0xcd, 0xae, 0x14, 0xcf,
+       0x17, 0xee, 0x36, 0x98, 0x81, 0xd6, 0x24, 0x5b, 0x3a, 0x6a, 0xb6, 0x35,
+       0x2e, 0xab, 0xae, 0xe5, 0x88, 0xa0, 0x58, 0x4b, 0x03, 0x03, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xf1, 0x6b, 0x5f, 0xc3, 0x61, 0x18, 0x3f, 0x58, 0x71, 0x20,
+       0xe6, 0x02, 0xc0, 0xd6, 0x57, 0x73, 0xaf, 0xdf, 0xe7, 0x86, 0x12, 0x41,
+       0x84, 0xfa, 0x70, 0x80, 0x52, 0x58, 0xd7, 0x6d, 0x59, 0x4c, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7e, 0x02, 0x1f, 0x15, 0xe3, 0xa6, 0x7b, 0x75, 0xac, 0xe8,
+       0x84, 0x99, 0x9b, 0xed, 0xff, 0xe3, 0x42, 0x13, 0x79, 0x2a, 0x61, 0x1e,
+       0x40, 0xe5, 0x62, 0xe8, 0x7e, 0x6b, 0x9a, 0x0c, 0xb2, 0x82, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xa5, 0xd1, 0x09, 0xb2, 0xaf, 0xa3, 0xfa, 0x90, 0x87, 0x8f,
+       0x70, 0x38, 0x2b, 0x23, 0x88, 0xfc, 0xd2, 0xfe, 0xae, 0xae, 0x8a, 0x51,
+       0xb8, 0x0a, 0xdd, 0x04, 0x8e, 0x9f, 0x87, 0x6b, 0x2a, 0x4e
+};
+
+#endif /* !TEST_DATA_EFIVARS_0_H_ */
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/test-data-efivars-1.h b/include/test-data-efivars-1.h
new file mode 100644 (file)
index 0000000..55090ed
--- /dev/null
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * test-data-efivars-1.h - test data
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#ifndef TEST_DATA_EFIVARS_1_H_
+#define TEST_DATA_EFIVARS_1_H_
+
+static const unsigned char test_data_efivars_1_MokListRT[] = {
+       0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15,
+       0x5c, 0x2b, 0xf0, 0x72, 0x98, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x7c, 0x03, 0x00, 0x00, 0x50, 0xab, 0x5d, 0x60, 0x46, 0xe0, 0x00, 0x43,
+       0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23, 0x30, 0x82, 0x03, 0x68,
+       0x30, 0x82, 0x02, 0x50, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x00,
+       0x99, 0x76, 0xf2, 0xf4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+       0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x20, 0x31, 0x1e, 0x30,
+       0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x46, 0x65, 0x64, 0x6f,
+       0x72, 0x61, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f,
+       0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,
+       0x32, 0x30, 0x37, 0x31, 0x36, 0x32, 0x35, 0x35, 0x34, 0x5a, 0x17, 0x0d,
+       0x32, 0x32, 0x31, 0x32, 0x30, 0x35, 0x31, 0x36, 0x32, 0x35, 0x35, 0x34,
+       0x5a, 0x30, 0x20, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03,
+       0x13, 0x15, 0x46, 0x65, 0x64, 0x6f, 0x72, 0x61, 0x20, 0x53, 0x65, 0x63,
+       0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
+       0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+       0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
+       0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xf5, 0xf7, 0x52,
+       0x81, 0xa9, 0x5c, 0x3e, 0x2b, 0xf7, 0x1d, 0x55, 0xf4, 0x5a, 0x68, 0x84,
+       0x2d, 0xbc, 0x8b, 0x76, 0x96, 0x85, 0x0d, 0x27, 0xb8, 0x18, 0xa5, 0xcd,
+       0xc1, 0x83, 0xb2, 0x8c, 0x27, 0x5d, 0x23, 0x0a, 0xd1, 0x12, 0x0a, 0x75,
+       0x98, 0xa2, 0xe6, 0x5d, 0x01, 0x8a, 0xf4, 0xd9, 0x9f, 0xfc, 0x70, 0xbc,
+       0xc3, 0xc4, 0x17, 0x7b, 0x02, 0xb5, 0x13, 0xc4, 0x51, 0x92, 0xe0, 0xc0,
+       0x05, 0x74, 0xb9, 0x2e, 0x3d, 0x24, 0x78, 0xa0, 0x79, 0x73, 0x94, 0xc0,
+       0xc2, 0x2b, 0xb2, 0x82, 0xa7, 0xf4, 0xab, 0x67, 0x4a, 0x22, 0xf3, 0x64,
+       0xcd, 0xc3, 0xf9, 0x0c, 0x26, 0x01, 0xbf, 0x1b, 0xd5, 0x3d, 0x39, 0xbf,
+       0xc9, 0xfa, 0xfb, 0x5e, 0x52, 0xb9, 0xa4, 0x48, 0xfb, 0x13, 0xbf, 0x87,
+       0x29, 0x0a, 0x64, 0xef, 0x21, 0x7b, 0xbc, 0x1e, 0x16, 0x7b, 0x88, 0x4f,
+       0xf1, 0x40, 0x2b, 0xd9, 0x22, 0x15, 0x47, 0x4e, 0x84, 0xf6, 0x24, 0x1c,
+       0x4d, 0x53, 0x16, 0x5a, 0xb1, 0x29, 0xbb, 0x5e, 0x7d, 0x7f, 0xc0, 0xd4,
+       0xe2, 0xd5, 0x79, 0xaf, 0x59, 0x73, 0x02, 0xdc, 0xb7, 0x48, 0xbf, 0xae,
+       0x2b, 0x70, 0xc1, 0xfa, 0x74, 0x7f, 0x79, 0xf5, 0xee, 0x23, 0xd0, 0x03,
+       0x05, 0xb1, 0x79, 0x18, 0x4f, 0xfd, 0x4f, 0x2f, 0xe2, 0x63, 0x19, 0x4d,
+       0x77, 0xba, 0xc1, 0x2c, 0x8b, 0xb3, 0xd9, 0x05, 0x2e, 0xd9, 0xd8, 0xb6,
+       0x51, 0x13, 0xbf, 0xce, 0x36, 0x67, 0x97, 0xe4, 0xad, 0x58, 0x56, 0x07,
+       0xab, 0xd0, 0x8c, 0x66, 0x12, 0x49, 0xdc, 0x91, 0x68, 0xb4, 0xc8, 0xea,
+       0xdd, 0x9c, 0xc0, 0x81, 0xc6, 0x91, 0x5b, 0xdb, 0x12, 0x78, 0xdb, 0xff,
+       0xc1, 0xaf, 0x08, 0x16, 0xfc, 0x70, 0x13, 0x97, 0x5b, 0x57, 0xad, 0x6b,
+       0x44, 0x98, 0x7e, 0x1f, 0xec, 0xed, 0x46, 0x66, 0x95, 0x0f, 0x05, 0x55,
+       0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa8, 0x30, 0x81, 0xa5, 0x30,
+       0x4e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
+       0x42, 0x30, 0x40, 0x30, 0x3e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+       0x07, 0x30, 0x02, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
+       0x2f, 0x66, 0x65, 0x64, 0x6f, 0x72, 0x61, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+       0x63, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x69, 0x6b, 0x69, 0x2f,
+       0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2f, 0x53, 0x65, 0x63,
+       0x75, 0x72, 0x65, 0x42, 0x6f, 0x6f, 0x74, 0x30, 0x1f, 0x06, 0x03, 0x55,
+       0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xfd, 0xe3, 0x25, 0x99,
+       0xc2, 0xd6, 0x1d, 0xb1, 0xbf, 0x58, 0x07, 0x33, 0x5d, 0x7b, 0x20, 0xe4,
+       0xcd, 0x96, 0x3b, 0x42, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
+       0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
+       0x03, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+       0xfd, 0xe3, 0x25, 0x99, 0xc2, 0xd6, 0x1d, 0xb1, 0xbf, 0x58, 0x07, 0x33,
+       0x5d, 0x7b, 0x20, 0xe4, 0xcd, 0x96, 0x3b, 0x42, 0x30, 0x0d, 0x06, 0x09,
+       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+       0x82, 0x01, 0x01, 0x00, 0x37, 0x77, 0xf0, 0x3a, 0x41, 0xa2, 0x1c, 0x9f,
+       0x71, 0x3b, 0xd6, 0x9b, 0x95, 0xb5, 0x15, 0xdf, 0x4a, 0xb6, 0xf4, 0xd1,
+       0x51, 0xba, 0x0d, 0x04, 0xda, 0x9c, 0xb2, 0x23, 0xf0, 0xf3, 0x34, 0x59,
+       0x8d, 0xb8, 0xd4, 0x9a, 0x75, 0x74, 0x65, 0x80, 0x17, 0x61, 0x3a, 0xc1,
+       0x96, 0x7f, 0xa7, 0xc1, 0x2b, 0xd3, 0x1a, 0xd6, 0x60, 0x3c, 0x71, 0x3a,
+       0xa4, 0xc4, 0xe3, 0x39, 0x03, 0x02, 0x15, 0x12, 0x08, 0x1f, 0x4e, 0xcd,
+       0x97, 0x50, 0xf8, 0xff, 0x50, 0xcc, 0xb6, 0x3e, 0x03, 0x7d, 0x7a, 0xe7,
+       0x82, 0x7a, 0xc2, 0x67, 0xbe, 0xc9, 0x0e, 0x11, 0x0f, 0x16, 0x2e, 0x1e,
+       0xa9, 0xf2, 0x6e, 0xfe, 0x04, 0xbd, 0xea, 0x9e, 0xf4, 0xa9, 0xb3, 0xd9,
+       0xd4, 0x61, 0x57, 0x08, 0x87, 0xc4, 0x98, 0xd8, 0xa2, 0x99, 0x64, 0xde,
+       0x15, 0x54, 0x8d, 0x57, 0x79, 0x14, 0x1f, 0xfa, 0x0d, 0x4d, 0x6b, 0xcd,
+       0x98, 0x35, 0xf5, 0x0c, 0x06, 0xbd, 0xf3, 0x31, 0xd6, 0xfe, 0x05, 0x1f,
+       0x60, 0x90, 0xb6, 0x1e, 0x10, 0xf7, 0x24, 0xe0, 0x3c, 0xf6, 0x33, 0x50,
+       0xcd, 0x44, 0xc2, 0x71, 0x18, 0x51, 0xbd, 0x18, 0x31, 0x81, 0x1e, 0x32,
+       0xe1, 0xe6, 0x9f, 0xf9, 0x9c, 0x02, 0x53, 0xb4, 0xe5, 0x6a, 0x41, 0xd6,
+       0x65, 0xb4, 0x2e, 0xf1, 0xcf, 0xb3, 0xb8, 0x82, 0xb0, 0xa3, 0x96, 0xe2,
+       0x24, 0xd8, 0x83, 0xae, 0x06, 0x5b, 0xb3, 0x24, 0x74, 0x4d, 0xd1, 0xa4,
+       0x0a, 0x1d, 0x0a, 0x32, 0x1b, 0x75, 0xa2, 0x96, 0xd1, 0x0e, 0x3e, 0xe1,
+       0x30, 0xc3, 0x18, 0xe8, 0xcb, 0x53, 0xc4, 0x0b, 0x00, 0xad, 0x7e, 0xad,
+       0xc8, 0x49, 0x41, 0xef, 0x97, 0x69, 0xbd, 0x13, 0x5f, 0xef, 0xef, 0x3c,
+       0xda, 0x60, 0x05, 0xd8, 0x92, 0xfc, 0xda, 0x6a, 0xea, 0x48, 0x3f, 0x0e,
+       0x3e, 0x73, 0x77, 0xfd, 0xa6, 0x89, 0xe9, 0x3f
+};
+
+static const unsigned char test_data_efivars_1_MokListXRT[] = {
+       0x26, 0x16, 0xc4, 0xc1, 0x4c, 0x50, 0x92, 0x40, 0xac, 0xa9, 0x41,
+       0xf9, 0x36, 0x93, 0x43, 0x28, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x50, 0xab, 0x5d, 0x60, 0x46,
+       0xe0, 0x00, 0x43, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char test_data_efivars_1_SbatLevelRT[] = {
+       0x73, 0x62, 0x61, 0x74, 0x2c, 0x31, 0x2c, 0x32, 0x30,
+       0x32, 0x31, 0x30, 0x33, 0x30, 0x32, 0x31, 0x38, 0x0a
+};
+
+#endif /* !TEST_DATA_EFIVARS_1_H_ */
+// vim:fenc=utf-8:tw=75:noet
index 012ffc51e18072f02a6b585e7495642c41c4f787..5261dbd9074a59e4c503c93cb96976a577ea63ee 100644 (file)
@@ -8,7 +8,14 @@
 #ifndef TEST_H_
 #define TEST_H_
 
+#define _GNU_SOURCE
+
 #include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
 
 #if defined(__aarch64__)
 #include <aarch64/efibind.h>
 
 #include <stdlib.h>
 
-#define ZeroMem(buf, sz) memset(buf, 0, sz)
-#define SetMem(buf, sz, value) memset(buf, value, sz)
-#define CopyMem(dest, src, len) memcpy(dest, src, len)
-#define CompareMem(dest, src, len) memcmp(dest, src, len)
+#include <assert.h>
+
+#include <efiui.h>
+#include <efilib.h>
+
+#include <efivar/efivar.h>
 
 #include <assert.h>
 
-#define AllocateZeroPool(x) calloc(1, (x))
-#define AllocatePool(x) malloc(x)
-#define FreePool(x) free(x)
-#define ReallocatePool(old, oldsz, newsz) realloc(old, newsz)
+#include "list.h"
+
+INTN StrCmp(IN CONST CHAR16 *s1,
+           IN CONST CHAR16 *s2);
+INTN StrnCmp(IN CONST CHAR16 *s1,
+            IN CONST CHAR16 *s2,
+            IN UINTN len);
+VOID StrCpy(IN CHAR16 *Dest,
+           IN CONST CHAR16 *Src);
+VOID StrnCpy(IN CHAR16 *Dest,
+            IN CONST CHAR16 *Src,
+            IN UINTN Len);
+CHAR16 *StrDuplicate(IN CONST CHAR16 *Src);
+UINTN StrLen(IN CONST CHAR16 *s1);
+UINTN StrSize(IN CONST CHAR16 *s1);
+VOID StrCat(IN CHAR16 *Dest, IN CONST CHAR16 *Src);
+CHAR16 *DevicePathToStr(EFI_DEVICE_PATH *DevPath);
+
+extern EFI_SYSTEM_TABLE *ST;
+extern EFI_BOOT_SERVICES *BS;
+extern EFI_RUNTIME_SERVICES *RT;
+
+#define GUID_FMT "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+#define GUID_ARGS(guid) \
+       ((EFI_GUID)guid).Data1, ((EFI_GUID)guid).Data2, ((EFI_GUID)guid).Data3, \
+       ((EFI_GUID)guid).Data4[1], ((EFI_GUID)guid).Data4[0], \
+       ((EFI_GUID)guid).Data4[2], ((EFI_GUID)guid).Data4[3], \
+       ((EFI_GUID)guid).Data4[4], ((EFI_GUID)guid).Data4[5], \
+       ((EFI_GUID)guid).Data4[6], ((EFI_GUID)guid).Data4[7]
+
+static inline INT64
+guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1)
+{
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s(): Comparing "GUID_FMT" to "GUID_FMT"\n",
+              __FILE__, __LINE__-1, __func__,
+              GUID_ARGS(*guid0), GUID_ARGS(*guid1));
+#endif
+
+       if (guid0->Data1 != guid1->Data1) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
+                      __FILE__, __LINE__-1, __func__,
+                      (INT64)guid0->Data1, (INT64)guid1->Data1,
+                      (INT64)guid0->Data1 - (INT64)guid1->Data1);
+#endif
+               return (INT64)guid0->Data1 - (INT64)guid1->Data1;
+       }
+
+       if (guid0->Data2 != guid1->Data2) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
+                      __FILE__, __LINE__-1, __func__,
+                      (INT64)guid0->Data2, (INT64)guid1->Data2,
+                      (INT64)guid0->Data2 - (INT64)guid1->Data2);
+#endif
+               return (INT64)guid0->Data2 - (INT64)guid1->Data2;
+       }
+
+       if (guid0->Data3 != guid1->Data3) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
+                      __FILE__, __LINE__-1, __func__,
+                      (INT64)guid0->Data3, (INT64)guid1->Data3,
+                      (INT64)guid0->Data3 - (INT64)guid1->Data3);
+#endif
+               return (INT64)guid0->Data3 - (INT64)guid1->Data3;
+       }
+
+       /*
+        * This is out of order because that's also true in the string
+        * representation of it.
+        */
+       if (guid0->Data4[1] != guid1->Data4[1]) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
+                      __FILE__, __LINE__-1, __func__,
+                      (INT64)guid0->Data4[1], (INT64)guid1->Data4[1],
+                      (INT64)guid0->Data4[1] - (INT64)guid1->Data4[1]);
+#endif
+               return (INT64)guid0->Data4[1] - (INT64)guid1->Data4[1];
+       }
+
+       if (guid0->Data4[0] != guid1->Data4[0]) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
+                      __FILE__, __LINE__-1, __func__,
+                      (INT64)guid0->Data4[0], (INT64)guid1->Data4[0],
+                      (INT64)guid0->Data4[0] - (INT64)guid1->Data4[0]);
+#endif
+               return (INT64)guid0->Data4[0] - (INT64)guid1->Data4[0];
+       }
+
+       for (UINTN i = 2; i < 8; i++) {
+               if (guid0->Data4[i] != guid1->Data4[i]) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+                       printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
+                              __FILE__, __LINE__-1, __func__,
+                              (INT64)guid0->Data4[i], (INT64)guid1->Data4[i],
+                              (INT64)guid0->Data4[i] - (INT64)guid1->Data4[i]);
+#endif
+                       return (INT64)guid0->Data4[i] - (INT64)guid1->Data4[i];
+               }
+       }
+
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s(): returning 0x0\n",
+              __FILE__, __LINE__-1, __func__);
+#endif
+       return 0;
+}
+
+static inline int
+guidcmp(const EFI_GUID * const guid0, const EFI_GUID * const guid1)
+{
+       INT64 cmp;
+       int ret;
+       EFI_GUID empty;
+       const EFI_GUID * const guida = guid0 ? guid0 : &empty;
+       const EFI_GUID * const guidb = guid1 ? guid1 : &empty;
+
+       SetMem(&empty, sizeof(EFI_GUID), 0);
+
+       cmp = guidcmp_helper(guida, guidb);
+       ret = cmp < 0 ? -1 : (cmp > 0 ? 1 : 0);
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():CompareGuid("GUID_FMT","GUID_FMT")->%lld (%d)\n",
+              __FILE__, __LINE__-1, __func__,
+              GUID_ARGS(*guida), GUID_ARGS(*guidb), cmp, ret);
+#endif
+       return ret;
+}
+
+#define CompareGuid(a, b) guidcmp(a, b)
+
+static inline char *
+efi_strerror(EFI_STATUS status)
+{
+       static char buf0[1024];
+       static char buf1[1024];
+       char *out;
+       static int n;
+
+       out = n++ % 2 ? buf0 : buf1;
+       if (n > 1)
+               n -= 2;
+       SetMem(out, 1024, 0);
+
+       switch (status) {
+       case EFI_SUCCESS:
+               strcpy(out, "EFI_SUCCESS");
+               break;
+       case EFI_LOAD_ERROR:
+               strcpy(out, "EFI_LOAD_ERROR");
+               break;
+       case EFI_INVALID_PARAMETER:
+               strcpy(out, "EFI_INVALID_PARAMETER");
+               break;
+       case EFI_UNSUPPORTED:
+               strcpy(out, "EFI_UNSUPPORTED");
+               break;
+       case EFI_BAD_BUFFER_SIZE:
+               strcpy(out, "EFI_BAD_BUFFER_SIZE");
+               break;
+       case EFI_BUFFER_TOO_SMALL:
+               strcpy(out, "EFI_BUFFER_TOO_SMALL");
+               break;
+       case EFI_NOT_READY:
+               strcpy(out, "EFI_NOT_READY");
+               break;
+       case EFI_DEVICE_ERROR:
+               strcpy(out, "EFI_DEVICE_ERROR");
+               break;
+       case EFI_WRITE_PROTECTED:
+               strcpy(out, "EFI_WRITE_PROTECTED");
+               break;
+       case EFI_OUT_OF_RESOURCES:
+               strcpy(out, "EFI_OUT_OF_RESOURCES");
+               break;
+       case EFI_VOLUME_CORRUPTED:
+               strcpy(out, "EFI_VOLUME_CORRUPTED");
+               break;
+       case EFI_VOLUME_FULL:
+               strcpy(out, "EFI_VOLUME_FULL");
+               break;
+       case EFI_NO_MEDIA:
+               strcpy(out, "EFI_NO_MEDIA");
+               break;
+       case EFI_MEDIA_CHANGED:
+               strcpy(out, "EFI_MEDIA_CHANGED");
+               break;
+       case EFI_NOT_FOUND:
+               strcpy(out, "EFI_NOT_FOUND");
+               break;
+       case EFI_ACCESS_DENIED:
+               strcpy(out, "EFI_ACCESS_DENIED");
+               break;
+       case EFI_NO_RESPONSE:
+               strcpy(out, "EFI_NO_RESPONSE");
+               break;
+       case EFI_NO_MAPPING:
+               strcpy(out, "EFI_NO_MAPPING");
+               break;
+       case EFI_TIMEOUT:
+               strcpy(out, "EFI_TIMEOUT");
+               break;
+       case EFI_NOT_STARTED:
+               strcpy(out, "EFI_NOT_STARTED");
+               break;
+       case EFI_ALREADY_STARTED:
+               strcpy(out, "EFI_ALREADY_STARTED");
+               break;
+       case EFI_ABORTED:
+               strcpy(out, "EFI_ABORTED");
+               break;
+       case EFI_ICMP_ERROR:
+               strcpy(out, "EFI_ICMP_ERROR");
+               break;
+       case EFI_TFTP_ERROR:
+               strcpy(out, "EFI_TFTP_ERROR");
+               break;
+       case EFI_PROTOCOL_ERROR:
+               strcpy(out, "EFI_PROTOCOL_ERROR");
+               break;
+       case EFI_INCOMPATIBLE_VERSION:
+               strcpy(out, "EFI_INCOMPATIBLE_VERSION");
+               break;
+       case EFI_SECURITY_VIOLATION:
+               strcpy(out, "EFI_SECURITY_VIOLATION");
+               break;
+       case EFI_CRC_ERROR:
+               strcpy(out, "EFI_CRC_ERROR");
+               break;
+       case EFI_END_OF_MEDIA:
+               strcpy(out, "EFI_END_OF_MEDIA");
+               break;
+       case EFI_END_OF_FILE:
+               strcpy(out, "EFI_END_OF_FILE");
+               break;
+       case EFI_INVALID_LANGUAGE:
+               strcpy(out, "EFI_INVALID_LANGUAGE");
+               break;
+       case EFI_COMPROMISED_DATA:
+               strcpy(out, "EFI_COMPROMISED_DATA");
+               break;
+       default:
+               sprintf(out, "0x%lx", status);
+               break;
+       }
+       return out;
+}
+
+static inline char *
+Str2str(CHAR16 *in)
+{
+       static char buf0[1024];
+       static char buf1[1024];
+       char *out;
+       static int n;
+
+       out = n++ % 2 ? buf0 : buf1;
+       if (n > 1)
+               n -= 2;
+       SetMem(out, 1024, 0);
+       for (UINTN i = 0; i < 1023 && in[i]; i++)
+               out[i] = in[i];
+       return out;
+}
+
+static inline char *
+format_var_attrs(UINT32 attr)
+{
+       static char buf0[1024];
+       static char buf1[1024];
+       static int n;
+       int pos = 0;
+       bool found = false;
+       char *buf, *bufp;
+
+       buf = n++ % 2 ? buf0 : buf1;
+       if (n > 1)
+               n -= 2;
+       SetMem(buf, sizeof(buf0), 0);
+       bufp = &buf[0];
+       for (UINT32 i = 0; i < 8; i++) {
+               switch((1ul << i) & attr) {
+               case EFI_VARIABLE_NON_VOLATILE:
+                       if (found)
+                               bufp = stpcpy(bufp, "|");
+                       bufp = stpcpy(bufp, "NV");
+                       attr &= ~EFI_VARIABLE_NON_VOLATILE;
+                       found = true;
+                       break;
+               case EFI_VARIABLE_BOOTSERVICE_ACCESS:
+                       if (found)
+                               bufp = stpcpy(bufp, "|");
+                       bufp = stpcpy(bufp, "BS");
+                       attr &= ~EFI_VARIABLE_BOOTSERVICE_ACCESS;
+                       found = true;
+                       break;
+               case EFI_VARIABLE_RUNTIME_ACCESS:
+                       if (found)
+                               bufp = stpcpy(bufp, "|");
+                       bufp = stpcpy(bufp, "RT");
+                       attr &= ~EFI_VARIABLE_RUNTIME_ACCESS;
+                       found = true;
+                       break;
+               case EFI_VARIABLE_HARDWARE_ERROR_RECORD:
+                       if (found)
+                               bufp = stpcpy(bufp, "|");
+                       bufp = stpcpy(bufp, "HER");
+                       attr &= ~EFI_VARIABLE_HARDWARE_ERROR_RECORD;
+                       found = true;
+                       break;
+               case EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS:
+                       if (found)
+                               bufp = stpcpy(bufp, "|");
+                       bufp = stpcpy(bufp, "AUTH");
+                       attr &= ~EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
+                       found = true;
+                       break;
+               case EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS:
+                       if (found)
+                               bufp = stpcpy(bufp, "|");
+                       bufp = stpcpy(bufp, "TIMEAUTH");
+                       attr &= ~EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+                       found = true;
+                       break;
+               case EFI_VARIABLE_APPEND_WRITE:
+                       if (found)
+                               bufp = stpcpy(bufp, "|");
+                       bufp = stpcpy(bufp, "APPEND");
+                       attr &= ~EFI_VARIABLE_APPEND_WRITE;
+                       found = true;
+                       break;
+               case EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS:
+                       if (found)
+                               bufp = stpcpy(bufp, "|");
+                       bufp = stpcpy(bufp, "ENHANCED_AUTH");
+                       attr &= ~EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS;
+                       found = true;
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (attr) {
+               if (found)
+                       bufp = stpcpy(bufp, "|");
+               snprintf(bufp, bufp - buf - 1, "0x%x", attr);
+       }
+       return &buf[0];
+}
 
 extern int debug;
 #ifdef dprint
@@ -54,6 +412,14 @@ extern int debug;
 #define dprint(fmt, ...) {( if (debug) printf("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); })
 #endif
 
+void EFIAPI mock_efi_void();
+EFI_STATUS EFIAPI mock_efi_success();
+EFI_STATUS EFIAPI mock_efi_unsupported();
+EFI_STATUS EFIAPI mock_efi_not_found();
+void init_efi_system_table(void);
+void reset_efi_system_table(void);
+void print_traceback(int skip);
+
 #define eassert(cond, fmt, ...)                                  \
        ({                                                       \
                if (!(cond)) {                                   \
@@ -63,24 +429,24 @@ extern int debug;
                assert(cond);                                    \
        })
 
-#define assert_true_as_expr(a, status, fmt, ...)                           \
-       ({                                                                 \
-               int rc_ = 0;                                               \
-               if (!(a)) {                                                \
-                       printf("%s:%d:got %lld, expected nonzero " fmt,    \
-                              __func__, __LINE__, (long long)(a),         \
-                              ##__VA_ARGS__);                             \
-                       printf("%s:%d:Assertion `%s' failed.\n", __func__, \
-                              __LINE__, __stringify(!(a)));               \
-                       rc_ = status;                                      \
-               }                                                          \
-               rc_;                                                       \
+#define assert_true_as_expr(a, status, fmt, ...)                              \
+       ({                                                                    \
+               __typeof__(status) rc_ = 0;                                   \
+               if (!(a)) {                                                   \
+                       printf("%s:%d:got %lld, expected nonzero " fmt,       \
+                              __func__, __LINE__, (long long)(uintptr_t)(a), \
+                              ##__VA_ARGS__);                                \
+                       printf("%s:%d:Assertion `%s' failed.\n", __func__,    \
+                              __LINE__, __stringify(!(a)));                  \
+                       rc_ = status;                                         \
+               }                                                             \
+               rc_;                                                          \
        })
 #define assert_nonzero_as_expr(a, ...) assert_true_as_expr(a, ##__VA_ARGS__)
 
 #define assert_false_as_expr(a, status, fmt, ...)                              \
        ({                                                                     \
-               int rc_ = 0;                                                   \
+               __typeof__(status) rc_ = (__typeof__(status))0;                \
                if (a) {                                                       \
                        printf("%s:%d:got %lld, expected zero " fmt, __func__, \
                               __LINE__, (long long)(a), ##__VA_ARGS__);       \
@@ -94,7 +460,7 @@ extern int debug;
 
 #define assert_positive_as_expr(a, status, fmt, ...)                          \
        ({                                                                    \
-               int rc_ = 0;                                                  \
+               __typeof__(status) rc_ = (__typeof__(status))0;               \
                if ((a) <= 0) {                                               \
                        printf("%s:%d:got %lld, expected > 0 " fmt, __func__, \
                               __LINE__, (long long)(a), ##__VA_ARGS__);      \
@@ -107,7 +473,7 @@ extern int debug;
 
 #define assert_negative_as_expr(a, status, fmt, ...)                          \
        ({                                                                    \
-               int rc_ = 0;                                                  \
+               __typeof__(status) rc_ = (__typeof__(status))0;               \
                if ((a) >= 0) {                                               \
                        printf("%s:%d:got %lld, expected < 0 " fmt, __func__, \
                               __LINE__, (long long)(a), ##__VA_ARGS__);      \
@@ -120,7 +486,7 @@ extern int debug;
 
 #define assert_equal_as_expr(a, b, status, fmt, ...)                       \
        ({                                                                 \
-               int rc_ = 0;                                               \
+               __typeof__(status) rc_ = (__typeof__(status))0;            \
                if (!((a) == (b))) {                                       \
                        printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \
                               ##__VA_ARGS__);                             \
@@ -131,9 +497,22 @@ extern int debug;
                rc_;                                                       \
        })
 
+#define assert_not_equal_as_expr(a, b, status, fmt, ...)                   \
+       ({                                                                 \
+               __typeof__(status) rc_ = (__typeof__(status))0;            \
+               if (!((a) != (b))) {                                       \
+                       printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \
+                              ##__VA_ARGS__);                             \
+                       printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+                              __LINE__, __stringify(a != b));             \
+                       rc_ = status;                                      \
+               }                                                          \
+               rc_;                                                       \
+       })
+
 #define assert_as_expr(cond, status, fmt, ...)                             \
        ({                                                                 \
-               int rc_ = 0;                                               \
+               __typeof__(status) rc_ = (__typeof__(status))0;            \
                if (!(cond)) {                                             \
                        printf("%s:%d:" fmt, __func__, __LINE__,           \
                               ##__VA_ARGS__);                             \
@@ -144,51 +523,62 @@ extern int debug;
                rc_;                                                       \
        })
 
-#define assert_true_return(a, status, fmt, ...)                               \
-       ({                                                                    \
-               int rc_ = assert_true_as_expr(a, status, fmt, ##__VA_ARGS__); \
-               if (rc_ != 0)                                                 \
-                       return rc_;                                           \
+#define assert_true_return(a, status, fmt, ...)                             \
+       ({                                                                  \
+               __typeof__(status) rc_ =                                    \
+                       assert_true_as_expr(a, status, fmt, ##__VA_ARGS__); \
+               if (rc_ != 0)                                               \
+                       return rc_;                                         \
        })
 #define assert_nonzero_return(a, ...) assert_true_return(a, ##__VA_ARGS__)
 
-#define assert_false_return(a, status, fmt, ...)                               \
-       ({                                                                     \
-               int rc_ = assert_false_as_expr(a, status, fmt, ##__VA_ARGS__); \
-               if (rc_ != 0)                                                  \
-                       return rc_;                                            \
+#define assert_false_return(a, status, fmt, ...)                             \
+       ({                                                                   \
+               __typeof__(status) rc_ =                                     \
+                       assert_false_as_expr(a, status, fmt, ##__VA_ARGS__); \
+               if (rc_ != 0)                                                \
+                       return rc_;                                          \
        })
 #define assert_zero_return(a, ...) assert_false_return(a, ##__VA_ARGS__)
 
 #define assert_positive_return(a, status, fmt, ...)               \
        ({                                                        \
-               int rc_ = assert_positive_as_expr(a, status, fmt, \
-                                                 ##__VA_ARGS__); \
+               __typeof__(status) rc_ = assert_positive_as_expr( \
+                       a, status, fmt, ##__VA_ARGS__);           \
                if (rc_ != 0)                                     \
                        return rc_;                               \
        })
 
 #define assert_negative_return(a, status, fmt, ...)               \
        ({                                                        \
-               int rc_ = assert_negative_as_expr(a, status, fmt, \
-                                                 ##__VA_ARGS__); \
+               __typeof__(status) rc_ = assert_negative_as_expr( \
+                       a, status, fmt, ##__VA_ARGS__);           \
                if (rc_ != 0)                                     \
                        return rc_;                               \
        })
 
-#define assert_equal_return(a, b, status, fmt, ...)               \
-       ({                                                        \
-               int rc_ = assert_equal_as_expr(a, b, status, fmt, \
-                                              ##__VA_ARGS__);    \
-               if (rc_ != 0)                                     \
-                       return rc_;                               \
+#define assert_equal_return(a, b, status, fmt, ...)            \
+       ({                                                     \
+               __typeof__(status) rc_ = assert_equal_as_expr( \
+                       a, b, status, fmt, ##__VA_ARGS__);     \
+               if (rc_ != 0)                                  \
+                       return rc_;                            \
        })
 
-#define assert_return(cond, status, fmt, ...)                               \
-       ({                                                                  \
-               int rc_ = assert_as_expr(cond, status, fmt, ##__VA_ARGS__); \
-               if (rc_ != 0)                                               \
-                       return rc_;                                         \
+#define assert_not_equal_return(a, b, status, fmt, ...)            \
+       ({                                                         \
+               __typeof__(status) rc_ = assert_not_equal_as_expr( \
+                       a, b, status, fmt, ##__VA_ARGS__);         \
+               if (rc_ != 0)                                      \
+                       return rc_;                                \
+       })
+
+#define assert_return(cond, status, fmt, ...)                             \
+       ({                                                                \
+               __typeof__(status) rc_ =                                  \
+                       assert_as_expr(cond, status, fmt, ##__VA_ARGS__); \
+               if (rc_ != 0)                                             \
+                       return rc_;                                       \
        })
 
 #define assert_goto(cond, label, fmt, ...)                                 \
@@ -213,6 +603,41 @@ extern int debug;
                }                                                          \
        })
 
+#define assert_not_equal_goto(a, b, label, fmt, ...)                       \
+       ({                                                                 \
+               if (!((a) != (b))) {                                       \
+                       printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \
+                              ##__VA_ARGS__);                             \
+                       printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+                              __LINE__, __stringify(a != b));             \
+                       goto label;                                        \
+               }                                                          \
+       })
+
+#define assert_true_goto(a, label, fmt, ...)                               \
+       ({                                                                 \
+               if (!(a)) {                                                \
+                       printf("%s:%d:" fmt, __func__, __LINE__, (a),      \
+                              ##__VA_ARGS__);                             \
+                       printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+                              __LINE__, __stringify(!(a)));               \
+                       goto label;                                        \
+               }                                                          \
+       })
+#define assert_nonzero_goto(a, ...) assert_true_goto(a, ##__VA_ARGS__)
+
+#define assert_false_goto(a, label, fmt, ...)                              \
+       ({                                                                 \
+               if (a) {                                                   \
+                       printf("%s:%d:" fmt, __func__, __LINE__, (a),      \
+                              ##__VA_ARGS__);                             \
+                       printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+                              __LINE__, __stringify(a));                  \
+                       goto label;                                        \
+               }                                                          \
+       })
+#define assert_zero_goto(a, ...) assert_false_goto(a, ##__VA_ARGS__)
+
 #define assert_negative_goto(a, label, fmt, ...)                              \
        ({                                                                    \
                int rc_ = assert_negative_as_expr(a, -1, fmt, ##__VA_ARGS__); \
index 62cf983a0c3c81824b3d09b308af62a18685ffd5..1a4fc2204c2629ecf39cd95459460495bf23c4fc 100644 (file)
@@ -5,21 +5,39 @@
 
 .SUFFIXES:
 
+include Make.defaults
+
 CC = gcc
 VALGRIND ?=
 DEBUG_PRINTS ?= 0
-CFLAGS = -O2 -ggdb -std=gnu11 \
+OPTIMIZATIONS=-O2 -ggdb
+CFLAGS_LTO =
+CFLAGS_GCOV =
+CFLAGS = $(OPTIMIZATIONS) -std=gnu11 \
         -isystem $(TOPDIR)/include/system \
         $(EFI_INCLUDES) \
         -Iinclude -iquote . \
-        -fshort-wchar -flto -fno-builtin \
-        -Wall \
-        -Wextra \
+        -isystem /usr/include \
+        -isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include) \
+        $(ARCH_CFLAGS) \
+        $(CFLAGS_LTO) \
+        $(CFLAGS_GCOV) \
+        -fshort-wchar \
+        -fno-builtin \
+        -rdynamic \
+        -fno-inline \
+        -fno-eliminate-unused-debug-types \
+        -fno-eliminate-unused-debug-symbols \
+        -gpubnames \
+        -grecord-gcc-switches \
+        $(if $(findstring clang,$(CC)),-Wno-unknown-warning-option) \
+        $(DEFAULT_WARNFLAGS) \
         -Wsign-compare \
         -Wno-deprecated-declarations \
+        $(if $(findstring gcc,$(CC)),-Wno-unused-but-set-variable) \
+        -Wno-unused-variable \
         -Wno-pointer-sign \
-        -Wno-unused \
-        -Werror \
+        $(DEFAULT_WERRFLAGS) \
         -Werror=nonnull \
         $(shell $(CC) -Werror=nonnull-compare -E -x c /dev/null >/dev/null 2>&1 && echo -Werror=nonnull-compare) \
         $(ARCH_DEFINES) \
@@ -28,29 +46,79 @@ CFLAGS = -O2 -ggdb -std=gnu11 \
         -DSHIM_UNIT_TEST \
         "-DDEFAULT_DEBUG_PRINT_STATE=$(DEBUG_PRINTS)"
 
-$(wildcard test-*.c) :: %.c : test-random.h
-$(patsubst %.c,%,$(wildcard test-*.c)) :: | test-random.h
-$(patsubst %.c,%.o,$(wildcard test-*.c)) : | test-random.h
+# On some systems (e.g. Arch Linux), limits.h is in the "include-fixed" instead
+# of the "include" directory
+CFLAGS += -isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include-fixed)
+
+export CFLAGS_LTO CFLAGS_GCOV
+
+libefi-test.a :
+       $(MAKE) -C gnu-efi \
+               COMPILER="$(COMPILER)" \
+               CC="$(CC)" \
+               ARCH=$(ARCH_GNUEFI) \
+               TOPDIR=$(TOPDIR)/gnu-efi \
+               CFLAGS_LTO="$(CFLAGS_LTO)" \
+               CFLAGS_GCOV="$(CFLAGS_GCOV)" \
+               -f $(TOPDIR)/gnu-efi/Makefile \
+               clean lib
+       mv gnu-efi/$(ARCH)/lib/libefi.a $@
+       $(MAKE) -C gnu-efi \
+               COMPILER="$(COMPILER)" \
+               ARCH=$(ARCH_GNUEFI) \
+               TOPDIR=$(TOPDIR)/gnu-efi \
+               CFLAGS_LTO="$(CFLAGS_LTO)" \
+               CFLAGS_GCOV="$(CFLAGS_GCOV)" \
+               -f $(TOPDIR)/gnu-efi/Makefile \
+               clean
 
 test-random.h:
        dd if=/dev/urandom bs=512 count=17 of=random.bin
        xxd -i random.bin test-random.h
 
-test-sbat_FILES = csv.c
+$(wildcard test-*.c) :: %.c : test-random.h
+$(patsubst %.c,%,$(wildcard test-*.c)) :: | test-random.h
+$(patsubst %.c,%.o,$(wildcard test-*.c)) : | test-random.h
+
+test-load-options_FILES = lib/guid.c
+test-load-options : CFLAGS+=-DHAVE_SHIM_LOCK_GUID
+
+test-mock-variables_FILES = mok.c globals.c tpm.c lib/guid.c lib/variables.c mock-variables.c
+test-mock-variables: CFLAGS+=-DHAVE_SHIM_LOCK_GUID
+
+test-mok-mirror_FILES = mok.c globals.c tpm.c lib/guid.c lib/variables.c mock-variables.c
+test-mok-mirror: CFLAGS+=-DHAVE_START_IMAGE -DHAVE_SHIM_LOCK_GUID
+
+test-sbat_FILES = csv.c lib/variables.c lib/guid.c
+test-sbat :: CFLAGS+=-DHAVE_GET_VARIABLE -DHAVE_GET_VARIABLE_ATTR -DHAVE_SHIM_LOCK_GUID
+
 test-str_FILES = lib/string.c
 
 tests := $(patsubst %.c,%,$(wildcard test-*.c))
 
+$(tests) :: test-% : | libefi-test.a
+
 $(tests) :: test-% : test.c test-%.c $(test-%_FILES)
-       $(CC) $(CFLAGS) -o $@ $^ $(wildcard $*.c) $(test-$*_FILES)
+       $(CC) $(CFLAGS) -o $@ $(sort $^ $(wildcard $*.c) $(test-$*_FILES)) libefi-test.a -lefivar
        $(VALGRIND) ./$@
 
 test : $(tests)
+       $(MAKE) -f include/test.mk test-clean
+
+test-lto : CFLAGS_LTO+=-flto
+test-lto : $(tests)
+       $(MAKE) -f include/test.mk test-clean
+
+test-coverage : CFLAGS_GCOV+=--coverage
+test-coverage : $(tests)
+
+test-clean :
+       @rm -vf test-random.h random.bin libefi-test.a
+       @rm -vf *.gcda *.gcno *.gcov vgcore.*
 
-clean :
-       @rm -vf test-random.h random.bin
+clean : test-clean
 
-all : clean test
+all : test-clean test
 
 .PHONY: $(tests) all test clean
 .SECONDARY: random.bin
index e43c341fbc2e2ed2c3e11ea90ff45b33bf665546..ee038ce798a0c65020d5d3810300fff45aeea403 100644 (file)
@@ -81,31 +81,4 @@ is_all_nuls(UINT8 *data, UINTN data_size)
        return true;
 }
 
-static inline UINTN
-__attribute__((__unused__))
-count_ucs2_strings(UINT8 *data, UINTN data_size)
-{
-       UINTN pos = 0;
-       UINTN last_nul_pos = 0;
-       UINTN num_nuls = 0;
-       UINTN i;
-
-       if (data_size % 2 != 0)
-               return 0;
-
-       for (i = pos; i < data_size; i++) {
-               if (i % 2 != 0) {
-                       if (data[i] != 0)
-                               return 0;
-               } else if (data[i] == 0) {
-                       last_nul_pos = i;
-                       num_nuls++;
-               }
-               pos = i;
-       }
-       if (num_nuls > 0 && last_nul_pos != pos - 1)
-               return 0;
-       return num_nuls;
-}
-
 #endif /* SHIM_UCS2_H */
index c310d21368a8e1b2b1dd1bdcc7756cb68a9a2d63..7be5d5437f5bfe3110520b547d9519c217b0b788 100644 (file)
@@ -34,8 +34,11 @@ console_get_keystroke(EFI_INPUT_KEY *key)
        UINTN EventIndex;
        EFI_STATUS efi_status;
 
+       if (!ci)
+               return EFI_UNSUPPORTED;
+
        do {
-               gBS->WaitForEvent(1, &ci->WaitForKey, &EventIndex);
+               BS->WaitForEvent(1, &ci->WaitForKey, &EventIndex);
                efi_status = ci->ReadKeyStroke(ci, key);
        } while (efi_status == EFI_NOT_READY);
 
@@ -109,7 +112,8 @@ console_print_at(UINTN col, UINTN row, const CHAR16 *fmt, ...)
        if (!console_text_mode)
                setup_console(1);
 
-       co->SetCursorPosition(co, col, row);
+       if (co)
+               co->SetCursorPosition(co, col, row);
 
        ms_va_start(args, fmt);
        ret = VPrint(fmt, args);
@@ -136,6 +140,9 @@ console_print_box_at(CHAR16 *str_arr[], int highlight,
        if (!console_text_mode)
                setup_console(1);
 
+       if (!co)
+               return;
+
        co->QueryMode(co, co->Mode->Mode, &cols, &rows);
 
        /* last row on screen is unusable without scrolling, so ignore it */
@@ -241,6 +248,9 @@ console_print_box(CHAR16 *str_arr[], int highlight)
        if (!console_text_mode)
                setup_console(1);
 
+       if (!co)
+               return;
+
        CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
        co->EnableCursor(co, FALSE);
        co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
@@ -274,6 +284,9 @@ console_select(CHAR16 *title[], CHAR16* selectors[], unsigned int start)
        if (!console_text_mode)
                setup_console(1);
 
+       if (!co)
+               return -1;
+
        co->QueryMode(co, co->Mode->Mode, &cols, &rows);
 
        for (i = 0; i < selector_lines; i++) {
@@ -413,6 +426,9 @@ console_save_and_set_mode(SIMPLE_TEXT_OUTPUT_MODE * SavedMode)
                return;
        }
 
+       if (!co)
+               return;
+
        CopyMem(SavedMode, co->Mode, sizeof(SIMPLE_TEXT_OUTPUT_MODE));
        co->EnableCursor(co, FALSE);
        co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
@@ -423,6 +439,9 @@ console_restore_mode(SIMPLE_TEXT_OUTPUT_MODE * SavedMode)
 {
        SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
 
+       if (!co)
+               return;
+
        co->EnableCursor(co, SavedMode->CursorVisible);
        co->SetCursorPosition(co, SavedMode->CursorColumn,
                                SavedMode->CursorRow);
@@ -441,6 +460,9 @@ console_countdown(CHAR16* title, const CHAR16* message, int timeout)
        CHAR16 *titles[2];
        int wait = 10000000;
 
+       if (!co || !ci)
+               return -1;
+
        console_save_and_set_mode(&SavedMode);
 
        titles[0] = title;
@@ -495,7 +517,10 @@ console_mode_handle(VOID)
        UINTN rows = 0, columns = 0;
        EFI_STATUS efi_status = EFI_SUCCESS;
 
-       efi_status = gBS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
+       if (!co)
+               return;
+
+       efi_status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
        if (EFI_ERROR(efi_status)) {
                console_error(L"Locate graphic output protocol fail", efi_status);
                return;
@@ -555,7 +580,7 @@ console_mode_handle(VOID)
                efi_status = co->SetMode(co, mode_set);
        }
 
-       co->ClearScreen(co);
+       clear_screen();
 
        if (EFI_ERROR(efi_status)) {
                console_error(L"Console set mode fail", efi_status);
@@ -649,13 +674,25 @@ console_reset(void)
        if (!console_text_mode)
                setup_console(1);
 
+       if (!co)
+               return;
+
        co->Reset(co, TRUE);
        /* set mode 0 - required to be 80x25 */
        co->SetMode(co, 0);
        co->ClearScreen(co);
 }
 
-UINT32 verbose = 0;
+void
+clear_screen(void)
+{
+       SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
+
+       if (!co)
+               return;
+
+       co->ClearScreen(co);
+}
 
 VOID
 setup_verbosity(VOID)
@@ -679,7 +716,7 @@ setup_verbosity(VOID)
 VOID
 msleep(unsigned long msecs)
 {
-       gBS->Stall(msecs);
+       BS->Stall(msecs);
 }
 
 /* This is used in various things to determine if we should print to the
index 642f94a38780ae0404d75a5aaad5e08a982040e9..0eb872e4ab480d4baddb5967652b96df499618a2 100644 (file)
@@ -63,8 +63,8 @@ execute(EFI_HANDLE image, CHAR16 *name)
        EFI_DEVICE_PATH *devpath;
        CHAR16 *PathName;
 
-       efi_status = gBS->HandleProtocol(image, &IMAGE_PROTOCOL,
-                                        (void **) &li);
+       efi_status = BS->HandleProtocol(image, &IMAGE_PROTOCOL,
+                                       (void **) &li);
        if (EFI_ERROR(efi_status))
                return efi_status;
 
@@ -72,12 +72,12 @@ execute(EFI_HANDLE image, CHAR16 *name)
        if (EFI_ERROR(efi_status))
                return efi_status;
 
-       efi_status = gBS->LoadImage(FALSE, image, devpath, NULL, 0, &h);
+       efi_status = BS->LoadImage(FALSE, image, devpath, NULL, 0, &h);
        if (EFI_ERROR(efi_status))
                goto out;
 
-       efi_status = gBS->StartImage(h, NULL, NULL);
-       gBS->UnloadImage(h);
+       efi_status = BS->StartImage(h, NULL, NULL);
+       BS->UnloadImage(h);
 
  out:
        FreePool(PathName);
index 6c42cc1439abe63d24c274390dde422448474a40..0f2569b0e6ef77f72d10215cbceaae62269e94a4 100644 (file)
@@ -123,7 +123,7 @@ security_policy_authentication (
         * EFI_SECURITY_VIOLATION */
        fail_status = efi_status;
 
-       efi_status = gBS->LocateDevicePath(&SIMPLE_FS_PROTOCOL, &DevPath, &h);
+       efi_status = BS->LocateDevicePath(&SIMPLE_FS_PROTOCOL, &DevPath, &h);
        if (EFI_ERROR(efi_status))
                goto out;
 
index 146d9a215ad55ab260fce2055e848c95805d995e..8be4fe088a5b6d35cf360b3e5a9ca2291c000856 100644 (file)
@@ -16,7 +16,7 @@ argsplit(EFI_HANDLE image, int *argc, CHAR16*** ARGV)
 
        *argc = 0;
 
-       efi_status = gBS->HandleProtocol(image, &LoadedImageProtocol,
+       efi_status = BS->HandleProtocol(image, &LoadedImageProtocol,
                                         (VOID **) &info);
        if (EFI_ERROR(efi_status)) {
                console_print(L"Failed to get arguments\n");
index 5fd3e1a68307f5956e552ecb0dace7b89ac53fc2..f22852d4cef1311f7d4175917536d4f8f45fb32c 100644 (file)
@@ -11,8 +11,8 @@ simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UIN
        EFI_FILE_IO_INTERFACE *drive;
        EFI_FILE *root;
 
-       efi_status = gBS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
-                                        (void **)&drive);
+       efi_status = BS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
+                                       (void **)&drive);
        if (EFI_ERROR(efi_status)) {
                console_print(L"Unable to find simple file protocol (%d)\n",
                              efi_status);
@@ -40,8 +40,8 @@ simple_file_open(EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode)
        EFI_DEVICE_PATH *loadpath = NULL;
        CHAR16 *PathName = NULL;
 
-       efi_status = gBS->HandleProtocol(image, &IMAGE_PROTOCOL,
-                                        (void **) &li);
+       efi_status = BS->HandleProtocol(image, &IMAGE_PROTOCOL,
+                                       (void **) &li);
        if (EFI_ERROR(efi_status))
                return simple_file_open_by_handle(image, name, file, mode);
 
@@ -176,9 +176,9 @@ simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h)
        CHAR16 **entries;
        int val;
 
-       efi_status = gBS->LocateHandleBuffer(ByProtocol,
-                                            &EFI_SIMPLE_FILE_SYSTEM_GUID,
-                                            NULL, &count, &vol_handles);
+       efi_status = BS->LocateHandleBuffer(ByProtocol,
+                                           &EFI_SIMPLE_FILE_SYSTEM_GUID,
+                                           NULL, &count, &vol_handles);
        if (EFI_ERROR(efi_status))
                return efi_status;
        if (!count || !vol_handles)
@@ -196,9 +196,9 @@ simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h)
                CHAR16 *name;
                EFI_FILE_IO_INTERFACE *drive;
 
-               efi_status = gBS->HandleProtocol(vol_handles[i],
-                                              &EFI_SIMPLE_FILE_SYSTEM_GUID,
-                                                (void **) &drive);
+               efi_status = BS->HandleProtocol(vol_handles[i],
+                                               &EFI_SIMPLE_FILE_SYSTEM_GUID,
+                                               (void **) &drive);
                if (EFI_ERROR(efi_status) || !drive)
                        continue;
 
index f606e248493dc4775f3044dd8bae75efccd9479d..8e63aa8f3dbfeba2b81b52132e841042ae305481 100644 (file)
  */
 #include "shim.h"
 
+extern EFI_SYSTEM_TABLE *ST;
+extern EFI_BOOT_SERVICES *BS;
+extern EFI_RUNTIME_SERVICES *RT;
+
 EFI_STATUS
 fill_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany,
         const EFI_GUID *type, const UINT32 sig_size,
@@ -45,7 +49,7 @@ fill_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany,
        sl->SignatureListSize = needed;
 
        sd = (EFI_SIGNATURE_DATA *)(out + sizeof(EFI_SIGNATURE_LIST));
-       CopyMem(sd, first_sig, data_len);
+       CopyMem(sd, (void *)first_sig, data_len);
 
        return EFI_SUCCESS;
 }
@@ -64,9 +68,11 @@ fill_esl_with_one_signature(const uint8_t *data, const uint32_t data_len,
 
        if (out) {
                sd = AllocateZeroPool(sig_size);
+               if (!sd)
+                       return EFI_OUT_OF_RESOURCES;
                if (owner)
-                       CopyMem(sd, owner, sizeof(EFI_GUID));
-               CopyMem(sd->SignatureData, data, data_len);
+                       CopyMem(sd, (void *)owner, sizeof(EFI_GUID));
+               CopyMem(sd->SignatureData, (void *)data, data_len);
        }
 
        efi_status = fill_esl(sd, 1, type, sig_size, out, outlen);
@@ -154,7 +160,7 @@ CreateTimeBasedPayload(IN OUT UINTN * DataSize, IN OUT UINT8 ** Data)
        DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
 
        ZeroMem(&Time, sizeof(EFI_TIME));
-       efi_status = gRT->GetTime(&Time, NULL);
+       efi_status = RT->GetTime(&Time, NULL);
        if (EFI_ERROR(efi_status)) {
                FreePool(NewData);
                return efi_status;
@@ -225,7 +231,7 @@ SetSecureVariable(const CHAR16 * const var, UINT8 *Data, UINTN len,
                return efi_status;
        }
 
-       efi_status = gRT->SetVariable((CHAR16 *)var, &owner,
+       efi_status = RT->SetVariable((CHAR16 *)var, &owner,
                        EFI_VARIABLE_NON_VOLATILE |
                        EFI_VARIABLE_RUNTIME_ACCESS |
                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
@@ -241,8 +247,8 @@ GetOSIndications(void)
        UINTN DataSize = sizeof(indications);
        EFI_STATUS efi_status;
 
-       efi_status = gRT->GetVariable(L"OsIndicationsSupported", &GV_GUID,
-                                     NULL, &DataSize, &indications);
+       efi_status = RT->GetVariable(L"OsIndicationsSupported", &GV_GUID,
+                                    NULL, &DataSize, &indications);
        if (EFI_ERROR(efi_status))
                return 0;
 
@@ -255,15 +261,15 @@ SETOSIndicationsAndReboot(UINT64 indications)
        UINTN DataSize = sizeof(indications);
        EFI_STATUS efi_status;
 
-       efi_status = gRT->SetVariable(L"OsIndications", &GV_GUID,
-                                     EFI_VARIABLE_NON_VOLATILE |
-                                     EFI_VARIABLE_RUNTIME_ACCESS |
-                                     EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                                     DataSize, &indications);
+       efi_status = RT->SetVariable(L"OsIndications", &GV_GUID,
+                                    EFI_VARIABLE_NON_VOLATILE |
+                                    EFI_VARIABLE_RUNTIME_ACCESS |
+                                    EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                    DataSize, &indications);
        if (EFI_ERROR(efi_status))
                return efi_status;
 
-       gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
+       RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
        /* does not return */
 
        return EFI_SUCCESS;
@@ -280,7 +286,7 @@ get_variable_attr(const CHAR16 * const var, UINT8 **data, UINTN *len,
 
        *len = 0;
 
-       efi_status = gRT->GetVariable((CHAR16 *)var, &owner, NULL, len, NULL);
+       efi_status = RT->GetVariable((CHAR16 *)var, &owner, NULL, len, NULL);
        if (efi_status != EFI_BUFFER_TOO_SMALL) {
                if (!EFI_ERROR(efi_status)) /* this should never happen */
                        return EFI_PROTOCOL_ERROR;
@@ -298,7 +304,7 @@ get_variable_attr(const CHAR16 * const var, UINT8 **data, UINTN *len,
        if (!*data)
                return EFI_OUT_OF_RESOURCES;
 
-       efi_status = gRT->GetVariable((CHAR16 *)var, &owner, attributes, len, *data);
+       efi_status = RT->GetVariable((CHAR16 *)var, &owner, attributes, len, *data);
        if (EFI_ERROR(efi_status)) {
                FreePool(*data);
                *data = NULL;
@@ -341,7 +347,7 @@ EFI_STATUS
 set_variable(CHAR16 *var, EFI_GUID owner, UINT32 attributes,
             UINTN datasize, void *data)
 {
-       return gRT->SetVariable(var, &owner, attributes, datasize, data);
+       return RT->SetVariable(var, &owner, attributes, datasize, data);
 }
 
 EFI_STATUS
@@ -394,8 +400,8 @@ variable_is_setupmode(int default_return)
        UINTN DataSize = sizeof(SetupMode);
        EFI_STATUS efi_status;
 
-       efi_status = gRT->GetVariable(L"SetupMode", &GV_GUID, NULL,
-                                     &DataSize, &SetupMode);
+       efi_status = RT->GetVariable(L"SetupMode", &GV_GUID, NULL,
+                                    &DataSize, &SetupMode);
        if (EFI_ERROR(efi_status))
                return default_return;
 
@@ -411,8 +417,8 @@ variable_is_secureboot(void)
        EFI_STATUS efi_status;
 
        DataSize = sizeof(SecureBoot);
-       efi_status = gRT->GetVariable(L"SecureBoot", &GV_GUID, NULL,
-                                     &DataSize, &SecureBoot);
+       efi_status = RT->GetVariable(L"SecureBoot", &GV_GUID, NULL,
+                                    &DataSize, &SecureBoot);
        if (EFI_ERROR(efi_status))
                return 0;
 
@@ -445,10 +451,10 @@ variable_enroll_hash(const CHAR16 * const var, EFI_GUID owner,
                efi_status = SetSecureVariable(var, sig, sizeof(sig), owner,
                                               EFI_VARIABLE_APPEND_WRITE, 0);
        else
-               efi_status = gRT->SetVariable((CHAR16 *)var, &owner,
-                                             EFI_VARIABLE_NON_VOLATILE |
-                                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
-                                             EFI_VARIABLE_APPEND_WRITE,
-                                             sizeof(sig), sig);
+               efi_status = RT->SetVariable((CHAR16 *)var, &owner,
+                                            EFI_VARIABLE_NON_VOLATILE |
+                                            EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                            EFI_VARIABLE_APPEND_WRITE,
+                                            sizeof(sig), sig);
        return efi_status;
 }
diff --git a/load-options.c b/load-options.c
new file mode 100644 (file)
index 0000000..c6bb742
--- /dev/null
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * load-options.c - all the stuff we need to parse the load options
+ */
+
+#include "shim.h"
+
+CHAR16 *second_stage;
+void *load_options;
+UINT32 load_options_size;
+
+/*
+ * Generate the path of an executable given shim's path and the name
+ * of the executable
+ */
+EFI_STATUS
+generate_path_from_image_path(EFI_LOADED_IMAGE *li,
+                             CHAR16 *ImagePath,
+                             CHAR16 **PathName)
+{
+       EFI_DEVICE_PATH *devpath;
+       unsigned int i;
+       int j, last = -1;
+       unsigned int pathlen = 0;
+       EFI_STATUS efi_status = EFI_SUCCESS;
+       CHAR16 *bootpath;
+
+       /*
+        * Suuuuper lazy technique here, but check and see if this is a full
+        * path to something on the ESP.  Backwards compatibility demands
+        * that we don't just use \\, because we (not particularly brightly)
+        * used to require that the relative file path started with that.
+        *
+        * If it is a full path, don't try to merge it with the directory
+        * from our Loaded Image handle.
+        */
+       if (StrSize(ImagePath) > 5 && StrnCmp(ImagePath, L"\\EFI\\", 5) == 0) {
+               *PathName = StrDuplicate(ImagePath);
+               if (!*PathName) {
+                       perror(L"Failed to allocate path buffer\n");
+                       return EFI_OUT_OF_RESOURCES;
+               }
+               return EFI_SUCCESS;
+       }
+
+       devpath = li->FilePath;
+
+       bootpath = DevicePathToStr(devpath);
+
+       pathlen = StrLen(bootpath);
+
+       /*
+        * DevicePathToStr() concatenates two nodes with '/'.
+        * Convert '/' to '\\'.
+        */
+       for (i = 0; i < pathlen; i++) {
+               if (bootpath[i] == '/')
+                       bootpath[i] = '\\';
+       }
+
+       for (i=pathlen; i>0; i--) {
+               if (bootpath[i] == '\\' && bootpath[i-1] == '\\')
+                       bootpath[i] = '/';
+               else if (last == -1 && bootpath[i] == '\\')
+                       last = i;
+       }
+
+       if (last == -1 && bootpath[0] == '\\')
+               last = 0;
+       bootpath[last+1] = '\0';
+
+       if (last > 0) {
+               for (i = 0, j = 0; bootpath[i] != '\0'; i++) {
+                       if (bootpath[i] != '/') {
+                               bootpath[j] = bootpath[i];
+                               j++;
+                       }
+               }
+               bootpath[j] = '\0';
+       }
+
+       for (i = 0, last = 0; i < StrLen(ImagePath); i++)
+               if (ImagePath[i] == '\\')
+                       last = i + 1;
+
+       ImagePath = ImagePath + last;
+       *PathName = AllocatePool(StrSize(bootpath) + StrSize(ImagePath));
+
+       if (!*PathName) {
+               perror(L"Failed to allocate path buffer\n");
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto error;
+       }
+
+       *PathName[0] = '\0';
+       if (StrnCaseCmp(bootpath, ImagePath, StrLen(bootpath)))
+               StrCat(*PathName, bootpath);
+       StrCat(*PathName, ImagePath);
+
+error:
+       FreePool(bootpath);
+
+       return efi_status;
+}
+
+/*
+ * Extract the OptionalData and OptionalData fields from an
+ * EFI_LOAD_OPTION.
+ */
+static inline EFI_STATUS
+get_load_option_optional_data(VOID *data, UINT32 data_size,
+                             VOID **od, UINT32 *ods)
+{
+       /*
+        * If it's not at least Attributes + FilePathListLength +
+        * Description=L"" + 0x7fff0400 (EndEntrireDevicePath), it can't
+        * be valid.
+        */
+       if (data_size < (sizeof(UINT32) + sizeof(UINT16) + 2 + 4))
+               return EFI_INVALID_PARAMETER;
+
+       UINT8 *start = (UINT8 *)data;
+       UINT8 *cur = start + sizeof(UINT32);
+       UINT16 fplistlen = *(UINT16 *)cur;
+       /*
+        * If there's not enough space for the file path list and the
+        * smallest possible description (L""), it's not valid.
+        */
+       if (fplistlen > data_size - (sizeof(UINT32) + 2 + 4))
+               return EFI_INVALID_PARAMETER;
+
+       cur += sizeof(UINT16);
+       UINT32 limit = data_size - (cur - start) - fplistlen;
+       UINT32 i;
+       for (i = 0; i < limit ; i++) {
+               /* If the description isn't valid UCS2-LE, it's not valid. */
+               if (i % 2 != 0) {
+                       if (cur[i] != 0)
+                               return EFI_INVALID_PARAMETER;
+               } else if (cur[i] == 0) {
+                       /* we've found the end */
+                       i++;
+                       if (i >= limit || cur[i] != 0)
+                               return EFI_INVALID_PARAMETER;
+                       break;
+               }
+       }
+       i++;
+       if (i > limit)
+               return EFI_INVALID_PARAMETER;
+
+       /*
+        * If i is limit, we know the rest of this is the FilePathList and
+        * there's no optional data.  So just bail now.
+        */
+       if (i == limit) {
+               *od = NULL;
+               *ods = 0;
+               return EFI_SUCCESS;
+       }
+
+       cur += i;
+       limit -= i;
+       limit += fplistlen;
+       i = 0;
+       while (limit - i >= 4) {
+               struct {
+                       UINT8 type;
+                       UINT8 subtype;
+                       UINT16 len;
+               } dp = {
+                       .type = cur[i],
+                       .subtype = cur[i+1],
+                       /*
+                        * it's a little endian UINT16, but we're not
+                        * guaranteed alignment is sane, so we can't just
+                        * typecast it directly.
+                        */
+                       .len = (cur[i+3] << 8) | cur[i+2],
+               };
+
+               /*
+                * We haven't found an EndEntire, so this has to be a valid
+                * EFI_DEVICE_PATH in order for the data to be valid.  That
+                * means it has to fit, and it can't be smaller than 4 bytes.
+                */
+               if (dp.len < 4 || dp.len > limit)
+                       return EFI_INVALID_PARAMETER;
+
+               /*
+                * see if this is an EndEntire node...
+                */
+               if (dp.type == 0x7f && dp.subtype == 0xff) {
+                       /*
+                        * if we've found the EndEntire node, it must be 4
+                        * bytes
+                        */
+                       if (dp.len != 4)
+                               return EFI_INVALID_PARAMETER;
+
+                       i += dp.len;
+                       break;
+               }
+
+               /*
+                * It's just some random DP node; skip it.
+                */
+               i += dp.len;
+       }
+       if (i != fplistlen)
+               return EFI_INVALID_PARAMETER;
+
+       /*
+        * if there's any space left, it's "optional data"
+        */
+       *od = cur + i;
+       *ods = limit - i;
+       return EFI_SUCCESS;
+}
+
+static int
+is_our_path(EFI_LOADED_IMAGE *li, CHAR16 *path)
+{
+       CHAR16 *dppath = NULL;
+       CHAR16 *PathName = NULL;
+       EFI_STATUS efi_status;
+       int ret = 1;
+
+       dppath = DevicePathToStr(li->FilePath);
+       if (!dppath)
+               return 0;
+
+       efi_status = generate_path_from_image_path(li, path, &PathName);
+       if (EFI_ERROR(efi_status)) {
+               perror(L"Unable to generate path %s: %r\n", path,
+                      efi_status);
+               goto done;
+       }
+
+       dprint(L"dppath: %s\n", dppath);
+       dprint(L"path:   %s\n", path);
+       if (StrnCaseCmp(dppath, PathName, StrLen(dppath)))
+               ret = 0;
+
+done:
+       FreePool(dppath);
+       FreePool(PathName);
+       return ret;
+}
+
+/*
+ * Split the supplied load options in to a NULL terminated
+ * string representing the path of the second stage loader,
+ * and return a pointer to the remaining load options data
+ * and its remaining size.
+ *
+ * This expects the supplied load options to begin with a
+ * string that is either NULL terminated or terminated with
+ * a space and some optional data. It will return NULL if
+ * the supplied load options contains no spaces or NULL
+ * terminators.
+ */
+static CHAR16 *
+split_load_options(VOID *in, UINT32 in_size,
+                  VOID **remaining,
+                  UINT32 *remaining_size) {
+       UINTN i;
+       CHAR16 *arg0 = NULL;
+       CHAR16 *start = (CHAR16 *)in;
+
+       /* Skip spaces */
+       for (i = 0; i < in_size / sizeof(CHAR16); i++) {
+               if (*start != L' ')
+                       break;
+
+               start++;
+       }
+
+       in_size -= ((VOID *)start - in);
+
+       /*
+        * Ensure that the first argument is NULL terminated by
+        * replacing L' ' with L'\0'.
+        */
+       for (i = 0; i < in_size / sizeof(CHAR16); i++) {
+               if (start[i] == L' ' || start[i] == L'\0') {
+                       start[i] = L'\0';
+                       arg0 = (CHAR16 *)start;
+                       break;
+               }
+       }
+
+       if (arg0) {
+               UINTN skip = i + 1;
+               *remaining_size = in_size - (skip * sizeof(CHAR16));
+               *remaining = *remaining_size > 0 ? start + skip : NULL;
+       }
+
+       return arg0;
+}
+
+/*
+ * Check the load options to specify the second stage loader
+ */
+EFI_STATUS
+parse_load_options(EFI_LOADED_IMAGE *li)
+{
+       EFI_STATUS efi_status;
+       VOID *remaining = NULL;
+       UINT32 remaining_size;
+       CHAR16 *loader_str = NULL;
+
+       dprint(L"full load options:\n");
+       dhexdumpat(li->LoadOptions, li->LoadOptionsSize, 0);
+
+       /*
+        * Sanity check since we make several assumptions about the length
+        * Some firmware feeds the following load option when booting from
+        * an USB device:
+        *
+        *    0x46 0x4a 0x00 |FJ.|
+        *
+        * The string is meaningless for shim and so just ignore it.
+        */
+       if (li->LoadOptionsSize % 2 != 0)
+               return EFI_SUCCESS;
+
+       /* So, load options are a giant pain in the ass.  If we're invoked
+        * from the EFI shell, we get something like this:
+
+00000000  5c 00 45 00 36 00 49 00  5c 00 66 00 65 00 64 00  |\.E.F.I.\.f.e.d.|
+00000010  6f 00 72 00 61 00 5c 00  73 00 68 00 69 00 6d 00  |o.r.a.\.s.h.i.m.|
+00000020  78 00 36 00 34 00 2e 00  64 00 66 00 69 00 20 00  |x.6.4...e.f.i. .|
+00000030  5c 00 45 00 46 00 49 00  5c 00 66 00 65 00 64 00  |\.E.F.I.\.f.e.d.|
+00000040  6f 00 72 00 61 00 5c 00  66 00 77 00 75 00 70 00  |o.r.a.\.f.w.u.p.|
+00000050  64 00 61 00 74 00 65 00  2e 00 65 00 66 00 20 00  |d.a.t.e.e.f.i. .|
+00000060  00 00 66 00 73 00 30 00  3a 00 5c 00 00 00        |..f.s.0.:.\...|
+
+       *
+       * which is just some paths rammed together separated by a UCS-2 NUL.
+       * But if we're invoked from BDS, we get something more like:
+       *
+
+00000000  01 00 00 00 62 00 4c 00  69 00 6e 00 75 00 78 00  |....b.L.i.n.u.x.|
+00000010  20 00 46 00 69 00 72 00  6d 00 77 00 61 00 72 00  | .F.i.r.m.w.a.r.|
+00000020  65 00 20 00 55 00 70 00  64 00 61 00 74 00 65 00  |e. .U.p.d.a.t.e.|
+00000030  72 00 00 00 40 01 2a 00  01 00 00 00 00 08 00 00  |r.....*.........|
+00000040  00 00 00 00 00 40 06 00  00 00 00 00 1a 9e 55 bf  |.....@........U.|
+00000050  04 57 f2 4f b4 4a ed 26  4a 40 6a 94 02 02 04 04  |.W.O.:.&J@j.....|
+00000060  34 00 5c 00 45 00 46 00  49 00 5c 00 66 00 65 00  |4.\.E.F.I.f.e.d.|
+00000070  64 00 6f 00 72 00 61 00  5c 00 73 00 68 00 69 00  |o.r.a.\.s.h.i.m.|
+00000080  6d 00 78 00 36 00 34 00  2e 00 65 00 66 00 69 00  |x.6.4...e.f.i...|
+00000090  00 00 7f ff 40 00 20 00  5c 00 66 00 77 00 75 00  |...... .\.f.w.u.|
+000000a0  70 00 78 00 36 00 34 00  2e 00 65 00 66 00 69 00  |p.x.6.4...e.f.i.|
+000000b0  00 00                                             |..|
+
+       *
+       * which is clearly an EFI_LOAD_OPTION filled in halfway reasonably.
+       * In short, the UEFI shell is still a useless piece of junk.
+       *
+       * But then on some versions of BDS, we get:
+
+00000000  5c 00 66 00 77 00 75 00  70 00 78 00 36 00 34 00  |\.f.w.u.p.x.6.4.|
+00000010  2e 00 65 00 66 00 69 00  00 00                    |..e.f.i...|
+0000001a
+
+       * which as you can see is one perfectly normal UCS2-EL string
+       * containing the load option from the Boot#### variable.
+       *
+       * We also sometimes find a guid or partial guid at the end, because
+       * BDS will add that, but we ignore that here.
+       */
+
+       /*
+        * Maybe there just aren't any options...
+        */
+       if (li->LoadOptionsSize == 0)
+               return EFI_SUCCESS;
+
+       /*
+        * In either case, we've got to have at least a UCS2 NUL...
+        */
+       if (li->LoadOptionsSize < 2)
+               return EFI_BAD_BUFFER_SIZE;
+
+       /*
+        * Some awesome versions of BDS will add entries for Linux.  On top
+        * of that, some versions of BDS will "tag" any Boot#### entries they
+        * create by putting a GUID at the very end of the optional data in
+        * the EFI_LOAD_OPTIONS, thus screwing things up for everybody who
+        * tries to actually *use* the optional data for anything.  Why they
+        * did this instead of adding a flag to the spec to /say/ it's
+        * created by BDS, I do not know.  For shame.
+        *
+        * Anyway, just nerf that out from the start.  It's always just
+        * garbage at the end.
+        */
+       if (li->LoadOptionsSize > 16) {
+               if (CompareGuid((EFI_GUID *)(li->LoadOptions
+                                            + (li->LoadOptionsSize - 16)),
+                               &BDS_GUID) == 0)
+                       li->LoadOptionsSize -= 16;
+       }
+
+       /*
+        * Apparently sometimes we get L"\0\0"?  Which isn't useful at all.
+        */
+       if (is_all_nuls(li->LoadOptions, li->LoadOptionsSize))
+               return EFI_SUCCESS;
+
+       /*
+        * See if this is an EFI_LOAD_OPTION and extract the optional
+        * data if it is. This will return an error if it is not a valid
+        * EFI_LOAD_OPTION.
+        */
+       efi_status = get_load_option_optional_data(li->LoadOptions,
+                                                  li->LoadOptionsSize,
+                                                  &li->LoadOptions,
+                                                  &li->LoadOptionsSize);
+       if (EFI_ERROR(efi_status)) {
+               /*
+                * it's not an EFI_LOAD_OPTION, so it's probably just a string
+                * or list of strings.
+                *
+                * UEFI shell copies the whole line of the command into
+                * LoadOptions. We ignore the first string, i.e. the name of this
+                * program in this case.
+                */
+               loader_str = split_load_options(li->LoadOptions,
+                                               li->LoadOptionsSize,
+                                               &remaining,
+                                               &remaining_size);
+
+               if (loader_str && is_our_path(li, loader_str)) {
+                       li->LoadOptions = remaining;
+                       li->LoadOptionsSize = remaining_size;
+               }
+       }
+
+       loader_str = split_load_options(li->LoadOptions, li->LoadOptionsSize,
+                                       &remaining, &remaining_size);
+
+       /*
+        * Set up the name of the alternative loader and the LoadOptions for
+        * the loader
+        */
+       if (loader_str) {
+               second_stage = loader_str;
+               load_options = remaining;
+               load_options_size = remaining_size;
+       }
+
+       return EFI_SUCCESS;
+}
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/mock-variables.c b/mock-variables.c
new file mode 100644 (file)
index 0000000..e9bce54
--- /dev/null
@@ -0,0 +1,1400 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * mock-variables.c - a mock GetVariable/SetVariable/GNVN/etc
+ *                    implementation for testing.
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+#include "shim.h"
+#include "mock-variables.h"
+
+#include <dirent.h>
+#include <efivar/efivar.h>
+#include <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+list_t mock_default_variable_limits;
+list_t *mock_qvi_limits = &mock_default_variable_limits;
+list_t *mock_sv_limits = &mock_default_variable_limits;
+
+list_t mock_variables = LIST_HEAD_INIT(mock_variables);
+
+mock_sort_policy_t mock_variable_sort_policy = MOCK_SORT_APPEND;
+mock_sort_policy_t mock_config_table_sort_policy = MOCK_SORT_APPEND;
+
+UINT32 mock_variable_delete_attr_policy;
+
+mock_set_variable_pre_hook_t *mock_set_variable_pre_hook = NULL;
+mock_set_variable_post_hook_t *mock_set_variable_post_hook = NULL;
+mock_get_variable_pre_hook_t *mock_get_variable_pre_hook = NULL;
+mock_get_variable_post_hook_t *mock_get_variable_post_hook = NULL;
+mock_get_next_variable_name_pre_hook_t *mock_get_next_variable_name_pre_hook = NULL;
+mock_get_next_variable_name_post_hook_t *mock_get_next_variable_name_post_hook = NULL;
+mock_query_variable_info_pre_hook_t *mock_query_variable_info_pre_hook = NULL;
+mock_query_variable_info_post_hook_t *mock_query_variable_info_post_hook = NULL;
+
+static EFI_STATUS
+mock_sv_pre_hook(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size,
+                VOID *data)
+{
+       EFI_STATUS status = EFI_SUCCESS;
+       if (mock_set_variable_pre_hook)
+               status = mock_set_variable_pre_hook(name, guid,
+                                                   attrs, size, data);
+       return status;
+}
+
+static void
+mock_sv_post_hook_(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size,
+                  VOID *data, EFI_STATUS *status, mock_variable_op_t op,
+                  const char * const file, const int line,
+                  const char * const func)
+{
+       if (mock_set_variable_post_hook)
+               mock_set_variable_post_hook(name, guid, attrs, size,
+                                           data, status, op, file, line, func);
+}
+#define mock_sv_post_hook(name, guid, attrs, size, data, status, op) \
+       mock_sv_post_hook_(name, guid, attrs, size, data, status, op,\
+                          __FILE__, __LINE__, __func__)
+
+static EFI_STATUS
+mock_gv_pre_hook(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size,
+                 VOID *data)
+{
+       EFI_STATUS status = EFI_SUCCESS;
+       if (mock_get_variable_pre_hook)
+               status = mock_get_variable_pre_hook(name, guid,
+                                                   attrs, size, data);
+       return status;
+}
+
+static void
+mock_gv_post_hook_(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size,
+                  VOID *data, EFI_STATUS *status, const char * const file,
+                  const int line, const char * const func)
+{
+       if (mock_get_variable_post_hook)
+               mock_get_variable_post_hook(name, guid, attrs, size, data,
+                                           status, file, line, func);
+}
+#define mock_gv_post_hook(name, guid, attrs, size, data, status) \
+       mock_gv_post_hook_(name, guid, attrs, size, data, status,\
+                          __FILE__, __LINE__, __func__)
+
+static EFI_STATUS
+mock_gnvn_pre_hook(UINTN *size, CHAR16 *name, EFI_GUID *guid)
+{
+       EFI_STATUS status = EFI_SUCCESS;
+       if (mock_get_next_variable_name_pre_hook)
+               status = mock_get_next_variable_name_pre_hook(size, name, guid);
+       return status;
+}
+
+static void
+mock_gnvn_post_hook_(UINTN *size, CHAR16 *name, EFI_GUID *guid,
+                    EFI_STATUS *status, const char * const file,
+                    const int line, const char * const func)
+{
+       if (mock_get_next_variable_name_post_hook)
+               mock_get_next_variable_name_post_hook(size, name, guid, status,
+                                                     file, line, func);
+}
+#define mock_gnvn_post_hook(size, name, guid, status) \
+       mock_gnvn_post_hook_(size, name, guid, status,\
+                            __FILE__, __LINE__, __func__)
+
+static EFI_STATUS
+mock_qvi_pre_hook(UINT32 attrs, UINT64 *max_var_storage,
+                  UINT64 *remaining_var_storage, UINT64 *max_var_size)
+{
+       EFI_STATUS status = EFI_SUCCESS;
+       if (mock_query_variable_info_pre_hook)
+               status = mock_query_variable_info_pre_hook(
+                                       attrs, max_var_storage,
+                                       remaining_var_storage, max_var_size);
+       return status;
+}
+
+static void
+mock_qvi_post_hook_(UINT32 attrs, UINT64 *max_var_storage,
+                   UINT64 *remaining_var_storage, UINT64 *max_var_size,
+                   EFI_STATUS *status, const char * const file,
+                   const int line, const char * const func)
+{
+       if (mock_query_variable_info_post_hook)
+               mock_query_variable_info_post_hook(attrs, max_var_storage,
+                                                  remaining_var_storage,
+                                                  max_var_size, status,
+                                                  file, line, func);
+}
+#define mock_qvi_post_hook(attrs, max_var_storage, remaining_var_storage,\
+                          max_var_size, status) \
+       mock_qvi_post_hook_(attrs, max_var_storage, remaining_var_storage,\
+                           max_var_size, status, \
+                           __FILE__, __LINE__, __func__)
+
+static const size_t guidstr_size = sizeof("8be4df61-93ca-11d2-aa0d-00e098032b8c");
+
+static int
+variable_limits_cmp(const struct mock_variable_limits * const v0,
+                   const struct mock_variable_limits * const v1)
+{
+       UINT32 mask = EFI_VARIABLE_NON_VOLATILE |
+                     EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                     EFI_VARIABLE_RUNTIME_ACCESS;
+
+       return (v0->attrs & mask) - (v1->attrs & mask);
+}
+
+static INT64
+variable_cmp(const struct mock_variable * const v0,
+            const struct mock_variable * const v1)
+{
+       INT64 ret;
+       if (v0 == NULL || v1 == NULL)
+               return (uintptr_t)v0 - (uintptr_t)v1;
+
+       ret = CompareGuid(&v0->guid, &v1->guid);
+       ret <<= 8ul;
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():  "GUID_FMT" %s "GUID_FMT" (0x%011"PRIx64" %"PRId64")\n",
+              __FILE__, __LINE__-1, __func__,
+              GUID_ARGS(v0->guid),
+              ret < 0 ? "<" : (ret > 0 ? ">" : "="),
+              GUID_ARGS(v1->guid),
+              (UINT64)ret & 0x1fffffffffful,
+              ret);
+#endif
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = StrCmp(v0->name, v1->name);
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():   \"%s\" %s \"%s\" (0x%02hhx (%d)\n",
+              __FILE__, __LINE__-1, __func__,
+              Str2str(v0->name),
+              ret < 0 ? "<" : (ret > 0 ? ">" : "=="),
+              Str2str(v1->name),
+              ret, ret);
+#endif
+       return ret;
+}
+
+static char *
+list2var(list_t *pos)
+{
+       static char buf0[1024];
+       static char buf1[1024];
+       char *out;
+       static int n;
+       struct mock_variable *var;
+
+       out = n++ % 2 ? buf0 : buf1;
+       if (n > 1)
+               n -= 2;
+       SetMem(out, 1024, 0);
+       if (pos == &mock_variables) {
+               strcpy(out, "list tail");
+               return out;
+       }
+       var = list_entry(pos, struct mock_variable, list);
+       snprintf(out, 1023, GUID_FMT"-%s",
+                GUID_ARGS(var->guid),
+                Str2str(var->name));
+       return out;
+}
+
+EFI_STATUS EFIAPI
+mock_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size,
+                  VOID *data)
+{
+       list_t *pos = NULL;
+       struct mock_variable goal = {
+               .name = name,
+               .guid = *guid,
+       };
+       struct mock_variable *result = NULL;
+       EFI_STATUS status;
+
+       status = mock_gv_pre_hook(name, guid, attrs, size, data);
+       if (EFI_ERROR(status))
+               return status;
+
+       if (name == NULL || guid == NULL || size == NULL) {
+               status = EFI_INVALID_PARAMETER;
+               mock_gv_post_hook(name, guid, attrs, size, data, &status);
+               return status;
+       }
+
+       list_for_each(pos, &mock_variables) {
+               struct mock_variable *var;
+
+               var = list_entry(pos, struct mock_variable, list);
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n",
+                      __FILE__, __LINE__-1, __func__,
+                      GUID_ARGS(goal.guid), Str2str(goal.name),
+                      GUID_ARGS(var->guid), Str2str(var->name));
+#endif
+               if (variable_cmp(&goal, var) == 0) {
+                       if (attrs != NULL)
+                               *attrs = var->attrs;
+                       if (var->size > *size) {
+                               *size = var->size;
+                               status = EFI_BUFFER_TOO_SMALL;
+                               mock_gv_post_hook(name, guid, attrs, size, data,
+                                                 &status);
+                               return status;
+                       }
+                       if (data == NULL) {
+                               status = EFI_INVALID_PARAMETER;
+                               mock_gv_post_hook(name, guid, attrs, size, data,
+                                                 &status);
+                               return status;
+                       }
+                       *size = var->size;
+                       memcpy(data, var->data, var->size);
+                       status = EFI_SUCCESS;
+                       mock_gv_post_hook(name, guid, attrs, size, data,
+                                         &status);
+                       return status;
+               }
+       }
+
+       status = EFI_NOT_FOUND;
+       mock_gv_post_hook(name, guid, attrs, size, data, &status);
+       return status;
+}
+
+static EFI_STATUS
+mock_gnvn_set_result(UINTN *size, CHAR16 *name, EFI_GUID *guid,
+                    struct mock_variable *result)
+{
+       EFI_STATUS status;
+
+       if (*size < StrSize(result->name)) {
+               *size = StrSize(result->name);
+               status = EFI_BUFFER_TOO_SMALL;
+               mock_gnvn_post_hook(size, name, guid, &status);
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():  returning %lx\n",
+                      __FILE__, __LINE__-1, __func__, status);
+#endif
+               return status;
+       }
+
+       *size = StrLen(result->name) + 1;
+       StrCpy(name, result->name);
+       memcpy(guid, &result->guid, sizeof(EFI_GUID));
+
+       status = EFI_SUCCESS;
+       mock_gnvn_post_hook(size, name, guid, &status);
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():  returning %lx\n",
+              __FILE__, __LINE__-1, __func__, status);
+#endif
+       return status;
+}
+
+EFI_STATUS EFIAPI
+mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid)
+{
+       list_t *pos = NULL;
+       struct mock_variable goal = {
+               .name = name,
+               .guid = *guid,
+       };
+       struct mock_variable *result = NULL;
+       bool found = false;
+       EFI_STATUS status;
+
+       status = mock_gnvn_pre_hook(size, name, guid);
+       if (EFI_ERROR(status))
+               return status;
+
+       if (size == NULL || name == NULL || guid == NULL) {
+               status = EFI_INVALID_PARAMETER;
+               mock_gnvn_post_hook(size, name, guid, &status);
+               return status;
+       }
+
+       for (size_t i = 0; i < *size; i++) {
+               if (name[i] == 0) {
+                       found = true;
+                       break;
+               }
+       }
+
+       if (found == false) {
+               status = EFI_INVALID_PARAMETER;
+               mock_gnvn_post_hook(size, name, guid, &status);
+               return status;
+       }
+
+       found = false;
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():searching for "GUID_FMT"%s%s\n",
+              __FILE__, __LINE__-1, __func__,
+              GUID_ARGS(*guid),
+              name[0] == 0 ? "" : "-",
+              name[0] == 0 ? "" : Str2str(name));
+#endif
+       list_for_each(pos, &mock_variables) {
+               struct mock_variable *var;
+
+               var = list_entry(pos, struct mock_variable, list);
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():  candidate var:%p &var->guid:%p &var->list:%p\n",
+                       __FILE__, __LINE__-1, __func__, var, &var->guid, &var->list);
+#endif
+               if (name[0] == 0) {
+                       if (CompareGuid(&var->guid, guid) == 0) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+                               printf("%s:%d:%s():  found\n",
+                                      __FILE__, __LINE__-1, __func__);
+#endif
+                               result = var;
+                               found = true;
+                               break;
+                       }
+               } else {
+                       if (found) {
+                               if (CompareGuid(&var->guid, guid) == 0) {
+                                       result = var;
+                                       break;
+                               }
+                               continue;
+                       }
+
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n",
+                      __FILE__, __LINE__-1, __func__,
+                      GUID_ARGS(goal.guid), Str2str(goal.name),
+                      GUID_ARGS(var->guid), Str2str(var->name));
+#endif
+                       if (variable_cmp(&goal, var) == 0) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+                               printf("%s:%d:%s():  found\n",
+                                      __FILE__, __LINE__-1, __func__);
+#endif
+                               found = true;
+                       }
+               }
+       }
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       if (result) {
+               printf("%s:%d:%s():  found:%d result:%p &result->guid:%p &result->list:%p\n"
+                      __FILE__, __LINE__-1, __func__, found, result,
+                      &result->guid, &result->list);
+               printf("%s:%d:%s():  "GUID_FMT"-%s\n",
+                      __FILE__, __LINE__-1, __func__, GUID_ARGS(result->guid),
+                      Str2str(result->name));
+       } else {
+               printf("%s:%d:%s():  not found\n",
+                      __FILE__, __LINE__-1, __func__);
+       }
+#endif
+
+       if (!found) {
+               if (name[0] == 0)
+                       status = EFI_NOT_FOUND;
+               else
+                       status = EFI_INVALID_PARAMETER;
+               mock_gnvn_post_hook(size, name, guid, &status);
+               return status;
+       }
+
+       if (!result) {
+               status = EFI_NOT_FOUND;
+               mock_gnvn_post_hook(size, name, guid, &status);
+               return status;
+       }
+
+       return mock_gnvn_set_result(size, name, guid, result);
+}
+
+static void
+free_var(struct mock_variable *var)
+{
+       if (!var)
+               return;
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s(): var:%p &var->guid:%p ",
+              __FILE__, __LINE__-1, __func__,
+              var, var ? &var->guid : NULL);
+       if (var)
+               printf(GUID_FMT"-%s", GUID_ARGS(var->guid),
+                      var->name ? Str2str(var->name) : "");
+       printf("\n");
+#endif
+       list_del(&var->list);
+       if (var->size && var->data)
+               free(var->data);
+       SetMem(var, sizeof(*var), 0);
+       free(var);
+}
+
+static bool
+mock_sv_attrs_match(UINT32 old, UINT32 new)
+{
+       UINT32 mask = ~EFI_VARIABLE_APPEND_WRITE;
+
+       return (old & mask) == (new & mask);
+}
+
+static EFI_STATUS
+mock_sv_adjust_usage_data(UINT32 attrs, size_t size, ssize_t change)
+{
+       const UINT32 bs = EFI_VARIABLE_BOOTSERVICE_ACCESS;
+       const UINT32 bs_nv = bs | EFI_VARIABLE_NON_VOLATILE;
+       const UINT32 bs_rt = bs | EFI_VARIABLE_RUNTIME_ACCESS;
+       const UINT32 bs_rt_nv = bs_nv | bs_rt;
+       struct mock_variable_limits goal = {
+               .attrs = attrs & bs_rt_nv,
+       };
+       struct mock_variable_limits *qvi_limits = NULL;
+       struct mock_variable_limits *sv_limits = NULL;
+       list_t var, *pos = NULL;
+       UINT64 remaining;
+
+       list_for_each(pos, mock_qvi_limits) {
+               struct mock_variable_limits *candidate;
+
+               candidate = list_entry(pos, struct mock_variable_limits, list);
+               if (variable_limits_cmp(&goal, candidate) == 0) {
+                       qvi_limits = candidate;
+                       break;
+               }
+       }
+
+       list_for_each(pos, mock_sv_limits) {
+               struct mock_variable_limits *candidate;
+
+               candidate = list_entry(pos, struct mock_variable_limits, list);
+               if (variable_limits_cmp(&goal, candidate) == 0) {
+                       sv_limits = candidate;
+                       break;
+               }
+       }
+       if (!sv_limits) {
+               return EFI_UNSUPPORTED;
+       }
+
+       if (sv_limits->status != EFI_SUCCESS)
+               return sv_limits->status;
+
+       if (*sv_limits->max_var_size < size) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():*sv_limits->max_var_size:%zu size:%zu\n",
+                      __FILE__, __LINE__, __func__,
+                      *sv_limits->max_var_size, size);
+#endif
+               return EFI_OUT_OF_RESOURCES;
+       }
+
+       if (change > 0 && (UINT64)change > *sv_limits->remaining_var_storage) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():*sv_limits->remaining_var_storage:%zu change:%zd\n",
+                      __FILE__, __LINE__, __func__,
+                      *sv_limits->remaining_var_storage, change);
+#endif
+               return EFI_OUT_OF_RESOURCES;
+       }
+
+       *sv_limits->remaining_var_storage += change;
+
+       if (qvi_limits) {
+               /*
+                * If the adjustment here is wrong, we don't want to not do
+                * the set variable, we also don't want to not account
+                * for it, and of course we can't have any integer UB.  So
+                * just limit it safely and move on, even though that may
+                * result in wrong checks against QueryVariableInfo() later.
+                *
+                * As if there are correct checks against QueryVariableInfo()...
+                */
+               if (qvi_limits->remaining_var_storage == sv_limits->remaining_var_storage)
+                       ;
+               else if (change < 0 && (UINT64)-change > *qvi_limits->remaining_var_storage)
+                       *qvi_limits->remaining_var_storage = 0;
+               else if (change > 0 && UINT64_MAX - *qvi_limits->remaining_var_storage < (UINT64)change)
+                       *qvi_limits->remaining_var_storage = UINT64_MAX;
+               else
+                       *qvi_limits->remaining_var_storage += change;
+       }
+       return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+mock_delete_variable(struct mock_variable *var)
+{
+       EFI_STATUS status;
+
+       status = mock_sv_adjust_usage_data(var->attrs, 0, - var->size);
+       if (EFI_ERROR(status)) {
+               printf("%s:%d:%s():  status:0x%lx\n",
+                      __FILE__, __LINE__ - 1, __func__, status);
+               mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
+                                 var->data, &status, DELETE);
+               return status;
+       }
+
+       status = EFI_SUCCESS;
+       mock_sv_post_hook(var->name, &var->guid, var->attrs, 0, 0, &status,
+                         DELETE);
+       free_var(var);
+       return status;
+}
+
+static EFI_STATUS
+mock_replace_variable(struct mock_variable *var, VOID *data, UINTN size)
+{
+       EFI_STATUS status;
+       VOID *new;
+
+       status = mock_sv_adjust_usage_data(var->attrs, size,
+                                          - var->size + size);
+       if (EFI_ERROR(status)) {
+               mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
+                                 var->data, &status, REPLACE);
+               return status;
+       }
+
+       new = calloc(1, size);
+       if (!new) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():calloc(1, %zu) failed\n",
+                      __FILE__, __LINE__, __func__,
+                      size);
+#endif
+               status = EFI_OUT_OF_RESOURCES;
+               mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
+                                 var->data, &status, REPLACE);
+               return status;
+       }
+       memcpy(new, data, size);
+       free(var->data);
+       var->data = new;
+       var->size = size;
+
+       status = EFI_SUCCESS;
+       mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
+                         var->data, &status, REPLACE);
+       return status;
+}
+
+static EFI_STATUS
+mock_sv_extend(struct mock_variable *var, VOID *data, UINTN size)
+{
+       EFI_STATUS status;
+       uint8_t *new;
+
+       if (size == 0) {
+               status = EFI_SUCCESS;
+               mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
+                                 var->data, &status, APPEND);
+               return status;
+       }
+
+       status = mock_sv_adjust_usage_data(var->attrs, var->size + size, size);
+       if (EFI_ERROR(status)) {
+               mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
+                                 var->data, &status, APPEND);
+               return status;
+       }
+
+       new = realloc(var->data, var->size + size);
+       if (!new) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():realloc(%zu) failed\n",
+                      __FILE__, __LINE__, __func__,
+                      var->size + size);
+#endif
+               status = EFI_OUT_OF_RESOURCES;
+               mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
+                                 var->data, &status, APPEND);
+               return status;
+       }
+
+       memcpy(&new[var->size], data, size);
+       var->data = (void *)new;
+       var->size += size;
+
+       status = EFI_SUCCESS;
+       mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
+                         var->data, &status, APPEND);
+       return status;
+}
+
+void
+mock_print_var_list(list_t *head)
+{
+       list_t *pos = NULL;
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():variables so far:\n", __FILE__, __LINE__, __func__);
+#endif
+       list_for_each(pos, head) {
+               struct mock_variable *var = NULL;
+
+               var = list_entry(pos, struct mock_variable, list);
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():  "GUID_FMT"-%s (%lu bytes)\n",
+                      __FILE__, __LINE__ - 1, __func__,
+                      GUID_ARGS(var->guid), Str2str(var->name), var->size);
+#endif
+       }
+}
+
+static EFI_STATUS
+mock_new_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size,
+                 VOID *data, struct mock_variable **out)
+{
+       EFI_STATUS status;
+       struct mock_variable *var;
+       uint8_t *buf;
+
+       if (size == 0) {
+               status = EFI_INVALID_PARAMETER;
+               return status;
+       }
+
+       status = EFI_OUT_OF_RESOURCES;
+       buf = calloc(1, sizeof(struct mock_variable) + StrSize(name));
+       if (!buf) {
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():  calloc(1, %zu) failed\n",
+                      __FILE__, __LINE__, __func__,
+                      sizeof(struct mock_variable) + StrSize(name));
+#endif
+               goto err;
+       }
+       var = (struct mock_variable *)buf;
+
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():  var:%p &var->guid:%p &var->list:%p\n",
+              __FILE__, __LINE__-1, __func__, var, &var->guid, &var->list);
+#endif
+
+       var->data = malloc(size);
+       if (!var->data)
+               goto err_free;
+
+       var->name = (CHAR16 *)&buf[sizeof(*var)];
+       StrCpy(var->name, name);
+       memcpy(&var->guid, guid, sizeof(EFI_GUID));
+       memcpy(var->data, data, size);
+       var->size = size;
+       var->attrs = attrs;
+       INIT_LIST_HEAD(&var->list);
+
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():  var: "GUID_FMT"-%s\n",
+              __FILE__, __LINE__-1, __func__,
+              GUID_ARGS(var->guid), Str2str(var->name));
+#endif
+
+       *out = var;
+       status = EFI_SUCCESS;
+err_free:
+       if (EFI_ERROR(status))
+               free_var(var);
+err:
+       return status;
+}
+
+EFI_STATUS EFIAPI
+mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size,
+                  VOID *data)
+{
+       list_t *pos = NULL, *tmp = NULL, *var_list = NULL;
+       struct mock_variable goal = {
+               .name = name,
+               .guid = *guid,
+       };
+       struct mock_variable *var = NULL;
+       bool found = false;
+       bool add_tail = true;
+       EFI_STATUS status;
+       long cmp = -1;
+
+       status = mock_sv_pre_hook(name, guid, attrs, size, data);
+       if (EFI_ERROR(status))
+               return status;
+
+       if (!name || name[0] == 0 || !guid) {
+               status = EFI_INVALID_PARAMETER;
+               mock_sv_post_hook(name, guid, attrs, size, data, &status,
+                                 CREATE);
+               return status;
+       }
+
+       if ((attrs & EFI_VARIABLE_RUNTIME_ACCESS) &&
+           !(attrs & EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
+               status = EFI_INVALID_PARAMETER;
+               mock_sv_post_hook(name, guid, attrs, size, data, &status,
+                                 CREATE);
+               return status;
+       }
+
+#if 0
+       /*
+        * We don't ever operate after ExitBootServices(), so I'm not
+        * checking for the missing EFI_VARIABLE_RUNTIME_ACCESS case
+        */
+       if (has_exited_boot_services() && !(attrs & EFI_VARIABLE_RUNTIME_ACCESS)) {
+               status = EFI_INVALID_PARAMETER;
+               mock_sv_post_hook(name, guid, attrs, size, data, &status,
+                                 CREATE);
+               return status;
+       }
+#endif
+
+#if 0
+       /*
+        * For now, we're ignoring that we don't support these.
+        */
+       if (attrs & (EFI_VARIABLE_HARDWARE_ERROR_RECORD |
+                    EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
+                    EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS |
+                    EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS)) {
+               status = EFI_UNSUPPORTED;
+               mock_sv_post_hook(name, guid, attrs, size, data, &status,
+                                 CREATE);
+               return status;
+       }
+#endif
+
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():Setting "GUID_FMT"-%s\n",
+              __FILE__, __LINE__ - 1, __func__,
+              GUID_ARGS(*guid), Str2str(name));
+#endif
+       switch (mock_variable_sort_policy) {
+       case MOCK_SORT_PREPEND:
+               var_list = &mock_variables;
+               add_tail = false;
+               break;
+       case MOCK_SORT_APPEND:
+               var_list = &mock_variables;
+               add_tail = true;
+               break;
+       case MOCK_SORT_DESCENDING:
+               add_tail = true;
+               break;
+       case MOCK_SORT_ASCENDING:
+               add_tail = true;
+               break;
+       default:
+               break;
+       }
+
+       pos = &mock_variables;
+       list_for_each_safe(pos, tmp, &mock_variables) {
+               found = false;
+               var = list_entry(pos, struct mock_variable, list);
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n",
+                      __FILE__, __LINE__-1, __func__,
+                      GUID_ARGS(goal.guid), Str2str(goal.name),
+                      GUID_ARGS(var->guid), Str2str(var->name));
+#endif
+               cmp = variable_cmp(&goal, var);
+               cmp = cmp < 0 ? -1 : (cmp > 0 ? 1 : 0);
+
+               switch (mock_variable_sort_policy) {
+               case MOCK_SORT_DESCENDING:
+                       if (cmp >= 0) {
+                               var_list = pos;
+                               found = true;
+                       }
+                       break;
+               case MOCK_SORT_ASCENDING:
+                       if (cmp <= 0) {
+                               var_list = pos;
+                               found = true;
+                       }
+                       break;
+               default:
+                       if (cmp == 0) {
+                               var_list = pos;
+                               found = true;
+                       }
+                       break;
+               }
+               if (found)
+                       break;
+       }
+#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
+       printf("%s:%d:%s():var_list:%p &mock_variables:%p cmp:%ld\n",
+              __FILE__, __LINE__ - 1, __func__,
+              var_list, &mock_variables, cmp);
+#endif
+       if (cmp != 0 || (cmp == 0 && var_list == &mock_variables)) {
+               size_t totalsz = size + StrSize(name);
+#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
+               printf("%s:%d:%s():var:%p attrs:0x%lx\n",
+                      __FILE__, __LINE__ - 1, __func__, var, attrs);
+#endif
+               status = mock_new_variable(name, guid, attrs, size, data, &var);
+               if (EFI_ERROR(status)) {
+                       mock_sv_post_hook(name, guid, attrs, size, data,
+                                         &status, CREATE);
+                       return status;
+               }
+               mock_sv_adjust_usage_data(attrs, size, totalsz);
+               mock_sv_post_hook(name, guid, attrs, size, data,
+                                 &status, CREATE);
+               if (EFI_ERROR(status)) {
+                       mock_sv_adjust_usage_data(attrs, 0, -totalsz);
+                       return status;
+               }
+
+#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
+               printf("%s:%d:%s(): Adding "GUID_FMT"-%s %s %s\n",
+                      __FILE__, __LINE__ - 1, __func__,
+                      GUID_ARGS(var->guid), Str2str(var->name),
+                      add_tail ? "after" : "before",
+                      list2var(pos));
+#endif
+               if (add_tail)
+                       list_add_tail(&var->list, pos);
+               else
+                       list_add(&var->list, pos);
+               return status;
+       }
+
+       var = list_entry(var_list, struct mock_variable, list);
+#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
+       printf("%s:%d:%s():var:%p attrs:%s cmp:%ld size:%ld\n",
+              __FILE__, __LINE__ - 1, __func__,
+              var, format_var_attrs(var->attrs), cmp, size);
+#endif
+       if (!mock_sv_attrs_match(var->attrs, attrs)) {
+               status = EFI_INVALID_PARAMETER;
+               if (size == 0 && !(attrs & EFI_VARIABLE_APPEND_WRITE)) {
+                       if ((mock_variable_delete_attr_policy & MOCK_VAR_DELETE_ATTR_ALLOW_ZERO)
+                           && attrs == 0) {
+                               status = EFI_SUCCESS;
+                       } else if (mock_variable_delete_attr_policy & MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH) {
+                               status = EFI_SUCCESS;
+                       }
+               }
+               if (EFI_ERROR(status)) {
+                       printf("%s:%d:%s(): var->attrs:%s attrs:%s\n",
+                              __FILE__, __LINE__ - 1, __func__,
+                              format_var_attrs(var->attrs),
+                              format_var_attrs(attrs));
+                       mock_sv_post_hook(name, guid, attrs, size, data,
+                                         &status, REPLACE);
+                       return status;
+               }
+       }
+
+       if (attrs & EFI_VARIABLE_APPEND_WRITE)
+               return mock_sv_extend(var, data, size);
+
+       if (size == 0) {
+               UINT32 mask = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+                             | EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS;
+               /*
+                * We can't process deletes on these correctly unless we
+                * parse the header.
+                */
+               if (attrs & mask) {
+                       return EFI_INVALID_PARAMETER;
+               }
+
+               return mock_delete_variable(var);
+       }
+
+       return mock_replace_variable(var, data, size);
+}
+
+EFI_STATUS EFIAPI
+mock_query_variable_info(UINT32 attrs, UINT64 *max_var_storage,
+                         UINT64 *remaining_var_storage, UINT64 *max_var_size)
+{
+       list_t mvl, *pos = NULL;
+       struct mock_variable_limits goal = {
+               .attrs = attrs,
+       };
+       struct mock_variable_limits *limits = NULL;
+       EFI_STATUS status;
+
+       status = mock_qvi_pre_hook(attrs, max_var_storage,
+                                  remaining_var_storage, max_var_size);
+       if (EFI_ERROR(status))
+               return status;
+
+       if (max_var_storage == NULL ||
+           remaining_var_storage == NULL ||
+           max_var_size == NULL) {
+               status = EFI_INVALID_PARAMETER;
+               mock_qvi_post_hook(attrs, max_var_storage,
+                                  remaining_var_storage, max_var_size,
+                                  &status);
+               return status;
+       }
+
+       list_for_each(pos, mock_qvi_limits) {
+               limits = list_entry(pos, struct mock_variable_limits, list);
+               if (variable_limits_cmp(&goal, limits) == 0) {
+                       *max_var_storage = *limits->max_var_storage;
+                       *remaining_var_storage = *limits->remaining_var_storage;
+                       *max_var_size = *limits->max_var_size;
+
+                       status = EFI_SUCCESS;
+                       mock_qvi_post_hook(attrs, max_var_storage,
+                                          remaining_var_storage, max_var_size,
+                                          &status);
+                       return status;
+               }
+       }
+
+       status = EFI_UNSUPPORTED;
+       mock_qvi_post_hook(attrs, max_var_storage, remaining_var_storage,
+                          max_var_size, &status);
+       return status;
+}
+
+static UINT64 default_max_var_storage;
+static UINT64 default_remaining_var_storage;
+static UINT64 default_max_var_size;
+
+static struct mock_variable_limits default_limits[] = {
+       {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS,
+        .max_var_storage = &default_max_var_storage,
+        .remaining_var_storage = &default_remaining_var_storage,
+        .max_var_size = &default_max_var_size,
+        .status = EFI_SUCCESS,
+       },
+       {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                 EFI_VARIABLE_RUNTIME_ACCESS,
+        .max_var_storage = &default_max_var_storage,
+        .remaining_var_storage = &default_remaining_var_storage,
+        .max_var_size = &default_max_var_size,
+        .status = EFI_SUCCESS,
+       },
+       {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                 EFI_VARIABLE_NON_VOLATILE,
+        .max_var_storage = &default_max_var_storage,
+        .remaining_var_storage = &default_remaining_var_storage,
+        .max_var_size = &default_max_var_size,
+        .status = EFI_SUCCESS,
+       },
+       {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                 EFI_VARIABLE_RUNTIME_ACCESS |
+                 EFI_VARIABLE_NON_VOLATILE,
+        .max_var_storage = &default_max_var_storage,
+        .remaining_var_storage = &default_remaining_var_storage,
+        .max_var_size = &default_max_var_size,
+        .status = EFI_SUCCESS,
+       },
+       {.attrs = 0, }
+};
+
+void
+mock_set_default_usage_limits(void)
+{
+       default_max_var_storage = 65536;
+       default_remaining_var_storage = 65536;
+       default_max_var_size = 32768;
+
+       INIT_LIST_HEAD(&mock_default_variable_limits);
+       for (size_t i = 0; default_limits[i].attrs != 0; i++) {
+               INIT_LIST_HEAD(&default_limits[i].list);
+               list_add_tail(&default_limits[i].list,
+                             &mock_default_variable_limits);
+       }
+}
+
+void
+mock_load_one_variable(int dfd, const char * const dirname, char * const name)
+{
+       int fd;
+       FILE *f;
+       int rc;
+       struct stat statbuf;
+       size_t guidlen, namelen;
+       efi_guid_t guid;
+       size_t sz;
+       ssize_t offset = 0;
+       EFI_STATUS status;
+       UINT32 attrs;
+
+       rc = fstatat(dfd, name, &statbuf, 0);
+       if (rc < 0)
+               err(2, "Could not stat \"%s/%s\"", dirname, name);
+
+       if (!(S_ISREG(statbuf.st_mode)))
+               return;
+
+       if (statbuf.st_size < 5)
+               errx(2, "Test data variable \"%s/%s\" is too small (%ld bytes)",
+                    dirname, name, statbuf.st_size);
+
+#if 0
+       mock_print_var_list(&mock_variables);
+#endif
+
+       uint8_t buf[statbuf.st_size];
+
+       fd = openat(dfd, name, O_RDONLY);
+       if (fd < 0)
+               err(2, "Could not open \"%s/%s\"", dirname, name);
+
+       f = fdopen(fd, "r");
+       if (!f)
+               err(2, "Could not open \"%s/%s\"", dirname, name);
+
+       while (offset != statbuf.st_size) {
+               sz = fread(buf + offset, 1, statbuf.st_size - offset, f);
+               if (sz == 0) {
+                       if (ferror(f))
+                               err(2, "Could not read from \"%s/%s\"",
+                                   dirname, name);
+                       if (feof(f))
+                               errx(2, "Unexpected end of file reading \"%s/%s\"",
+                                    dirname, name);
+               }
+
+               offset += sz;
+       }
+
+       guidlen = strlen("8be4df61-93ca-11d2-aa0d-00e098032b8c");
+       namelen = strlen(name) - guidlen;
+
+       if (namelen < 2)
+               errx(2, "namelen for \"%s\" is %zu!?!", name, namelen);
+
+       CHAR16 namebuf[namelen];
+
+       name[namelen-1] = 0;
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("loading %s-%s\n", &name[namelen], name);
+#endif
+       for (size_t i = 0; i < namelen; i++)
+               namebuf[i] = name[i];
+
+       rc = efi_str_to_guid(&name[namelen], &guid);
+       if (rc < 0)
+               err(2, "Could not parse \"%s\" as EFI GUID", &name[namelen]);
+
+       memcpy(&attrs, (UINT32 *)buf, sizeof(UINT32));
+
+       status = RT->SetVariable(namebuf, (EFI_GUID *)&guid, attrs,
+                                statbuf.st_size - sizeof(attrs),
+                                &buf[sizeof(attrs)]);
+       if (EFI_ERROR(status))
+               errx(2, "%s:%d:%s(): Could not set variable: 0x%llx",
+                    __FILE__, __LINE__ - 1, __func__,
+                    (unsigned long long)status);
+
+       fclose(f);
+}
+
+void
+mock_load_variables(const char *const dirname, const char *filters[],
+                   bool filter_out)
+{
+       int dfd;
+       DIR *d;
+       struct dirent *entry;
+
+       d = opendir(dirname);
+       if (!d)
+               err(1, "Could not open directory \"%s\"", dirname);
+
+       dfd = dirfd(d);
+       if (dfd < 0)
+               err(1, "Could not get directory file descriptor for \"%s\"",
+                   dirname);
+
+       while ((entry = readdir(d)) != NULL) {
+               size_t len = strlen(entry->d_name);
+               bool found = false;
+               if (filters && len > guidstr_size + 1) {
+                       char spacebuf[len];
+
+                       len -= guidstr_size;
+                       SetMem(spacebuf, sizeof(spacebuf)-1, ' ');
+                       spacebuf[len] = '\0';
+                       for (size_t i = 0; filters[i]; i++) {
+                               if (strlen(filters[i]) > len)
+                                       continue;
+                               if (!strncmp(entry->d_name, filters[i], len)) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+               }
+               if ((found == false && filter_out == true) ||
+                   (found == true && filter_out == false)) {
+                       mock_load_one_variable(dfd, dirname, entry->d_name);
+               }
+       }
+
+       closedir(d);
+#if 0
+       mock_print_var_list(&mock_variables);
+#endif
+}
+
+static bool qvi_installed = false;
+
+void
+mock_install_query_variable_info(void)
+{
+       qvi_installed = true;
+       RT->Hdr.Revision = 2ul << 16ul;
+       RT->QueryVariableInfo = mock_query_variable_info;
+}
+
+void
+mock_uninstall_query_variable_info(void)
+{
+       qvi_installed = false;
+       RT->Hdr.Revision = EFI_1_10_SYSTEM_TABLE_REVISION;
+       RT->QueryVariableInfo = mock_efi_unsupported;
+}
+
+EFI_CONFIGURATION_TABLE mock_config_table[MOCK_CONFIG_TABLE_ENTRIES] = {
+       {
+               .VendorGuid = { 0, },
+               .VendorTable = NULL
+       },
+};
+
+int
+mock_config_table_cmp(const void *p0, const void *p1)
+{
+       EFI_CONFIGURATION_TABLE *entry0, *entry1;
+       long cmp;
+
+       if (!p0 || !p1) {
+               cmp = (int)((intptr_t)p0 - (intptr_t)p1);
+       } else {
+               entry0 = (EFI_CONFIGURATION_TABLE *)p0;
+               entry1 = (EFI_CONFIGURATION_TABLE *)p1;
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("comparing %p to %p\n", p0, p1);
+#endif
+               cmp = CompareGuid(&entry0->VendorGuid, &entry1->VendorGuid);
+       }
+
+       if (mock_config_table_sort_policy == MOCK_SORT_DESCENDING) {
+               cmp = -cmp;
+       }
+
+       return cmp;
+}
+
+EFI_STATUS EFIAPI
+mock_install_configuration_table(EFI_GUID *guid, VOID *table)
+{
+       bool found = false;
+       EFI_CONFIGURATION_TABLE *entry;
+       int idx = 0;
+       size_t sz;
+
+       if (!guid)
+               return EFI_INVALID_PARAMETER;
+
+       for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) {
+               EFI_CONFIGURATION_TABLE *entry = &ST->ConfigurationTable[i];
+
+               if (CompareGuid(guid, &entry->VendorGuid) == 0) {
+                       found = true;
+                       if (table) {
+                               // replace it
+                               entry->VendorTable = table;
+                       } else {
+                               // delete it
+                               ST->NumberOfTableEntries -= 1;
+                               sz = ST->NumberOfTableEntries - i;
+                               sz *= sizeof(*entry);
+                               memmove(&entry[0], &entry[1], sz);
+                       }
+                       return EFI_SUCCESS;
+               }
+       }
+       if (!found && table == NULL)
+               return EFI_NOT_FOUND;
+       if (ST->NumberOfTableEntries == MOCK_CONFIG_TABLE_ENTRIES - 1) {
+               /*
+                * If necessary, we could allocate another table and copy
+                * the data, but I'm lazy and we probably don't need to.
+                */
+               return EFI_OUT_OF_RESOURCES;
+       }
+
+       switch (mock_config_table_sort_policy) {
+       case MOCK_SORT_DESCENDING:
+       case MOCK_SORT_ASCENDING:
+       case MOCK_SORT_APPEND:
+               idx = ST->NumberOfTableEntries;
+               break;
+       case MOCK_SORT_PREPEND:
+               sz = ST->NumberOfTableEntries ? ST->NumberOfTableEntries : 0;
+               sz *= sizeof(ST->ConfigurationTable[0]);
+               memmove(&ST->ConfigurationTable[1], &ST->ConfigurationTable[0], sz);
+               idx = 0;
+               break;
+       default:
+               break;
+       }
+
+       entry = &ST->ConfigurationTable[idx];
+       memcpy(&entry->VendorGuid, guid, sizeof(EFI_GUID));
+       entry->VendorTable = table;
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s(): installing entry %p={%p,%p} as entry %d\n",
+              __FILE__, __LINE__, __func__,
+              entry, &entry->VendorGuid, entry->VendorTable, idx);
+#endif
+       ST->NumberOfTableEntries += 1;
+
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s():ST->ConfigurationTable:%p\n"
+              "\t[%d]:%p\n"
+              "\t[%d]:%p\n",
+              __FILE__, __LINE__, __func__, ST->ConfigurationTable,
+              0, &ST->ConfigurationTable[0],
+              1, &ST->ConfigurationTable[1]);
+#endif
+       switch (mock_config_table_sort_policy) {
+       case MOCK_SORT_DESCENDING:
+       case MOCK_SORT_ASCENDING:
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s(): entries before sorting:\n", __FILE__, __LINE__, __func__);
+               for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) {
+                       printf("\t[%d] = %p = {", i, &ST->ConfigurationTable[i]);
+                       printf(".VendorGuid=" GUID_FMT, GUID_ARGS(ST->ConfigurationTable[i].VendorGuid));
+                       printf(".VendorTable=%p}\n", ST->ConfigurationTable[i].VendorTable);
+               }
+#endif
+               qsort(&ST->ConfigurationTable[0], ST->NumberOfTableEntries,
+                     sizeof(ST->ConfigurationTable[0]),
+                     mock_config_table_cmp);
+               break;
+       default:
+               break;
+       }
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+       printf("%s:%d:%s(): entries:\n", __FILE__, __LINE__, __func__);
+       for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) {
+               printf("\t[%d] = %p = {", i, &ST->ConfigurationTable[i]);
+               printf(".VendorGuid=" GUID_FMT, GUID_ARGS(ST->ConfigurationTable[i].VendorGuid));
+               printf(".VendorTable=%p}\n", ST->ConfigurationTable[i].VendorTable);
+       }
+#endif
+
+       return EFI_SUCCESS;
+}
+
+void CONSTRUCTOR
+mock_reset_variables(void)
+{
+       list_t *pos = NULL, *tmp = NULL;
+       static bool once = true;
+
+       init_efi_system_table();
+
+       mock_set_variable_pre_hook = NULL;
+       mock_set_variable_post_hook = NULL;
+       mock_get_variable_pre_hook = NULL;
+       mock_get_variable_post_hook = NULL;
+       mock_get_next_variable_name_pre_hook = NULL;
+       mock_get_next_variable_name_post_hook = NULL;
+       mock_query_variable_info_pre_hook = NULL;
+       mock_query_variable_info_post_hook = NULL;
+
+       if (once) {
+               INIT_LIST_HEAD(&mock_variables);
+               once = false;
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():mock_variables = {%p,%p};\n",
+                      __FILE__, __LINE__-1, __func__,
+                      mock_variables.next,
+                      mock_variables.prev);
+               printf("%s:%d:%s():list_empty(&mock_variables):%d\n",
+                      __FILE__, __LINE__-1, __func__, list_empty(&mock_variables));
+               printf("%s:%d:%s():list_size(&mock_variables):%d\n",
+                      __FILE__, __LINE__-1, __func__, list_size(&mock_variables));
+#endif
+       }
+
+       list_for_each_safe(pos, tmp, &mock_variables) {
+               struct mock_variable *var = NULL;
+               var = list_entry(pos, struct mock_variable, list);
+
+#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
+               printf("%s:%d:%s():var:"GUID_FMT"-%s\n",
+                      __FILE__, __LINE__-1, __func__,
+                      GUID_ARGS(var->guid), Str2str(var->name));
+#endif
+               mock_delete_variable(var);
+       }
+       INIT_LIST_HEAD(&mock_variables);
+       mock_set_default_usage_limits();
+
+       mock_variable_delete_attr_policy = MOCK_VAR_DELETE_ATTR_ALLOW_ZERO;
+
+       RT->GetVariable = mock_get_variable;
+       RT->GetNextVariableName = mock_get_next_variable_name;
+       RT->SetVariable = mock_set_variable;
+       if (qvi_installed)
+               mock_install_query_variable_info();
+       else
+               mock_uninstall_query_variable_info();
+}
+
+void CONSTRUCTOR
+mock_reset_config_table(void)
+{
+       init_efi_system_table();
+
+       /*
+        * Note that BS->InstallConfigurationTable() is *not* defined as
+        * freeing these.  If a test case installs non-malloc()ed tables,
+        * it needs to call BS->InstallConfigurationTable(guid, NULL) to
+        * clear them.
+        */
+       for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) {
+               EFI_CONFIGURATION_TABLE *entry = &ST->ConfigurationTable[i];
+
+               if (entry->VendorTable)
+                       free(entry->VendorTable);
+       }
+
+       SetMem(ST->ConfigurationTable,
+              ST->NumberOfTableEntries * sizeof(EFI_CONFIGURATION_TABLE),
+              0);
+
+       ST->NumberOfTableEntries = 0;
+
+       if (ST->ConfigurationTable != mock_config_table) {
+               free(ST->ConfigurationTable);
+               ST->ConfigurationTable = mock_config_table;
+               SetMem(mock_config_table, sizeof(mock_config_table), 0);
+       }
+
+       BS->InstallConfigurationTable = mock_install_configuration_table;
+}
+
+void DESTRUCTOR
+mock_finalize_vars_and_configs(void)
+{
+       mock_reset_variables();
+       mock_reset_config_table();
+}
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/mok.c b/mok.c
index 5ad9072beec753dc2608360f5c7d1db36aa0915c..289628535974628875ea94ea04eed98fc35606e4 100644 (file)
--- a/mok.c
+++ b/mok.c
@@ -16,8 +16,8 @@ static BOOLEAN check_var(CHAR16 *varname)
        UINT32 MokVar;
        UINT32 attributes;
 
-       efi_status = gRT->GetVariable(varname, &SHIM_LOCK_GUID, &attributes,
-                                     &size, (void *)&MokVar);
+       efi_status = RT->GetVariable(varname, &SHIM_LOCK_GUID, &attributes,
+                                    &size, (void *)&MokVar);
        if (!EFI_ERROR(efi_status) || efi_status == EFI_BUFFER_TOO_SMALL)
                return TRUE;
 
@@ -27,7 +27,7 @@ static BOOLEAN check_var(CHAR16 *varname)
 #define SetVariable(name, guid, attrs, varsz, var)                                  \
        ({                                                                          \
                EFI_STATUS efi_status_;                                             \
-               efi_status_ = gRT->SetVariable(name, guid, attrs, varsz, var);      \
+               efi_status_ = RT->SetVariable(name, guid, attrs, varsz, var);       \
                dprint_(L"%a:%d:%a() SetVariable(\"%s\", ... varsz=0x%llx) = %r\n", \
                        __FILE__, __LINE__ - 5, __func__, name, varsz,              \
                        efi_status_);                                               \
@@ -46,7 +46,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
            check_var(L"MokPW") || check_var(L"MokAuth") ||
            check_var(L"MokDel") || check_var(L"MokDB") ||
            check_var(L"MokXNew") || check_var(L"MokXDel") ||
-           check_var(L"MokXAuth")) {
+           check_var(L"MokXAuth") || check_var(L"MokListTrustedNew")) {
                efi_status = start_image(image_handle, MOK_MANAGER);
 
                if (EFI_ERROR(efi_status)) {
@@ -58,85 +58,6 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
        return EFI_SUCCESS;
 }
 
-typedef enum {
-       VENDOR_ADDEND_DB,
-       VENDOR_ADDEND_X509,
-       VENDOR_ADDEND_NONE,
-} vendor_addend_category_t;
-
-struct mok_state_variable;
-typedef vendor_addend_category_t (vendor_addend_categorizer_t)(struct mok_state_variable *);
-
-/*
- * MoK variables that need to have their storage validated.
- *
- * The order here is important, since this is where we measure for the
- * tpm as well.
- */
-struct mok_state_variable {
-       CHAR16 *name;   /* UCS-2 BS|NV variable name */
-       char *name8;    /* UTF-8 BS|NV variable name */
-       CHAR16 *rtname; /* UCS-2 RT variable name */
-       char *rtname8;  /* UTF-8 RT variable name */
-       EFI_GUID *guid; /* variable GUID */
-
-       /*
-        * these are used during processing, they shouldn't be filled out
-        * in the static table below.
-        */
-       UINT8 *data;
-       UINTN data_size;
-
-       /*
-        * addend are added to the input variable, as part of the runtime
-        * variable, so that they're visible to the kernel.  These are
-        * where we put vendor_cert / vendor_db / vendor_dbx
-        *
-        * These are indirect pointers just to make initialization saner...
-        */
-       vendor_addend_categorizer_t *categorize_addend; /* determines format */
-       /*
-        * we call categorize_addend() and it determines what kind of thing
-        * this is.  That is, if this shim was built with VENDOR_CERT, for
-        * the DB entry it'll return VENDOR_ADDEND_X509; if you used
-        * VENDOR_DB instead, it'll return VENDOR_ADDEND_DB.  If you used
-        * neither, it'll do VENDOR_ADDEND_NONE.
-        *
-        * The existing categorizers are for db and dbx; they differ
-        * because we don't currently support a CERT for dbx.
-        */
-       UINT8 **addend;
-       UINT32 *addend_size;
-
-       /*
-        * build_cert is our build-time cert.  Like addend, this is added
-        * to the input variable, as part of the runtime variable, so that
-        * they're visible to the kernel.  This is the ephemeral cert used
-        * for signing MokManager.efi and fallback.efi.
-        *
-        * These are indirect pointers just to make initialization saner...
-        */
-       UINT8 **build_cert;
-       UINT32 *build_cert_size;
-
-       UINT32 yes_attr;        /* var attrs that must be set */
-       UINT32 no_attr;         /* var attrs that must not be set */
-       UINT32 flags;           /* flags on what and how to mirror */
-       /*
-        * MOK_MIRROR_KEYDB         mirror this as a key database
-        * MOK_MIRROR_DELETE_FIRST  delete any existing variable first
-        * MOK_VARIABLE_MEASURE     extend PCR 7 and log the hash change
-        * MOK_VARIABLE_LOG         measure into whatever .pcr says and log
-        */
-       UINTN pcr;              /* PCR to measure and hash to */
-
-       /*
-        * if this is a state value, a pointer to our internal state to be
-        * mirrored.
-        */
-       UINT8 *state;
-};
-
 static vendor_addend_category_t
 categorize_authorized(struct mok_state_variable *v)
 {
@@ -164,7 +85,7 @@ categorize_deauthorized(struct mok_state_variable *v)
 #define MOK_VARIABLE_MEASURE   0x04
 #define MOK_VARIABLE_LOG       0x08
 
-struct mok_state_variable mok_state_variables[] = {
+struct mok_state_variable mok_state_variable_data[] = {
        {.name = L"MokList",
         .name8 = "MokList",
         .rtname = L"MokListRT",
@@ -245,8 +166,24 @@ struct mok_state_variable mok_state_variables[] = {
                  MOK_VARIABLE_MEASURE,
         .pcr = 7,
        },
+       {.name = L"MokListTrusted",
+        .name8 = "MokListTrusted",
+        .rtname = L"MokListTrustedRT",
+        .rtname8 = "MokListTrustedRT",
+        .guid = &SHIM_LOCK_GUID,
+        .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                    EFI_VARIABLE_NON_VOLATILE,
+        .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
+        .flags = MOK_MIRROR_DELETE_FIRST |
+                 MOK_VARIABLE_MEASURE |
+                 MOK_VARIABLE_LOG,
+        .pcr = 14,
+        .state = &trust_mok_list,
+       },
        { NULL, }
 };
+size_t n_mok_state_variables = sizeof(mok_state_variable_data) / sizeof(mok_state_variable_data[0]);
+struct mok_state_variable *mok_state_variables = &mok_state_variable_data[0];
 
 #define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE))
 
@@ -261,6 +198,9 @@ static const uint8_t null_sha256[32] = { 0, };
 
 typedef UINTN SIZE_T;
 
+#define EFI_MAJOR_VERSION(tablep) ((UINT16)((((tablep)->Hdr.Revision) >> 16) & 0xfffful))
+#define EFI_MINOR_VERSION(tablep) ((UINT16)(((tablep)->Hdr.Revision) & 0xfffful))
+
 static EFI_STATUS
 get_max_var_sz(UINT32 attrs, SIZE_T *max_var_szp)
 {
@@ -270,11 +210,21 @@ get_max_var_sz(UINT32 attrs, SIZE_T *max_var_szp)
        uint64_t max_var_sz = 0;
 
        *max_var_szp = 0;
-       efi_status = gRT->QueryVariableInfo(attrs, &max_storage_sz,
-                                           &remaining_sz, &max_var_sz);
-       if (EFI_ERROR(efi_status)) {
-               perror(L"Could not get variable storage info: %r\n", efi_status);
-               return efi_status;
+       if (EFI_MAJOR_VERSION(RT) < 2) {
+               dprint(L"EFI %d.%d; no RT->QueryVariableInfo().  Using 1024!\n",
+                      EFI_MAJOR_VERSION(RT), EFI_MINOR_VERSION(RT));
+               max_var_sz = remaining_sz = max_storage_sz = 1024;
+               efi_status = EFI_SUCCESS;
+       } else {
+               dprint(L"calling RT->QueryVariableInfo() at 0x%lx\n",
+                      RT->QueryVariableInfo);
+               efi_status = RT->QueryVariableInfo(attrs, &max_storage_sz,
+                                                  &remaining_sz, &max_var_sz);
+               if (EFI_ERROR(efi_status)) {
+                       perror(L"Could not get variable storage info: %r\n",
+                              efi_status);
+                       return efi_status;
+               }
        }
 
        /*
@@ -351,13 +301,18 @@ mirror_mok_db(CHAR16 *name, CHAR8 *name8, EFI_GUID *guid, UINT32 attrs,
        SIZE_T max_var_sz;
 
        efi_status = get_max_var_sz(attrs, &max_var_sz);
-       if (EFI_ERROR(efi_status)) {
+       if (EFI_ERROR(efi_status) && efi_status != EFI_UNSUPPORTED) {
                LogError(L"Could not get maximum variable size: %r",
                         efi_status);
                return efi_status;
        }
 
-       if (FullDataSize <= max_var_sz) {
+       /* Some UEFI environment such as u-boot doesn't implement
+        * QueryVariableInfo() and we will only get EFI_UNSUPPORTED when
+        * querying the available space. In this case, we just mirror
+        * the variable directly. */
+       if (FullDataSize <= max_var_sz || efi_status == EFI_UNSUPPORTED) {
+               efi_status = EFI_SUCCESS;
                if (only_first)
                        efi_status = SetVariable(name, guid, attrs,
                                                 FullDataSize, FullData);
@@ -850,7 +805,7 @@ maybe_mirror_one_mok_variable(struct mok_state_variable *v,
        BOOLEAN present = FALSE;
 
        if (v->rtname) {
-               if (!only_first && (v->flags & MOK_MIRROR_DELETE_FIRST)) {
+               if (only_first && (v->flags & MOK_MIRROR_DELETE_FIRST)) {
                        dprint(L"deleting \"%s\"\n", v->rtname);
                        efi_status = LibDeleteVariable(v->rtname, v->guid);
                        dprint(L"LibDeleteVariable(\"%s\",...) => %r\n", v->rtname, efi_status);
@@ -876,50 +831,43 @@ maybe_mirror_one_mok_variable(struct mok_state_variable *v,
        return ret;
 }
 
-struct mok_variable_config_entry {
-       CHAR8 name[256];
-       UINT64 data_size;
-       UINT8 data[];
-};
-
 EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
                                BOOLEAN only_first)
 {
        EFI_STATUS ret = EFI_SUCCESS;
        EFI_STATUS efi_status;
 
-       user_insecure_mode = 0;
-       ignore_db = 0;
-
        UINT32 attrs = 0;
        BOOLEAN delete = FALSE;
 
        dprint(L"importing mok state for \"%s\"\n", v->name);
 
-       efi_status = get_variable_attr(v->name,
-                                      &v->data, &v->data_size,
-                                      *v->guid, &attrs);
-       if (efi_status == EFI_NOT_FOUND) {
-               v->data = NULL;
-               v->data_size = 0;
-       } else if (EFI_ERROR(efi_status)) {
-               perror(L"Could not verify %s: %r\n", v->name,
-                      efi_status);
-               delete = TRUE;
-       } else {
-               if (!(attrs & v->yes_attr)) {
-                       perror(L"Variable %s is missing attributes:\n",
-                              v->name);
-                       perror(L"  0x%08x should have 0x%08x set.\n",
-                              attrs, v->yes_attr);
-                       delete = TRUE;
-               }
-               if (attrs & v->no_attr) {
-                       perror(L"Variable %s has incorrect attribute:\n",
-                              v->name);
-                       perror(L"  0x%08x should not have 0x%08x set.\n",
-                              attrs, v->no_attr);
+       if (!v->data && !v->data_size) {
+               efi_status = get_variable_attr(v->name,
+                                              &v->data, &v->data_size,
+                                              *v->guid, &attrs);
+               if (efi_status == EFI_NOT_FOUND) {
+                       v->data = NULL;
+                       v->data_size = 0;
+               } else if (EFI_ERROR(efi_status)) {
+                       perror(L"Could not verify %s: %r\n", v->name,
+                              efi_status);
                        delete = TRUE;
+               } else {
+                       if (!(attrs & v->yes_attr)) {
+                               perror(L"Variable %s is missing attributes:\n",
+                                      v->name);
+                               perror(L"  0x%08x should have 0x%08x set.\n",
+                                      attrs, v->yes_attr);
+                               delete = TRUE;
+                       }
+                       if (attrs & v->no_attr) {
+                               perror(L"Variable %s has incorrect attribute:\n",
+                                      v->name);
+                               perror(L"  0x%08x should not have 0x%08x set.\n",
+                                      attrs, v->no_attr);
+                               delete = TRUE;
+                       }
                }
        }
        if (delete == TRUE) {
@@ -935,7 +883,9 @@ EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
        }
 
        dprint(L"maybe mirroring \"%s\".  original data:\n", v->name);
-       dhexdumpat(v->data, v->data_size, 0);
+       if (v->data && v->data_size) {
+               dhexdumpat(v->data, v->data_size, 0);
+       }
 
        ret = maybe_mirror_one_mok_variable(v, ret, only_first);
        dprint(L"returning %r\n", ret);
@@ -963,6 +913,7 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
 
        user_insecure_mode = 0;
        ignore_db = 0;
+       trust_mok_list = 0;
 
        UINT64 config_sz = 0;
        UINT8 *config_table = NULL;
@@ -1001,10 +952,9 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
                config_sz += sizeof(config_template);
                npages = ALIGN_VALUE(config_sz, PAGE_SIZE) >> EFI_PAGE_SHIFT;
                config_table = NULL;
-               efi_status = gBS->AllocatePages(AllocateAnyPages,
-                                               EfiRuntimeServicesData,
-                                               npages,
-                                               (EFI_PHYSICAL_ADDRESS *)&config_table);
+               efi_status = BS->AllocatePages(
+                       AllocateAnyPages, EfiRuntimeServicesData, npages,
+                       (EFI_PHYSICAL_ADDRESS *)&config_table);
                if (EFI_ERROR(efi_status) || !config_table) {
                        console_print(L"Allocating %lu pages for mok config table failed: %r\n",
                                      npages, efi_status);
@@ -1024,17 +974,19 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
 
                config_template.data_size = v->data_size;
 
-               CopyMem(p, &config_template, sizeof(config_template));
-               p += sizeof(config_template);
-               CopyMem(p, v->data, v->data_size);
-               p += v->data_size;
+               if (v->data && v->data_size) {
+                       CopyMem(p, &config_template, sizeof(config_template));
+                       p += sizeof(config_template);
+                       CopyMem(p, v->data, v->data_size);
+                       p += v->data_size;
+               }
        }
        if (p) {
                ZeroMem(&config_template, sizeof(config_template));
                CopyMem(p, &config_template, sizeof(config_template));
 
-               efi_status = gBS->InstallConfigurationTable(&MOK_VARIABLE_STORE,
-                                                           config_table);
+               efi_status = BS->InstallConfigurationTable(&MOK_VARIABLE_STORE,
+                                                          config_table);
                if (EFI_ERROR(efi_status)) {
                        console_print(L"Couldn't install MoK configuration table\n");
                }
index 3f5c5198185a3e1f6460de258794b0b32de9df03..cf5882c1e798aef22614204e5b02b40e9f3176dd 100644 (file)
--- a/netboot.c
+++ b/netboot.c
@@ -36,8 +36,8 @@ BOOLEAN findNetboot(EFI_HANDLE device)
 {
        EFI_STATUS efi_status;
 
-       efi_status = gBS->HandleProtocol(device, &PxeBaseCodeProtocol,
-                                        (VOID **) &pxe);
+       efi_status = BS->HandleProtocol(device, &PxeBaseCodeProtocol,
+                                       (VOID **) &pxe);
        if (EFI_ERROR(efi_status)) {
                pxe = NULL;
                return FALSE;
diff --git a/pe.c b/pe.c
index 365e32aa3bc04a092862eb84b8b7658bf1b8a83d..92c2804b42dd621384266543644e29f4f503c3b8 100644 (file)
--- a/pe.c
+++ b/pe.c
@@ -298,26 +298,22 @@ get_section_vma_by_name (char *name, size_t namesz,
  */
 
 EFI_STATUS
-generate_hash(char *data, unsigned int datasize_in,
+generate_hash(char *data, unsigned int datasize,
              PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash,
              UINT8 *sha1hash)
 {
        unsigned int sha256ctxsize, sha1ctxsize;
-       unsigned int size = datasize_in;
        void *sha256ctx = NULL, *sha1ctx = NULL;
        char *hashbase;
        unsigned int hashsize;
        unsigned int SumOfBytesHashed, SumOfSectionBytes;
        unsigned int index, pos;
-       unsigned int datasize;
        EFI_IMAGE_SECTION_HEADER *Section;
        EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL;
        EFI_STATUS efi_status = EFI_SUCCESS;
        EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data;
        unsigned int PEHdr_offset = 0;
 
-       size = datasize = datasize_in;
-
        if (datasize <= sizeof (*DosHdr) ||
            DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
                perror(L"Invalid signature\n");
@@ -346,7 +342,7 @@ generate_hash(char *data, unsigned int datasize_in,
        hashbase = data;
        hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum -
                hashbase;
-       check_size(data, datasize_in, hashbase, hashsize);
+       check_size(data, datasize, hashbase, hashsize);
 
        if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
            !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@@ -359,7 +355,7 @@ generate_hash(char *data, unsigned int datasize_in,
        hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum +
                sizeof (int);
        hashsize = (char *)context->SecDir - hashbase;
-       check_size(data, datasize_in, hashbase, hashsize);
+       check_size(data, datasize, hashbase, hashsize);
 
        if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
            !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@@ -372,12 +368,12 @@ generate_hash(char *data, unsigned int datasize_in,
        EFI_IMAGE_DATA_DIRECTORY *dd = context->SecDir + 1;
        hashbase = (char *)dd;
        hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data);
-       if (hashsize > datasize_in) {
+       if (hashsize > datasize) {
                perror(L"Data Directory size %d is invalid\n", hashsize);
                efi_status = EFI_INVALID_PARAMETER;
                goto done;
        }
-       check_size(data, datasize_in, hashbase, hashsize);
+       check_size(data, datasize, hashbase, hashsize);
 
        if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
            !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@@ -491,7 +487,8 @@ generate_hash(char *data, unsigned int datasize_in,
                        continue;
                }
 
-               hashbase  = ImageAddress(data, size, Section->PointerToRawData);
+               hashbase  = ImageAddress(data, datasize,
+                                        Section->PointerToRawData);
                if (!hashbase) {
                        perror(L"Malformed section header\n");
                        efi_status = EFI_INVALID_PARAMETER;
@@ -506,7 +503,7 @@ generate_hash(char *data, unsigned int datasize_in,
                        goto done;
                }
                hashsize  = (unsigned int) Section->SizeOfRawData;
-               check_size(data, datasize_in, hashbase, hashsize);
+               check_size(data, datasize, hashbase, hashsize);
 
                if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
                    !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@@ -532,7 +529,7 @@ generate_hash(char *data, unsigned int datasize_in,
                        efi_status = EFI_INVALID_PARAMETER;
                        goto done;
                }
-               check_size(data, datasize_in, hashbase, hashsize);
+               check_size(data, datasize, hashbase, hashsize);
 
                if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
                    !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@@ -552,7 +549,7 @@ generate_hash(char *data, unsigned int datasize_in,
                hashbase = data + SumOfBytesHashed;
                hashsize = datasize - SumOfBytesHashed;
 
-               check_size(data, datasize_in, hashbase, hashsize);
+               check_size(data, datasize, hashbase, hashsize);
 
                if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
                    !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@@ -949,8 +946,8 @@ handle_image (void *data, unsigned int datasize,
                                 PAGE_SIZE);
        *alloc_pages = alloc_size / PAGE_SIZE;
 
-       efi_status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderCode,
-                                       *alloc_pages, alloc_address);
+       efi_status = BS->AllocatePages(AllocateAnyPages, EfiLoaderCode,
+                                      *alloc_pages, alloc_address);
        if (EFI_ERROR(efi_status)) {
                perror(L"Failed to allocate image buffer\n");
                return EFI_OUT_OF_RESOURCES;
@@ -963,7 +960,7 @@ handle_image (void *data, unsigned int datasize,
        *entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
        if (!*entry_point) {
                perror(L"Entry point is invalid\n");
-               gBS->FreePages(*alloc_address, *alloc_pages);
+               BS->FreePages(*alloc_address, *alloc_pages);
                return EFI_UNSUPPORTED;
        }
 
@@ -1004,7 +1001,7 @@ handle_image (void *data, unsigned int datasize,
 
                if (end < base) {
                        perror(L"Section %d has negative size\n", i);
-                       gBS->FreePages(*alloc_address, *alloc_pages);
+                       BS->FreePages(*alloc_address, *alloc_pages);
                        return EFI_UNSUPPORTED;
                }
 
@@ -1144,17 +1141,15 @@ handle_image (void *data, unsigned int datasize,
        li->ImageSize = context.ImageSize;
 
        /* Pass the load options to the second stage loader */
-       if ( load_options ) {
-               li->LoadOptions = load_options;
-               li->LoadOptionsSize = load_options_size;
-       }
+       li->LoadOptions = load_options;
+       li->LoadOptionsSize = load_options_size;
 
        if (!found_entry_point) {
                perror(L"Entry point is not within sections\n");
                return EFI_UNSUPPORTED;
        }
        if (found_entry_point > 1) {
-               perror(L"%d sections contain entry point\n");
+               perror(L"%d sections contain entry point\n", found_entry_point);
                return EFI_UNSUPPORTED;
        }
 
diff --git a/post-process-pe.c b/post-process-pe.c
new file mode 100644 (file)
index 0000000..8414a5f
--- /dev/null
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * post-process-pe.c - fix up timestamps and checksums in broken PE files
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#define _GNU_SOURCE 1
+
+#include <err.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+static int verbosity;
+#define ERROR         0
+#define WARNING       1
+#define INFO          2
+#define NOISE         3
+#define MIN_VERBOSITY ERROR
+#define MAX_VERBOSITY NOISE
+#define debug(level, ...)                                        \
+       ({                                                       \
+               if (verbosity >= (level)) {                      \
+                       printf("%s():%d: ", __func__, __LINE__); \
+                       printf(__VA_ARGS__);                     \
+               }                                                \
+               0;                                               \
+       })
+
+typedef uint8_t UINT8;
+typedef uint16_t UINT16;
+typedef uint32_t UINT32;
+typedef uint64_t UINT64;
+
+typedef uint16_t CHAR16;
+
+typedef unsigned long UINTN;
+
+typedef struct {
+       UINT32 Data1;
+       UINT16 Data2;
+       UINT16 Data3;
+       UINT8 Data4[8];
+} EFI_GUID;
+
+#include "include/peimage.h"
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define GNUC_PREREQ(maj, min) \
+       ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define GNUC_PREREQ(maj, min) 0
+#endif
+
+#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
+#define CLANG_PREREQ(maj, min)        \
+       ((__clang_major__ > (maj)) || \
+        (__clang_major__ == (maj) && __clang_minor__ >= (min)))
+#else
+#define CLANG_PREREQ(maj, min) 0
+#endif
+
+#if GNUC_PREREQ(5, 1) || CLANG_PREREQ(3, 8)
+#define add(a0, a1, s) __builtin_add_overflow(a0, a1, s)
+#define sub(s0, s1, d) __builtin_sub_overflow(s0, s1, d)
+#define mul(f0, f1, p) __builtin_mul_overflow(f0, f1, p)
+#else
+#define add(a0, a1, s)                \
+       ({                            \
+               (*s) = ((a0) + (a1)); \
+               0;                    \
+       })
+#define sub(s0, s1, d)                \
+       ({                            \
+               (*d) = ((s0) - (s1)); \
+               0;                    \
+       })
+#define mul(f0, f1, p)                \
+       ({                            \
+               (*p) = ((f0) * (f1)); \
+               0;                    \
+       })
+#endif
+#define div(d0, d1, q)                           \
+       ({                                       \
+               unsigned int ret_ = ((d1) == 0); \
+               if (ret_ == 0)                   \
+                       (*q) = ((d0) / (d1));    \
+               ret_;                            \
+       })
+
+static int
+image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
+{
+       /* .Magic is the same offset in all cases */
+       if (PEHdr->Pe32Plus.OptionalHeader.Magic ==
+           EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+               return 1;
+       return 0;
+}
+
+static void
+load_pe(const char *const file, void *const data, const size_t datasize,
+        PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
+{
+       EFI_IMAGE_DOS_HEADER *DOSHdr = data;
+       EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
+       size_t HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
+       size_t FileAlignment = 0;
+       size_t sz0 = 0, sz1 = 0;
+       uintptr_t loc = 0;
+
+       debug(NOISE, "datasize:%zu sizeof(PEHdr->Pe32):%zu\n", datasize,
+             sizeof(PEHdr->Pe32));
+       if (datasize < sizeof(PEHdr->Pe32))
+               errx(1, "%s: Invalid image size %zu (%zu < %zu)", file,
+                    datasize, datasize, sizeof(PEHdr->Pe32));
+
+       debug(NOISE,
+             "DOSHdr->e_magic:0x%02hx EFI_IMAGE_DOS_SIGNATURE:0x%02hx\n",
+             DOSHdr->e_magic, EFI_IMAGE_DOS_SIGNATURE);
+       if (DOSHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE)
+               errx(1,
+                    "%s: Invalid DOS header signature 0x%04hx (expected 0x%04hx)",
+                    file, DOSHdr->e_magic, EFI_IMAGE_DOS_SIGNATURE);
+
+       debug(NOISE, "DOSHdr->e_lfanew:%u datasize:%zu\n", DOSHdr->e_lfanew,
+             datasize);
+       if (DOSHdr->e_lfanew >= datasize ||
+           add((uintptr_t)data, DOSHdr->e_lfanew, &loc))
+               errx(1, "%s: invalid pe header location", file);
+
+       ctx->PEHdr = PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)loc;
+       debug(NOISE, "PE signature:0x%04x EFI_IMAGE_NT_SIGNATURE:0x%04x\n",
+             PEHdr->Pe32.Signature, EFI_IMAGE_NT_SIGNATURE);
+       if (PEHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE)
+               errx(1, "%s: Unsupported image type", file);
+
+       if (image_is_64_bit(PEHdr)) {
+               debug(NOISE, "image is 64bit\n");
+               ctx->NumberOfRvaAndSizes =
+                       PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
+               ctx->SizeOfHeaders =
+                       PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
+               ctx->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
+               ctx->SectionAlignment =
+                       PEHdr->Pe32Plus.OptionalHeader.SectionAlignment;
+               FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment;
+               OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
+       } else {
+               debug(NOISE, "image is 32bit\n");
+               ctx->NumberOfRvaAndSizes =
+                       PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
+               ctx->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
+               ctx->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
+               ctx->SectionAlignment =
+                       PEHdr->Pe32.OptionalHeader.SectionAlignment;
+               FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment;
+               OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
+       }
+
+       if (FileAlignment % 2 != 0)
+               errx(1, "%s: Invalid file alignment %ld", file, FileAlignment);
+
+       if (FileAlignment == 0)
+               FileAlignment = 0x200;
+       if (ctx->SectionAlignment == 0)
+               ctx->SectionAlignment = PAGE_SIZE;
+       if (ctx->SectionAlignment < FileAlignment)
+               ctx->SectionAlignment = FileAlignment;
+
+       ctx->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
+
+       debug(NOISE,
+             "Number of RVAs:%"PRIu64" EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES:%d\n",
+             ctx->NumberOfRvaAndSizes, EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES);
+       if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < ctx->NumberOfRvaAndSizes)
+               errx(1, "%s: invalid number of RVAs (%lu entries, max is %d)",
+                    file, ctx->NumberOfRvaAndSizes,
+                    EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES);
+
+       if (mul(sizeof(EFI_IMAGE_DATA_DIRECTORY),
+               EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, &sz0) ||
+           sub(OptHeaderSize, sz0, &HeaderWithoutDataDir) ||
+           sub(PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
+               HeaderWithoutDataDir, &sz0) ||
+           mul(ctx->NumberOfRvaAndSizes, sizeof(EFI_IMAGE_DATA_DIRECTORY),
+               &sz1) ||
+           (sz0 != sz1)) {
+               if (mul(sizeof(EFI_IMAGE_DATA_DIRECTORY),
+                       EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, &sz0))
+                       debug(ERROR,
+                             "sizeof(EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES overflows\n");
+               else
+                       debug(ERROR,
+                             "sizeof(EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES = %zu\n",
+                             sz0);
+               if (sub(OptHeaderSize, sz0, &HeaderWithoutDataDir))
+                       debug(ERROR,
+                             "OptHeaderSize (%zu) - HeaderWithoutDataDir (%zu) overflows\n",
+                             OptHeaderSize, HeaderWithoutDataDir);
+               else
+                       debug(ERROR,
+                             "OptHeaderSize (%zu) - HeaderWithoutDataDir (%zu) = %zu\n",
+                             OptHeaderSize, sz0, HeaderWithoutDataDir);
+
+               if (sub(PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
+                       HeaderWithoutDataDir, &sz0)) {
+                       debug(ERROR,
+                             "PEHdr->Pe32.FileHeader.SizeOfOptionalHeader (%d) - %zu overflows\n",
+                             PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
+                             HeaderWithoutDataDir);
+               } else {
+                       debug(ERROR,
+                             "PEHdr->Pe32.FileHeader.SizeOfOptionalHeader (%d)- %zu = %zu\n",
+                             PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
+                             HeaderWithoutDataDir, sz0);
+               }
+               if (mul(ctx->NumberOfRvaAndSizes,
+                       sizeof(EFI_IMAGE_DATA_DIRECTORY), &sz1))
+                       debug(ERROR,
+                             "ctx->NumberOfRvaAndSizes (%zu) * sizeof(EFI_IMAGE_DATA_DIRECTORY) overflows\n",
+                             ctx->NumberOfRvaAndSizes);
+               else
+                       debug(ERROR,
+                             "ctx->NumberOfRvaAndSizes (%zu) * sizeof(EFI_IMAGE_DATA_DIRECTORY) = %zu\n",
+                             ctx->NumberOfRvaAndSizes, sz1);
+               debug(ERROR,
+                     "space after image header:%zu data directory size:%zu\n",
+                     sz0, sz1);
+
+               errx(1, "%s: image header overflows data directory", file);
+       }
+
+       if (add(DOSHdr->e_lfanew, sizeof(UINT32), &SectionHeaderOffset) ||
+           add(SectionHeaderOffset, sizeof(EFI_IMAGE_FILE_HEADER),
+               &SectionHeaderOffset) ||
+           add(SectionHeaderOffset,
+               PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
+               &SectionHeaderOffset)) {
+               debug(ERROR, "SectionHeaderOffset:%" PRIu32 " + %zu + %zu + %d",
+                     DOSHdr->e_lfanew, sizeof(UINT32),
+                     sizeof(EFI_IMAGE_FILE_HEADER),
+                     PEHdr->Pe32.FileHeader.SizeOfOptionalHeader);
+               errx(1, "%s: SectionHeaderOffset would overflow", file);
+       }
+
+       if (sub(ctx->ImageSize, SectionHeaderOffset, &sz0) ||
+           div(sz0, EFI_IMAGE_SIZEOF_SECTION_HEADER, &sz0) ||
+           (sz0 <= ctx->NumberOfSections)) {
+               debug(ERROR, "(%" PRIu64 " - %zu) / %d > %d\n", ctx->ImageSize,
+                     SectionHeaderOffset, EFI_IMAGE_SIZEOF_SECTION_HEADER,
+                     ctx->NumberOfSections);
+               errx(1, "%s: image sections overflow image size", file);
+       }
+
+       if (sub(ctx->SizeOfHeaders, SectionHeaderOffset, &sz0) ||
+           div(sz0, EFI_IMAGE_SIZEOF_SECTION_HEADER, &sz0) ||
+           (sz0 < ctx->NumberOfSections)) {
+               debug(ERROR, "(%zu - %zu) / %d >= %d\n", ctx->SizeOfHeaders,
+                     SectionHeaderOffset, EFI_IMAGE_SIZEOF_SECTION_HEADER,
+                     ctx->NumberOfSections);
+               errx(1, "%s: image sections overflow section headers", file);
+       }
+
+       if (sub((uintptr_t)PEHdr, (uintptr_t)data, &sz0) ||
+           add(sz0, sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION), &sz0) ||
+           (sz0 > datasize)) {
+               errx(1, "%s: PE Image size %zu > %zu", file, sz0, datasize);
+       }
+
+       if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED)
+               errx(1, "%s: Unsupported image - Relocations have been stripped", file);
+
+       if (image_is_64_bit(PEHdr)) {
+               ctx->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
+               ctx->EntryPoint =
+                       PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
+               ctx->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory
+                                        [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+               ctx->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory
+                                      [EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+       } else {
+               ctx->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
+               ctx->EntryPoint =
+                       PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
+               ctx->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory
+                                        [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+               ctx->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory
+                                      [EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+       }
+
+       if (add((uintptr_t)PEHdr, PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
+               &loc) ||
+           add(loc, sizeof(UINT32), &loc) ||
+           add(loc, sizeof(EFI_IMAGE_FILE_HEADER), &loc))
+               errx(1, "%s: invalid location for first section", file);
+
+       ctx->FirstSection = (EFI_IMAGE_SECTION_HEADER *)loc;
+
+       if (ctx->ImageSize < ctx->SizeOfHeaders)
+               errx(1,
+                    "%s: Image size %"PRIu64" is smaller than header size %lu",
+                    file, ctx->ImageSize, ctx->SizeOfHeaders);
+
+       if (sub((uintptr_t)ctx->SecDir, (uintptr_t)data, &sz0) ||
+           sub(datasize, sizeof(EFI_IMAGE_DATA_DIRECTORY), &sz1) ||
+           sz0 > sz1)
+               errx(1,
+                    "%s: security direcory offset %zu past data directory at %zu",
+                    file, sz0, sz1);
+
+       if (ctx->SecDir->VirtualAddress > datasize ||
+           (ctx->SecDir->VirtualAddress == datasize &&
+            ctx->SecDir->Size > 0))
+               errx(1, "%s: Security directory extends past end", file);
+}
+
+static void
+fix_timestamp(PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
+{
+       uint32_t ts;
+
+       if (image_is_64_bit(ctx->PEHdr)) {
+               ts = ctx->PEHdr->Pe32Plus.FileHeader.TimeDateStamp;
+       } else {
+               ts = ctx->PEHdr->Pe32.FileHeader.TimeDateStamp;
+       }
+
+       if (ts != 0) {
+               debug(INFO, "Updating timestamp from 0x%08x to 0\n", ts);
+               if (image_is_64_bit(ctx->PEHdr)) {
+                       ctx->PEHdr->Pe32Plus.FileHeader.TimeDateStamp = 0;
+               } else {
+                       ctx->PEHdr->Pe32.FileHeader.TimeDateStamp = 0;
+               }
+       }
+}
+
+static void
+fix_checksum(PE_COFF_LOADER_IMAGE_CONTEXT *ctx, void *map, size_t mapsize)
+{
+       uint32_t old;
+       uint32_t checksum = 0;
+       uint16_t word;
+       uint8_t *data = map;
+
+       if (image_is_64_bit(ctx->PEHdr)) {
+               old = ctx->PEHdr->Pe32Plus.OptionalHeader.CheckSum;
+               ctx->PEHdr->Pe32Plus.OptionalHeader.CheckSum = 0;
+       } else {
+               old = ctx->PEHdr->Pe32.OptionalHeader.CheckSum;
+               ctx->PEHdr->Pe32.OptionalHeader.CheckSum = 0;
+       }
+       debug(NOISE, "old checksum was 0x%08x\n", old);
+
+       for (size_t i = 0; i < mapsize - 1; i += 2) {
+               word = (data[i + 1] << 8ul) | data[i];
+               checksum += word;
+               checksum = 0xffff & (checksum + (checksum >> 0x10));
+       }
+       debug(NOISE, "checksum = 0x%08x + 0x%08zx = 0x%08zx\n", checksum,
+             mapsize, checksum + mapsize);
+
+       checksum += mapsize;
+
+       if (checksum != old)
+               debug(INFO, "Updating checksum from 0x%08x to 0x%08x\n",
+                     old, checksum);
+
+       if (image_is_64_bit(ctx->PEHdr)) {
+               ctx->PEHdr->Pe32Plus.OptionalHeader.CheckSum = checksum;
+       } else {
+               ctx->PEHdr->Pe32.OptionalHeader.CheckSum = checksum;
+       }
+}
+
+static void
+handle_one(char *f)
+{
+       int fd;
+       int rc;
+       struct stat statbuf;
+       size_t sz;
+       void *map;
+       int failed = 0;
+
+       PE_COFF_LOADER_IMAGE_CONTEXT ctx = { 0, 0 };
+
+       fd = open(f, O_RDWR | O_EXCL);
+       if (fd < 0)
+               err(1, "Could not open \"%s\"", f);
+
+       rc = fstat(fd, &statbuf);
+       if (rc < 0)
+               err(1, "Could not stat \"%s\"", f);
+
+       sz = statbuf.st_size;
+
+       map = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       if (map == MAP_FAILED)
+               err(1, "Could not map \"%s\"", f);
+
+       load_pe(f, map, sz, &ctx);
+
+       fix_timestamp(&ctx);
+
+       fix_checksum(&ctx, map, sz);
+
+       rc = msync(map, sz, MS_SYNC);
+       if (rc < 0) {
+               warn("msync(%p, %zu, MS_SYNC) failed", map, sz);
+               failed = 1;
+       }
+       munmap(map, sz);
+       if (rc < 0) {
+               warn("munmap(%p, %zu) failed", map, sz);
+               failed = 1;
+       }
+       rc = close(fd);
+       if (rc < 0) {
+               warn("close(%d) failed", fd);
+               failed = 1;
+       }
+       if (failed)
+               exit(1);
+}
+
+static void __attribute__((__noreturn__)) usage(int status)
+{
+       FILE *out = status ? stderr : stdout;
+
+       fprintf(out,
+               "Usage: post-process-pe [OPTIONS] file0 [file1 [.. fileN]]\n");
+       fprintf(out, "Options:\n");
+       fprintf(out, "       -q    Be more quiet\n");
+       fprintf(out, "       -v    Be more verbose\n");
+       fprintf(out, "       -h    Print this help text and exit\n");
+
+       exit(status);
+}
+
+int main(int argc, char **argv)
+{
+       int i;
+       struct option options[] = {
+               {.name = "help",
+                .val = '?',
+                },
+               {.name = "usage",
+                .val = '?',
+                },
+               {.name = "quiet",
+                .val = 'q',
+               },
+               {.name = "verbose",
+                .val = 'v',
+               },
+               {.name = ""}
+       };
+       int longindex = -1;
+
+       while ((i = getopt_long(argc, argv, "hqsv", options, &longindex)) != -1) {
+               switch (i) {
+               case 'h':
+               case '?':
+                       usage(longindex == -1 ? 1 : 0);
+                       break;
+               case 'q':
+                       verbosity = MAX(verbosity - 1, MIN_VERBOSITY);
+                       break;
+               case 'v':
+                       verbosity = MIN(verbosity + 1, MAX_VERBOSITY);
+                       break;
+               }
+       }
+
+       if (optind == argc)
+               usage(1);
+
+       for (i = optind; i < argc; i++)
+               handle_one(argv[i]);
+
+       return 0;
+}
+
+// vim:fenc=utf-8:tw=75:noet
index 278a8e7848e4102699ab0e7fc4433c50ef0808d9..bf781a8b50862a8b6d17daf58f387283f2b3dba5 100644 (file)
@@ -33,7 +33,9 @@ get_active_systab(void)
 static typeof(systab->BootServices->LoadImage) system_load_image;
 static typeof(systab->BootServices->StartImage) system_start_image;
 static typeof(systab->BootServices->Exit) system_exit;
+#if !defined(DISABLE_EBS_PROTECTION)
 static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services;
+#endif /* !defined(DISABLE_EBS_PROTECTION) */
 
 static EFI_HANDLE last_loaded_image;
 
@@ -45,8 +47,10 @@ unhook_system_services(void)
 
        systab->BootServices->LoadImage = system_load_image;
        systab->BootServices->StartImage = system_start_image;
+#if !defined(DISABLE_EBS_PROTECTION)
        systab->BootServices->ExitBootServices = system_exit_boot_services;
-       gBS = systab->BootServices;
+#endif /* !defined(DISABLE_EBS_PROTECTION) */
+       BS = systab->BootServices;
 }
 
 static EFI_STATUS EFIAPI
@@ -57,8 +61,8 @@ load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
        EFI_STATUS efi_status;
 
        unhook_system_services();
-       efi_status = gBS->LoadImage(BootPolicy, ParentImageHandle, DevicePath,
-                                   SourceBuffer, SourceSize, ImageHandle);
+       efi_status = BS->LoadImage(BootPolicy, ParentImageHandle, DevicePath,
+                                  SourceBuffer, SourceSize, ImageHandle);
        hook_system_services(systab);
        if (EFI_ERROR(efi_status))
                last_loaded_image = NULL;
@@ -77,7 +81,7 @@ replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 *
                loader_is_participating = 1;
                uninstall_shim_protocols();
        }
-       efi_status = gBS->StartImage(image_handle, exit_data_size, exit_data);
+       efi_status = BS->StartImage(image_handle, exit_data_size, exit_data);
        if (EFI_ERROR(efi_status)) {
                if (image_handle == last_loaded_image) {
                        EFI_STATUS efi_status2 = install_shim_protocols();
@@ -87,9 +91,9 @@ replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 *
                                              efi_status2);
                                console_print(L"shim cannot continue, sorry.\n");
                                msleep(5000000);
-                               gRT->ResetSystem(EfiResetShutdown,
-                                                EFI_SECURITY_VIOLATION,
-                                                0, NULL);
+                               RT->ResetSystem(EfiResetShutdown,
+                                               EFI_SECURITY_VIOLATION,
+                                               0, NULL);
                        }
                }
                hook_system_services(systab);
@@ -106,7 +110,7 @@ exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
            verification_method == VERIFIED_BY_HASH) {
                unhook_system_services();
                EFI_STATUS efi_status;
-               efi_status = gBS->ExitBootServices(image_key, map_key);
+               efi_status = BS->ExitBootServices(image_key, map_key);
                if (EFI_ERROR(efi_status))
                        hook_system_services(systab);
                return efi_status;
@@ -115,7 +119,7 @@ exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
        console_print(L"Bootloader has not verified loaded image.\n");
        console_print(L"System is compromised.  halting.\n");
        msleep(5000000);
-       gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, 0, NULL);
+       RT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, 0, NULL);
        return EFI_SECURITY_VIOLATION;
 }
 #endif /* !defined(DISABLE_EBS_PROTECTION) */
@@ -130,8 +134,8 @@ do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
 
        restore_loaded_image();
 
-       efi_status = gBS->Exit(ImageHandle, ExitStatus,
-                              ExitDataSize, ExitData);
+       efi_status = BS->Exit(ImageHandle, ExitStatus,
+                             ExitDataSize, ExitData);
        if (EFI_ERROR(efi_status)) {
                EFI_STATUS efi_status2 = shim_init();
 
@@ -140,8 +144,8 @@ do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
                                      efi_status2);
                        console_print(L"shim cannot continue, sorry.\n");
                        msleep(5000000);
-                       gRT->ResetSystem(EfiResetShutdown,
-                                        EFI_SECURITY_VIOLATION, 0, NULL);
+                       RT->ResetSystem(EfiResetShutdown,
+                                       EFI_SECURITY_VIOLATION, 0, NULL);
                }
        }
        return efi_status;
@@ -151,7 +155,7 @@ void
 hook_system_services(EFI_SYSTEM_TABLE *local_systab)
 {
        systab = local_systab;
-       gBS = systab->BootServices;
+       BS = systab->BootServices;
 
        /* We need to hook various calls to make this work... */
 
@@ -181,18 +185,15 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab)
 void
 unhook_exit(void)
 {
-#if !defined(DISABLE_EBS_PROTECTION)
        systab->BootServices->Exit = system_exit;
-       gBS = systab->BootServices;
-#endif /* defined(DISABLE_EBS_PROTECTION) */
-       return;
+       BS = systab->BootServices;
 }
 
 void
 hook_exit(EFI_SYSTEM_TABLE *local_systab)
 {
        systab = local_systab;
-       gBS = local_systab->BootServices;
+       BS = local_systab->BootServices;
 
        /* we need to hook Exit() so that we can allow users to quit the
         * bootloader and still e.g. start a new one or run an internal
diff --git a/shim.c b/shim.c
index c5cfbb830d72e974b3a4c3730568d1fb1b5e82cc..604c0db150035d718634b9a16de41b017473615a 100644 (file)
--- a/shim.c
+++ b/shim.c
@@ -40,10 +40,6 @@ static EFI_HANDLE global_image_handle;
 static EFI_LOADED_IMAGE *shim_li;
 static EFI_LOADED_IMAGE shim_li_bak;
 
-static CHAR16 *second_stage;
-void *load_options;
-UINT32 load_options_size;
-
 list_t sbat_var;
 
 /*
@@ -56,28 +52,8 @@ extern struct {
        UINT32 vendor_deauthorized_offset;
 } cert_table;
 
-UINT32 vendor_authorized_size = 0;
-UINT8 *vendor_authorized = NULL;
-
-UINT32 vendor_deauthorized_size = 0;
-UINT8 *vendor_deauthorized = NULL;
-
-#if defined(ENABLE_SHIM_CERT)
-UINT32 build_cert_size;
-UINT8 *build_cert;
-#endif /* defined(ENABLE_SHIM_CERT) */
-
-/*
- * indicator of how an image has been verified
- */
-verification_method_t verification_method;
-int loader_is_participating;
-
 #define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }}
 
-UINT8 user_insecure_mode;
-UINT8 ignore_db;
-
 typedef enum {
        DATA_FOUND,
        DATA_NOT_FOUND,
@@ -453,8 +429,11 @@ BOOLEAN secure_mode (void)
                return FALSE;
 
        if (variable_is_secureboot() != 1) {
-               if (verbose && !in_protocol && first)
-                       console_notify(L"Secure boot not enabled");
+               if (verbose && !in_protocol && first) {
+                       CHAR16 *title = L"Secure boot not enabled";
+                       CHAR16 *message = L"Press any key to continue";
+                       console_countdown(title, message, 5);
+               }
                first = 0;
                return FALSE;
        }
@@ -466,8 +445,11 @@ BOOLEAN secure_mode (void)
         * to consider it.
         */
        if (variable_is_setupmode(0) == 1) {
-               if (verbose && !in_protocol && first)
-                       console_notify(L"Platform is in setup mode");
+               if (verbose && !in_protocol && first) {
+                       CHAR16 *title = L"Platform is in setup mode";
+                       CHAR16 *message = L"Press any key to continue";
+                       console_countdown(title, message, 5);
+               }
                first = 0;
                return FALSE;
        }
@@ -714,25 +696,12 @@ verify_buffer (char *data, int datasize,
 }
 
 static int
-should_use_fallback(EFI_HANDLE image_handle)
+is_removable_media_path(EFI_LOADED_IMAGE *li)
 {
-       EFI_LOADED_IMAGE *li;
        unsigned int pathlen = 0;
        CHAR16 *bootpath = NULL;
-       EFI_FILE_IO_INTERFACE *fio = NULL;
-       EFI_FILE *vh = NULL;
-       EFI_FILE *fh = NULL;
-       EFI_STATUS efi_status;
        int ret = 0;
 
-       efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
-                                        (void **)&li);
-       if (EFI_ERROR(efi_status)) {
-               perror(L"Could not get image for bootx64.efi: %r\n",
-                      efi_status);
-               return 0;
-       }
-
        bootpath = DevicePathToStr(li->FilePath);
 
        /* Check the beginning of the string and the end, to avoid
@@ -750,8 +719,38 @@ should_use_fallback(EFI_HANDLE image_handle)
        if (pathlen < 5 || StrCaseCmp(bootpath + pathlen - 4, L".EFI"))
                goto error;
 
-       efi_status = gBS->HandleProtocol(li->DeviceHandle, &FileSystemProtocol,
-                                        (void **) &fio);
+       ret = 1;
+
+error:
+       if (bootpath)
+               FreePool(bootpath);
+
+       return ret;
+}
+
+static int
+should_use_fallback(EFI_HANDLE image_handle)
+{
+       EFI_LOADED_IMAGE *li;
+       EFI_FILE_IO_INTERFACE *fio = NULL;
+       EFI_FILE *vh = NULL;
+       EFI_FILE *fh = NULL;
+       EFI_STATUS efi_status;
+       int ret = 0;
+
+       efi_status = BS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
+                                       (void **)&li);
+       if (EFI_ERROR(efi_status)) {
+               perror(L"Could not get image for boot" EFI_ARCH L".efi: %r\n",
+                      efi_status);
+               return 0;
+       }
+
+       if (!is_removable_media_path(li))
+               goto error;
+
+       efi_status = BS->HandleProtocol(li->DeviceHandle, &FileSystemProtocol,
+                                       (void **) &fio);
        if (EFI_ERROR(efi_status)) {
                perror(L"Could not get fio for li->DeviceHandle: %r\n",
                       efi_status);
@@ -782,105 +781,9 @@ error:
                fh->Close(fh);
        if (vh)
                vh->Close(vh);
-       if (bootpath)
-               FreePool(bootpath);
 
        return ret;
 }
-
-/*
- * Generate the path of an executable given shim's path and the name
- * of the executable
- */
-static EFI_STATUS generate_path_from_image_path(EFI_LOADED_IMAGE *li,
-                                               CHAR16 *ImagePath,
-                                               CHAR16 **PathName)
-{
-       EFI_DEVICE_PATH *devpath;
-       unsigned int i;
-       int j, last = -1;
-       unsigned int pathlen = 0;
-       EFI_STATUS efi_status = EFI_SUCCESS;
-       CHAR16 *bootpath;
-
-       /*
-        * Suuuuper lazy technique here, but check and see if this is a full
-        * path to something on the ESP.  Backwards compatibility demands
-        * that we don't just use \\, because we (not particularly brightly)
-        * used to require that the relative file path started with that.
-        *
-        * If it is a full path, don't try to merge it with the directory
-        * from our Loaded Image handle.
-        */
-       if (StrSize(ImagePath) > 5 && StrnCmp(ImagePath, L"\\EFI\\", 5) == 0) {
-               *PathName = StrDuplicate(ImagePath);
-               if (!*PathName) {
-                       perror(L"Failed to allocate path buffer\n");
-                       return EFI_OUT_OF_RESOURCES;
-               }
-               return EFI_SUCCESS;
-       }
-
-       devpath = li->FilePath;
-
-       bootpath = DevicePathToStr(devpath);
-
-       pathlen = StrLen(bootpath);
-
-       /*
-        * DevicePathToStr() concatenates two nodes with '/'.
-        * Convert '/' to '\\'.
-        */
-       for (i = 0; i < pathlen; i++) {
-               if (bootpath[i] == '/')
-                       bootpath[i] = '\\';
-       }
-
-       for (i=pathlen; i>0; i--) {
-               if (bootpath[i] == '\\' && bootpath[i-1] == '\\')
-                       bootpath[i] = '/';
-               else if (last == -1 && bootpath[i] == '\\')
-                       last = i;
-       }
-
-       if (last == -1 && bootpath[0] == '\\')
-               last = 0;
-       bootpath[last+1] = '\0';
-
-       if (last > 0) {
-               for (i = 0, j = 0; bootpath[i] != '\0'; i++) {
-                       if (bootpath[i] != '/') {
-                               bootpath[j] = bootpath[i];
-                               j++;
-                       }
-               }
-               bootpath[j] = '\0';
-       }
-
-       for (i = 0, last = 0; i < StrLen(ImagePath); i++)
-               if (ImagePath[i] == '\\')
-                       last = i + 1;
-
-       ImagePath = ImagePath + last;
-       *PathName = AllocatePool(StrSize(bootpath) + StrSize(ImagePath));
-
-       if (!*PathName) {
-               perror(L"Failed to allocate path buffer\n");
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto error;
-       }
-
-       *PathName[0] = '\0';
-       if (StrnCaseCmp(bootpath, ImagePath, StrLen(bootpath)))
-               StrCat(*PathName, bootpath);
-       StrCat(*PathName, ImagePath);
-
-error:
-       FreePool(bootpath);
-
-       return efi_status;
-}
-
 /*
  * Open the second stage bootloader and read it into a buffer
  */
@@ -900,8 +803,8 @@ static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
        /*
         * Open the device
         */
-       efi_status = gBS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
-                                        (void **) &drive);
+       efi_status = BS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
+                                       (void **) &drive);
        if (EFI_ERROR(efi_status)) {
                perror(L"Failed to find fs: %r\n", efi_status);
                goto error;
@@ -1101,8 +1004,8 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
         * We need to refer to the loaded image protocol on the running
         * binary in order to find our path
         */
-       efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
-                                        (void **)&shim_li);
+       efi_status = BS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
+                                       (void **)&shim_li);
        if (EFI_ERROR(efi_status)) {
                perror(L"Unable to init protocol\n");
                return efi_status;
@@ -1233,151 +1136,25 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
                                         use_fb ? FALLBACK : second_stage);
        }
 
-       if (EFI_ERROR(efi_status)) {
-               console_print(L"start_image() returned %r\n", efi_status);
+       // If the filename is invalid, or the file does not exist,
+       // just fallback to the default loader.
+       if (!use_fb && (efi_status == EFI_INVALID_PARAMETER ||
+                       efi_status == EFI_NOT_FOUND)) {
+               console_print(
+                       L"start_image() returned %r, falling back to default loader\n",
+                       efi_status);
                msleep(2000000);
+               load_options = NULL;
+               load_options_size = 0;
+               efi_status = start_image(image_handle, DEFAULT_LOADER);
        }
 
-       return efi_status;
-}
-
-static inline EFI_STATUS
-get_load_option_optional_data(UINT8 *data, UINTN data_size,
-                             UINT8 **od, UINTN *ods)
-{
-       /*
-        * If it's not at least Attributes + FilePathListLength +
-        * Description=L"" + 0x7fff0400 (EndEntrireDevicePath), it can't
-        * be valid.
-        */
-       if (data_size < (sizeof(UINT32) + sizeof(UINT16) + 2 + 4))
-               return EFI_INVALID_PARAMETER;
-
-       UINT8 *cur = data + sizeof(UINT32);
-       UINT16 fplistlen = *(UINT16 *)cur;
-       /*
-        * If there's not enough space for the file path list and the
-        * smallest possible description (L""), it's not valid.
-        */
-       if (fplistlen > data_size - (sizeof(UINT32) + 2 + 4))
-               return EFI_INVALID_PARAMETER;
-
-       cur += sizeof(UINT16);
-       UINTN limit = data_size - (cur - data) - fplistlen;
-       UINTN i;
-       for (i = 0; i < limit ; i++) {
-               /* If the description isn't valid UCS2-LE, it's not valid. */
-               if (i % 2 != 0) {
-                       if (cur[i] != 0)
-                               return EFI_INVALID_PARAMETER;
-               } else if (cur[i] == 0) {
-                       /* we've found the end */
-                       i++;
-                       if (i >= limit || cur[i] != 0)
-                               return EFI_INVALID_PARAMETER;
-                       break;
-               }
-       }
-       i++;
-       if (i > limit)
-               return EFI_INVALID_PARAMETER;
-
-       /*
-        * If i is limit, we know the rest of this is the FilePathList and
-        * there's no optional data.  So just bail now.
-        */
-       if (i == limit) {
-               *od = NULL;
-               *ods = 0;
-               return EFI_SUCCESS;
-       }
-
-       cur += i;
-       limit -= i;
-       limit += fplistlen;
-       i = 0;
-       while (limit - i >= 4) {
-               struct {
-                       UINT8 type;
-                       UINT8 subtype;
-                       UINT16 len;
-               } dp = {
-                       .type = cur[i],
-                       .subtype = cur[i+1],
-                       /*
-                        * it's a little endian UINT16, but we're not
-                        * guaranteed alignment is sane, so we can't just
-                        * typecast it directly.
-                        */
-                       .len = (cur[i+3] << 8) | cur[i+2],
-               };
-
-               /*
-                * We haven't found an EndEntire, so this has to be a valid
-                * EFI_DEVICE_PATH in order for the data to be valid.  That
-                * means it has to fit, and it can't be smaller than 4 bytes.
-                */
-               if (dp.len < 4 || dp.len > limit)
-                       return EFI_INVALID_PARAMETER;
-
-               /*
-                * see if this is an EndEntire node...
-                */
-               if (dp.type == 0x7f && dp.subtype == 0xff) {
-                       /*
-                        * if we've found the EndEntire node, it must be 4
-                        * bytes
-                        */
-                       if (dp.len != 4)
-                               return EFI_INVALID_PARAMETER;
-
-                       i += dp.len;
-                       break;
-               }
-
-               /*
-                * It's just some random DP node; skip it.
-                */
-               i += dp.len;
-       }
-       if (i != fplistlen)
-               return EFI_INVALID_PARAMETER;
-
-       /*
-        * if there's any space left, it's "optional data"
-        */
-       *od = cur + i;
-       *ods = limit - i;
-       return EFI_SUCCESS;
-}
-
-static int is_our_path(EFI_LOADED_IMAGE *li, CHAR16 *path)
-{
-       CHAR16 *dppath = NULL;
-       CHAR16 *PathName = NULL;
-       EFI_STATUS efi_status;
-       int ret = 1;
-
-       dppath = DevicePathToStr(li->FilePath);
-       if (!dppath)
-               return 0;
-
-       efi_status = generate_path_from_image_path(li, path, &PathName);
        if (EFI_ERROR(efi_status)) {
-               perror(L"Unable to generate path %s: %r\n", path,
-                      efi_status);
-               goto done;
+               console_print(L"start_image() returned %r\n", efi_status);
+               msleep(2000000);
        }
 
-       dprint(L"dppath: %s\n", dppath);
-       dprint(L"path:   %s\n", path);
-       if (StrnCaseCmp(dppath, PathName, StrLen(dppath)))
-               ret = 0;
-
-done:
-       FreePool(dppath);
-       FreePool(PathName);
-       return ret;
+       return efi_status;
 }
 
 /*
@@ -1387,218 +1164,33 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
 {
        EFI_STATUS efi_status;
        EFI_LOADED_IMAGE *li = NULL;
-       CHAR16 *start = NULL;
-       UINTN remaining_size = 0;
-       CHAR16 *loader_str = NULL;
-       UINTN loader_len = 0;
-       unsigned int i;
-       UINTN second_stage_len;
-
-       second_stage_len = (StrLen(DEFAULT_LOADER) + 1) * sizeof(CHAR16);
-       second_stage = AllocatePool(second_stage_len);
-       if (!second_stage) {
-               perror(L"Could not allocate %lu bytes\n", second_stage_len);
-               return EFI_OUT_OF_RESOURCES;
-       }
-       StrCpy(second_stage, DEFAULT_LOADER);
+
+       second_stage = DEFAULT_LOADER;
        load_options = NULL;
        load_options_size = 0;
 
-       efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol,
-                                        (void **) &li);
+       efi_status = BS->HandleProtocol(image_handle, &LoadedImageProtocol,
+                                       (void **) &li);
        if (EFI_ERROR(efi_status)) {
                perror (L"Failed to get load options: %r\n", efi_status);
                return efi_status;
        }
 
-       /* Sanity check since we make several assumptions about the length */
-       if (li->LoadOptionsSize % 2 != 0)
-               return EFI_INVALID_PARAMETER;
-
-       /* So, load options are a giant pain in the ass.  If we're invoked
-        * from the EFI shell, we get something like this:
-
-00000000  5c 00 45 00 36 00 49 00  5c 00 66 00 65 00 64 00  |\.E.F.I.\.f.e.d.|
-00000010  6f 00 72 00 61 00 5c 00  73 00 68 00 69 00 6d 00  |o.r.a.\.s.h.i.m.|
-00000020  78 00 36 00 34 00 2e 00  64 00 66 00 69 00 20 00  |x.6.4...e.f.i. .|
-00000030  5c 00 45 00 46 00 49 00  5c 00 66 00 65 00 64 00  |\.E.F.I.\.f.e.d.|
-00000040  6f 00 72 00 61 00 5c 00  66 00 77 00 75 00 70 00  |o.r.a.\.f.w.u.p.|
-00000050  64 00 61 00 74 00 65 00  2e 00 65 00 66 00 20 00  |d.a.t.e.e.f.i. .|
-00000060  00 00 66 00 73 00 30 00  3a 00 5c 00 00 00        |..f.s.0.:.\...|
-
-       *
-       * which is just some paths rammed together separated by a UCS-2 NUL.
-       * But if we're invoked from BDS, we get something more like:
-       *
-
-00000000  01 00 00 00 62 00 4c 00  69 00 6e 00 75 00 78 00  |....b.L.i.n.u.x.|
-00000010  20 00 46 00 69 00 72 00  6d 00 77 00 61 00 72 00  | .F.i.r.m.w.a.r.|
-00000020  65 00 20 00 55 00 70 00  64 00 61 00 74 00 65 00  |e. .U.p.d.a.t.e.|
-00000030  72 00 00 00 40 01 2a 00  01 00 00 00 00 08 00 00  |r.....*.........|
-00000040  00 00 00 00 00 40 06 00  00 00 00 00 1a 9e 55 bf  |.....@........U.|
-00000050  04 57 f2 4f b4 4a ed 26  4a 40 6a 94 02 02 04 04  |.W.O.:.&J@j.....|
-00000060  34 00 5c 00 45 00 46 00  49 00 5c 00 66 00 65 00  |4.\.E.F.I.f.e.d.|
-00000070  64 00 6f 00 72 00 61 00  5c 00 73 00 68 00 69 00  |o.r.a.\.s.h.i.m.|
-00000080  6d 00 78 00 36 00 34 00  2e 00 65 00 66 00 69 00  |x.6.4...e.f.i...|
-00000090  00 00 7f ff 40 00 20 00  5c 00 66 00 77 00 75 00  |...... .\.f.w.u.|
-000000a0  70 00 78 00 36 00 34 00  2e 00 65 00 66 00 69 00  |p.x.6.4...e.f.i.|
-000000b0  00 00                                             |..|
-
-       *
-       * which is clearly an EFI_LOAD_OPTION filled in halfway reasonably.
-       * In short, the UEFI shell is still a useless piece of junk.
-       *
-       * But then on some versions of BDS, we get:
-
-00000000  5c 00 66 00 77 00 75 00  70 00 78 00 36 00 34 00  |\.f.w.u.p.x.6.4.|
-00000010  2e 00 65 00 66 00 69 00  00 00                    |..e.f.i...|
-0000001a
-
-       * which as you can see is one perfectly normal UCS2-EL string
-       * containing the load option from the Boot#### variable.
-       *
-       * We also sometimes find a guid or partial guid at the end, because
-       * BDS will add that, but we ignore that here.
-       */
-
-       /*
-        * Maybe there just aren't any options...
-        */
-       if (li->LoadOptionsSize == 0)
-               return EFI_SUCCESS;
-
-       /*
-        * In either case, we've got to have at least a UCS2 NUL...
-        */
-       if (li->LoadOptionsSize < 2)
-               return EFI_BAD_BUFFER_SIZE;
-
-       /*
-        * Some awesome versions of BDS will add entries for Linux.  On top
-        * of that, some versions of BDS will "tag" any Boot#### entries they
-        * create by putting a GUID at the very end of the optional data in
-        * the EFI_LOAD_OPTIONS, thus screwing things up for everybody who
-        * tries to actually *use* the optional data for anything.  Why they
-        * did this instead of adding a flag to the spec to /say/ it's
-        * created by BDS, I do not know.  For shame.
-        *
-        * Anyway, just nerf that out from the start.  It's always just
-        * garbage at the end.
-        */
-       if (li->LoadOptionsSize > 16) {
-               if (CompareGuid((EFI_GUID *)(li->LoadOptions
-                                            + (li->LoadOptionsSize - 16)),
-                               &BDS_GUID) == 0)
-                       li->LoadOptionsSize -= 16;
-       }
-
+#if defined(DISABLE_REMOVABLE_LOAD_OPTIONS)
        /*
-        * Apparently sometimes we get L"\0\0"?  Which isn't useful at all.
+        * boot services build very strange load options, and we might misparse them,
+        * causing boot failures on removable media.
         */
-       if (is_all_nuls(li->LoadOptions, li->LoadOptionsSize))
+       if (is_removable_media_path(li)) {
+               dprint("Invoked from removable media path, ignoring boot options");
                return EFI_SUCCESS;
-
-       /*
-        * Check and see if this is just a list of strings.  If it's an
-        * EFI_LOAD_OPTION, it'll be 0, since we know EndEntire device path
-        * won't pass muster as UCS2-LE.
-        *
-        * If there are 3 strings, we're launched from the shell most likely,
-        * But we actually only care about the second one.
-        */
-       UINTN strings = count_ucs2_strings(li->LoadOptions,
-                                          li->LoadOptionsSize);
-
-       /*
-        * In some cases we get strings == 1 because BDS is using L' ' as the
-        * delimeter:
-        * 0000:74 00 65 00 73 00 74 00 2E 00 65 00 66 00 69 00 t.e.s.t...e.f.i.
-        * 0016:20 00 6F 00 6E 00 65 00 20 00 74 00 77 00 6F 00 ..o.n.e...t.w.o.
-        * 0032:20 00 74 00 68 00 72 00 65 00 65 00 00 00       ..t.h.r.e.e...
-        *
-        * If so replace it with NULs since the code already handles that
-        * case.
-        */
-       if (strings == 1) {
-               UINT16 *cur = start = li->LoadOptions;
-
-               /* replace L' ' with L'\0' if we find any */
-               for (i = 0; i < li->LoadOptionsSize / 2; i++) {
-                       if (cur[i] == L' ')
-                               cur[i] = L'\0';
-               }
-
-               /* redo the string count */
-               strings = count_ucs2_strings(li->LoadOptions,
-                                            li->LoadOptionsSize);
        }
+#endif
 
-       /*
-        * If it's not string data, try it as an EFI_LOAD_OPTION.
-        */
-       if (strings == 0) {
-               /*
-                * We at least didn't find /enough/ strings.  See if it works
-                * as an EFI_LOAD_OPTION.
-                */
-               efi_status = get_load_option_optional_data(li->LoadOptions,
-                                                          li->LoadOptionsSize,
-                                                          (UINT8 **)&start,
-                                                          &loader_len);
-               if (EFI_ERROR(efi_status))
-                       return EFI_SUCCESS;
-
-               remaining_size = 0;
-       } else if (strings >= 2) {
-               /*
-                * UEFI shell copies the whole line of the command into
-                * LoadOptions.  We ignore the string before the first L'\0',
-                * i.e. the name of this program.
-                */
-               UINT16 *cur = li->LoadOptions;
-               for (i = 1; i < li->LoadOptionsSize / 2; i++) {
-                       if (cur[i - 1] == L'\0') {
-                               start = &cur[i];
-                               remaining_size = li->LoadOptionsSize - (i * 2);
-                               break;
-                       }
-               }
-
-               remaining_size -= i * 2 + 2;
-       } else if (strings == 1 && is_our_path(li, start)) {
-               /*
-                * And then I found a version of BDS that gives us our own path
-                * in LoadOptions:
-
-77162C58                           5c 00 45 00 46 00 49 00          |\.E.F.I.|
-77162C60  5c 00 42 00 4f 00 4f 00  54 00 5c 00 42 00 4f 00  |\.B.O.O.T.\.B.O.|
-77162C70  4f 00 54 00 58 00 36 00  34 00 2e 00 45 00 46 00  |O.T.X.6.4...E.F.|
-77162C80  49 00 00 00                                       |I...|
-
-               * which is just cruel... So yeah, just don't use it.
-               */
-               return EFI_SUCCESS;
-       }
-
-       /*
-        * Set up the name of the alternative loader and the LoadOptions for
-        * the loader
-        */
-       if (loader_len > 0) {
-               /* we might not always have a NULL at the end */
-               loader_str = AllocatePool(loader_len + 2);
-               if (!loader_str) {
-                       perror(L"Failed to allocate loader string\n");
-                       return EFI_OUT_OF_RESOURCES;
-               }
-
-               for (i = 0; i < loader_len / 2; i++)
-                       loader_str[i] = start[i];
-               loader_str[loader_len/2] = L'\0';
-
-               second_stage = loader_str;
-               load_options = remaining_size ? start + (loader_len/2) : NULL;
-               load_options_size = remaining_size;
+       efi_status = parse_load_options(li);
+       if (EFI_ERROR(efi_status)) {
+               perror (L"Failed to get load options: %r\n", efi_status);
+               return efi_status;
        }
 
        return EFI_SUCCESS;
@@ -1677,10 +1269,10 @@ install_shim_protocols(void)
        /*
         * Install the protocol
         */
-       efi_status = gBS->InstallProtocolInterface(&shim_lock_handle,
-                                                  &SHIM_LOCK_GUID,
-                                                  EFI_NATIVE_INTERFACE,
-                                                  &shim_lock_interface);
+       efi_status = BS->InstallProtocolInterface(&shim_lock_handle,
+                                                 &SHIM_LOCK_GUID,
+                                                 EFI_NATIVE_INTERFACE,
+                                                 &shim_lock_interface);
        if (EFI_ERROR(efi_status)) {
                console_error(L"Could not install security protocol",
                              efi_status);
@@ -1706,8 +1298,8 @@ uninstall_shim_protocols(void)
        /*
         * If we're back here then clean everything up before exiting
         */
-       gBS->UninstallProtocolInterface(shim_lock_handle, &SHIM_LOCK_GUID,
-                                       &shim_lock_interface);
+       BS->UninstallProtocolInterface(shim_lock_handle, &SHIM_LOCK_GUID,
+                                      &shim_lock_interface);
 
        if (!secure_mode())
                return;
@@ -1777,12 +1369,6 @@ shim_fini(void)
 
        unhook_exit();
 
-       /*
-        * Free the space allocated for the alternative 2nd stage loader
-        */
-       if (load_options_size > 0 && second_stage)
-               FreePool(second_stage);
-
        console_fini();
 }
 
@@ -1837,7 +1423,7 @@ debug_hook(void)
                if (x > 12000)
                        break;
 #endif
-               pause();
+               wait_for_debug();
        }
        x = 1;
 }
@@ -1867,7 +1453,7 @@ devel_egress(devel_egress_action action UNUSED)
        console_print(L"\ndoing %a\n", action);
 
        if (action == COLD_RESET)
-               gRT->ResetSystem(EfiResetCold, EFI_SECURITY_VIOLATION, 0, NULL);
+               RT->ResetSystem(EfiResetCold, EFI_SECURITY_VIOLATION, 0, NULL);
 #endif
 }
 
@@ -1973,10 +1559,13 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
         * boot-services-only state variables are what we think they are.
         */
        efi_status = import_mok_state(image_handle);
-       if (!secure_mode() && efi_status == EFI_INVALID_PARAMETER) {
+       if (!secure_mode() &&
+           (efi_status == EFI_INVALID_PARAMETER ||
+            efi_status == EFI_OUT_OF_RESOURCES)) {
                /*
                 * Make copy failures fatal only if secure_mode is enabled, or
-                * the error was anything else than EFI_INVALID_PARAMETER.
+                * the error was anything else than EFI_INVALID_PARAMETER or
+                * EFI_OUT_OF_RESOURCES.
                 * There are non-secureboot firmware implementations that don't
                 * reserve enough EFI variable memory to fit the variable.
                 */
@@ -1991,8 +1580,8 @@ die:
                devel_egress(COLD_RESET);
 #else
                msleep(5000000);
-               gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION,
-                                0, NULL);
+               RT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION,
+                               0, NULL);
 #endif
        }
 
diff --git a/shim.h b/shim.h
index 69ad2cc34a3a607eaf5b3aa9aa619d6f38e8ae24..69442da3fdd8ddc801280231c0513be26cb51c12 100644 (file)
--- a/shim.h
+++ b/shim.h
 #error On x86_64 you must have a compiler new enough to support __attribute__((__ms_abi__))
 #endif
 
+#if CLANG_PREREQ(3, 4)
+#pragma GCC diagnostic ignored "-Wpointer-bool-conversion"
+#endif
+
 #if !defined(GNU_EFI_USE_EXTERNAL_STDARG)
 #define GNU_EFI_USE_EXTERNAL_STDARG
 #endif
 #include "include/httpboot.h"
 #include "include/ip4config2.h"
 #include "include/ip6config.h"
+#include "include/load-options.h"
+#include "include/mok.h"
 #include "include/netboot.h"
 #include "include/passwordcrypt.h"
 #include "include/peimage.h"
@@ -249,6 +255,7 @@ extern UINT8 *build_cert;
 
 extern UINT8 user_insecure_mode;
 extern UINT8 ignore_db;
+extern UINT8 trust_mok_list;
 extern UINT8 in_protocol;
 extern void *load_options;
 extern UINT32 load_options_size;
index 4acf966b062388225249f0a627e47c404b9b516f..2d22c2db8d97ffb2026dd3bbafdee4686202011d 100644 (file)
@@ -337,6 +337,68 @@ fail:
        return -1;
 }
 
+int
+test_csv_3(void)
+{
+       char csv[] =
+               "a,b,c,d,e,f,g,h\n"
+               "a,b,c\n"
+               "\n"
+               "\n"
+               "a,b,c,d,e,f,g,h\n"
+               "a,b,c\0x,y\0z\0";
+       struct test_entry test_entries[]= {
+               { 7, { "a", "b", "c", "d", "e", "f", "g" } },
+               { 3, { "a", "b", "c", NULL, NULL, NULL, NULL } },
+               { 7, { "a", "b", "c", "d", "e", "f", "g" } },
+               { 3, { "a", "b", "c", NULL, NULL, NULL, NULL } },
+       };
+       list_t entry_list;
+       size_t i;
+       char *current, *end;
+       list_t *pos = NULL;
+       EFI_STATUS efi_status;
+
+       INIT_LIST_HEAD(&entry_list);
+       assert_equal_return(list_size(&entry_list), 0, -1,
+                           "got %d expected %d\n");
+
+       current = csv;
+       end = csv + sizeof(csv) - 1;
+
+       efi_status = parse_csv_data(current, end, 7, &entry_list);
+       assert_equal_return(efi_status, EFI_SUCCESS, -1, "got %x expected %x\n");
+
+       i = 0;
+       list_for_each(pos, &entry_list) {
+               struct csv_row *csv_row;
+               struct test_entry *test_entry = &test_entries[i++];
+               size_t j;
+
+               assert_goto(i > 0 && i <= 4, fail, "got %d expected 0 to 4\n", i);
+
+               csv_row = list_entry(pos, struct csv_row, list);
+
+               assert_equal_goto(csv_row->n_columns, test_entry->n_columns,
+                                 fail, "got %d expected %d\n");
+               for (j = 0; j < csv_row->n_columns; j++) {
+                       assert_equal_goto(strcmp(csv_row->columns[j],
+                                          test_entry->columns[j]), 0,
+                                   fail, "got %d expected %d\n");
+               }
+       }
+
+       assert_equal_return(list_size(&entry_list), 4, -1,
+                           "got %d expected %d\n");
+       free_csv_list(&entry_list);
+       assert_equal_return(list_size(&entry_list), 0, -1,
+                           "got %d expected %d\n");
+       return 0;
+fail:
+       free_csv_list(&entry_list);
+       return -1;
+}
+
 int
 test_simple_sbat_csv(void)
 {
@@ -456,6 +518,7 @@ main(void)
        test(test_csv_0);
        test(test_csv_1);
        test(test_csv_2);
+       test(test_csv_3);
        test(test_simple_sbat_csv);
        test(test_csv_simple_fuzz, random_bin, random_bin_len, false);
        for (i = 0; i < random_bin_len; i++) {
diff --git a/test-data/efivars-0/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 b/test-data/efivars-0/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226
new file mode 100644 (file)
index 0000000..3e375f0
Binary files /dev/null and b/test-data/efivars-0/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 differ
diff --git a/test-data/efivars-0/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 b/test-data/efivars-0/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86
new file mode 100644 (file)
index 0000000..ad58e85
Binary files /dev/null and b/test-data/efivars-0/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 differ
diff --git a/test-data/efivars-0/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e b/test-data/efivars-0/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e
new file mode 100644 (file)
index 0000000..480c8c8
Binary files /dev/null and b/test-data/efivars-0/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e differ
diff --git a/test-data/efivars-0/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-0/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..1bebe83
Binary files /dev/null and b/test-data/efivars-0/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-0/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f b/test-data/efivars-0/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f
new file mode 100644 (file)
index 0000000..794e223
Binary files /dev/null and b/test-data/efivars-0/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f differ
diff --git a/test-data/efivars-0/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-0/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..caa9288
Binary files /dev/null and b/test-data/efivars-0/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-0/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f b/test-data/efivars-0/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f
new file mode 100644 (file)
index 0000000..7fe7023
Binary files /dev/null and b/test-data/efivars-0/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f differ
diff --git a/test-data/efivars-0/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-0/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..b747b47
Binary files /dev/null and b/test-data/efivars-0/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 b/test-data/efivars-1/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226
new file mode 100644 (file)
index 0000000..3e375f0
Binary files /dev/null and b/test-data/efivars-1/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 differ
diff --git a/test-data/efivars-1/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 b/test-data/efivars-1/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86
new file mode 100644 (file)
index 0000000..ad58e85
Binary files /dev/null and b/test-data/efivars-1/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 differ
diff --git a/test-data/efivars-1/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e b/test-data/efivars-1/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e
new file mode 100644 (file)
index 0000000..480c8c8
Binary files /dev/null and b/test-data/efivars-1/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e differ
diff --git a/test-data/efivars-1/AMITSESetup-c811fa38-42c8-4579-a9bb-60e94eddfb34 b/test-data/efivars-1/AMITSESetup-c811fa38-42c8-4579-a9bb-60e94eddfb34
new file mode 100644 (file)
index 0000000..ccf2dc2
Binary files /dev/null and b/test-data/efivars-1/AMITSESetup-c811fa38-42c8-4579-a9bb-60e94eddfb34 differ
diff --git a/test-data/efivars-1/AOD_SETUP-5ed15dc0-edef-4161-9151-6014c4cc630c b/test-data/efivars-1/AOD_SETUP-5ed15dc0-edef-4161-9151-6014c4cc630c
new file mode 100644 (file)
index 0000000..77b1eed
Binary files /dev/null and b/test-data/efivars-1/AOD_SETUP-5ed15dc0-edef-4161-9151-6014c4cc630c differ
diff --git a/test-data/efivars-1/AmdAcpiVar-79941ecd-ed36-49d0-8124-e4c31ac75cd4 b/test-data/efivars-1/AmdAcpiVar-79941ecd-ed36-49d0-8124-e4c31ac75cd4
new file mode 100644 (file)
index 0000000..269345b
Binary files /dev/null and b/test-data/efivars-1/AmdAcpiVar-79941ecd-ed36-49d0-8124-e4c31ac75cd4 differ
diff --git a/test-data/efivars-1/AmdSetup-3a997502-647a-4c82-998e-52ef9486a247 b/test-data/efivars-1/AmdSetup-3a997502-647a-4c82-998e-52ef9486a247
new file mode 100644 (file)
index 0000000..ea257e2
Binary files /dev/null and b/test-data/efivars-1/AmdSetup-3a997502-647a-4c82-998e-52ef9486a247 differ
diff --git a/test-data/efivars-1/AmiHardwareSignatureSetupUpdateCountVar-81c76078-bfde-4368-9790-570914c01a65 b/test-data/efivars-1/AmiHardwareSignatureSetupUpdateCountVar-81c76078-bfde-4368-9790-570914c01a65
new file mode 100644 (file)
index 0000000..78bf659
Binary files /dev/null and b/test-data/efivars-1/AmiHardwareSignatureSetupUpdateCountVar-81c76078-bfde-4368-9790-570914c01a65 differ
diff --git a/test-data/efivars-1/ApSyncFlagNv-ad3f6761-f0a3-46c8-a4cb-19b70ffdb305 b/test-data/efivars-1/ApSyncFlagNv-ad3f6761-f0a3-46c8-a4cb-19b70ffdb305
new file mode 100644 (file)
index 0000000..c100358
Binary files /dev/null and b/test-data/efivars-1/ApSyncFlagNv-ad3f6761-f0a3-46c8-a4cb-19b70ffdb305 differ
diff --git a/test-data/efivars-1/AsbkpInfo-cb825795-feb1-4c0b-894f-cc70f8064395 b/test-data/efivars-1/AsbkpInfo-cb825795-feb1-4c0b-894f-cc70f8064395
new file mode 100644 (file)
index 0000000..e673fc1
Binary files /dev/null and b/test-data/efivars-1/AsbkpInfo-cb825795-feb1-4c0b-894f-cc70f8064395 differ
diff --git a/test-data/efivars-1/AsusExtFancard-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/AsusExtFancard-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..f37b1b7
Binary files /dev/null and b/test-data/efivars-1/AsusExtFancard-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/AsusFanSetupFeatures-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/AsusFanSetupFeatures-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..1f4faec
Binary files /dev/null and b/test-data/efivars-1/AsusFanSetupFeatures-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/AsusHwmSetupOneof-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/AsusHwmSetupOneof-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..0f3fe32
Binary files /dev/null and b/test-data/efivars-1/AsusHwmSetupOneof-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/AsusNodePsu-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/AsusNodePsu-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..f37b1b7
Binary files /dev/null and b/test-data/efivars-1/AsusNodePsu-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/AsusQFanSetupData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/AsusQFanSetupData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..974cea3
Binary files /dev/null and b/test-data/efivars-1/AsusQFanSetupData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/AsusRomLayout-7186d975-2dba-4413-81a8-9f1538faef5e b/test-data/efivars-1/AsusRomLayout-7186d975-2dba-4413-81a8-9f1538faef5e
new file mode 100644 (file)
index 0000000..efdb73d
Binary files /dev/null and b/test-data/efivars-1/AsusRomLayout-7186d975-2dba-4413-81a8-9f1538faef5e differ
diff --git a/test-data/efivars-1/AsusSetupDataBackup-1111b056-c5e9-40ca-aba3-ec172533d814 b/test-data/efivars-1/AsusSetupDataBackup-1111b056-c5e9-40ca-aba3-ec172533d814
new file mode 100644 (file)
index 0000000..418e63b
Binary files /dev/null and b/test-data/efivars-1/AsusSetupDataBackup-1111b056-c5e9-40ca-aba3-ec172533d814 differ
diff --git a/test-data/efivars-1/AutoDetectData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/AutoDetectData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..730e919
Binary files /dev/null and b/test-data/efivars-1/AutoDetectData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/BiosEventLog-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 b/test-data/efivars-1/BiosEventLog-4034591c-48ea-4cdc-864f-e7cb61cfd0f2
new file mode 100644 (file)
index 0000000..4ef9507
Binary files /dev/null and b/test-data/efivars-1/BiosEventLog-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 differ
diff --git a/test-data/efivars-1/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..1bebe83
Binary files /dev/null and b/test-data/efivars-1/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..fdbf58a
Binary files /dev/null and b/test-data/efivars-1/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..395525b
Binary files /dev/null and b/test-data/efivars-1/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..d4a6326
Binary files /dev/null and b/test-data/efivars-1/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/Boot0004-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/Boot0004-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..9a151ed
Binary files /dev/null and b/test-data/efivars-1/Boot0004-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/Boot0005-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/Boot0005-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..aa8ba6f
Binary files /dev/null and b/test-data/efivars-1/Boot0005-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/Boot0006-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/Boot0006-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..cb32ae7
Binary files /dev/null and b/test-data/efivars-1/Boot0006-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..4be6b17
Binary files /dev/null and b/test-data/efivars-1/BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/BootFromUSB-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/BootFromUSB-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..f37b1b7
Binary files /dev/null and b/test-data/efivars-1/BootFromUSB-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..f06270d
Binary files /dev/null and b/test-data/efivars-1/BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..9711909
Binary files /dev/null and b/test-data/efivars-1/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/CMOSfailflag-c89dc9c7-5105-472c-a743-b1621e142b41 b/test-data/efivars-1/CMOSfailflag-c89dc9c7-5105-472c-a743-b1621e142b41
new file mode 100644 (file)
index 0000000..7cfdbd2
Binary files /dev/null and b/test-data/efivars-1/CMOSfailflag-c89dc9c7-5105-472c-a743-b1621e142b41 differ
diff --git a/test-data/efivars-1/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..c687554
Binary files /dev/null and b/test-data/efivars-1/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..1530945
Binary files /dev/null and b/test-data/efivars-1/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..1f8a950
Binary files /dev/null and b/test-data/efivars-1/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..2dcf180
Binary files /dev/null and b/test-data/efivars-1/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/CurrentPolicy-77fa9abd-0359-4d32-bd60-28f4e78f784b b/test-data/efivars-1/CurrentPolicy-77fa9abd-0359-4d32-bd60-28f4e78f784b
new file mode 100644 (file)
index 0000000..88c1ba0
Binary files /dev/null and b/test-data/efivars-1/CurrentPolicy-77fa9abd-0359-4d32-bd60-28f4e78f784b differ
diff --git a/test-data/efivars-1/DefaultBootOrder-45cf35f6-0d6e-4d04-856a-0370a5b16f53 b/test-data/efivars-1/DefaultBootOrder-45cf35f6-0d6e-4d04-856a-0370a5b16f53
new file mode 100644 (file)
index 0000000..e8844a3
Binary files /dev/null and b/test-data/efivars-1/DefaultBootOrder-45cf35f6-0d6e-4d04-856a-0370a5b16f53 differ
diff --git a/test-data/efivars-1/DeploymentModeNv-97e8965f-c761-4f48-b6e4-9ffa9cb2a2d6 b/test-data/efivars-1/DeploymentModeNv-97e8965f-c761-4f48-b6e4-9ffa9cb2a2d6
new file mode 100644 (file)
index 0000000..f37b1b7
Binary files /dev/null and b/test-data/efivars-1/DeploymentModeNv-97e8965f-c761-4f48-b6e4-9ffa9cb2a2d6 differ
diff --git a/test-data/efivars-1/DownCoreStatus-29749bad-401b-4f6d-b124-cece8c590c48 b/test-data/efivars-1/DownCoreStatus-29749bad-401b-4f6d-b124-cece8c590c48
new file mode 100644 (file)
index 0000000..f37b1b7
Binary files /dev/null and b/test-data/efivars-1/DownCoreStatus-29749bad-401b-4f6d-b124-cece8c590c48 differ
diff --git a/test-data/efivars-1/EnWpData-cbab171f-f356-4009-baaa-6628353a0a29 b/test-data/efivars-1/EnWpData-cbab171f-f356-4009-baaa-6628353a0a29
new file mode 100644 (file)
index 0000000..6f0c2f1
Binary files /dev/null and b/test-data/efivars-1/EnWpData-cbab171f-f356-4009-baaa-6628353a0a29 differ
diff --git a/test-data/efivars-1/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..1f8a950
Binary files /dev/null and b/test-data/efivars-1/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/FPLayoutOrder-4db88a62-6721-47a0-9082-280b00323594 b/test-data/efivars-1/FPLayoutOrder-4db88a62-6721-47a0-9082-280b00323594
new file mode 100644 (file)
index 0000000..6d03295
Binary files /dev/null and b/test-data/efivars-1/FPLayoutOrder-4db88a62-6721-47a0-9082-280b00323594 differ
diff --git a/test-data/efivars-1/FTMActiveFlag-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 b/test-data/efivars-1/FTMActiveFlag-4034591c-48ea-4cdc-864f-e7cb61cfd0f2
new file mode 100644 (file)
index 0000000..f37b1b7
Binary files /dev/null and b/test-data/efivars-1/FTMActiveFlag-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 differ
diff --git a/test-data/efivars-1/FastBootOption-b540a530-6978-4da7-91cb-7207d764d262 b/test-data/efivars-1/FastBootOption-b540a530-6978-4da7-91cb-7207d764d262
new file mode 100644 (file)
index 0000000..502ad84
Binary files /dev/null and b/test-data/efivars-1/FastBootOption-b540a530-6978-4da7-91cb-7207d764d262 differ
diff --git a/test-data/efivars-1/FirstBootFlag-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/FirstBootFlag-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..a652cc8
Binary files /dev/null and b/test-data/efivars-1/FirstBootFlag-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/HddSmartInfo-a6f44860-b2e8-4fda-bd45-78368994b6ae b/test-data/efivars-1/HddSmartInfo-a6f44860-b2e8-4fda-bd45-78368994b6ae
new file mode 100644 (file)
index 0000000..7cfdbd2
Binary files /dev/null and b/test-data/efivars-1/HddSmartInfo-a6f44860-b2e8-4fda-bd45-78368994b6ae differ
diff --git a/test-data/efivars-1/HiiDB-1b838190-4625-4ead-abc9-cd5e6af18fe0 b/test-data/efivars-1/HiiDB-1b838190-4625-4ead-abc9-cd5e6af18fe0
new file mode 100644 (file)
index 0000000..89e10ea
Binary files /dev/null and b/test-data/efivars-1/HiiDB-1b838190-4625-4ead-abc9-cd5e6af18fe0 differ
diff --git a/test-data/efivars-1/HwErrRecSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/HwErrRecSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..60f8feb
Binary files /dev/null and b/test-data/efivars-1/HwErrRecSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..062abae
Binary files /dev/null and b/test-data/efivars-1/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/KEKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/KEKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..2ebd5c5
Binary files /dev/null and b/test-data/efivars-1/KEKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/Kernel_ATPSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b b/test-data/efivars-1/Kernel_ATPSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b
new file mode 100644 (file)
index 0000000..78bf659
Binary files /dev/null and b/test-data/efivars-1/Kernel_ATPSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ
diff --git a/test-data/efivars-1/Kernel_DriverSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b b/test-data/efivars-1/Kernel_DriverSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b
new file mode 100644 (file)
index 0000000..78bf659
Binary files /dev/null and b/test-data/efivars-1/Kernel_DriverSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ
diff --git a/test-data/efivars-1/Kernel_RvkSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b b/test-data/efivars-1/Kernel_RvkSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b
new file mode 100644 (file)
index 0000000..78bf659
Binary files /dev/null and b/test-data/efivars-1/Kernel_RvkSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ
diff --git a/test-data/efivars-1/Kernel_SiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b b/test-data/efivars-1/Kernel_SiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b
new file mode 100644 (file)
index 0000000..78bf659
Binary files /dev/null and b/test-data/efivars-1/Kernel_SiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ
diff --git a/test-data/efivars-1/Kernel_SkuSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b b/test-data/efivars-1/Kernel_SkuSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b
new file mode 100644 (file)
index 0000000..78bf659
Binary files /dev/null and b/test-data/efivars-1/Kernel_SkuSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ
diff --git a/test-data/efivars-1/Kernel_WinSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b b/test-data/efivars-1/Kernel_WinSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b
new file mode 100644 (file)
index 0000000..78bf659
Binary files /dev/null and b/test-data/efivars-1/Kernel_WinSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ
diff --git a/test-data/efivars-1/LastBoot-b540a530-6978-4da7-91cb-7207d764d262 b/test-data/efivars-1/LastBoot-b540a530-6978-4da7-91cb-7207d764d262
new file mode 100644 (file)
index 0000000..ef1bad0
Binary files /dev/null and b/test-data/efivars-1/LastBoot-b540a530-6978-4da7-91cb-7207d764d262 differ
diff --git a/test-data/efivars-1/MaximumTableSize-4b3082a3-80c6-4d7e-9cd0-583917265df1 b/test-data/efivars-1/MaximumTableSize-4b3082a3-80c6-4d7e-9cd0-583917265df1
new file mode 100644 (file)
index 0000000..b4637d8
Binary files /dev/null and b/test-data/efivars-1/MaximumTableSize-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ
diff --git a/test-data/efivars-1/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829 b/test-data/efivars-1/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829
new file mode 100644 (file)
index 0000000..f37b1b7
Binary files /dev/null and b/test-data/efivars-1/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829 differ
diff --git a/test-data/efivars-1/MemoryOverwriteRequestControlLock-bb983ccf-151d-40e1-a07b-4a17be168292 b/test-data/efivars-1/MemoryOverwriteRequestControlLock-bb983ccf-151d-40e1-a07b-4a17be168292
new file mode 100644 (file)
index 0000000..f37b1b7
Binary files /dev/null and b/test-data/efivars-1/MemoryOverwriteRequestControlLock-bb983ccf-151d-40e1-a07b-4a17be168292 differ
diff --git a/test-data/efivars-1/MokList-605dab50-e046-4300-abb6-3dd810dd8b23 b/test-data/efivars-1/MokList-605dab50-e046-4300-abb6-3dd810dd8b23
new file mode 100644 (file)
index 0000000..7567e40
Binary files /dev/null and b/test-data/efivars-1/MokList-605dab50-e046-4300-abb6-3dd810dd8b23 differ
diff --git a/test-data/efivars-1/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23 b/test-data/efivars-1/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23
new file mode 100644 (file)
index 0000000..a402477
Binary files /dev/null and b/test-data/efivars-1/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23 differ
diff --git a/test-data/efivars-1/MokListX-605dab50-e046-4300-abb6-3dd810dd8b23 b/test-data/efivars-1/MokListX-605dab50-e046-4300-abb6-3dd810dd8b23
new file mode 100644 (file)
index 0000000..d6de49f
Binary files /dev/null and b/test-data/efivars-1/MokListX-605dab50-e046-4300-abb6-3dd810dd8b23 differ
diff --git a/test-data/efivars-1/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23 b/test-data/efivars-1/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23
new file mode 100644 (file)
index 0000000..6c058bf
Binary files /dev/null and b/test-data/efivars-1/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23 differ
diff --git a/test-data/efivars-1/MonotonicCounter-01368881-c4ad-4b1d-b631-d57a8ec8db6b b/test-data/efivars-1/MonotonicCounter-01368881-c4ad-4b1d-b631-d57a8ec8db6b
new file mode 100644 (file)
index 0000000..92182fe
Binary files /dev/null and b/test-data/efivars-1/MonotonicCounter-01368881-c4ad-4b1d-b631-d57a8ec8db6b differ
diff --git a/test-data/efivars-1/MyFav-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 b/test-data/efivars-1/MyFav-4034591c-48ea-4cdc-864f-e7cb61cfd0f2
new file mode 100644 (file)
index 0000000..4ecf019
Binary files /dev/null and b/test-data/efivars-1/MyFav-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 differ
diff --git a/test-data/efivars-1/NVRAM_Verify-15a9dd61-e4f8-4a99-80db-353b13d76490 b/test-data/efivars-1/NVRAM_Verify-15a9dd61-e4f8-4a99-80db-353b13d76490
new file mode 100644 (file)
index 0000000..e055de8
Binary files /dev/null and b/test-data/efivars-1/NVRAM_Verify-15a9dd61-e4f8-4a99-80db-353b13d76490 differ
diff --git a/test-data/efivars-1/NetworkStackVar-d1405d16-7afc-4695-bb12-41459d3695a2 b/test-data/efivars-1/NetworkStackVar-d1405d16-7afc-4695-bb12-41459d3695a2
new file mode 100644 (file)
index 0000000..ab120d7
Binary files /dev/null and b/test-data/efivars-1/NetworkStackVar-d1405d16-7afc-4695-bb12-41459d3695a2 differ
diff --git a/test-data/efivars-1/NvHdd0-e57abcbd-9456-4639-8f65-06aab41d840f b/test-data/efivars-1/NvHdd0-e57abcbd-9456-4639-8f65-06aab41d840f
new file mode 100644 (file)
index 0000000..230f3f6
Binary files /dev/null and b/test-data/efivars-1/NvHdd0-e57abcbd-9456-4639-8f65-06aab41d840f differ
diff --git a/test-data/efivars-1/NvHdd8-e57abcbd-9456-4639-8f65-06aab41d840f b/test-data/efivars-1/NvHdd8-e57abcbd-9456-4639-8f65-06aab41d840f
new file mode 100644 (file)
index 0000000..137dd65
Binary files /dev/null and b/test-data/efivars-1/NvHdd8-e57abcbd-9456-4639-8f65-06aab41d840f differ
diff --git a/test-data/efivars-1/OsIndications-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/OsIndications-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..ad58e85
Binary files /dev/null and b/test-data/efivars-1/OsIndications-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..65902d3
Binary files /dev/null and b/test-data/efivars-1/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/PCI_COMMON-aca9f304-21e2-4852-9875-7ff4881d67a5 b/test-data/efivars-1/PCI_COMMON-aca9f304-21e2-4852-9875-7ff4881d67a5
new file mode 100644 (file)
index 0000000..1484033
Binary files /dev/null and b/test-data/efivars-1/PCI_COMMON-aca9f304-21e2-4852-9875-7ff4881d67a5 differ
diff --git a/test-data/efivars-1/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..2a784c4
Binary files /dev/null and b/test-data/efivars-1/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..38d00e8
Binary files /dev/null and b/test-data/efivars-1/PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/PcieSataModVar-5e9a565f-cdc0-413b-ad13-1fe8713ffdcd b/test-data/efivars-1/PcieSataModVar-5e9a565f-cdc0-413b-ad13-1fe8713ffdcd
new file mode 100644 (file)
index 0000000..7b89b91
Binary files /dev/null and b/test-data/efivars-1/PcieSataModVar-5e9a565f-cdc0-413b-ad13-1fe8713ffdcd differ
diff --git a/test-data/efivars-1/PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..456f5e7
Binary files /dev/null and b/test-data/efivars-1/PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..aacb9a6
Binary files /dev/null and b/test-data/efivars-1/PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/PreVgaInfo-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/PreVgaInfo-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..e85f1be
Binary files /dev/null and b/test-data/efivars-1/PreVgaInfo-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/RsdpAddr-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/RsdpAddr-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..b6949db
Binary files /dev/null and b/test-data/efivars-1/RsdpAddr-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/SIDSUPPORT-7d3dceee-cbce-4ea7-8709-6e552f1edbde b/test-data/efivars-1/SIDSUPPORT-7d3dceee-cbce-4ea7-8709-6e552f1edbde
new file mode 100644 (file)
index 0000000..a652cc8
Binary files /dev/null and b/test-data/efivars-1/SIDSUPPORT-7d3dceee-cbce-4ea7-8709-6e552f1edbde differ
diff --git a/test-data/efivars-1/SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23 b/test-data/efivars-1/SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23
new file mode 100644 (file)
index 0000000..8a889d3
Binary files /dev/null and b/test-data/efivars-1/SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23 differ
diff --git a/test-data/efivars-1/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23 b/test-data/efivars-1/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23
new file mode 100644 (file)
index 0000000..29c9a9b
Binary files /dev/null and b/test-data/efivars-1/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23 differ
diff --git a/test-data/efivars-1/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..687e561
Binary files /dev/null and b/test-data/efivars-1/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/SecureBootSetup-7b59104a-c00d-4158-87ff-f04d6396a915 b/test-data/efivars-1/SecureBootSetup-7b59104a-c00d-4158-87ff-f04d6396a915
new file mode 100644 (file)
index 0000000..65869b9
Binary files /dev/null and b/test-data/efivars-1/SecureBootSetup-7b59104a-c00d-4158-87ff-f04d6396a915 differ
diff --git a/test-data/efivars-1/Setup-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/Setup-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..8c8e7c3
Binary files /dev/null and b/test-data/efivars-1/Setup-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/SetupLedData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/SetupLedData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..4c6a285
Binary files /dev/null and b/test-data/efivars-1/SetupLedData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..39e2858
Binary files /dev/null and b/test-data/efivars-1/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..c71572c
Binary files /dev/null and b/test-data/efivars-1/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/SmbiosEntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 b/test-data/efivars-1/SmbiosEntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1
new file mode 100644 (file)
index 0000000..58fad41
Binary files /dev/null and b/test-data/efivars-1/SmbiosEntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ
diff --git a/test-data/efivars-1/SmbiosScratchBuffer-4b3082a3-80c6-4d7e-9cd0-583917265df1 b/test-data/efivars-1/SmbiosScratchBuffer-4b3082a3-80c6-4d7e-9cd0-583917265df1
new file mode 100644 (file)
index 0000000..7b65c3a
Binary files /dev/null and b/test-data/efivars-1/SmbiosScratchBuffer-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ
diff --git a/test-data/efivars-1/SmbiosV3EntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 b/test-data/efivars-1/SmbiosV3EntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1
new file mode 100644 (file)
index 0000000..4305692
Binary files /dev/null and b/test-data/efivars-1/SmbiosV3EntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ
diff --git a/test-data/efivars-1/StdDefaults-4599d26f-1a11-49b8-b91f-858745cff824 b/test-data/efivars-1/StdDefaults-4599d26f-1a11-49b8-b91f-858745cff824
new file mode 100644 (file)
index 0000000..da3d726
Binary files /dev/null and b/test-data/efivars-1/StdDefaults-4599d26f-1a11-49b8-b91f-858745cff824 differ
diff --git a/test-data/efivars-1/TPMPERBIOSFLAGS-7d3dceee-cbce-4ea7-8709-6e552f1edbde b/test-data/efivars-1/TPMPERBIOSFLAGS-7d3dceee-cbce-4ea7-8709-6e552f1edbde
new file mode 100644 (file)
index 0000000..60e6264
Binary files /dev/null and b/test-data/efivars-1/TPMPERBIOSFLAGS-7d3dceee-cbce-4ea7-8709-6e552f1edbde differ
diff --git a/test-data/efivars-1/Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..60f8feb
Binary files /dev/null and b/test-data/efivars-1/Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/TotalNumberOfRootBridges-fb5703f5-f8a7-f401-18b4-3f108deb2612 b/test-data/efivars-1/TotalNumberOfRootBridges-fb5703f5-f8a7-f401-18b4-3f108deb2612
new file mode 100644 (file)
index 0000000..ba50834
Binary files /dev/null and b/test-data/efivars-1/TotalNumberOfRootBridges-fb5703f5-f8a7-f401-18b4-3f108deb2612 differ
diff --git a/test-data/efivars-1/TpmServFlags-7d3dceee-cbce-4ea7-8709-6e552f1edbde b/test-data/efivars-1/TpmServFlags-7d3dceee-cbce-4ea7-8709-6e552f1edbde
new file mode 100644 (file)
index 0000000..c40690d
Binary files /dev/null and b/test-data/efivars-1/TpmServFlags-7d3dceee-cbce-4ea7-8709-6e552f1edbde differ
diff --git a/test-data/efivars-1/UsbSupport-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 b/test-data/efivars-1/UsbSupport-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9
new file mode 100644 (file)
index 0000000..8b3fa28
Binary files /dev/null and b/test-data/efivars-1/UsbSupport-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ
diff --git a/test-data/efivars-1/VARSTORE_OCMR_SETTINGS_NAME-c05fba7d-7a92-49e0-bcee-233b14dca803 b/test-data/efivars-1/VARSTORE_OCMR_SETTINGS_NAME-c05fba7d-7a92-49e0-bcee-233b14dca803
new file mode 100644 (file)
index 0000000..bec6d58
Binary files /dev/null and b/test-data/efivars-1/VARSTORE_OCMR_SETTINGS_NAME-c05fba7d-7a92-49e0-bcee-233b14dca803 differ
diff --git a/test-data/efivars-1/VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..39e2858
Binary files /dev/null and b/test-data/efivars-1/VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/WpBufAddr-cba83c4a-a5fc-48a8-b3a6-d33636166544 b/test-data/efivars-1/WpBufAddr-cba83c4a-a5fc-48a8-b3a6-d33636166544
new file mode 100644 (file)
index 0000000..c2632ec
Binary files /dev/null and b/test-data/efivars-1/WpBufAddr-cba83c4a-a5fc-48a8-b3a6-d33636166544 differ
diff --git a/test-data/efivars-1/WriteOnceStatus-4b3082a3-80c6-4d7e-9cd0-583917265df1 b/test-data/efivars-1/WriteOnceStatus-4b3082a3-80c6-4d7e-9cd0-583917265df1
new file mode 100644 (file)
index 0000000..65648ca
Binary files /dev/null and b/test-data/efivars-1/WriteOnceStatus-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ
diff --git a/test-data/efivars-1/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f b/test-data/efivars-1/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f
new file mode 100644 (file)
index 0000000..794e223
Binary files /dev/null and b/test-data/efivars-1/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f differ
diff --git a/test-data/efivars-1/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..caa9288
Binary files /dev/null and b/test-data/efivars-1/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-data/efivars-1/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f b/test-data/efivars-1/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f
new file mode 100644 (file)
index 0000000..7fe7023
Binary files /dev/null and b/test-data/efivars-1/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f differ
diff --git a/test-data/efivars-1/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c b/test-data/efivars-1/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c
new file mode 100644 (file)
index 0000000..b747b47
Binary files /dev/null and b/test-data/efivars-1/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ
diff --git a/test-load-options.c b/test-load-options.c
new file mode 100644 (file)
index 0000000..daf02d9
--- /dev/null
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * test-argv.c - test our loader_opts parsing
+ */
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic error "-Wnonnull"
+#pragma GCC diagnostic error "-Wunused-function"
+
+#pragma GCC diagnostic warning "-Wcpp"
+
+#ifndef SHIM_UNIT_TEST
+#define SHIM_UNIT_TEST
+#endif
+
+#include "shim.h"
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <efivar/efivar.h>
+
+EFI_DEVICE_PATH *
+make_file_dp(char *filename)
+{
+       void *filedp = NULL;
+       size_t filedpsz = 0, filedpneeded = 0;
+
+       filedpneeded = efidp_make_file(filedp, filedpneeded, filename);
+       assert_positive_return(filedpneeded, NULL, "\n");
+
+       filedp = calloc(1, filedpneeded + 4);
+       assert_nonzero_return(filedp, NULL, "\n");
+
+       filedpsz = efidp_make_file(filedp, filedpneeded, filename);
+       assert_equal_goto(filedpsz, filedpneeded, err, "got %zu expected %zu\n");
+
+       efidp_make_end_entire((uint8_t *)filedp + filedpneeded, 4);
+
+       return filedp;
+err:
+       free(filedp);
+       return NULL;
+}
+
+int
+test_parse_load_options(char *load_option_data,
+                       size_t load_option_data_size,
+                       char *file_path,
+                       CHAR16 *target_second_stage,
+                       char *target_remaining,
+                       size_t target_remaining_size)
+{
+       EFI_STATUS status = EFI_SUCCESS;
+       EFI_LOADED_IMAGE li = {
+               .LoadOptions = load_option_data,
+               .LoadOptionsSize = load_option_data_size,
+               .FilePath = make_file_dp(file_path),
+       };
+       CHAR16 *dummy_second_stage = calloc(1, 8);
+       int rc = -1;
+
+       assert_nonzero_goto(li.FilePath, err, "\n");
+       assert_nonzero_goto(dummy_second_stage, err, "\n");
+
+       StrCat(dummy_second_stage, L"foo");
+       second_stage = dummy_second_stage;
+
+       status = parse_load_options(&li);
+       assert_false_goto(EFI_ERROR(status), err, "\n");
+
+       assert_nonzero_goto(second_stage, err, "\n");
+       assert_not_equal_goto(second_stage, dummy_second_stage, err, "%p == %p\n");
+       assert_zero_goto(StrnCmp(second_stage, target_second_stage, 90),
+                        err_print_second_stage, "%d != 0\n");
+
+       assert_equal_goto(load_options_size, target_remaining_size, err_remaining, "%zu != %zu\n");
+       assert_equal_goto(load_options, target_remaining, err_remaining, "%p != %p\n");
+       assert_zero_goto(memcmp(load_options, target_remaining, load_options_size), err_remaining, "\n");
+
+       rc = 0;
+err_remaining:
+       if (rc != 0) {
+               printf("expected remaining:%p\n", target_remaining);
+               for (size_t i = 0; i < target_remaining_size; i++)
+                       printf("0x%02hhx ", target_remaining[i]);
+               printf("\n");
+               printf("actual remaining:%p\n", load_options);
+               for (size_t i = 0; i < load_options_size; i++)
+                       printf("0x%02hhx ", ((char *)load_options)[i]);
+               printf("\n");
+       }
+err_print_second_stage:
+       if (rc != 0) {
+               printf("second stage:\"");
+               for(int i = 0; second_stage[i] != 0; i++)
+                       printf("%c", second_stage[i]);
+               printf("\"\nexpected:\"");
+               for(int i = 0; target_second_stage[i] != 0; i++)
+                       printf("%c", target_second_stage[i]);
+               printf("\"\n");
+       }
+err:
+       if (rc != 0) {
+               print_traceback(0);
+       }
+       if (li.FilePath) {
+               free(li.FilePath);
+       }
+       if (dummy_second_stage && dummy_second_stage != second_stage) {
+               free(dummy_second_stage);
+       }
+       second_stage = NULL;
+
+       return rc;
+}
+
+int __attribute__((__flatten__))
+test_efi_shell_0(void)
+{
+/*
+00000000  5c 00 45 00 46 00 49 00  5c 00 66 00 65 00 64 00  |\.E.F.I.\.f.e.d.|
+00000010  6f 00 72 00 61 00 5c 00  73 00 68 00 69 00 6d 00  |o.r.a.\.s.h.i.m.|
+00000020  78 00 36 00 34 00 2e 00  65 00 66 00 69 00 20 00  |x.6.4...e.f.i. .|
+00000030  5c 00 45 00 46 00 49 00  5c 00 66 00 65 00 64 00  |\.E.F.I.\.f.e.d.|
+00000040  6f 00 72 00 61 00 5c 00  66 00 77 00 75 00 70 00  |o.r.a.\.f.w.u.p.|
+00000050  64 00 61 00 74 00 65 00  2e 00 65 00 66 00 69 00  |d.a.t.e...e.f.i.|
+00000060  20 00 00 00 66 00 73 00  30 00 3a 00 5c 00 00 00  | ...f.s.0.:.\...|
+*/
+
+       char load_option_data[] = {
+               0x5c, 0x00, 0x45, 0x00, 0x46, 0x00, 0x49, 0x00,
+               0x5c, 0x00, 0x66, 0x00, 0x65, 0x00, 0x64, 0x00,
+               0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x5c, 0x00,
+               0x73, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6d, 0x00,
+               0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x2e, 0x00,
+               0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x20, 0x00,
+               0x5c, 0x00, 0x45, 0x00, 0x46, 0x00, 0x49, 0x00,
+               0x5c, 0x00, 0x66, 0x00, 0x65, 0x00, 0x64, 0x00,
+               0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x5c, 0x00,
+               0x66, 0x00, 0x77, 0x00, 0x75, 0x00, 0x70, 0x00,
+               0x64, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+               0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
+               0x20, 0x00, 0x00, 0x00, 0x66, 0x00, 0x73, 0x00,
+               0x30, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x00, 0x00,
+       };
+       size_t load_option_data_size = sizeof(load_option_data);
+       char *remaining = &load_option_data[sizeof(load_option_data)-14];
+       size_t remaining_size = 14;
+
+       return test_parse_load_options(load_option_data,
+                                      load_option_data_size,
+                                      "\\EFI\\fedora\\shimx64.efi",
+                                      L"\\EFI\\fedora\\fwupdate.efi",
+                                      remaining, remaining_size);
+}
+
+int __attribute__((__flatten__))
+test_bds_0(void)
+{
+/*
+00000000  01 00 00 00 62 00 4c 00  69 00 6e 00 75 00 78 00  |....b.L.i.n.u.x.|
+00000010  20 00 46 00 69 00 72 00  6d 00 77 00 61 00 72 00  | .F.i.r.m.w.a.r.|
+00000020  65 00 20 00 55 00 70 00  64 00 61 00 74 00 65 00  |e. .U.p.d.a.t.e.|
+00000030  72 00 00 00 40 01 2a 00  01 00 00 00 00 08 00 00  |r.....*.........|
+00000040  00 00 00 00 00 40 06 00  00 00 00 00 1a 9e 55 bf  |.....@........U.|
+00000050  04 57 f2 4f b4 4a ed 26  4a 40 6a 94 02 02 04 04  |.W.O.:.&J@j.....|
+00000060  34 00 5c 00 45 00 46 00  49 00 5c 00 66 00 65 00  |4.\.E.F.I.\.f.e.|
+00000070  64 00 6f 00 72 00 61 00  5c 00 73 00 68 00 69 00  |d.o.r.a.\.s.h.i.|
+00000080  6d 00 78 00 36 00 34 00  2e 00 65 00 66 00 69 00  |m.x.6.4...e.f.i.|
+00000090  00 00 7f ff 04 00 20 00  5c 00 66 00 77 00 75 00  |...... .\.f.w.u.|
+000000a0  70 00 78 00 36 00 34 00  2e 00 65 00 66 00 69 00  |p.x.6.4...e.f.i.|
+000000b0  00 00                                             |..|
+*/
+       char load_option_data [] = {
+               0x01, 0x00, 0x00, 0x00, 0x62, 0x00, 0x4c, 0x00,
+               0x69, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x78, 0x00,
+               0x20, 0x00, 0x46, 0x00, 0x69, 0x00, 0x72, 0x00,
+               0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00,
+               0x65, 0x00, 0x20, 0x00, 0x55, 0x00, 0x70, 0x00,
+               0x64, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+               0x72, 0x00, 0x00, 0x00, 0x40, 0x01, 0x2a, 0x00,
+               0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x1a, 0x9e, 0x55, 0xbf,
+               0x04, 0x57, 0xf2, 0x4f, 0xb4, 0x4a, 0xed, 0x26,
+               0x4a, 0x40, 0x6a, 0x94, 0x02, 0x02, 0x04, 0x04,
+               0x34, 0x00, 0x5c, 0x00, 0x45, 0x00, 0x46, 0x00,
+               0x49, 0x00, 0x5c, 0x00, 0x66, 0x00, 0x65, 0x00,
+               0x64, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00,
+               0x5c, 0x00, 0x73, 0x00, 0x68, 0x00, 0x69, 0x00,
+               0x6d, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00,
+               0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
+               0x00, 0x00, 0x7f, 0xff, 0x04, 0x00, 0x20, 0x00,
+               0x5c, 0x00, 0x66, 0x00, 0x77, 0x00, 0x75, 0x00,
+               0x70, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00,
+               0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
+               0x00, 0x00
+       };
+       size_t load_option_data_size = sizeof(load_option_data);
+
+       return test_parse_load_options(load_option_data,
+                                      load_option_data_size,
+                                      "\\EFI\\fedora\\shimx64.efi",
+                                      L"\\fwupx64.efi",
+                                      NULL, 0);
+}
+
+int __attribute__((__flatten__))
+test_bds_1(void)
+{
+/*
+00000000  5c 00 66 00 77 00 75 00  70 00 78 00 36 00 34 00  |\.f.w.u.p.x.6.4.|
+00000010  2e 00 65 00 66 00 69 00  00 00                    |..e.f.i...|
+0000001a
+*/
+       char load_option_data [] = {
+               0x5c, 0x00, 0x66, 0x00, 0x77, 0x00, 0x75, 0x00,
+               0x70, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00,
+               0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
+               0x00, 0x00
+       };
+       size_t load_option_data_size = sizeof(load_option_data);
+
+       return test_parse_load_options(load_option_data,
+                                      load_option_data_size,
+                                      "\\EFI\\fedora\\shimx64.efi",
+                                      L"\\fwupx64.efi",
+                                      NULL, 0);
+}
+
+int
+test_bds_2(void)
+{
+/*
+00000000  74 00 65 00 73 00 74 00  2E 00 65 00 66 00 69 00  |t.e.s.t...e.f.i.|
+00000010  20 00 6F 00 6E 00 65 00  20 00 74 00 77 00 6F 00  |..o.n.e...t.w.o.|
+00000020  20 00 74 00 68 00 72 00  65 00 65 00 00 00        |..t.h.r.e.e...|
+*/
+       char load_option_data [] = {
+               0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+               0x2E, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
+               0x20, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x65, 0x00,
+               0x20, 0x00, 0x74, 0x00, 0x77, 0x00, 0x6F, 0x00,
+               0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x72, 0x00,
+               0x65, 0x00, 0x65, 0x00, 0x00, 0x00
+       };
+       size_t load_option_data_size = sizeof(load_option_data);
+       char *target_remaining = &load_option_data[26];
+       size_t target_remaining_size = 20;
+
+       return test_parse_load_options(load_option_data,
+                                      load_option_data_size,
+                                      "test.efi",
+                                      L"one",
+                                      target_remaining,
+                                      target_remaining_size);
+}
+
+int
+main(void)
+{
+       int status = 0;
+       test(test_efi_shell_0);
+       test(test_bds_0);
+       test(test_bds_1);
+       test(test_bds_2);
+       return status;
+}
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/test-mock-variables.c b/test-mock-variables.c
new file mode 100644 (file)
index 0000000..c7e42b0
--- /dev/null
@@ -0,0 +1,842 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * test-mock-variables.c - test our mock variable implementation (irony)
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#include "shim.h"
+#include "mock-variables.h"
+
+#include <errno.h>
+#include <efivar/efivar.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "test-data-efivars-0.h"
+
+#pragma GCC diagnostic ignored "-Wunused-label"
+
+static const size_t guidstr_size = sizeof("8be4df61-93ca-11d2-aa0d-00e098032b8c");
+
+void mock_print_guidname(EFI_GUID *guid, CHAR16 *name);
+void mock_print_var_list(list_t *head);
+
+static int
+test_filter_out_helper(size_t nvars, const CHAR16 *varnames[nvars],
+                      bool filter_out, UINTN expected_count)
+{
+       const char *mok_rt_vars[n_mok_state_variables];
+       EFI_STATUS status;
+       EFI_GUID guid = SHIM_LOCK_GUID;
+       CHAR16 name[1024] = L"";
+       UINTN sz;
+       char asciiname[1024];
+       bool found = false;
+       int ret = 0;
+       UINTN count = 0;
+
+       for (size_t i = 0; i < n_mok_state_variables; i++) {
+               mok_rt_vars[i] = mok_state_variables[i].rtname8;
+       }
+
+       sz = sizeof(name);
+       status = RT->GetNextVariableName(&sz, name, &guid);
+       assert_equal_return(status, EFI_NOT_FOUND, -1, "got %lx, expected %lx");
+
+       mock_load_variables("test-data/efivars-1", mok_rt_vars, filter_out);
+
+       while (true) {
+               int rc = 0;
+
+               sz = sizeof(name);
+               status = RT->GetNextVariableName(&sz, name, &guid);
+               if (status == EFI_NOT_FOUND)
+                       break;
+               if (EFI_ERROR(status))
+                       return -1;
+
+               count += 1;
+               SetMem(asciiname, sizeof(asciiname), 0);
+               for (UINTN i = 0; i < sizeof(asciiname); i++)
+                       asciiname[i] = name[i];
+               for (UINTN i = 0; varnames[i] != NULL; i++) {
+                       if (sz == 0 || StrLen(varnames[i]) != sz-1)
+                               continue;
+                       if (StrCmp(name, varnames[i]) == 0) {
+                               found = true;
+                               if (filter_out) {
+                                       rc = assert_false_as_expr(found, -1,
+                                               "found=%u for undesired variable \"%s\"\n",
+                                               asciiname);
+                                       break;
+                               }
+                       }
+               }
+               if (!filter_out)
+                       rc = assert_true_as_expr(found, -1,
+                               "found=%u for undesired variable \"%s\"\n",
+                               asciiname);
+               if (ret >= 0 && rc < 0)
+                       ret = rc;
+       }
+
+       mock_reset_variables();
+       assert_equal_return(count, expected_count, -1, "%lu != %lu\n");
+       assert_true_return(list_empty(&mock_variables), -1, "%lu != %lu\n");
+
+       return ret;
+}
+
+static int
+test_filter_out_true(void)
+{
+       const CHAR16 *varnames[] = {
+               L"MokListRT",
+               L"MokListXRT",
+               L"SbatLevelRT",
+               NULL
+       };
+       size_t nvars = sizeof(varnames) / sizeof(varnames[0]);
+
+       return test_filter_out_helper(nvars, varnames, true, 3);
+}
+
+static int
+test_filter_out_false(void)
+{
+       const CHAR16 *varnames[] = {
+               L"MokListRT",
+               L"MokListXRT",
+               L"SbatLevelRT",
+               NULL
+       };
+       size_t nvars = sizeof(varnames) / sizeof(varnames[0]);
+
+       return test_filter_out_helper(nvars, varnames, false, 3);
+}
+
+static int
+test_gnvn_buf_size_0(void)
+{
+       UINTN size = 0;
+       CHAR16 buf[6] = { 0, };
+       EFI_STATUS status;
+       EFI_GUID empty_guid = { 0, };
+       int ret = -1;
+
+       status = RT->GetNextVariableName(&size, &buf[0], &GV_GUID);
+       assert_equal_return(status, EFI_INVALID_PARAMETER, -1, "0x%lx != 0x%lx\n");
+
+       size = 1;
+       status = RT->GetNextVariableName(&size, &buf[0], &GV_GUID);
+       assert_equal_return(status, EFI_NOT_FOUND, -1, "0x%lx != 0x%lx\n");
+
+       status = RT->SetVariable(L"test", &GV_GUID,
+                                EFI_VARIABLE_BOOTSERVICE_ACCESS, 5, "test");
+       assert_equal_return(status, EFI_SUCCESS, -1, "0x%lx != 0x%lx\n");
+
+       size = 1;
+       status = RT->GetNextVariableName(&size, &buf[0], &empty_guid);
+       assert_equal_goto(status, EFI_NOT_FOUND, err, "0x%lx != 0x%lx\n");
+
+       size = 1;
+       status = RT->GetNextVariableName(&size, &buf[0], &GV_GUID);
+       assert_equal_goto(status, EFI_BUFFER_TOO_SMALL, err, "0x%lx != 0x%lx\n");
+       assert_equal_goto(size, StrSize(L"test"), err, "%zu != %zu\n");
+
+       size = StrSize(L"test");
+       status = RT->GetNextVariableName(&size, &buf[0], &GV_GUID);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+
+       status = RT->SetVariable(L"testa", &GV_GUID,
+                                EFI_VARIABLE_BOOTSERVICE_ACCESS, 5, "test");
+       assert_equal_return(status, EFI_SUCCESS, -1, "0x%lx != 0x%lx\n");
+
+       buf[0] = 0;
+       size = 1;
+       status = RT->GetNextVariableName(&size, &buf[0], &empty_guid);
+       assert_equal_goto(status, EFI_NOT_FOUND, err, "0x%lx != 0x%lx\n");
+
+       size = StrSize(L"test");
+       StrCpy(buf, L"test");
+       status = RT->GetNextVariableName(&size, &buf[0], &GV_GUID);
+       switch (mock_variable_sort_policy) {
+       case MOCK_SORT_DESCENDING:
+       case MOCK_SORT_PREPEND:
+               assert_equal_goto(status, EFI_NOT_FOUND, err, "0x%lx != 0x%lx\n");
+               break;
+       case MOCK_SORT_APPEND:
+       case MOCK_SORT_ASCENDING:
+               assert_equal_goto(status, EFI_BUFFER_TOO_SMALL, err, "0x%lx != 0x%lx\n");
+               break;
+       default:
+               break;
+       }
+
+       size = StrSize(L"testa");
+       StrCpy(buf, L"test");
+       status = RT->GetNextVariableName(&size, &buf[0], &GV_GUID);
+       switch (mock_variable_sort_policy) {
+       case MOCK_SORT_DESCENDING:
+       case MOCK_SORT_PREPEND:
+               assert_equal_goto(status, EFI_NOT_FOUND, err, "0x%lx != 0x%lx\n");
+               break;
+       case MOCK_SORT_APPEND:
+       case MOCK_SORT_ASCENDING:
+               assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+               break;
+       default:
+               break;
+       }
+
+       ret = 0;
+err:
+       mock_reset_variables();
+       return ret;
+}
+
+static int
+test_gnvn_helper(char *testvars)
+{
+       UINTN size = 0;
+       CHAR16 buf[8192] = { 0, };
+       EFI_STATUS status;
+       EFI_GUID empty_guid = { 0, };
+       int ret = -1;
+       const char *mok_rt_vars[n_mok_state_variables];
+
+       for (size_t i = 0; i < n_mok_state_variables; i++) {
+               mok_rt_vars[i] = mok_state_variables[i].rtname8;
+       }
+
+       mock_load_variables(testvars, mok_rt_vars, true);
+
+       size = sizeof(buf);
+       buf[0] = L'\0';
+       status = RT->GetNextVariableName(&size, buf, &GV_GUID);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+
+#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
+       dump_mock_variables(__FILE__, __LINE__, __func__);
+#endif
+       switch (mock_variable_sort_policy) {
+       case MOCK_SORT_DESCENDING:
+               dump_mock_variables_if_wrong(__FILE__, __LINE__, __func__,
+                                            &GV_GUID, L"dbxDefault");
+               assert_zero_goto(StrCmp(buf, L"dbxDefault"), err, "0x%lx != 0x%lx\n");
+               break;
+       case MOCK_SORT_ASCENDING:
+               dump_mock_variables_if_wrong(__FILE__, __LINE__, __func__,
+                                            &GV_GUID, L"Boot0000");
+               assert_zero_goto(StrCmp(buf, L"Boot0000"), err, "0x%lx != 0x%lx buf:\"%s\"\n",
+                                0, Str2str(buf));
+               break;
+       default:
+               break;
+       }
+
+       size = sizeof(buf);
+       buf[0] = 0;
+       status = RT->GetNextVariableName(&size, buf, &EFI_SECURE_BOOT_DB_GUID);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+       switch (mock_variable_sort_policy) {
+       case MOCK_SORT_DESCENDING:
+               assert_zero_goto(StrCmp(buf, L"dbx"), err, "0x%lx != 0x%lx\n");
+               break;
+       case MOCK_SORT_ASCENDING:
+               assert_zero_goto(StrCmp(buf, L"db"), err, "0x%lx != 0x%lx\n");
+               break;
+       default:
+               break;
+       }
+
+       ret = 0;
+err:
+       if (ret)
+               mock_print_var_list(&mock_variables);
+       mock_reset_variables();
+       return ret;
+}
+
+static int
+test_gnvn_0(void)
+{
+       return test_gnvn_helper("test-data/efivars-0");
+}
+
+static int
+test_gnvn_1(void)
+{
+       return test_gnvn_helper("test-data/efivars-1");
+}
+
+static int
+test_get_variable_0(void)
+{
+       UINTN size = 0;
+       uint8_t buf[8192] = { 0, };
+       EFI_STATUS status;
+       EFI_GUID empty_guid = { 0, };
+       UINT32 attrs = 0;
+       int ret = -1;
+       int cmp;
+       const char *mok_rt_vars[n_mok_state_variables];
+
+       for (size_t i = 0; i < n_mok_state_variables; i++) {
+               mok_rt_vars[i] = mok_state_variables[i].rtname8;
+       }
+
+       mock_load_variables("test-data/efivars-1", mok_rt_vars, true);
+
+       size = 0;
+       status = RT->GetVariable(L"Boot0000", &GV_GUID, &attrs, &size, buf);
+       assert_equal_goto(status, EFI_BUFFER_TOO_SMALL, err, "0x%lx != 0x%lx\n");
+
+       size = sizeof(buf);
+       status = RT->GetVariable(L"Boot0000", &GV_GUID, &attrs, &size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+       assert_equal_goto(size, sizeof(test_data_efivars_0_Boot0000), err, "%zu != %zu\n");
+       assert_zero_goto(memcmp(buf, test_data_efivars_0_Boot0000, size), err, "%zu != %zu\n");
+
+       ret = 0;
+err:
+       if (ret)
+               mock_print_var_list(&mock_variables);
+       mock_reset_variables();
+       return ret;
+}
+
+static int
+test_set_variable_0(void)
+{
+       UINTN size = 0;
+       uint8_t buf[8192] = { 0, };
+       EFI_STATUS status;
+       EFI_GUID empty_guid = { 0, };
+       UINT32 attrs = 0;
+       int ret = -1;
+       UINT32 bs_rt_nv = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_RUNTIME_ACCESS |
+                         EFI_VARIABLE_NON_VOLATILE;
+
+       size = 4;
+       strcpy(buf, "foo");
+       status = RT->SetVariable(L"tmp", &GV_GUID, bs_rt_nv, size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+
+       size = sizeof(buf);
+       SetMem(buf, sizeof(buf), 0);
+       status = RT->GetVariable(L"tmp", &GV_GUID, &attrs, &size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+       assert_equal_goto(size, 4, err, "%zu != %zu\n");
+       assert_zero_goto(memcmp(buf, "foo", 4), err, "0x%lx != 0x%lx\n");
+
+       size = 5;
+       strcpy(buf, "bang");
+       status = RT->SetVariable(L"tmp", &GV_GUID,
+                                EFI_VARIABLE_NON_VOLATILE |
+                                EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                EFI_VARIABLE_RUNTIME_ACCESS,
+                                size, buf);
+       size = sizeof(buf);
+       SetMem(buf, sizeof(buf), 0);
+       status = RT->GetVariable(L"tmp", &GV_GUID, &attrs, &size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+       assert_equal_goto(size, 5, err, "%zu != %zu\n");
+       assert_zero_goto(memcmp(buf, "bang", 5), err, "%d != %d\n");
+
+       size = 5;
+       strcpy(buf, "foop");
+       status = RT->SetVariable(L"tmp", &GV_GUID, bs_rt_nv, size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+
+       size = sizeof(buf);
+       SetMem(buf, sizeof(buf), 0);
+       status = RT->GetVariable(L"tmp", &GV_GUID, &attrs, &size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+       assert_equal_goto(size, 5, err, "%zu != %zu\n");
+       assert_zero_goto(memcmp(buf, "foop", 5), err, "%d != %d\n");
+
+       size = 0;
+       strcpy(buf, "");
+       status = RT->SetVariable(L"tmp", &GV_GUID, bs_rt_nv | EFI_VARIABLE_APPEND_WRITE, size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+
+       size = sizeof(buf);
+       SetMem(buf, sizeof(buf), 0);
+       status = RT->GetVariable(L"tmp", &GV_GUID, &attrs, &size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+       assert_equal_goto(size, 5, err, "%zu != %zu\n");
+       assert_zero_goto(memcmp(buf, "foop", 5), err, "%d != %d\n");
+
+       size = 5;
+       strcpy(buf, "poof");
+       status = RT->SetVariable(L"tmp", &GV_GUID, bs_rt_nv | EFI_VARIABLE_APPEND_WRITE, size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+
+       size = sizeof(buf);
+       SetMem(buf, sizeof(buf), 0);
+       status = RT->GetVariable(L"tmp", &GV_GUID, &attrs, &size, buf);
+       assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n");
+       assert_equal_goto(size, 10, err, "%zu != %zu\n");
+       assert_zero_goto(memcmp(buf, "foop\0poof", 10), err, "%d != %d\n");
+       ret = 0;
+err:
+       if (ret)
+               mock_print_var_list(&mock_variables);
+       mock_reset_variables();
+       return ret;
+}
+
+static void
+dump_config_table_if_wrong(const char * const func, int line, ...)
+{
+       va_list alist, blist;
+       bool okay = true;
+       size_t n = 0, m = 0;
+
+       va_start(alist, line);
+       va_copy(blist, alist);
+
+       int idx = va_arg(alist, int);
+       EFI_GUID *guid = va_arg(alist, EFI_GUID *);
+       while (idx >= 0 && guid != NULL) {
+               EFI_CONFIGURATION_TABLE *entry;
+               if (idx < 0)
+                       goto nexta;
+
+               n += 1;
+               if (idx >= (int)ST->NumberOfTableEntries) {
+                       okay = false;
+                       goto nexta;
+               }
+
+               entry = &ST->ConfigurationTable[idx];
+               if (CompareGuid(guid, &entry->VendorGuid) != 0)
+                       okay = false;
+
+nexta:
+               idx = va_arg(alist, int);
+               guid = va_arg(alist, EFI_GUID *);
+       }
+       va_end(alist);
+
+       if (okay)
+               return;
+
+       printf("%s:%d:%s(): %d entries:\n", __FILE__, line, func, ST->NumberOfTableEntries);
+       idx = va_arg(blist, int);
+       guid = va_arg(blist, EFI_GUID *);
+       while (idx >= 0 && guid != NULL) {
+               EFI_CONFIGURATION_TABLE *entry;
+
+               if (idx >= (int)ST->NumberOfTableEntries) {
+                       printf("\t[%d]: invalid index for " GUID_FMT "\n",
+                              idx, GUID_ARGS(*guid));
+                       goto nexta;
+               }
+
+               if (idx < 0) {
+                       printf("\t[%d]: " GUID_FMT "\n", idx, GUID_ARGS(*guid));
+               } else {
+                       entry = &ST->ConfigurationTable[idx];
+                       printf("\t[%d]: %p ", idx, entry);
+                       printf("{.VendorGuid:" GUID_FMT ",", GUID_ARGS(entry->VendorGuid));
+                       printf("&.VendorTable:%p}\n", entry->VendorTable);
+                       if (CompareGuid(guid, &entry->VendorGuid) != 0)
+                               printf("\t\t\t  expected:" GUID_FMT "\n", GUID_ARGS(*guid));
+               }
+next:
+               idx = va_arg(blist, int);
+               guid = va_arg(blist, EFI_GUID *);
+       }
+       va_end(blist);
+
+       if ((int)ST->NumberOfTableEntries - n == 0)
+               return;
+
+       printf("%d extra table entries:\n", ST->NumberOfTableEntries - n);
+       for (m = n; m < ST->NumberOfTableEntries; m++) {
+               EFI_CONFIGURATION_TABLE *entry;
+
+               entry = &ST->ConfigurationTable[m];
+
+               printf("\t[%d]: %p ", m, entry);
+               printf("{.VendorGuid:" GUID_FMT ",", GUID_ARGS(entry->VendorGuid));
+               printf("&.VendorTable:%p}\n", entry->VendorTable);
+       }
+}
+
+static int
+test_install_config_table_0(void)
+{
+       int ret = -1;
+       EFI_STATUS status;
+
+       /*
+        * These three guids are chosen on purpose: they start with "a",
+        * "b", and "c", respective to their variable names, so you can
+        * identify them when dumped.
+        */
+       EFI_GUID aguid = SECURITY_PROTOCOL_GUID;
+       char astr[guidstr_size];
+       void *astrp = &astr[0];
+       int aidx = -1;
+
+       EFI_GUID bguid = EFI_HTTP_BINDING_GUID;
+       char bstr[guidstr_size];
+       void *bstrp = &bstr[0];
+       int bidx = -1;
+
+       EFI_GUID cguid = MOK_VARIABLE_STORE;
+       char cstr[guidstr_size];
+       void *cstrp = &cstr[0];
+       int cidx = -1;
+
+       EFI_GUID lip = LOADED_IMAGE_PROTOCOL;
+
+       EFI_GUID guids[3];
+
+       char tmpstr[guidstr_size];
+
+       sprintf(astrp, GUID_FMT, GUID_ARGS(aguid));
+       sprintf(bstrp, GUID_FMT, GUID_ARGS(bguid));
+       sprintf(cstrp, GUID_FMT, GUID_ARGS(cguid));
+
+       assert_equal_return(ST->NumberOfTableEntries, 0, -1, "%lu != %lu\n");
+
+       /*
+        * test installing one
+        */
+       status = BS->InstallConfigurationTable(&bguid, bstrp);
+       assert_equal_return(status, EFI_SUCCESS, -1, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 1, err, "%lu != %lu\n");
+
+       sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[0].VendorGuid));
+       assert_zero_goto(CompareGuid(&ST->ConfigurationTable[0].VendorGuid, &bguid),
+                        err, "%d != 0 (%s != %s)\n", tmpstr, bstr);
+       assert_equal_goto(ST->ConfigurationTable[0].VendorTable,
+                         bstrp, err, "%p != %p\n");
+
+       /*
+        * test re-installing the same one
+        */
+       status = BS->InstallConfigurationTable(&bguid, bstrp);
+       assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 1, err, "%lu != %lu\n");
+
+       sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[0].VendorGuid));
+       assert_zero_goto(CompareGuid(&ST->ConfigurationTable[0].VendorGuid, &bguid),
+                        err, "%d != 0 (%s != %s)\n", tmpstr, bstr);
+       assert_equal_goto(ST->ConfigurationTable[0].VendorTable,
+                         bstrp, err, "%p != %p\n");
+
+       /*
+        * Test installing a second one
+        */
+       status = BS->InstallConfigurationTable(&aguid, astrp);
+       assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 2, err, "%lu != %lu\n");
+
+       switch (mock_config_table_sort_policy) {
+               case MOCK_SORT_DESCENDING:
+                       aidx = 1;
+                       bidx = 0;
+                       break;
+               case MOCK_SORT_PREPEND:
+                       aidx = 0;
+                       bidx = 1;
+                       break;
+               case MOCK_SORT_APPEND:
+                       aidx = 1;
+                       bidx = 0;
+                       break;
+               case MOCK_SORT_ASCENDING:
+                       aidx = 0;
+                       bidx = 1;
+                       break;
+               default:
+                       break;
+       }
+
+       dump_config_table_if_wrong(__func__, __LINE__,
+                                  aidx, &aguid,
+                                  bidx, &bguid,
+                                  cidx, &cguid,
+                                  -1, NULL);
+
+       sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[aidx].VendorGuid));
+       assert_zero_goto(CompareGuid(&ST->ConfigurationTable[aidx].VendorGuid, &aguid),
+                        err, "%d != 0 (%s != %s)\n", tmpstr, astr);
+       assert_equal_goto(ST->ConfigurationTable[aidx].VendorTable, astrp,
+                         err, "%p != %p\n");
+
+       sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[bidx].VendorGuid));
+       assert_zero_goto(CompareGuid(&ST->ConfigurationTable[bidx].VendorGuid, &bguid),
+                        err, "%d != 0 (%s != %s)\n", tmpstr, bstr);
+       assert_equal_goto(ST->ConfigurationTable[bidx].VendorTable, bstrp,
+                         err, "%p != %p\n");
+
+       /*
+        * Test installing a third one
+        */
+       status = BS->InstallConfigurationTable(&cguid, cstrp);
+       assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 3, err, "%lu != %lu\n");
+
+       switch (mock_config_table_sort_policy) {
+               case MOCK_SORT_DESCENDING:
+                       aidx = 2;
+                       bidx = 1;
+                       cidx = 0;
+                       break;
+               case MOCK_SORT_PREPEND:
+                       aidx = 1;
+                       bidx = 2;
+                       cidx = 0;
+                       break;
+               case MOCK_SORT_APPEND:
+                       aidx = 1;
+                       bidx = 0;
+                       cidx = 2;
+                       break;
+               case MOCK_SORT_ASCENDING:
+                       aidx = 0;
+                       bidx = 1;
+                       cidx = 2;
+                       break;
+               default:
+                       break;
+       }
+
+       dump_config_table_if_wrong(__func__, __LINE__,
+                                  aidx, &aguid,
+                                  bidx, &bguid,
+                                  cidx, &cguid,
+                                  -1, NULL);
+
+       sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[aidx].VendorGuid));
+       assert_zero_goto(CompareGuid(&ST->ConfigurationTable[aidx].VendorGuid, &aguid),
+                        err, "%d != 0 (%s != %s)\n", tmpstr, astr);
+       assert_equal_goto(ST->ConfigurationTable[aidx].VendorTable, astrp,
+                         err, "%p != %p\n");
+       memcpy(&guids[aidx], &aguid, sizeof(EFI_GUID));
+
+       sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[bidx].VendorGuid));
+       assert_zero_goto(CompareGuid(&ST->ConfigurationTable[bidx].VendorGuid, &bguid),
+                        err, "%d != 0 (%s != %s)\n", tmpstr, bstr);
+       assert_equal_goto(ST->ConfigurationTable[bidx].VendorTable, bstrp,
+                         err, "%p != %p\n");
+       memcpy(&guids[bidx], &bguid, sizeof(EFI_GUID));
+
+       sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[cidx].VendorGuid));
+       assert_zero_goto(CompareGuid(&ST->ConfigurationTable[cidx].VendorGuid, &cguid),
+                        err, "%d != 0 (%s != %s)\n", tmpstr, cstr);
+       assert_equal_goto(ST->ConfigurationTable[cidx].VendorTable, cstrp,
+                         err, "%p != %p\n");
+       memcpy(&guids[cidx], &cguid, sizeof(EFI_GUID));
+
+       /*
+        * Test removing NULL guid
+        */
+       status = BS->InstallConfigurationTable(NULL, NULL);
+       assert_equal_goto(status, EFI_INVALID_PARAMETER, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 3, err, "%lu != %lu\n");
+
+       /*
+        * Test removing a guid that's not present
+        */
+       status = BS->InstallConfigurationTable(&lip, NULL);
+       assert_equal_goto(status, EFI_NOT_FOUND, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 3, err, "%lu != %lu\n");
+
+       /*
+        * Test removing the middle one
+        */
+       status = BS->InstallConfigurationTable(&guids[1], NULL);
+       assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 2, err, "%lu != %lu\n");
+
+       switch (mock_config_table_sort_policy) {
+               case MOCK_SORT_DESCENDING:
+                       aidx = 1;
+                       bidx = -1;
+                       cidx = 0;
+                       break;
+               case MOCK_SORT_PREPEND:
+                       aidx = -1;
+                       bidx = 1;
+                       cidx = 0;
+                       break;
+               case MOCK_SORT_APPEND:
+                       aidx = -1;
+                       bidx = 0;
+                       cidx = 1;
+                       break;
+               case MOCK_SORT_ASCENDING:
+                       aidx = 0;
+                       bidx = -1;
+                       cidx = 1;
+                       break;
+               default:
+                       break;
+       }
+
+       dump_config_table_if_wrong(__func__, __LINE__,
+                                  aidx, &aguid,
+                                  bidx, &bguid,
+                                  cidx, &cguid,
+                                  -1, NULL);
+
+       if (aidx >= 0) {
+               sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[aidx].VendorGuid));
+               assert_zero_goto(CompareGuid(&ST->ConfigurationTable[aidx].VendorGuid, &aguid),
+                                err, "%d != 0 (%s != %s)\n", tmpstr, astr);
+               assert_equal_goto(ST->ConfigurationTable[aidx].VendorTable, astrp,
+                                 err, "%p != %p\n");
+               memcpy(&guids[aidx], &aguid, sizeof(EFI_GUID));
+       }
+
+       if (bidx >= 0) {
+               sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[bidx].VendorGuid));
+               assert_zero_goto(CompareGuid(&ST->ConfigurationTable[bidx].VendorGuid, &bguid),
+                                err, "%d != 0 (%s != %s)\n", tmpstr, bstr);
+               assert_equal_goto(ST->ConfigurationTable[bidx].VendorTable, bstrp,
+                                 err, "%p != %p\n");
+               memcpy(&guids[bidx], &bguid, sizeof(EFI_GUID));
+       }
+
+       if (cidx >= 0) {
+               sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[cidx].VendorGuid));
+               assert_zero_goto(CompareGuid(&ST->ConfigurationTable[cidx].VendorGuid, &cguid),
+                                err, "%d != 0 (%s != %s)\n", tmpstr, cstr);
+               assert_equal_goto(ST->ConfigurationTable[cidx].VendorTable, cstrp,
+                                 err, "%p != %p\n");
+               memcpy(&guids[cidx], &cguid, sizeof(EFI_GUID));
+       }
+
+       /*
+        * Test removing the lowest one
+        */
+       status = BS->InstallConfigurationTable(&guids[0], NULL);
+       assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 1, err, "%lu != %lu\n");
+
+       switch (mock_config_table_sort_policy) {
+               case MOCK_SORT_DESCENDING:
+                       aidx = 0;
+                       bidx = -1;
+                       cidx = -1;
+                       break;
+               case MOCK_SORT_PREPEND:
+                       aidx = -1;
+                       bidx = 0;
+                       cidx = -1;
+                       break;
+               case MOCK_SORT_APPEND:
+                       aidx = -1;
+                       bidx = -1;
+                       cidx = 0;
+                       break;
+               case MOCK_SORT_ASCENDING:
+                       aidx = -1;
+                       bidx = -1;
+                       cidx = 0;
+                       break;
+               default:
+                       break;
+       }
+
+       dump_config_table_if_wrong(__func__, __LINE__,
+                                  aidx, &aguid,
+                                  bidx, &bguid,
+                                  cidx, &cguid,
+                                  -1, NULL);
+
+       if (aidx >= 0) {
+               sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[aidx].VendorGuid));
+               assert_zero_goto(CompareGuid(&ST->ConfigurationTable[aidx].VendorGuid, &aguid),
+                                err, "%d != 0 (%s != %s)\n", tmpstr, astr);
+               assert_equal_goto(ST->ConfigurationTable[aidx].VendorTable, astrp,
+                                 err, "%p != %p\n");
+               memcpy(&guids[aidx], &aguid, sizeof(EFI_GUID));
+       }
+
+       if (bidx >= 0) {
+               sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[bidx].VendorGuid));
+               assert_zero_goto(CompareGuid(&ST->ConfigurationTable[bidx].VendorGuid, &bguid),
+                                err, "%d != 0 (%s != %s)\n", tmpstr, bstr);
+               assert_equal_goto(ST->ConfigurationTable[bidx].VendorTable, bstrp,
+                                 err, "%p != %p\n");
+               memcpy(&guids[bidx], &bguid, sizeof(EFI_GUID));
+       }
+
+       if (cidx >= 0) {
+               sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[cidx].VendorGuid));
+               assert_zero_goto(CompareGuid(&ST->ConfigurationTable[cidx].VendorGuid, &cguid),
+                                err, "%d != 0 (%s != %s)\n", tmpstr, cstr);
+               assert_equal_goto(ST->ConfigurationTable[cidx].VendorTable, cstrp,
+                                 err, "%p != %p\n");
+               memcpy(&guids[cidx], &cguid, sizeof(EFI_GUID));
+       }
+
+       /*
+        * Test removing the last one
+        */
+       status = BS->InstallConfigurationTable(&guids[0], NULL);
+       assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 0, err, "%lu != %lu\n");
+
+       /*
+        * Test removing it again
+        */
+       status = BS->InstallConfigurationTable(&guids[0], NULL);
+       assert_equal_goto(status, EFI_NOT_FOUND, err, "%lx != %lx\n");
+       assert_equal_goto(ST->NumberOfTableEntries, 0, err, "%lu != %lu\n");
+
+       ret = 0;
+err:
+       while (ST->NumberOfTableEntries)
+               BS->InstallConfigurationTable(&ST->ConfigurationTable[0].VendorGuid, NULL);
+       mock_reset_config_table();
+
+       return ret;
+}
+
+int
+main(void)
+{
+       int status = 0;
+       setbuf(stdout, NULL);
+
+       const char *policies[] = {
+               "MOCK_SORT_DESCENDING",
+               "MOCK_SORT_PREPEND",
+               "MOCK_SORT_APPEND",
+               "MOCK_SORT_ASCENDING",
+               "MOCK_SORT_MAX_SENTINEL"
+       };
+
+       test(test_filter_out_true);
+       test(test_filter_out_false);
+
+       for (int i = 0; i < MOCK_SORT_MAX_SENTINEL; i++) {
+               mock_variable_sort_policy = i;
+               mock_config_table_sort_policy = i;
+               printf("%s: setting variable sort policy to %s\n",
+                      program_invocation_short_name, policies[i]);
+
+               test(test_gnvn_buf_size_0);
+               test(test_gnvn_0);
+               test(test_gnvn_1);
+
+               test(test_install_config_table_0);
+       }
+
+       test(test_get_variable_0);
+       test(test_set_variable_0);
+       return status;
+}
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/test-mok-mirror.c b/test-mok-mirror.c
new file mode 100644 (file)
index 0000000..3479ddf
--- /dev/null
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * test-mok-mirror.c - try to test our mok mirroring code
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#include "shim.h"
+#include "mock-variables.h"
+#include "test-data-efivars-1.h"
+
+#include <stdio.h>
+
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+EFI_STATUS
+start_image(EFI_HANDLE image_handle UNUSED, CHAR16 *mm)
+{
+       printf("Attempted to launch %s\n", Str2str(mm));
+       return EFI_SUCCESS;
+}
+
+#define N_TEST_VAR_OPS 40
+struct test_var {
+       EFI_GUID guid;
+       CHAR16 *name;
+       UINT32 attrs;
+       UINTN n_ops;
+       bool must_be_present;
+       bool must_be_absent;
+       mock_variable_op_t ops[N_TEST_VAR_OPS];
+       EFI_STATUS results[N_TEST_VAR_OPS];
+};
+
+static struct test_var *test_vars;
+
+struct mock_mok_variable_config_entry {
+       CHAR8 name[256];
+       UINT64 data_size;
+       const unsigned char *data;
+};
+
+static void
+setvar_post(CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
+           UINTN size, VOID *data, EFI_STATUS *status,
+           mock_variable_op_t op, const char * const file,
+           const int line, const char * const func)
+{
+       if (!test_vars)
+               return;
+
+       for (UINTN i = 0; test_vars[i].name != NULL; i++) {
+               struct test_var *tv = &test_vars[i];
+
+               if (CompareGuid(&tv->guid, guid) != 0 ||
+                   StrCmp(tv->name, name) != 0)
+                       continue;
+               tv->ops[tv->n_ops] = op;
+               tv->results[tv->n_ops] = *status;
+               tv->n_ops += 1;
+       }
+}
+
+static void
+getvar_post(CHAR16 *name, EFI_GUID *guid,
+           UINT32 *attrs, UINTN *size,
+           VOID *data, EFI_STATUS *status,
+           const char * const file, const int line, const char * func)
+{
+       if (EFI_ERROR(*status) &&
+           (*status != EFI_NOT_FOUND &&
+            *status != EFI_BUFFER_TOO_SMALL)) {
+               printf("%s:%d:%s():Getting "GUID_FMT"-%s ",
+                      file, line, func,
+                      GUID_ARGS(*guid), Str2str(name));
+               if (attrs)
+                       printf("attrs:%s\n", format_var_attrs(*attrs));
+               else
+                       printf("attrs:NULL\n");
+               printf("failed:%s\n", efi_strerror(*status));
+       }
+
+       if (!test_vars)
+               return;
+
+       for (UINTN i = 0; test_vars[i].name != NULL; i++) {
+               struct test_var *tv = &test_vars[i];
+
+               if (CompareGuid(&tv->guid, guid) != 0 ||
+                   StrCmp(tv->name, name) != 0)
+                       continue;
+               tv->ops[tv->n_ops] = GET;
+               tv->results[tv->n_ops] = *status;
+               tv->n_ops += 1;
+       }
+}
+
+static int
+test_mok_mirror_0(void)
+{
+       const char *mok_rt_vars[n_mok_state_variables];
+       EFI_STATUS status;
+       EFI_GUID guid = SHIM_LOCK_GUID;
+       EFI_GUID mok_config_guid = MOK_VARIABLE_STORE;
+       int ret = -1;
+
+       struct test_var test_mok_mirror_0_vars[] = {
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"MokList",
+                .must_be_present = true,
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_NON_VOLATILE,
+                .ops = { NONE, },
+               },
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"MokListRT",
+                .must_be_present = true,
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_RUNTIME_ACCESS,
+                .ops = { NONE, },
+               },
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"MokListX",
+                .must_be_present = true,
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_NON_VOLATILE,
+                .ops = { NONE, },
+               },
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"MokListXRT",
+                .must_be_present = true,
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_RUNTIME_ACCESS,
+                .ops = { NONE, },
+               },
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"SbatLevel",
+                .must_be_present = true,
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_NON_VOLATILE,
+                .ops = { NONE, },
+               },
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"SbatLevelRT",
+                .must_be_present = true,
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_RUNTIME_ACCESS,
+                .ops = { NONE, },
+               },
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"MokIgnoreDB",
+                .must_be_absent = true,
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_RUNTIME_ACCESS,
+                .ops = { NONE, },
+               },
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"MokSBState",
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_NON_VOLATILE,
+                .ops = { NONE, },
+               },
+               {.guid = SHIM_LOCK_GUID,
+                .name = L"MokSBStateRT",
+                .must_be_absent = true,
+                .attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                         EFI_VARIABLE_RUNTIME_ACCESS,
+                .ops = { NONE, },
+               },
+               {.guid = { 0, },
+                .name = NULL,
+               }
+       };
+
+       struct mock_mok_variable_config_entry test_mok_config_table[] = {
+               {.name = "MokListRT",
+                .data_size = sizeof(test_data_efivars_1_MokListRT),
+                .data = test_data_efivars_1_MokListRT
+               },
+               {.name = "MokListXRT",
+                .data_size = sizeof(test_data_efivars_1_MokListXRT),
+                .data = test_data_efivars_1_MokListXRT
+               },
+               {.name = "SbatLevelRT",
+                .data_size = sizeof(test_data_efivars_1_SbatLevelRT),
+                .data = test_data_efivars_1_SbatLevelRT
+               },
+               {.name = { 0, },
+                .data_size = 0,
+                .data = NULL,
+               }
+       };
+
+       for (size_t i = 0; i < n_mok_state_variables; i++) {
+               mok_rt_vars[i] = mok_state_variables[i].rtname8;
+       }
+
+       mock_load_variables("test-data/efivars-1", mok_rt_vars, true);
+
+       mock_set_variable_post_hook = setvar_post;
+       mock_get_variable_post_hook = getvar_post;
+       test_vars = &test_mok_mirror_0_vars[0];
+
+       import_mok_state(NULL);
+
+       for (size_t i = 0; test_mok_mirror_0_vars[i].name != NULL; i++) {
+               struct test_var *tv = &test_mok_mirror_0_vars[i];
+               list_t *pos = NULL;
+               bool found = false;
+               char buf[1];
+               UINTN size = 0;
+               UINT32 attrs = 0;
+               bool present = false;
+
+               list_for_each(pos, &mock_variables) {
+                       struct mock_variable *var;
+                       bool deleted;
+                       bool created;
+                       int gets = 0;
+
+                       var = list_entry(pos, struct mock_variable, list);
+                       if (CompareGuid(&tv->guid, &var->guid) != 0 ||
+                           StrCmp(var->name, tv->name) != 0)
+                               continue;
+                       found = true;
+                       assert_equal_goto(var->attrs, tv->attrs, err,
+                                         "\"%s\": wrong attrs; got %s expected %s\n",
+                                         Str2str(tv->name),
+                                         format_var_attrs(var->attrs),
+                                         format_var_attrs(tv->attrs));
+                       for (UINTN j = 0; j < N_TEST_VAR_OPS
+                                         && tv->ops[j] != NONE; j++) {
+                               switch (tv->ops[j]) {
+                               case NONE:
+                               default:
+                                       break;
+                               case CREATE:
+                                       if (tv->results[j] == EFI_SUCCESS)
+                                               created = true;
+                                       break;
+                               case DELETE:
+                                       assert_goto(tv->results[j] != EFI_SUCCESS, err,
+                                                         "Tried to delete absent variable \"%s\"\n",
+                                                         Str2str(tv->name));
+                                       assert_goto(created == false, err,
+                                                   "Deleted variable \"%s\" was previously created.\n",
+                                                   Str2str(tv->name));
+                                       break;
+                               case APPEND:
+                                       assert_goto(false, err,
+                                                   "No append action should have been tested\n");
+                                       break;
+                               case REPLACE:
+                                       assert_goto(false, err,
+                                                   "No replace action should have been tested\n");
+                                       break;
+                               case GET:
+                                       if (tv->results[j] == EFI_SUCCESS)
+                                               gets += 1;
+                                       break;
+                               }
+                       }
+                       assert_goto(gets == 0 || gets == 1, err,
+                                   "Variable should not be read %d times.\n", gets);
+               }
+               if (tv->must_be_present) {
+                       assert_goto(found == true, err,
+                                "variable \"%s\" was not found.\n",
+                                Str2str(tv->name));
+               }
+
+               if (tv->must_be_absent) {
+                       assert_goto(found == false, err,
+                                "variable \"%s\" was found.\n",
+                                Str2str(tv->name));
+               }
+       }
+
+       uint8_t *pos = NULL;
+       for (size_t i = 0; i < ST->NumberOfTableEntries; i++) {
+               EFI_CONFIGURATION_TABLE *ct = &ST->ConfigurationTable[i];
+
+               if (CompareGuid(&ct->VendorGuid, &mok_config_guid) != 0)
+                       continue;
+
+               pos = (void *)ct->VendorTable;
+               break;
+       }
+
+       assert_nonzero_goto(pos, err, "%p != 0\n");
+
+       size_t i = 0;
+       while (pos) {
+               struct mock_mok_variable_config_entry *mock_entry =
+                       &test_mok_config_table[i];
+               struct mok_variable_config_entry *mok_entry =
+                       (struct mok_variable_config_entry *)pos;
+
+               /*
+                * If the tables are different lengths, this will trigger.
+                */
+               assert_equal_goto(mok_entry->name[0], mock_entry->name[0], err,
+                                 "mok.name[0] %ld != test.name[0] %ld\n");
+               if (mock_entry->name[0] == 0)
+                       break;
+
+               assert_nonzero_goto(mok_entry->name[0], err, "%ld != %ld\n");
+               assert_zero_goto(strncmp(mok_entry->name, mock_entry->name,
+                                        sizeof(mock_entry->name)),
+                                err, "%ld != %ld: strcmp(\"%s\",\"%s\")\n",
+                                mok_entry->name, mock_entry->name);
+
+               /*
+                * As of 7501b6bb449f ("mok: fix potential buffer overrun in
+                * import_mok_state"), we should not see any mok config
+                * variables with data_size == 0.
+                */
+               assert_nonzero_goto(mok_entry->data_size, err, "%ld != 0\n");
+
+               assert_equal_goto(mok_entry->data_size, mock_entry->data_size,
+                                 err, "%ld != %ld\n");
+               assert_zero_goto(CompareMem(mok_entry->data, mock_entry->data,
+                                           mok_entry->data_size),
+                                err, "%ld != %ld\n");
+               pos += offsetof(struct mok_variable_config_entry, data)
+                      + mok_entry->data_size;
+               i += 1;
+       }
+
+       ret = 0;
+err:
+       for (UINTN k = 0; k < n_mok_state_variables; k++) {
+               struct mok_state_variable *v =
+                       &mok_state_variables[k];
+               if (v->data_size && v->data) {
+                       free(v->data);
+                       v->data = NULL;
+                       v->data_size = 0;
+               }
+       }
+
+       test_vars = NULL;
+       mock_set_variable_post_hook = NULL;
+       mock_get_variable_post_hook = NULL;
+       return ret;
+}
+
+int
+main(void)
+{
+       int status = 0;
+       setbuf(stdout, NULL);
+
+       const char *sort_policy_names[] = {
+               "MOCK_SORT_DESCENDING",
+               "MOCK_SORT_PREPEND",
+               "MOCK_SORT_APPEND",
+               "MOCK_SORT_ASCENDING",
+               "MOCK_SORT_MAX_SENTINEL"
+       };
+
+       const char *del_policy_names[] = {
+               "MOCK_VAR_DELETE_ATTR_ALLOW_ZERO",
+               "MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH",
+               "MOCK_VAR_DELETE_ATTR_ALLOW_ZERO|MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH",
+               "MOCK_VAR_DELETE_ATTR_ALLOW_NONE",
+               NULL
+       };
+
+       int delete_policies[] = {
+               MOCK_VAR_DELETE_ATTR_ALLOW_ZERO,
+               MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH,
+               MOCK_VAR_DELETE_ATTR_ALLOW_ZERO
+               | MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH,
+               0
+       };
+
+       for (int i = 0; i < MOCK_SORT_MAX_SENTINEL; i++) {
+               mock_variable_sort_policy = i;
+               mock_config_table_sort_policy = i;
+               int j = 0;
+
+               printf("%s: setting variable sort policy to %s\n",
+                      program_invocation_short_name, sort_policy_names[i]);
+               do {
+                       printf("%s: setting delete policy to %s\n",
+                              program_invocation_short_name,
+                              del_policy_names[j]);
+
+                       mock_variable_delete_attr_policy = delete_policies[j];
+                       test(test_mok_mirror_0);
+                       mock_finalize_vars_and_configs();
+
+                       if (delete_policies[j] == 0)
+                               break;
+               } while (++j);
+       }
+
+       return status;
+}
+
+// vim:fenc=utf-8:tw=75:noet
index 70d1637c132aa15a1fe9dd48d340443106565ec4..9cb831deef9f0a1bc9e4af30dd64ff8c05c6ab3a 100644 (file)
@@ -1067,7 +1067,7 @@ test_strcat(void)
         * I don't know.
         */
 #pragma GCC diagnostic push
-#pragma GCC diagnostic warning "-Warray-bounds"
+#pragma GCC diagnostic ignored "-Warray-bounds"
        assert_zero_return(strncmp(s1, s0, sizeof(s)-1), 0, -1, "\n");
        assert_negative_return(memcmp(s1, s0, sizeof(s)), 0, -1, "\n");
 #pragma GCC diagnostic pop
diff --git a/test.c b/test.c
index dc71941f1b83348cce7f4bb292a284f1ef77b313..46cab533534079cdcab05e565b3eaebfdb5af9e0 100644 (file)
--- a/test.c
+++ b/test.c
  * Copyright Peter Jones <pjones@redhat.com>
  */
 
-#ifndef SHIM_UNIT_TEST
-#define SHIM_UNIT_TEST
-#endif
 #include "shim.h"
 
+#include <execinfo.h>
+#include <stdio.h>
+#include <string.h>
+
+#define BT_BUF_SIZE (4096/sizeof(void *))
+
+static void *frames[BT_BUF_SIZE] = { 0, };
+
 UINT8 in_protocol = 0;
 int debug = DEFAULT_DEBUG_PRINT_STATE;
 
+void
+print_traceback(int skip)
+{
+       int nptrs;
+       char **strings;
+
+       nptrs = backtrace(frames, BT_BUF_SIZE);
+       if (nptrs < skip)
+               return;
+
+       strings = backtrace_symbols(frames, nptrs);
+       for (int i = skip; strings != NULL && i < nptrs; i++) {
+               printf("%p %s\n", (void *)frames[i], strings[i]);
+       }
+       if (strings)
+               free(strings);
+}
+
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
+static EFI_STATUS EFIAPI
+mock_efi_allocate_pages(EFI_ALLOCATE_TYPE type,
+                       EFI_MEMORY_TYPE memory_type,
+                       UINTN nmemb,
+                       EFI_PHYSICAL_ADDRESS *memory)
+{
+       /*
+        * XXX so far this does not honor the type at all, and there's no
+        * tracking for memory_type either.
+        */
+       *memory = (EFI_PHYSICAL_ADDRESS)(uintptr_t)calloc(nmemb, 4096);
+       if ((void *)(uintptr_t)(*memory) == NULL)
+               return EFI_OUT_OF_RESOURCES;
+
+       return EFI_SUCCESS;
+}
+
+static EFI_STATUS EFIAPI
+mock_efi_free_pages(EFI_PHYSICAL_ADDRESS memory,
+                   UINTN nmemb)
+{
+       free((void *)(uintptr_t)memory);
+
+       return EFI_SUCCESS;
+}
+
+static EFI_STATUS EFIAPI
+mock_efi_allocate_pool(EFI_MEMORY_TYPE pool_type,
+                      UINTN size,
+                      VOID **buf)
+{
+       *buf = calloc(1, size);
+       if (*buf == NULL)
+               return EFI_OUT_OF_RESOURCES;
+
+       return EFI_SUCCESS;
+}
+
+static EFI_STATUS EFIAPI
+mock_efi_free_pool(void *buf)
+{
+       free(buf);
+
+       return EFI_SUCCESS;
+}
+
+void EFIAPI
+mock_efi_void()
+{
+       ;
+}
+
 EFI_STATUS EFIAPI
-LogError_(const char *file, int line, const char *func, const CHAR16 *fmt, ...)
+mock_efi_success()
 {
-       assert(0);
        return EFI_SUCCESS;
 }
 
-INTN
-StrCmp(CONST CHAR16 *s1, CONST CHAR16 *s2) {
-       assert(s1 != NULL);
-       assert(s2 != NULL);
+EFI_STATUS EFIAPI
+mock_efi_unsupported()
+{
+       return EFI_UNSUPPORTED;
+}
 
-       int i;
-       for (i = 0; s1[i] && s2[i]; i++) {
-               if (s1[i] != s2[i])
-                       return s2[i] - s1[i];
-       }
-       return 0;
+EFI_STATUS EFIAPI
+mock_efi_not_found()
+{
+       return EFI_NOT_FOUND;
 }
 
-INTN
-StrnCmp(CONST CHAR16 *s1, CONST CHAR16 *s2, UINTN len) {
-       assert(s1 != NULL);
-       assert(s2 != NULL);
+EFI_BOOT_SERVICES mock_bs, mock_default_bs = {
+       .Hdr = {
+               .Signature = EFI_BOOT_SERVICES_SIGNATURE,
+               .Revision = EFI_1_10_BOOT_SERVICES_REVISION,
+               .HeaderSize = offsetof(EFI_BOOT_SERVICES, SetMem)
+                             + sizeof(mock_bs.SetMem),
+       },
+
+       .RaiseTPL = mock_efi_unsupported,
+       .RestoreTPL = mock_efi_void,
+
+       .AllocatePages = mock_efi_allocate_pages,
+       .FreePages = mock_efi_free_pages,
+       .GetMemoryMap = mock_efi_unsupported,
+       .AllocatePool = mock_efi_allocate_pool,
+       .FreePool = mock_efi_free_pool,
+
+       .CreateEvent = mock_efi_unsupported,
+       .SetTimer = mock_efi_unsupported,
+       .WaitForEvent = mock_efi_unsupported,
+       .SignalEvent = mock_efi_unsupported,
+       .CloseEvent = mock_efi_unsupported,
+       .CheckEvent = mock_efi_unsupported,
+
+       .InstallProtocolInterface = mock_efi_unsupported,
+       .ReinstallProtocolInterface = mock_efi_unsupported,
+       .UninstallProtocolInterface = mock_efi_unsupported,
+       .HandleProtocol = mock_efi_unsupported,
+#if 0
+       /*
+        * EFI 1.10 has a "Reserved" field here that's not in later
+        * revisions.
+        *
+        * I don't think it's in any actual *firmware* either.
+        */
+       .Reserved = NULL,
+#endif
+       .RegisterProtocolNotify = mock_efi_unsupported,
+       .LocateHandle = mock_efi_not_found,
+       .LocateDevicePath = mock_efi_unsupported,
+       .InstallConfigurationTable = mock_efi_unsupported,
+
+       .LoadImage = (void *)mock_efi_unsupported,
+       .StartImage = mock_efi_unsupported,
+       .Exit = mock_efi_unsupported,
+       .UnloadImage = mock_efi_unsupported,
+       .ExitBootServices = mock_efi_unsupported,
+
+       .GetNextMonotonicCount = mock_efi_unsupported,
+       .Stall = mock_efi_unsupported,
+       .SetWatchdogTimer = mock_efi_unsupported,
+
+       .ConnectController = (void *)mock_efi_unsupported,
+       .DisconnectController = mock_efi_unsupported,
+
+       .OpenProtocol = mock_efi_unsupported,
+       .CloseProtocol = mock_efi_unsupported,
+       .OpenProtocolInformation = mock_efi_unsupported,
+
+       .ProtocolsPerHandle = mock_efi_unsupported,
+       .LocateHandleBuffer = mock_efi_unsupported,
+       .LocateProtocol = mock_efi_unsupported,
+
+       .InstallMultipleProtocolInterfaces = (void *)mock_efi_unsupported,
+       .UninstallMultipleProtocolInterfaces = (void *)mock_efi_unsupported,
+
+       .CalculateCrc32 = mock_efi_unsupported,
+
+       .CopyMem = NULL,
+       .SetMem = NULL,
+       .CreateEventEx = mock_efi_unsupported,
+};
+
+EFI_RUNTIME_SERVICES mock_rt, mock_default_rt = {
+       .Hdr = {
+               .Signature = EFI_RUNTIME_SERVICES_SIGNATURE,
+               .Revision = EFI_1_10_RUNTIME_SERVICES_REVISION,
+               .HeaderSize = offsetof(EFI_RUNTIME_SERVICES, ResetSystem)
+                             + sizeof(mock_rt.ResetSystem),
+       },
+
+       .GetTime = mock_efi_unsupported,
+       .SetTime = mock_efi_unsupported,
+       .GetWakeupTime = mock_efi_unsupported,
+       .SetWakeupTime = (void *)mock_efi_unsupported,
+
+       .SetVirtualAddressMap = mock_efi_unsupported,
+       .ConvertPointer = mock_efi_unsupported,
+
+       .GetVariable = mock_efi_unsupported,
+       .SetVariable = mock_efi_unsupported,
+       .GetNextVariableName = mock_efi_unsupported,
+
+       .GetNextHighMonotonicCount = mock_efi_unsupported,
+       .ResetSystem = mock_efi_unsupported,
+
+       .UpdateCapsule = mock_efi_unsupported,
+       .QueryCapsuleCapabilities = mock_efi_unsupported,
+
+       .QueryVariableInfo = mock_efi_unsupported,
+};
 
-       UINTN i;
-       for (i = 0; i < len && s1[i] && s2[i]; i++) {
-               if (s1[i] != s2[i])
-                       return s2[i] - s1[i];
+EFI_SYSTEM_TABLE mock_st, mock_default_st = {
+       .Hdr = {
+               .Signature = EFI_SYSTEM_TABLE_SIGNATURE,
+               .Revision = EFI_1_10_SYSTEM_TABLE_REVISION,
+               .HeaderSize = sizeof(EFI_SYSTEM_TABLE),
+       },
+       .BootServices = &mock_bs,
+       .RuntimeServices = &mock_rt,
+};
 
+void CONSTRUCTOR
+init_efi_system_table(void)
+{
+       static bool once = true;
+       if (once) {
+               once = false;
+               reset_efi_system_table();
        }
-       return 0;
 }
 
-EFI_STATUS
-get_variable_attr(const CHAR16 * const var, UINT8 **data, UINTN *len,
-                 EFI_GUID owner, UINT32 *attributes)
+void
+reset_efi_system_table(void)
 {
-       return EFI_UNSUPPORTED;
+       ST = &mock_st;
+       BS = &mock_bs;
+       RT = &mock_rt;
+
+       memcpy(&mock_bs, &mock_default_bs, sizeof(mock_bs));
+       memcpy(&mock_rt, &mock_default_rt, sizeof(mock_rt));
+       memcpy(&mock_st, &mock_default_st, sizeof(mock_st));
 }
 
-EFI_STATUS
-get_variable(const CHAR16 * const var, UINT8 **data, UINTN *len, EFI_GUID owner)
+EFI_STATUS EFIAPI
+LogError_(const char *file, int line, const char *func, const CHAR16 *fmt, ...)
 {
-       return get_variable_attr(var, data, len, owner, NULL);
+       assert(0);
+       return EFI_SUCCESS;
 }
 
+#ifndef HAVE_SHIM_LOCK_GUID
 EFI_GUID SHIM_LOCK_GUID = {0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } };
+#endif
+
+UINTN EFIAPI
+console_print(const CHAR16 *fmt, ...)
+{
+       return 0;
+}
+
+#ifndef HAVE_START_IMAGE
+EFI_STATUS
+start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
+{
+       return EFI_UNSUPPORTED;
+}
+#endif
 
 // vim:fenc=utf-8:tw=75:noet
diff --git a/tpm.c b/tpm.c
index 808e0444eb65904a124dd6c17e1b9b4593c43b62..41f36651e19e643752fe3cd3c88dbb8af1040b38 100644 (file)
--- a/tpm.c
+++ b/tpm.c
@@ -10,6 +10,7 @@ typedef struct {
 
 UINTN measuredcount = 0;
 VARIABLE_RECORD *measureddata = NULL;
+static BOOLEAN tpm_defective = FALSE;
 
 static BOOLEAN tpm_present(efi_tpm_protocol_t *tpm)
 {
@@ -18,6 +19,9 @@ static BOOLEAN tpm_present(efi_tpm_protocol_t *tpm)
        UINT32 flags;
        EFI_PHYSICAL_ADDRESS eventlog, lastevent;
 
+       if (tpm_defective)
+               return FALSE;
+
        caps.Size = (UINT8)sizeof(caps);
        efi_status = tpm->status_check(tpm, &caps, &flags,
                                       &eventlog, &lastevent);
@@ -192,6 +196,12 @@ static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
                                (UINT64)size, TPM_ALG_SHA, event, &eventnum,
                                &lastevent);
                }
+               if (efi_status == EFI_UNSUPPORTED) {
+                       perror(L"Could not write TPM event: %r. Considering "
+                              "the TPM as defective.\n", efi_status);
+                       tpm_defective = TRUE;
+                       efi_status = EFI_SUCCESS;
+               }
                FreePool(event);
                return efi_status;
        }
@@ -353,3 +363,25 @@ fallback_should_prefer_reset(void)
                return EFI_NOT_FOUND;
        return EFI_SUCCESS;
 }
+
+#ifdef SHIM_UNIT_TEST
+static void DESTRUCTOR
+tpm_clean_up_measurements(void)
+{
+       for (UINTN i = 0; i < measuredcount; i++) {
+               VARIABLE_RECORD *vr = &measureddata[i];
+
+               if (vr->VariableName)
+                       FreePool(vr->VariableName);
+               if (vr->VendorGuid)
+                       FreePool(vr->VendorGuid);
+               if (vr->Data)
+                       FreePool(vr->Data);
+       }
+       if (measureddata)
+               FreePool(measureddata);
+
+       measuredcount = 0;
+       measureddata = NULL;
+}
+#endif