Version in base suite: 15.4-7~deb10u1 Base version: shim_15.4-7~deb10u1 Target version: shim_15.6-1~deb10u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/s/shim/shim_15.4-7~deb10u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/s/shim/shim_15.6-1~deb10u1.dsc /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AMITSESetup-c811fa38-42c8-4579-a9bb-60e94eddfb34 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AOD_SETUP-5ed15dc0-edef-4161-9151-6014c4cc630c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AmdAcpiVar-79941ecd-ed36-49d0-8124-e4c31ac75cd4 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AmdSetup-3a997502-647a-4c82-998e-52ef9486a247 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AmiHardwareSignatureSetupUpdateCountVar-81c76078-bfde-4368-9790-570914c01a65 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ApSyncFlagNv-ad3f6761-f0a3-46c8-a4cb-19b70ffdb305 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsbkpInfo-cb825795-feb1-4c0b-894f-cc70f8064395 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusExtFancard-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusFanSetupFeatures-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusHwmSetupOneof-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusNodePsu-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusQFanSetupData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusRomLayout-7186d975-2dba-4413-81a8-9f1538faef5e |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusSetupDataBackup-1111b056-c5e9-40ca-aba3-ec172533d814 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AutoDetectData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BiosEventLog-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0004-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0005-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0006-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BootFromUSB-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/CMOSfailflag-c89dc9c7-5105-472c-a743-b1621e142b41 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/CurrentPolicy-77fa9abd-0359-4d32-bd60-28f4e78f784b |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/DefaultBootOrder-45cf35f6-0d6e-4d04-856a-0370a5b16f53 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/DeploymentModeNv-97e8965f-c761-4f48-b6e4-9ffa9cb2a2d6 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/DownCoreStatus-29749bad-401b-4f6d-b124-cece8c590c48 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/EnWpData-cbab171f-f356-4009-baaa-6628353a0a29 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/FPLayoutOrder-4db88a62-6721-47a0-9082-280b00323594 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/FTMActiveFlag-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/FastBootOption-b540a530-6978-4da7-91cb-7207d764d262 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/FirstBootFlag-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/HddSmartInfo-a6f44860-b2e8-4fda-bd45-78368994b6ae |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/HiiDB-1b838190-4625-4ead-abc9-cd5e6af18fe0 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/HwErrRecSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/KEKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_ATPSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_DriverSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_RvkSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_SiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_SkuSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_WinSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/LastBoot-b540a530-6978-4da7-91cb-7207d764d262 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MaximumTableSize-4b3082a3-80c6-4d7e-9cd0-583917265df1 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MemoryOverwriteRequestControlLock-bb983ccf-151d-40e1-a07b-4a17be168292 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MokList-605dab50-e046-4300-abb6-3dd810dd8b23 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MokListX-605dab50-e046-4300-abb6-3dd810dd8b23 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MonotonicCounter-01368881-c4ad-4b1d-b631-d57a8ec8db6b |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MyFav-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/NVRAM_Verify-15a9dd61-e4f8-4a99-80db-353b13d76490 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/NetworkStackVar-d1405d16-7afc-4695-bb12-41459d3695a2 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/NvHdd0-e57abcbd-9456-4639-8f65-06aab41d840f |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/NvHdd8-e57abcbd-9456-4639-8f65-06aab41d840f |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/OsIndications-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PCI_COMMON-aca9f304-21e2-4852-9875-7ff4881d67a5 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PcieSataModVar-5e9a565f-cdc0-413b-ad13-1fe8713ffdcd |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PreVgaInfo-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/RsdpAddr-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SIDSUPPORT-7d3dceee-cbce-4ea7-8709-6e552f1edbde |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SecureBootSetup-7b59104a-c00d-4158-87ff-f04d6396a915 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Setup-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SetupLedData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SmbiosEntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SmbiosScratchBuffer-4b3082a3-80c6-4d7e-9cd0-583917265df1 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SmbiosV3EntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/StdDefaults-4599d26f-1a11-49b8-b91f-858745cff824 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/TPMPERBIOSFLAGS-7d3dceee-cbce-4ea7-8709-6e552f1edbde |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/TotalNumberOfRootBridges-fb5703f5-f8a7-f401-18b4-3f108deb2612 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/TpmServFlags-7d3dceee-cbce-4ea7-8709-6e552f1edbde |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/UsbSupport-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/VARSTORE_OCMR_SETTINGS_NAME-c05fba7d-7a92-49e0-bcee-233b14dca803 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/WpBufAddr-cba83c4a-a5fc-48a8-b3a6-d33636166544 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/WriteOnceStatus-4b3082a3-80c6-4d7e-9cd0-583917265df1 |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f |binary /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c |binary shim-15.6/.github/workflows/pullrequest.yml | 64 shim-15.6/.gitignore | 9 shim-15.6/.gitmodules | 2 shim-15.6/BUILDING | 9 shim-15.6/CODE_OF_CONDUCT.md | 134 shim-15.6/Cryptlib/Hash/CryptMd5.c | 2 shim-15.6/Cryptlib/Hash/CryptSha1.c | 2 shim-15.6/Cryptlib/Hash/CryptSha256.c | 2 shim-15.6/Cryptlib/Hash/CryptSha512.c | 4 shim-15.6/Cryptlib/Include/OpenSslSupport.h | 4 shim-15.6/Cryptlib/Pk/CryptPkcs7Verify.c | 2 shim-15.6/Make.defaults | 19 shim-15.6/Make.rules | 3 shim-15.6/Makefile | 58 shim-15.6/MokManager.c | 296 +- shim-15.6/MokVars.txt | 6 shim-15.6/SBAT.example.md | 4 shim-15.6/SBAT.md | 48 shim-15.6/commit | 2 shim-15.6/csv.c | 14 shim-15.6/data/sbat.csv | 2 shim-15.6/debian/changelog | 12 shim-15.6/debian/control | 3 shim-15.6/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch | 62 shim-15.6/debian/patches/MOK-BootServicesData.patch | 34 shim-15.6/debian/patches/aarch64-gnuefi-old.patch | 184 + shim-15.6/debian/patches/aarch64-shim-old.patch | 190 + shim-15.6/debian/patches/fix-broken-ia32-reloc.patch | 27 shim-15.6/debian/patches/fix-import_one_mok_state.patch | 36 shim-15.6/debian/patches/fix_arm64_rela_sections.patch | 132 shim-15.6/debian/patches/relax_check_for_import_mok_state.patch | 53 shim-15.6/debian/patches/series | 8 shim-15.6/debian/rules | 3 shim-15.6/elf_aarch64_efi.lds | 125 shim-15.6/elf_arm_efi.lds | 24 shim-15.6/elf_ia32_efi.lds | 1 shim-15.6/fallback.c | 170 - shim-15.6/globals.c | 36 shim-15.6/gnu-efi/Make.defaults | 9 shim-15.6/gnu-efi/gnuefi/crt0-efi-aarch64.S | 143 - shim-15.6/gnu-efi/gnuefi/crt0-efi-ia32.S | 8 shim-15.6/gnu-efi/gnuefi/crt0-efi-x86_64.S | 10 shim-15.6/gnu-efi/inc/efiapi.h | 8 shim-15.6/gnu-efi/inc/efidef.h | 7 shim-15.6/gnu-efi/inc/efilib.h | 6 shim-15.6/gnu-efi/inc/efiprot.h | 35 shim-15.6/gnu-efi/lib/misc.c | 6 shim-15.6/gnu-efi/lib/str.c | 2 shim-15.6/httpboot.c | 49 shim-15.6/include/asm.h | 6 shim-15.6/include/compiler.h | 4 shim-15.6/include/console.h | 7 shim-15.6/include/efiauthenticated.h | 6 shim-15.6/include/guid.h | 2 shim-15.6/include/hexdump.h | 14 shim-15.6/include/load-options.h | 20 shim-15.6/include/mock-variables.h | 199 + shim-15.6/include/mok.h | 109 shim-15.6/include/pe.h | 8 shim-15.6/include/peimage.h | 66 shim-15.6/include/sbat.h | 41 shim-15.6/include/str.h | 2 shim-15.6/include/system/stdarg.h | 2 shim-15.6/include/test-data-efivars-0.h | 554 +++ shim-15.6/include/test-data-efivars-1.h | 110 shim-15.6/include/test.h | 529 +++ shim-15.6/include/test.mk | 99 shim-15.6/include/ucs2.h | 27 shim-15.6/lib/Makefile | 4 shim-15.6/lib/console.c | 99 shim-15.6/lib/execute.c | 10 shim-15.6/lib/guid.c | 2 shim-15.6/lib/security_policy.c | 2 shim-15.6/lib/shell.c | 2 shim-15.6/lib/simple_file.c | 20 shim-15.6/lib/variables.c | 56 shim-15.6/load-options.c | 456 +++ shim-15.6/mock-variables.c | 1400 ++++++++++ shim-15.6/mok.c | 260 - shim-15.6/netboot.c | 4 shim-15.6/pe.c | 403 ++ shim-15.6/post-process-pe.c | 547 +++ shim-15.6/replacements.c | 39 shim-15.6/sbat.c | 139 shim-15.6/shim.c | 849 ++---- shim-15.6/shim.h | 26 shim-15.6/test-csv.c | 63 shim-15.6/test-load-options.c | 269 + shim-15.6/test-mock-variables.c | 842 ++++++ shim-15.6/test-mok-mirror.c | 405 ++ shim-15.6/test-sbat.c | 113 shim-15.6/test-str.c | 21 shim-15.6/test.c | 275 + shim-15.6/tpm.c | 32 208 files changed, 8379 insertions(+), 1833 deletions(-) diff -Nru shim-15.4/.github/workflows/pullrequest.yml shim-15.6/.github/workflows/pullrequest.yml --- shim-15.4/.github/workflows/pullrequest.yml 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/.github/workflows/pullrequest.yml 2022-06-01 18:25:48.000000000 +0000 @@ -15,88 +15,64 @@ name: ${{ matrix.distro }} ${{ matrix.efiarch }} cross-build strategy: + fail-fast: false matrix: include: - arch: amd64 efiarch: aa64 gccarch: aarch64 makearch: aarch64 - distro: f35 - - arch: amd64 - efiarch: aa64 - gccarch: aarch64 - makearch: aarch64 - distro: f34 + distro: f36 - arch: amd64 efiarch: aa64 gccarch: aarch64 makearch: aarch64 - distro: f33 - - arch: amd64 - efiarch: aa64 - gccarch: aarch64 - makearch: aarch64 - distro: f32 - - arch: amd64 - efiarch: arm - gccarch: arm - makearch: arm distro: f35 - arch: amd64 efiarch: arm gccarch: arm makearch: arm - distro: f34 + distro: f36 - arch: amd64 efiarch: arm gccarch: arm makearch: arm - distro: f33 + distro: f35 - arch: amd64 efiarch: arm gccarch: arm makearch: arm - distro: f32 - - arch: amd64 - efiarch: x64 - gccarch: x86_64 - makearch: x86_64 - distro: f35 + distro: f34 - arch: amd64 efiarch: x64 gccarch: x86_64 makearch: x86_64 - distro: f34 + distro: f36 - arch: amd64 efiarch: x64 gccarch: x86_64 makearch: x86_64 - distro: f33 + distro: f35 - arch: amd64 efiarch: x64 gccarch: x86_64 makearch: x86_64 - distro: f32 - - arch: amd64 - efiarch: ia32 - gccarch: x86_64 - makearch: ia32 - distro: f35 + distro: f34 - arch: amd64 efiarch: ia32 gccarch: x86_64 makearch: ia32 - distro: f34 + distro: f36 - arch: amd64 efiarch: ia32 gccarch: x86_64 makearch: ia32 - distro: f33 + distro: f35 - arch: amd64 efiarch: ia32 gccarch: x86_64 makearch: ia32 - distro: f32 + distro: f34 steps: - name: Checkout @@ -142,19 +118,19 @@ - arch: amd64 efiarch: x64 makearch: x86_64 - distro: f35 + distro: f36 - arch: amd64 efiarch: x64 makearch: x86_64 - distro: f34 + distro: f35 - arch: amd64 efiarch: x64 makearch: x86_64 - distro: f33 + distro: f34 - arch: amd64 efiarch: x64 makearch: x86_64 - distro: f32 + distro: centos9 - arch: amd64 efiarch: x64 makearch: x86_64 @@ -166,19 +142,15 @@ - arch: amd64 efiarch: ia32 makearch: ia32 - distro: f35 + distro: f36 - arch: amd64 efiarch: ia32 makearch: ia32 - distro: f34 - - arch: amd64 - efiarch: ia32 - makearch: ia32 - distro: f33 + distro: f35 - arch: amd64 efiarch: ia32 makearch: ia32 - distro: f32 + distro: f34 - arch: amd64 efiarch: ia32 makearch: ia32 diff -Nru shim-15.4/.gitignore shim-15.6/.gitignore --- shim-15.4/.gitignore 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/.gitignore 2022-06-01 18:25:48.000000000 +0000 @@ -14,7 +14,10 @@ *.efi.debug *.efi.signed *.esl -*.gdbinit +*.gdb* +*.gcda +*.gcno +*.gcov *.hash *.key *.key @@ -27,8 +30,11 @@ *.sw? *.tar.* /build*/ +/.cache/ /certdb/ +/compile_commands.json /cov-int/ +/post-process-pe /random.bin /sbat.*.csv /scan-results/ @@ -36,5 +42,6 @@ shim_cert.h /test-* !/test-*.c +!/test-data/ /test-random.h version.c diff -Nru shim-15.4/.gitmodules shim-15.6/.gitmodules --- shim-15.4/.gitmodules 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/.gitmodules 2022-06-01 18:25:48.000000000 +0000 @@ -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.6 diff -Nru shim-15.4/BUILDING shim-15.6/BUILDING --- shim-15.4/BUILDING 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/BUILDING 2022-06-01 18:25:48.000000000 +0000 @@ -35,7 +35,8 @@ If this is set, we look for SHIM_DEVEL_DEBUG instead of SHIM_DEBUG in our debugger delay hook, thus meaning you can have it pause for a debugger only on the development branch and not the OS you need to boot - to scp in a new development build. + to scp in a new development build. Likewise, we look for + SHIM_DEVEL_VERBOSE rather than SHIM_VERBOSE. - DISABLE_EBS_PROTECTION On systems where a second stage bootloader is not used, and the Linux Kernel is embedded in the same EFI image as shim and booted directly @@ -45,6 +46,12 @@ 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 diff -Nru shim-15.4/CODE_OF_CONDUCT.md shim-15.6/CODE_OF_CONDUCT.md --- shim-15.4/CODE_OF_CONDUCT.md 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/CODE_OF_CONDUCT.md 2022-06-01 18:25:48.000000000 +0000 @@ -0,0 +1,134 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +rharwood AT redhat DOT com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available +at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff -Nru shim-15.4/Cryptlib/Hash/CryptMd5.c shim-15.6/Cryptlib/Hash/CryptMd5.c --- shim-15.4/Cryptlib/Hash/CryptMd5.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Cryptlib/Hash/CryptMd5.c 2022-06-01 18:25:48.000000000 +0000 @@ -93,7 +93,7 @@ return FALSE; } - CopyMem (NewMd5Context, Md5Context, sizeof (MD5_CTX)); + CopyMem (NewMd5Context, (void *)Md5Context, sizeof (MD5_CTX)); return TRUE; } diff -Nru shim-15.4/Cryptlib/Hash/CryptSha1.c shim-15.6/Cryptlib/Hash/CryptSha1.c --- shim-15.4/Cryptlib/Hash/CryptSha1.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Cryptlib/Hash/CryptSha1.c 2022-06-01 18:25:48.000000000 +0000 @@ -92,7 +92,7 @@ return FALSE; } - CopyMem (NewSha1Context, Sha1Context, sizeof (SHA_CTX)); + CopyMem (NewSha1Context, (void *)Sha1Context, sizeof (SHA_CTX)); return TRUE; } diff -Nru shim-15.4/Cryptlib/Hash/CryptSha256.c shim-15.6/Cryptlib/Hash/CryptSha256.c --- shim-15.4/Cryptlib/Hash/CryptSha256.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Cryptlib/Hash/CryptSha256.c 2022-06-01 18:25:48.000000000 +0000 @@ -91,7 +91,7 @@ return FALSE; } - CopyMem (NewSha256Context, Sha256Context, sizeof (SHA256_CTX)); + CopyMem (NewSha256Context, (void *)Sha256Context, sizeof (SHA256_CTX)); return TRUE; } diff -Nru shim-15.4/Cryptlib/Hash/CryptSha512.c shim-15.6/Cryptlib/Hash/CryptSha512.c --- shim-15.4/Cryptlib/Hash/CryptSha512.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Cryptlib/Hash/CryptSha512.c 2022-06-01 18:25:48.000000000 +0000 @@ -93,7 +93,7 @@ return FALSE; } - CopyMem (NewSha384Context, Sha384Context, sizeof (SHA512_CTX)); + CopyMem (NewSha384Context, (void *)Sha384Context, sizeof (SHA512_CTX)); return TRUE; } @@ -308,7 +308,7 @@ return FALSE; } - CopyMem (NewSha512Context, Sha512Context, sizeof (SHA512_CTX)); + CopyMem (NewSha512Context, (void *)Sha512Context, sizeof (SHA512_CTX)); return TRUE; } diff -Nru shim-15.4/Cryptlib/Include/OpenSslSupport.h shim-15.6/Cryptlib/Include/OpenSslSupport.h --- shim-15.4/Cryptlib/Include/OpenSslSupport.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Cryptlib/Include/OpenSslSupport.h 2022-06-01 18:25:48.000000000 +0000 @@ -262,11 +262,11 @@ // // Macros that directly map functions to BaseLib, BaseMemoryLib, and DebugLib functions // -#define memcpy(dest,source,count) ( {CopyMem(dest,source,(UINTN)(count)); dest; }) +#define memcpy(dest,source,count) ( {CopyMem(dest,(void *)source,(UINTN)(count)); dest; }) #define memset(dest,ch,count) SetMem(dest,(UINTN)(count),(UINT8)(ch)) #define memchr(buf,ch,count) ScanMem8((CHAR8 *)buf,(UINTN)(count),ch) #define memcmp(buf1,buf2,count) (int)(CompareMem(buf1,buf2,(UINTN)(count))) -#define memmove(dest,source,count) CopyMem(dest,source,(UINTN)(count)) +#define memmove(dest,source,count) CopyMem(dest,(void *)source,(UINTN)(count)) #define localtime(timer) NULL #define assert(expression) #define atoi(nptr) AsciiStrDecimalToUintn((const CHAR8 *)nptr) diff -Nru shim-15.4/Cryptlib/Pk/CryptPkcs7Verify.c shim-15.6/Cryptlib/Pk/CryptPkcs7Verify.c --- shim-15.4/Cryptlib/Pk/CryptPkcs7Verify.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Cryptlib/Pk/CryptPkcs7Verify.c 2022-06-01 18:25:48.000000000 +0000 @@ -216,7 +216,7 @@ // // Part7: P7Data. // - CopyMem (SignedData + 19, P7Data, P7Length); + CopyMem (SignedData + 19, (void *)P7Data, P7Length); } *WrapFlag = Wrapped; diff -Nru shim-15.4/Make.defaults shim-15.6/Make.defaults --- shim-15.4/Make.defaults 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Make.defaults 2022-06-01 18:25:48.000000000 +0000 @@ -52,7 +52,11 @@ 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 @@ 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,18 +78,14 @@ 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 ARCH_GNUEFI ?= aarch64 ARCH_SUFFIX ?= aa64 ARCH_SUFFIX_UPPER ?= AA64 - FORMAT := -O binary - SUBSYSTEM := 0xa - ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM) + ARCH_LDFLAGS ?= ARCH_CFLAGS ?= - TIMESTAMP_LOCATION := 72 endif ifeq ($(ARCH),arm) ARCH_CFLAGS ?= -DMDE_CPU_ARM -DPAGE_SIZE=4096 -mno-unaligned-access @@ -96,7 +95,6 @@ FORMAT := -O binary SUBSYSTEM := 0xa ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM) - TIMESTAMP_LOCATION := 72 endif DEFINES = -DDEFAULT_LOADER='L"$(DEFAULT_LOADER)"' \ @@ -135,6 +133,7 @@ CFLAGS = $(FEATUREFLAGS) \ $(OPTIMIZATIONS) \ $(WARNFLAGS) \ + $(if $(findstring clang,$(CC)),$(CLANG_WARNINGS)) \ $(ARCH_CFLAGS) \ $(WERRFLAGS) \ $(INCLUDES) \ @@ -152,6 +151,10 @@ 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) diff -Nru shim-15.4/Make.rules shim-15.6/Make.rules --- shim-15.4/Make.rules 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Make.rules 2022-06-01 18:25:48.000000000 +0000 @@ -35,4 +35,7 @@ $(eval override $(1)+=$(x))))) endef +%.o : %.S + $(CC) $(CFLAGS) -c -o $@ $< + # vim:filetype=make diff -Nru shim-15.4/Makefile shim-15.6/Makefile --- shim-15.4/Makefile 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/Makefile 2022-06-01 18:25:48.000000000 +0000 @@ -1,7 +1,7 @@ default : all NAME = shim -VERSION = 15.4 +VERSION = 15.6 ifneq ($(origin RELEASE),undefined) DASHRELEASE ?= -$(RELEASE) else @@ -38,12 +38,12 @@ 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) cert.S +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 @@ 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 @@ -104,9 +108,6 @@ endif shim.o: $(wildcard $(TOPDIR)/*.h) -cert.o : $(TOPDIR)/cert.S - $(CC) $(CFLAGS) -c -o $@ $< - sbat.%.csv : data/sbat.%.csv $(DOS2UNIX) $(D2UFLAGS) $< $@ tail -c1 $@ | read -r _ || echo >> $@ # ensure a trailing newline @@ -121,9 +122,10 @@ $@ $(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 +150,11 @@ 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)" \ + CCC_CC="$(COMPILER)" \ + CC="$(CC)" \ + ARCH=$(ARCH_GNUEFI) \ + TOPDIR=$(TOPDIR)/gnu-efi \ -f $(TOPDIR)/gnu-efi/Makefile \ lib gnuefi inc @@ -164,6 +170,9 @@ 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 +252,10 @@ 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 +268,7 @@ 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 +285,14 @@ $(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 +305,11 @@ 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 +321,7 @@ 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 diff -Nru shim-15.4/MokManager.c shim-15.6/MokManager.c --- shim-15.4/MokManager.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/MokManager.c 2022-06-01 18:25:48.000000000 +0000 @@ -41,6 +41,12 @@ } __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 @@ for (i = 0; i < n; i++) { CatPrint(&serial_string, L"%02x:", hexbuf[i]); } + BN_free(bnser); } if (serial_string.str) @@ -735,7 +742,7 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ return EFI_INVALID_PARAMETER; } - ST->ConOut->ClearScreen(ST->ConOut); + clear_screen(); message[0] = L"Change DB state"; message[1] = NULL; @@ -1656,25 +1663,138 @@ } if (var->MokDBState == 0) { - efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID, - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS, - 1, &dbval); + 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 = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID, + 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, 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; + } + } else { + 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 MokListTrusted state"); return efi_status; } } - return EFI_SUCCESS; } @@ -1691,7 +1811,7 @@ return EFI_INVALID_PARAMETER; } - ST->ConOut->ClearScreen(ST->ConOut); + clear_screen(); SetMem(hash, PASSWORD_CRYPT_SIZE, 0); @@ -1707,9 +1827,9 @@ 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 +1849,10 @@ 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 +2114,8 @@ *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 +2128,7 @@ 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 +2196,8 @@ 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 +2216,8 @@ 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 +2244,29 @@ 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 +2293,9 @@ if (MokDB) menucount++; + if (MokTML) + menucount++; + menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (menucount + 1)); if (!menu_strings) @@ -2242,6 +2367,12 @@ 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 +2483,17 @@ 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 +2518,7 @@ 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 +2526,7 @@ 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 +2579,18 @@ 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 +2613,7 @@ 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 +2636,9 @@ 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 +2654,7 @@ UINT64 seed; BOOLEAN status; - efi_status = gRT->GetTime(&time, NULL); + efi_status = RT->GetTime(&time, NULL); if (EFI_ERROR(efi_status)) return efi_status; diff -Nru shim-15.4/MokVars.txt shim-15.6/MokVars.txt --- shim-15.4/MokVars.txt 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/MokVars.txt 2022-06-01 18:25:48.000000000 +0000 @@ -77,3 +77,9 @@ 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 diff -Nru shim-15.4/SBAT.example.md shim-15.6/SBAT.example.md --- shim-15.4/SBAT.example.md 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/SBAT.example.md 2022-06-01 18:25:48.000000000 +0000 @@ -16,7 +16,7 @@ `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 @@ 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 -Nru shim-15.4/SBAT.md shim-15.6/SBAT.md --- shim-15.4/SBAT.md 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/SBAT.md 2022-06-01 18:25:48.000000000 +0000 @@ -6,7 +6,7 @@ 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 @@ #### 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 @@ 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 @@ 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 @@ 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 @@ customer impact with as few re-releases as possible, while not creating an unnecessarily large UEFI revocation variable payload. -| | prior to
disclosure | after
disclosure | after Vendor C's
first update | after Vendor C's
second update | after next global
disclosure | +| | prior to
disclosure\* | after
disclosure | after Vendor C's
first update | after Vendor C's
second update | after next global
disclosure | |--------------------------------------------------------------------------------------|------------------------|---------------------|----------------------------------|----------------------------------|---------------------------------| | GRUB global
generation number in
artifacts .sbat section | 3 | 4 | 4 | 4 | 5 | -| Vendor C's product-specific
generation number in artifact's
.sbat section | 1 | 1 | 5 | 6 | 1 | +| Vendor C's product-specific
generation number in artifact's
.sbat section | 1 | 1 | 2 | 3 | 1 | | GRUB global
generation number in
UEFI SBAT revocation variable | 3 | 4 | 4 | 4 | 5 | -| Vendor C's product-specific
generation number in
UEFI SBAT revocation variable | not set | not set | 5 | 6 | not set | +| Vendor C's product-specific
generation number in
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 @@ 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 @@ 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 @@ 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 @@ | 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 -Nru shim-15.4/commit shim-15.6/commit --- shim-15.4/commit 2021-03-30 21:04:30.000000000 +0000 +++ shim-15.6/commit 2022-06-01 18:27:14.000000000 +0000 @@ -1 +1 @@ -20e4d9486fcae54ee44d2323ae342ffe68c920e6 \ No newline at end of file +505cdb678b319fcf9a7fdee77c0f091b4147cbe5 \ No newline at end of file diff -Nru shim-15.4/csv.c shim-15.6/csv.c --- shim-15.4/csv.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/csv.c 2022-06-01 18:25:48.000000000 +0000 @@ -15,6 +15,7 @@ char *token = NULL; bool valid = true; + for (n = 0; n < *n_columns; n++) { if (valid) { @@ -62,19 +63,21 @@ } 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 @@ } } } + /* 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_line(line, max, &m_columns, (const char **)entry->columns); entry->n_columns = m_columns; + if (eof) + break; + line = end + 1; } diff -Nru shim-15.4/data/sbat.csv shim-15.6/data/sbat.csv --- shim-15.4/data/sbat.csv 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/data/sbat.csv 2022-06-01 18:25:48.000000000 +0000 @@ -1,2 +1,2 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -shim,1,UEFI shim,shim,1,https://github.com/rhboot/shim +shim,2,UEFI shim,shim,1,https://github.com/rhboot/shim diff -Nru shim-15.4/debian/changelog shim-15.6/debian/changelog --- shim-15.4/debian/changelog 2021-07-12 07:59:53.000000000 +0000 +++ shim-15.6/debian/changelog 2022-07-28 06:46:16.000000000 +0000 @@ -1,3 +1,15 @@ +shim (15.6-1~deb10u1) buster; urgency=medium + + * New upstream release fixing more bugs + + Remove all our old patches, all now upstream: + - fix-32b-format-strings.patch + - fix-test-includes.patch + * Rebuild for buster + + Add new patches reverting arm64 build system changes so we can + build using older binutils. + + -- Steve McIntyre <93sam@debian.org> Thu, 28 Jul 2022 07:46:16 +0100 + shim (15.4-7~deb10u1) buster; urgency=high * Tweak how we call grub-install; don't abort on error. Not ideal diff -Nru shim-15.4/debian/control shim-15.6/debian/control --- shim-15.4/debian/control 2021-07-12 07:59:53.000000000 +0000 +++ shim-15.6/debian/control 2022-07-28 06:46:16.000000000 +0000 @@ -11,7 +11,8 @@ gcc-8, dos2unix, pesign (>= 0.112-5), - xxd + xxd, + libefivar-dev Vcs-Browser: https://salsa.debian.org/efi-team/shim Vcs-Git: https://salsa.debian.org/efi-team/shim.git diff -Nru shim-15.4/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch shim-15.6/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch --- shim-15.4/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch 2021-04-21 00:04:51.000000000 +0000 +++ shim-15.6/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -From 8b59591775a0412863aab9596ab87bdd493a9c1e Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Sat, 10 Apr 2021 16:05:23 -0400 -Subject: [PATCH] Don't call QueryVariableInfo() on EFI 1.10 machines - -The EFI 1.10 spec (and presumably earlier revisions as well) didn't have -RT->QueryVariableInfo(), and on Chris Murphy's MacBookPro8,2 , that -memory appears to be initialized randomly. - -This patch changes it to not call RT->QueryVariableInfo() if the -EFI_RUNTIME_SERVICES table's major revision is less than two, and -assumes our maximum variable size is 1024 in that case. - -Signed-off-by: Peter Jones ---- - mok.c | 23 ++++++++++++++++++----- - 1 file changed, 18 insertions(+), 5 deletions(-) - -diff --git a/mok.c b/mok.c -index 9b8fc2bc..beac0ff6 100644 ---- a/mok.c -+++ b/mok.c -@@ -261,6 +261,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 +273,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(gRT) < 2) { -+ dprint(L"EFI %d.%d; no RT->QueryVariableInfo(). Using 1024!\n", -+ EFI_MAJOR_VERSION(gRT), EFI_MINOR_VERSION(gRT)); -+ max_var_sz = remaining_sz = max_storage_sz = 1024; -+ efi_status = EFI_SUCCESS; -+ } else { -+ dprint(L"calling RT->QueryVariableInfo() at 0x%lx\n", -+ gRT->QueryVariableInfo); -+ 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; -+ } - } - - /* --- -2.20.1 - diff -Nru shim-15.4/debian/patches/MOK-BootServicesData.patch shim-15.6/debian/patches/MOK-BootServicesData.patch --- shim-15.4/debian/patches/MOK-BootServicesData.patch 2021-04-14 20:45:09.000000000 +0000 +++ shim-15.6/debian/patches/MOK-BootServicesData.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -commit 4068fd42c891ea6ebdec056f461babc6e4048844 -Author: Gary Lin -Date: Thu Apr 8 16:23:03 2021 +0800 - - mok: allocate MOK config table as BootServicesData - - Linux kernel is picky when reserving the memory for x86 and it only - expects BootServicesData: - - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/platform/efi/quirks.c?h=v5.11#n254 - - Otherwise, the following error would show during system boot: - - Apr 07 12:31:56.743925 localhost kernel: efi: Failed to lookup EFI memory descriptor for 0x000000003dcf8000 - - Although BootServicesData would be reclaimed after ExitBootService(), - linux kernel reserves MOK config table when it detects the existence of - the table, so it's fine to allocate the table as BootServicesData. - - Signed-off-by: Gary Lin - -diff --git a/mok.c b/mok.c -index 9e37d6ab..9b8fc2bc 100644 ---- a/mok.c -+++ b/mok.c -@@ -999,7 +999,7 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle) - npages = ALIGN_VALUE(config_sz, PAGE_SIZE) >> EFI_PAGE_SHIFT; - config_table = NULL; - efi_status = gBS->AllocatePages(AllocateAnyPages, -- EfiRuntimeServicesData, -+ EfiBootServicesData, - npages, - (EFI_PHYSICAL_ADDRESS *)&config_table); - if (EFI_ERROR(efi_status) || !config_table) { diff -Nru shim-15.4/debian/patches/aarch64-gnuefi-old.patch shim-15.6/debian/patches/aarch64-gnuefi-old.patch --- shim-15.4/debian/patches/aarch64-gnuefi-old.patch 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/debian/patches/aarch64-gnuefi-old.patch 2022-07-28 06:46:16.000000000 +0000 @@ -0,0 +1,184 @@ +shim 15.6 onwards needs newer binutils to build on aarch64. That works +better, but we don't have that binutils update in older Debian +releases. Undo the build changes here so that we can build for aarch64 +on older stable releases. We're not going to sign them, but we need +the binaries for aarch64. + +diff --git a/gnu-efi/Make.defaults b/gnu-efi/Make.defaults +index 3b56150..5ce8f7c 100755 +--- a/gnu-efi/Make.defaults ++++ b/gnu-efi/Make.defaults +@@ -153,11 +153,13 @@ endif + # Set HAVE_EFI_OBJCOPY if objcopy understands --target efi-[app|bsdrv|rtdrv], + # otherwise we need to compose the PE/COFF header using the assembler + # ++ifneq ($(ARCH),aarch64) + ifneq ($(ARCH),arm) + ifneq ($(ARCH),mips64el) + export HAVE_EFI_OBJCOPY=y + endif + endif ++endif + + ifeq ($(ARCH),arm) + CFLAGS += -marm +diff --git a/gnu-efi/gnuefi/crt0-efi-aarch64.S b/gnu-efi/gnuefi/crt0-efi-aarch64.S +index 37a3bd9..a96b5eb 100644 +--- a/gnu-efi/gnuefi/crt0-efi-aarch64.S ++++ b/gnu-efi/gnuefi/crt0-efi-aarch64.S +@@ -16,11 +16,136 @@ + * either version 2 of the License, or (at your option) any later version. + */ + ++ .section .text.head + +- .text +- .align 12 ++ /* ++ * Magic "MZ" signature for PE/COFF ++ */ ++ .globl ImageBase ++ImageBase: ++ .ascii "MZ" ++ .skip 58 // 'MZ' + pad + offset == 64 ++ .long pe_header - ImageBase // Offset to the PE header. ++pe_header: ++ .ascii "PE" ++ .short 0 ++coff_header: ++ .short 0xaa64 // AArch64 ++ .short 4 // nr_sections ++ .long 0 // TimeDateStamp ++ .long 0 // PointerToSymbolTable ++ .long 1 // NumberOfSymbols ++ .short section_table - optional_header // SizeOfOptionalHeader ++ .short 0x206 // Characteristics. ++ // IMAGE_FILE_DEBUG_STRIPPED | ++ // IMAGE_FILE_EXECUTABLE_IMAGE | ++ // IMAGE_FILE_LINE_NUMS_STRIPPED ++optional_header: ++ .short 0x20b // PE32+ format ++ .byte 0x02 // MajorLinkerVersion ++ .byte 0x14 // MinorLinkerVersion ++ .long _text_size // SizeOfCode ++ .long _alldata_size // SizeOfInitializedData ++ .long 0 // SizeOfUninitializedData ++ .long _start - ImageBase // AddressOfEntryPoint ++ .long _start - ImageBase // BaseOfCode ++ ++extra_header_fields: ++ .quad 0 // ImageBase ++ .long 0x1000 // SectionAlignment ++ .long 0x200 // FileAlignment ++ .short 0 // MajorOperatingSystemVersion ++ .short 0 // MinorOperatingSystemVersion ++ .short 0 // MajorImageVersion ++ .short 0 // MinorImageVersion ++ .short 0 // MajorSubsystemVersion ++ .short 0 // MinorSubsystemVersion ++ .long 0 // Win32VersionValue ++ ++ .long _erodata - ImageBase // SizeOfImage ++ ++ // Everything before the kernel image is considered part of the header ++ .long _start - ImageBase // SizeOfHeaders ++ .long 0 // CheckSum ++ .short EFI_SUBSYSTEM // Subsystem ++ .short 0 // DllCharacteristics ++ .quad 0 // SizeOfStackReserve ++ .quad 0 // SizeOfStackCommit ++ .quad 0 // SizeOfHeapReserve ++ .quad 0 // SizeOfHeapCommit ++ .long 0 // LoaderFlags ++ .long 0x6 // NumberOfRvaAndSizes ++ ++ .quad 0 // ExportTable ++ .quad 0 // ImportTable ++ .quad 0 // ResourceTable ++ .quad 0 // ExceptionTable ++ .quad 0 // CertificationTable ++ .quad 0 // BaseRelocationTable ++ ++ // Section table ++section_table: ++ .ascii ".text\0\0\0" ++ .long _evtext - _start // VirtualSize ++ .long _start - ImageBase // VirtualAddress ++ .long _etext - _start // SizeOfRawData ++ .long _start - ImageBase // PointerToRawData ++ ++ .long 0 // PointerToRelocations (0 for executables) ++ .long 0 // PointerToLineNumbers (0 for executables) ++ .short 0 // NumberOfRelocations (0 for executables) ++ .short 0 // NumberOfLineNumbers (0 for executables) ++ /* ++ * EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_CNT_CODE ++ */ ++ .long 0x60000020 // Characteristics (section flags) ++ ++ .ascii ".data\0\0\0" ++ .long _data_vsize // VirtualSize ++ .long _data - ImageBase // VirtualAddress ++ .long _data_size // SizeOfRawData ++ .long _data - ImageBase // PointerToRawData + +- .globl _start ++ .long 0 // PointerToRelocations (0 for executables) ++ .long 0 // PointerToLineNumbers (0 for executables) ++ .short 0 // NumberOfRelocations (0 for executables) ++ .short 0 // NumberOfLineNumbers (0 for executables) ++ /* ++ * EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA ++ */ ++ .long 0xc0000040 // Characteristics (section flags) ++ ++ .ascii ".sbat\0\0\0" ++ .long _sbat_vsize // VirtualSize ++ .long _sbat - ImageBase // VirtualAddress ++ .long _sbat_size // SizeOfRawData ++ .long _sbat - ImageBase // PointerToRawData ++ ++ .long 0 // PointerToRelocations (0 for executables) ++ .long 0 // PointerToLineNumbers (0 for executables) ++ .short 0 // NumberOfRelocations (0 for executables) ++ .short 0 // NumberOfLineNumbers (0 for executables) ++ /* ++ * EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_ALIGN_8BYTES | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA ++ */ ++ .long 0x40400040 // Characteristics (section flags) ++ ++ .ascii ".rodata\0" ++ .long _rodata_vsize // VirtualSize ++ .long _rodata - ImageBase // VirtualAddress ++ .long _rodata_size // SizeOfRawData ++ .long _rodata - ImageBase // PointerToRawData ++ ++ .long 0 // PointerToRelocations (0 for executables) ++ .long 0 // PointerToLineNumbers (0 for executables) ++ .short 0 // NumberOfRelocations (0 for executables) ++ .short 0 // NumberOfLineNumbers (0 for executables) ++ /* ++ * EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_ALIGN_8BYTES | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA ++ */ ++ .long 0x40400040 // Characteristics (section flags) ++ ++ .align 12 + _start: + stp x29, x30, [sp, #-32]! + mov x29, sp +@@ -39,15 +164,3 @@ _start: + + 0: ldp x29, x30, [sp], #32 + ret +- +- // hand-craft a dummy .reloc section so EFI knows it's a relocatable executable: +- .data +-.dummy0: +-.dummy1: +- .4byte 0 +- +-#define IMAGE_REL_ABSOLUTE 0 +- .section .reloc, "a" +- .4byte .dummy1-.dummy0 // Page RVA +- .4byte 10 // Block Size (2*4+2) +- .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy diff -Nru shim-15.4/debian/patches/aarch64-shim-old.patch shim-15.6/debian/patches/aarch64-shim-old.patch --- shim-15.4/debian/patches/aarch64-shim-old.patch 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/debian/patches/aarch64-shim-old.patch 2022-07-28 06:46:16.000000000 +0000 @@ -0,0 +1,190 @@ +shim 15.6 onwards needs newer binutils to build on aarch64. That works +better, but we don't have that binutils update in older Debian +releases. Undo the build changes here so that we can build for aarch64 +on older stable releases. We're not going to sign them, but we need +the binaries for aarch64. + +diff --git a/Make.defaults b/Make.defaults +index dfed9c4a..18677daa 100644 +--- a/Make.defaults ++++ b/Make.defaults +@@ -84,7 +84,9 @@ ifeq ($(ARCH),aarch64) + ARCH_GNUEFI ?= aarch64 + ARCH_SUFFIX ?= aa64 + ARCH_SUFFIX_UPPER ?= AA64 +- ARCH_LDFLAGS ?= ++ FORMAT := -O binary ++ SUBSYSTEM := 0xa ++ ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM) + ARCH_CFLAGS ?= + endif + ifeq ($(ARCH),arm) +diff --git a/elf_aarch64_efi.lds b/elf_aarch64_efi.lds +index 60c55ba5..42825fd9 100644 +--- a/elf_aarch64_efi.lds ++++ b/elf_aarch64_efi.lds +@@ -3,94 +3,109 @@ OUTPUT_ARCH(aarch64) + ENTRY(_start) + SECTIONS + { +- . = 0; +- ImageBase = .; +- .hash : { *(.hash) } /* this MUST come first! */ +- . = ALIGN(4096); +- .eh_frame : +- { +- *(.eh_frame) +- } +- . = ALIGN(4096); +- .text : +- { +- _text = .; +- *(.text) +- *(.text.*) +- *(.gnu.linkonce.t.*) +- _etext = .; +- } +- . = ALIGN(4096); +- .reloc : +- { +- *(.reloc) +- } +- . = ALIGN(4096); +- .note.gnu.build-id : { +- *(.note.gnu.build-id) +- } +- +- . = ALIGN(4096); +- .data.ident : { +- *(.data.ident) ++ .text 0x0 : { ++ _text = .; ++ *(.text.head) ++ *(.text) ++ *(.text.*) ++ *(.gnu.linkonce.t.*) ++ _evtext = .; ++ . = ALIGN(4096); + } ++ _etext = .; ++ _text_size = . - _text; ++ _text_vsize = _evtext - _text; + + . = ALIGN(4096); + .data : + { + _data = .; +- *(.rodata*) ++ *(.sdata) ++ *(.data) ++ *(.data1) ++ *(.data.*) + *(.got.plt) + *(.got) +- *(.data*) +- *(.sdata) ++ ++ *(.dynamic) ++ + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ ++ . = ALIGN(16); ++ _bss = .; + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) +- *(.rel.local) ++ _evdata = .; ++ . = ALIGN(4096); ++ _bss_end = .; + } ++ _edata = .; ++ _data_vsize = _evdata - _data; ++ _data_size = . - _data; + ++ /* ++ * Note that _sbat must be the beginning of the data, and _esbat must be the ++ * end and must be before any section padding. The sbat self-check uses ++ * _esbat to find the bounds of the data, and if the padding is included, the ++ * CSV parser (correctly) rejects the data as having NUL values in one of the ++ * required columns. ++ */ + . = ALIGN(4096); +- .vendor_cert : ++ .sbat : + { +- *(.vendor_cert) ++ _sbat = .; ++ *(.sbat) ++ *(.sbat.*) ++ _esbat = .; ++ . = ALIGN(4096); ++ _epsbat = .; + } ++ _sbat_size = _epsbat - _sbat; ++ _sbat_vsize = _esbat - _sbat; ++ + . = ALIGN(4096); +- .dynamic : { *(.dynamic) } ++ .rodata : ++ { ++ _rodata = .; ++ *(.rodata*) ++ *(.srodata) ++ . = 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*) +- *(.rela.got*) +- *(.rela.stab*) + } +- _edata = .; +- _data_size = . - _data; + . = ALIGN(4096); +- .sbat : ++ .dyn : + { +- _sbat = .; +- *(.sbat) +- *(.sbat.*) ++ *(.dynsym) ++ *(.dynstr) ++ _evrodata = .; ++ . = ALIGN(4096); + } +- _esbat = .; +- _sbat_size = . - _sbat; ++ _erodata = .; ++ _rodata_size = . - _rodata; ++ _rodata_vsize = _evrodata - _rodata; ++ _alldata_size = . - _data; + +- . = ALIGN(4096); +- .dynsym : { *(.dynsym) } +- . = ALIGN(4096); +- .dynstr : { *(.dynstr) } +- . = ALIGN(4096); +- .ignored.reloc : ++ /DISCARD/ : + { +- *(.rela.reloc) ++ *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +- .note.gnu.build-id : { *(.note.gnu.build-id) } + } diff -Nru shim-15.4/debian/patches/fix-broken-ia32-reloc.patch shim-15.6/debian/patches/fix-broken-ia32-reloc.patch --- shim-15.4/debian/patches/fix-broken-ia32-reloc.patch 2021-03-31 19:58:04.000000000 +0000 +++ shim-15.6/debian/patches/fix-broken-ia32-reloc.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -commit 1bea91ba72165d97c3b453cf769cb4bc5c07207a -Author: Peter Jones -Date: Wed Mar 31 14:54:52 2021 -0400 - - Fix a broken file header on ia32 - - Commit c6281c6a195edee61185 needs to have included a ". = ALIGN(4096)" - directive before .reloc, but fails to do so. - - As a result, binutils, which does not care about the actual binary - format's constraints in any way, does not enforce the section alignment, - and it will not load. - - Signed-off-by: Peter Jones - -diff --git a/elf_ia32_efi.lds b/elf_ia32_efi.lds -index 742e0a47..497a3a15 100644 ---- a/elf_ia32_efi.lds -+++ b/elf_ia32_efi.lds -@@ -15,6 +15,7 @@ SECTIONS - *(.gnu.linkonce.t.*) - _etext = .; - } -+ . = ALIGN(4096); - .reloc : - { - *(.reloc) diff -Nru shim-15.4/debian/patches/fix-import_one_mok_state.patch shim-15.6/debian/patches/fix-import_one_mok_state.patch --- shim-15.4/debian/patches/fix-import_one_mok_state.patch 2021-04-21 00:04:46.000000000 +0000 +++ shim-15.6/debian/patches/fix-import_one_mok_state.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -commit 822d07ad4f07ef66fe447a130e1027c88d02a394 -Author: Adam Williamson -Date: Thu Apr 8 22:39:02 2021 -0700 - - Fix handling of ignore_db and user_insecure_mode - - In 65be350308783a8ef537246c8ad0545b4e6ad069, import_mok_state() is split - up into a function that manages the whole mok state, and one that - handles the state machine for an individual state variable. - Unfortunately, the code that initializes the global ignore_db and - user_insecure_mode was copied from import_mok_state() into the new - import_one_mok_state() function, and thus re-initializes that state each - time it processes a MoK state variable, before even assessing if that - variable is set. As a result, we never honor either flag, and the - machine owner cannot disable trusting the system firmware's db/dbx - databases or disable validation altogether. - - This patch removes the extra re-initialization, allowing those variables - to be set properly. - - Signed-off-by: Adam Williamson - -diff --git a/mok.c b/mok.c -index 5ad9072b..9e37d6ab 100644 ---- a/mok.c -+++ b/mok.c -@@ -888,9 +888,6 @@ EFI_STATUS import_one_mok_state(struct mok_state_variable *v, - EFI_STATUS ret = EFI_SUCCESS; - EFI_STATUS efi_status; - -- user_insecure_mode = 0; -- ignore_db = 0; -- - UINT32 attrs = 0; - BOOLEAN delete = FALSE; - diff -Nru shim-15.4/debian/patches/fix_arm64_rela_sections.patch shim-15.6/debian/patches/fix_arm64_rela_sections.patch --- shim-15.4/debian/patches/fix_arm64_rela_sections.patch 2021-06-22 21:59:41.000000000 +0000 +++ shim-15.6/debian/patches/fix_arm64_rela_sections.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,132 +0,0 @@ -From 9828f65f3e9de29da7bc70cb71069cc1d7ca1b4a Mon Sep 17 00:00:00 2001 -From: Gary Lin -Date: Wed, 16 Jun 2021 16:13:32 +0800 -Subject: [PATCH] arm/aa64: fix the size of .rela* sections - -The previous commit(*) merged .rel* and .dyn* into .rodata, and this -made ld to generate the wrong size for .rela* sections that covered -other unrelated sections. When the EFI image was loaded, _relocate() -went through the unexpected data and may cause unexpected crash. -This commit moves .rel* and .dyn* out of .rodata in the ld script but -also moves the related variables, such as _evrodata, _rodata_size, -and _rodata_vsize, to the end of the new .dyn section, so that the -crafted pe-coff section header for .rodata still covers our new -.rela and .dyn sections. - -(*) 212ba30544f ("arm/aa64 targets: put .rel* and .dyn* in .rodata") - -Fix issue: https://github.com/rhboot/shim/issues/371 - -Signed-off-by: Gary Lin ---- - Makefile | 4 ++-- - elf_aarch64_efi.lds | 24 ++++++++++++++++-------- - elf_arm_efi.lds | 24 ++++++++++++++++-------- - 3 files changed, 34 insertions(+), 18 deletions(-) - -Index: shim.git/Makefile -=================================================================== ---- shim.git.orig/Makefile -+++ shim.git/Makefile -@@ -244,7 +244,7 @@ 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 .vendor_cert -j .sbat \ -+ -j .vendor_cert -j .dyn -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=$@ -@@ -260,7 +260,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 \ -Index: shim.git/elf_aarch64_efi.lds -=================================================================== ---- shim.git.orig/elf_aarch64_efi.lds -+++ shim.git/elf_aarch64_efi.lds -@@ -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: shim.git/elf_arm_efi.lds -=================================================================== ---- shim.git.orig/elf_arm_efi.lds -+++ shim.git/elf_arm_efi.lds -@@ -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); - } diff -Nru shim-15.4/debian/patches/relax_check_for_import_mok_state.patch shim-15.6/debian/patches/relax_check_for_import_mok_state.patch --- shim-15.4/debian/patches/relax_check_for_import_mok_state.patch 2021-06-22 22:02:18.000000000 +0000 +++ shim-15.6/debian/patches/relax_check_for_import_mok_state.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -From: Gary Lin -Date: Tue, 11 May 2021 10:41:43 +0800 -Subject: Relax the check for import_mok_state() -MIME-Version: 1.0 -Content-Type: text/plain; charset="utf-8" -Content-Transfer-Encoding: 8bit - -An openSUSE user reported(*) that shim 15.4 failed to boot the system -with the following message: - - "Could not create MokListXRT: Out of Resources" - -In the beginning, I thought it's caused by the growing size of -vendor-dbx. However, we found the following messages after set -SHIM_VERBOSE: - - max_var_sz:8000 remaining_sz:85EC max_storage_sz:9000 - SetVariable(“MokListXRT”, ... varsz=0x1404) = Out of Resources - -Even though the firmware claimed the remaining storage size is 0x85EC -and the maximum variable size is 0x8000, it still rejected MokListXRT -with size 0x1404. It seems that the return values from QueryVariableInfo() -are not reliable. Since this firmware didn't really support Secure Boot, -the variable mirroring is not so critical, so we can just accept the -failure of import_mok_state() and continue boot. - -(*) https://bugzilla.suse.com/show_bug.cgi?id=1185261 - -Signed-off-by: Gary Lin ---- - shim.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/shim.c b/shim.c -index c5cfbb8..40e4894 100644 ---- a/shim.c -+++ b/shim.c -@@ -1973,10 +1973,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. - */ diff -Nru shim-15.4/debian/patches/series shim-15.6/debian/patches/series --- shim-15.4/debian/patches/series 2021-06-22 22:02:18.000000000 +0000 +++ shim-15.6/debian/patches/series 2022-07-28 06:46:16.000000000 +0000 @@ -1,6 +1,2 @@ -fix-import_one_mok_state.patch -fix-broken-ia32-reloc.patch -MOK-BootServicesData.patch -Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch -relax_check_for_import_mok_state.patch -fix_arm64_rela_sections.patch +aarch64-gnuefi-old.patch +aarch64-shim-old.patch diff -Nru shim-15.4/debian/rules shim-15.6/debian/rules --- shim-15.4/debian/rules 2021-07-12 07:59:53.000000000 +0000 +++ shim-15.6/debian/rules 2022-07-28 06:46:16.000000000 +0000 @@ -70,6 +70,9 @@ override_dh_auto_build: $(DBX_LIST) $(SBAT_DATA) dh_auto_build -- $(COMMON_OPTIONS) +override_dh_auto_test: $(DBX_LIST) $(SBAT_DATA) + dh_auto_test -- INSTALL=install $(COMMON_OPTIONS) + override_dh_auto_install: dh_auto_install --destdir=debian/tmp -- $(COMMON_OPTIONS) # Remove the copy of the source that's installed - we have git diff -Nru shim-15.4/elf_aarch64_efi.lds shim-15.6/elf_aarch64_efi.lds --- shim-15.4/elf_aarch64_efi.lds 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/elf_aarch64_efi.lds 2022-06-01 18:25:48.000000000 +0000 @@ -3,101 +3,94 @@ ENTRY(_start) SECTIONS { - .text 0x0 : { - _text = .; - *(.text.head) - *(.text) - *(.text.*) - *(.gnu.linkonce.t.*) - _evtext = .; - . = ALIGN(4096); - } - _etext = .; - _text_size = . - _text; - _text_vsize = _evtext - _text; + . = 0; + ImageBase = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = ALIGN(4096); + .eh_frame : + { + *(.eh_frame) + } + . = ALIGN(4096); + .text : + { + _text = .; + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + _etext = .; + } + . = ALIGN(4096); + .reloc : + { + *(.reloc) + } + . = ALIGN(4096); + .note.gnu.build-id : { + *(.note.gnu.build-id) + } + + . = ALIGN(4096); + .data.ident : { + *(.data.ident) + } . = ALIGN(4096); .data : { _data = .; - *(.sdata) - *(.data) - *(.data1) - *(.data.*) + *(.rodata*) *(.got.plt) *(.got) - - *(.dynamic) - + *(.data*) + *(.sdata) /* the EFI loader doesn't seem to like a .bss section, so we stick it all into .data: */ - . = ALIGN(16); - _bss = .; *(.sbss) *(.scommon) *(.dynbss) *(.bss) *(COMMON) - _evdata = .; - . = ALIGN(4096); - _bss_end = .; + *(.rel.local) + } + + . = ALIGN(4096); + .vendor_cert : + { + *(.vendor_cert) + } + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rela : + { + *(.rela.data*) + *(.rela.got*) + *(.rela.stab*) } _edata = .; - _data_vsize = _evdata - _data; _data_size = . - _data; - - /* - * Note that _sbat must be the beginning of the data, and _esbat must be the - * end and must be before any section padding. The sbat self-check uses - * _esbat to find the bounds of the data, and if the padding is included, the - * CSV parser (correctly) rejects the data as having NUL values in one of the - * required columns. - */ . = ALIGN(4096); .sbat : { _sbat = .; *(.sbat) *(.sbat.*) - _esbat = .; - . = ALIGN(4096); - _epsbat = .; } - _sbat_size = _epsbat - _sbat; - _sbat_vsize = _esbat - _sbat; + _esbat = .; + _sbat_size = . - _sbat; . = ALIGN(4096); - .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) - _evrodata = .; - . = ALIGN(4096); - } - _erodata = .; - _rodata_size = . - _rodata; - _rodata_vsize = _evrodata - _rodata; - _alldata_size = . - _data; - - /DISCARD/ : + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .ignored.reloc : { - *(.rel.reloc) + *(.rela.reloc) *(.eh_frame) *(.note.GNU-stack) } .comment 0 : { *(.comment) } + .note.gnu.build-id : { *(.note.gnu.build-id) } } diff -Nru shim-15.4/elf_arm_efi.lds shim-15.6/elf_arm_efi.lds --- shim-15.4/elf_arm_efi.lds 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/elf_arm_efi.lds 2022-06-01 18:25:48.000000000 +0000 @@ -70,21 +70,29 @@ .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); } diff -Nru shim-15.4/elf_ia32_efi.lds shim-15.6/elf_ia32_efi.lds --- shim-15.4/elf_ia32_efi.lds 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/elf_ia32_efi.lds 2022-06-01 18:25:48.000000000 +0000 @@ -15,6 +15,7 @@ *(.gnu.linkonce.t.*) _etext = .; } + . = ALIGN(4096); .reloc : { *(.reloc) diff -Nru shim-15.4/fallback.c shim-15.6/fallback.c --- shim-15.4/fallback.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/fallback.c 2022-06-01 18:25:48.000000000 +0000 @@ -24,7 +24,7 @@ if (state != -1) return state; - efi_status = get_variable(L"FALLBACK_VERBOSE", + efi_status = get_variable(FALLBACK_VERBOSE_VAR_NAME, &data, &dataSize, SHIM_LOCK_GUID); if (EFI_ERROR(efi_status)) { state = 0; @@ -158,7 +158,7 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ } FreePool(candidate); FreePool(data); - return EFI_NOT_FOUND; + FreePool(varname); + return efi_status; } EFI_STATUS @@ -513,15 +541,15 @@ 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 @@ 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 @@ dp = full_device_path; } else { efi_status = EFI_OUT_OF_RESOURCES; - goto err; + goto done; } } @@ -587,21 +615,53 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ return choice; } +#endif extern EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab); @@ -1068,7 +1130,7 @@ register volatile int x = 0; extern char _etext, _edata; - efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize, + efi_status = get_variable(DEBUG_VAR_NAME, &data, &dataSize, SHIM_LOCK_GUID); if (EFI_ERROR(efi_status)) { return; @@ -1097,8 +1159,8 @@ */ 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 @@ try_start_first_option(image); } +#ifndef FALLBACK_NONINTERACTIVE int timeout = draw_countdown(); if (timeout == 0) goto reset; @@ -1141,6 +1204,7 @@ 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 @@ msleep(fallback_verbose_wait); } - gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); return EFI_SUCCESS; } diff -Nru shim-15.4/globals.c shim-15.6/globals.c --- shim-15.4/globals.c 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/globals.c 2022-06-01 18:25:48.000000000 +0000 @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * globals.c - global shim state + * Copyright Peter Jones + */ + +#include "shim.h" + +UINT32 vendor_authorized_size = 0; +UINT8 *vendor_authorized = NULL; + +UINT32 vendor_deauthorized_size = 0; +UINT8 *vendor_deauthorized = NULL; + +UINT32 user_cert_size; +UINT8 *user_cert; + +#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; +UINT8 mok_policy = 0; + +UINT32 verbose = 0; + +// vim:fenc=utf-8:tw=75:noet diff -Nru shim-15.4/gnu-efi/Make.defaults shim-15.6/gnu-efi/Make.defaults --- shim-15.4/gnu-efi/Make.defaults 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/Make.defaults 2022-04-27 14:11:02.000000000 +0000 @@ -124,10 +124,10 @@ || ( [ $(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 @@ -153,13 +153,11 @@ # Set HAVE_EFI_OBJCOPY if objcopy understands --target efi-[app|bsdrv|rtdrv], # otherwise we need to compose the PE/COFF header using the assembler # -ifneq ($(ARCH),aarch64) ifneq ($(ARCH),arm) ifneq ($(ARCH),mips64el) export HAVE_EFI_OBJCOPY=y endif endif -endif ifeq ($(ARCH),arm) CFLAGS += -marm @@ -193,6 +191,7 @@ -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,) diff -Nru shim-15.4/gnu-efi/gnuefi/crt0-efi-aarch64.S shim-15.6/gnu-efi/gnuefi/crt0-efi-aarch64.S --- shim-15.4/gnu-efi/gnuefi/crt0-efi-aarch64.S 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/gnuefi/crt0-efi-aarch64.S 2022-04-27 14:11:02.000000000 +0000 @@ -16,136 +16,11 @@ * either version 2 of the License, or (at your option) any later version. */ - .section .text.head - - /* - * Magic "MZ" signature for PE/COFF - */ - .globl ImageBase -ImageBase: - .ascii "MZ" - .skip 58 // 'MZ' + pad + offset == 64 - .long pe_header - ImageBase // Offset to the PE header. -pe_header: - .ascii "PE" - .short 0 -coff_header: - .short 0xaa64 // AArch64 - .short 4 // nr_sections - .long 0 // TimeDateStamp - .long 0 // PointerToSymbolTable - .long 1 // NumberOfSymbols - .short section_table - optional_header // SizeOfOptionalHeader - .short 0x206 // Characteristics. - // IMAGE_FILE_DEBUG_STRIPPED | - // IMAGE_FILE_EXECUTABLE_IMAGE | - // IMAGE_FILE_LINE_NUMS_STRIPPED -optional_header: - .short 0x20b // PE32+ format - .byte 0x02 // MajorLinkerVersion - .byte 0x14 // MinorLinkerVersion - .long _text_size // SizeOfCode - .long _alldata_size // SizeOfInitializedData - .long 0 // SizeOfUninitializedData - .long _start - ImageBase // AddressOfEntryPoint - .long _start - ImageBase // BaseOfCode - -extra_header_fields: - .quad 0 // ImageBase - .long 0x1000 // SectionAlignment - .long 0x200 // FileAlignment - .short 0 // MajorOperatingSystemVersion - .short 0 // MinorOperatingSystemVersion - .short 0 // MajorImageVersion - .short 0 // MinorImageVersion - .short 0 // MajorSubsystemVersion - .short 0 // MinorSubsystemVersion - .long 0 // Win32VersionValue - - .long _erodata - ImageBase // SizeOfImage - - // Everything before the kernel image is considered part of the header - .long _start - ImageBase // SizeOfHeaders - .long 0 // CheckSum - .short EFI_SUBSYSTEM // Subsystem - .short 0 // DllCharacteristics - .quad 0 // SizeOfStackReserve - .quad 0 // SizeOfStackCommit - .quad 0 // SizeOfHeapReserve - .quad 0 // SizeOfHeapCommit - .long 0 // LoaderFlags - .long 0x6 // NumberOfRvaAndSizes - - .quad 0 // ExportTable - .quad 0 // ImportTable - .quad 0 // ResourceTable - .quad 0 // ExceptionTable - .quad 0 // CertificationTable - .quad 0 // BaseRelocationTable - - // Section table -section_table: - .ascii ".text\0\0\0" - .long _evtext - _start // VirtualSize - .long _start - ImageBase // VirtualAddress - .long _etext - _start // SizeOfRawData - .long _start - ImageBase // PointerToRawData - - .long 0 // PointerToRelocations (0 for executables) - .long 0 // PointerToLineNumbers (0 for executables) - .short 0 // NumberOfRelocations (0 for executables) - .short 0 // NumberOfLineNumbers (0 for executables) - /* - * EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_CNT_CODE - */ - .long 0x60000020 // Characteristics (section flags) - - .ascii ".data\0\0\0" - .long _data_vsize // VirtualSize - .long _data - ImageBase // VirtualAddress - .long _data_size // SizeOfRawData - .long _data - ImageBase // PointerToRawData - - .long 0 // PointerToRelocations (0 for executables) - .long 0 // PointerToLineNumbers (0 for executables) - .short 0 // NumberOfRelocations (0 for executables) - .short 0 // NumberOfLineNumbers (0 for executables) - /* - * EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA - */ - .long 0xc0000040 // Characteristics (section flags) - - .ascii ".sbat\0\0\0" - .long _sbat_vsize // VirtualSize - .long _sbat - ImageBase // VirtualAddress - .long _sbat_size // SizeOfRawData - .long _sbat - ImageBase // PointerToRawData - - .long 0 // PointerToRelocations (0 for executables) - .long 0 // PointerToLineNumbers (0 for executables) - .short 0 // NumberOfRelocations (0 for executables) - .short 0 // NumberOfLineNumbers (0 for executables) - /* - * EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_ALIGN_8BYTES | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA - */ - .long 0x40400040 // Characteristics (section flags) - - .ascii ".rodata\0" - .long _rodata_vsize // VirtualSize - .long _rodata - ImageBase // VirtualAddress - .long _rodata_size // SizeOfRawData - .long _rodata - ImageBase // PointerToRawData - - .long 0 // PointerToRelocations (0 for executables) - .long 0 // PointerToLineNumbers (0 for executables) - .short 0 // NumberOfRelocations (0 for executables) - .short 0 // NumberOfLineNumbers (0 for executables) - /* - * EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_ALIGN_8BYTES | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA - */ - .long 0x40400040 // Characteristics (section flags) + .text .align 12 + + .globl _start _start: stp x29, x30, [sp, #-32]! mov x29, sp @@ -164,3 +39,15 @@ 0: ldp x29, x30, [sp], #32 ret + + // hand-craft a dummy .reloc section so EFI knows it's a relocatable executable: + .data +.dummy0: +.dummy1: + .4byte 0 + +#define IMAGE_REL_ABSOLUTE 0 + .section .reloc, "a" + .4byte .dummy1-.dummy0 // Page RVA + .4byte 10 // Block Size (2*4+2) + .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy diff -Nru shim-15.4/gnu-efi/gnuefi/crt0-efi-ia32.S shim-15.6/gnu-efi/gnuefi/crt0-efi-ia32.S --- shim-15.4/gnu-efi/gnuefi/crt0-efi-ia32.S 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/gnuefi/crt0-efi-ia32.S 2022-04-27 14:11:02.000000000 +0000 @@ -68,10 +68,10 @@ .data .dummy0: .dummy1: - .long 0 + .4byte 0 #define IMAGE_REL_ABSOLUTE 0 .section .reloc, "a" - .long .dummy1-.dummy0 // Page RVA - .long 10 // Block Size (2*4+2) - .word (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy + .4byte .dummy1-.dummy0 // Page RVA + .4byte 10 // Block Size (2*4+2) + .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy diff -Nru shim-15.4/gnu-efi/gnuefi/crt0-efi-x86_64.S shim-15.6/gnu-efi/gnuefi/crt0-efi-x86_64.S --- shim-15.4/gnu-efi/gnuefi/crt0-efi-x86_64.S 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/gnuefi/crt0-efi-x86_64.S 2022-04-27 14:11:02.000000000 +0000 @@ -59,18 +59,16 @@ call efi_main addq $8, %rsp -.exit: ret // hand-craft a dummy .reloc section so EFI knows it's a relocatable executable: .data .dummy0: .dummy1: - .long 0 + .4byte 0 #define IMAGE_REL_ABSOLUTE 0 .section .reloc, "a" - .long .dummy1-.dummy0 // Page RVA - .long 10 // Block Size (2*4+2) - .word (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy - + .4byte .dummy1-.dummy0 // Page RVA + .4byte 10 // Block Size (2*4+2) + .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy diff -Nru shim-15.4/gnu-efi/inc/efiapi.h shim-15.6/gnu-efi/inc/efiapi.h --- shim-15.4/gnu-efi/inc/efiapi.h 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/inc/efiapi.h 2022-04-27 14:11:02.000000000 +0000 @@ -229,6 +229,7 @@ #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 @@ // #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 @@ // #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 @@ #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 { diff -Nru shim-15.4/gnu-efi/inc/efidef.h shim-15.6/gnu-efi/inc/efidef.h --- shim-15.4/gnu-efi/inc/efidef.h 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/inc/efidef.h 2022-04-27 14:11:02.000000000 +0000 @@ -169,12 +169,13 @@ #define EFI_MEMORY_WC 0x0000000000000002 #define EFI_MEMORY_WT 0x0000000000000004 #define EFI_MEMORY_WB 0x0000000000000008 -#define EFI_MEMORY_UCE 0x0000000000000010 - -// physical memory protection on range +#define EFI_MEMORY_UCE 0x0000000000000010 #define EFI_MEMORY_WP 0x0000000000001000 + +// physical memory protection on range #define EFI_MEMORY_RP 0x0000000000002000 #define EFI_MEMORY_XP 0x0000000000004000 +#define EFI_MEMORY_RO 0x0000000000020000 // range requires a runtime mapping #define EFI_MEMORY_RUNTIME 0x8000000000000000 diff -Nru shim-15.4/gnu-efi/inc/efilib.h shim-15.6/gnu-efi/inc/efilib.h --- shim-15.4/gnu-efi/inc/efilib.h 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/inc/efilib.h 2022-04-27 14:11:02.000000000 +0000 @@ -272,17 +272,17 @@ 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 ); diff -Nru shim-15.4/gnu-efi/inc/efiprot.h shim-15.6/gnu-efi/inc/efiprot.h --- shim-15.4/gnu-efi/inc/efiprot.h 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/inc/efiprot.h 2022-04-27 14:11:02.000000000 +0000 @@ -1422,4 +1422,39 @@ EFI_EBC_GET_VERSION GetVersion; } EFI_EBC_PROTOCOL; +INTERFACE_DECL(_EFI_MEMORY_ATTRIBUTE_PROTOCOL); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_ATTRIBUTES)( + IN struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + OUT UINT64 *Attributes + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_MEMORY_ATTRIBUTES)( + IN struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CLEAR_MEMORY_ATTRIBUTES)( + IN struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +typedef struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL { + EFI_GET_MEMORY_ATTRIBUTES GetMemoryAttributes; + EFI_SET_MEMORY_ATTRIBUTES SetMemoryAttributes; + EFI_CLEAR_MEMORY_ATTRIBUTES ClearMemoryAttributes; +} EFI_MEMORY_ATTRIBUTE_PROTOCOL; + #endif diff -Nru shim-15.4/gnu-efi/lib/misc.c shim-15.6/gnu-efi/lib/misc.c --- shim-15.4/gnu-efi/lib/misc.c 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/lib/misc.c 2022-04-27 14:11:02.000000000 +0000 @@ -98,7 +98,7 @@ RtZeroMem (Buffer, Size); } -VOID +VOID EFIAPI SetMem ( IN VOID *Buffer, IN UINTN Size, @@ -108,10 +108,10 @@ RtSetMem (Buffer, Size, Value); } -VOID +VOID EFIAPI CopyMem ( IN VOID *Dest, - IN CONST VOID *Src, + IN VOID *Src, IN UINTN len ) { diff -Nru shim-15.4/gnu-efi/lib/str.c shim-15.6/gnu-efi/lib/str.c --- shim-15.4/gnu-efi/lib/str.c 2021-03-26 22:41:36.000000000 +0000 +++ shim-15.6/gnu-efi/lib/str.c 2022-04-27 14:11:02.000000000 +0000 @@ -211,7 +211,7 @@ Size = StrSize(Src); Dest = AllocatePool (Size); if (Dest) { - CopyMem (Dest, Src, Size); + CopyMem (Dest, (void *)Src, Size); } return Dest; } diff -Nru shim-15.4/httpboot.c shim-15.6/httpboot.c --- shim-15.4/httpboot.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/httpboot.c 2022-06-01 18:25:48.000000000 +0000 @@ -179,8 +179,8 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ /* 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 @@ } 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 @@ *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 @@ } /* 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; diff -Nru shim-15.4/include/asm.h shim-15.6/include/asm.h --- shim-15.4/include/asm.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/asm.h 2022-06-01 18:25:48.000000000 +0000 @@ -26,17 +26,17 @@ } #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; diff -Nru shim-15.4/include/compiler.h shim-15.6/include/compiler.h --- shim-15.4/include/compiler.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/compiler.h 2022-06-01 18:25:48.000000000 +0000 @@ -47,8 +47,12 @@ #define ALIAS(x) __attribute__((weak, alias (#x))) #endif #ifndef ALLOCFUNC +#if defined(__COVERITY__) +#define ALLOCFUNC(a, b) +#else #define ALLOCFUNC(dealloc, dealloc_arg) __attribute__((__malloc__(dealloc, dealloc_arg))) #endif +#endif #ifndef PRINTF #define PRINTF(first, args...) __attribute__((__format__(printf, first, ## args))) #endif diff -Nru shim-15.4/include/console.h shim-15.6/include/console.h --- shim-15.4/include/console.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/console.h 2022-06-01 18:25:48.000000000 +0000 @@ -50,6 +50,9 @@ 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 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__) diff -Nru shim-15.4/include/efiauthenticated.h shim-15.6/include/efiauthenticated.h --- shim-15.4/include/efiauthenticated.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/efiauthenticated.h 2022-06-01 18:25:48.000000000 +0000 @@ -124,9 +124,15 @@ /* * 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 diff -Nru shim-15.4/include/guid.h shim-15.6/include/guid.h --- shim-15.4/include/guid.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/guid.h 2022-06-01 18:25:48.000000000 +0000 @@ -33,8 +33,8 @@ extern EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID; extern EFI_GUID SECURITY_PROTOCOL_GUID; extern EFI_GUID SECURITY2_PROTOCOL_GUID; +extern EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; extern EFI_GUID SHIM_LOCK_GUID; - extern EFI_GUID MOK_VARIABLE_STORE; #endif /* SHIM_GUID_H */ diff -Nru shim-15.4/include/hexdump.h shim-15.6/include/hexdump.h --- shim-15.4/include/hexdump.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/hexdump.h 2022-06-01 18:25:48.000000000 +0000 @@ -71,7 +71,7 @@ else buf[offset++] = '.'; } - buf[offset++] = size > 0 ? '|' : 'X'; + buf[offset++] = '|'; buf[offset] = '\0'; } @@ -89,6 +89,11 @@ 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 @@ 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 -Nru shim-15.4/include/load-options.h shim-15.6/include/load-options.h --- shim-15.4/include/load-options.h 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/include/load-options.h 2022-06-01 18:25:48.000000000 +0000 @@ -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 -Nru shim-15.4/include/mock-variables.h shim-15.6/include/mock-variables.h --- shim-15.4/include/mock-variables.h 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/include/mock-variables.h 2022-06-01 18:25:48.000000000 +0000 @@ -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 + */ + +#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 -Nru shim-15.4/include/mok.h shim-15.6/include/mok.h --- shim-15.4/include/mok.h 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/include/mok.h 2022-06-01 18:25:48.000000000 +0000 @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * mok.h - structs for MoK data + * Copyright Peter Jones + */ + +#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; + + UINT8 **user_cert; + UINT32 *user_cert_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[]; +}; + +/* + * bit definitions for MokPolicy + */ +#define MOK_POLICY_REQUIRE_NX 1 + +#endif /* !SHIM_MOK_H_ */ +// vim:fenc=utf-8:tw=75:noet diff -Nru shim-15.4/include/pe.h shim-15.6/include/pe.h --- shim-15.4/include/pe.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/pe.h 2022-06-01 18:25:48.000000000 +0000 @@ -14,8 +14,12 @@ read_header(void *data, unsigned int datasize, PE_COFF_LOADER_IMAGE_CONTEXT *context); +EFI_STATUS verify_image(void *data, unsigned int datasize, + EFI_LOADED_IMAGE *li, + PE_COFF_LOADER_IMAGE_CONTEXT *context); + EFI_STATUS -handle_sbat(char *SBATBase, size_t SBATSize); +verify_sbat_section(char *SBATBase, size_t SBATSize); EFI_STATUS handle_image (void *data, unsigned int datasize, @@ -25,7 +29,7 @@ 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); diff -Nru shim-15.4/include/peimage.h shim-15.6/include/peimage.h --- shim-15.4/include/peimage.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/peimage.h 2022-06-01 18:25:48.000000000 +0000 @@ -17,10 +17,14 @@ #include "wincert.h" -#define SIGNATURE_16(A, B) ((A) | (B << 8)) -#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16)) -#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ - (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32)) +#define SIGNATURE_16(A, B) \ + ((UINT16)(((UINT16)(A)) | (((UINT16)(B)) << ((UINT16)8)))) +#define SIGNATURE_32(A, B, C, D) \ + ((UINT32)(((UINT32)SIGNATURE_16(A, B)) | \ + (((UINT32)SIGNATURE_16(C, D)) << (UINT32)16))) +#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ + ((UINT64)((UINT64)SIGNATURE_32(A, B, C, D) | \ + ((UINT64)(SIGNATURE_32(E, F, G, H)) << (UINT64)32))) #define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1))) #define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment)))) @@ -236,6 +240,24 @@ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; } EFI_IMAGE_OPTIONAL_HEADER64; +#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0001 0x0001 +#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0002 0x0002 +#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0004 0x0004 +#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0008 0x0008 +#if 0 /* This is not in the PE spec. */ +#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0010 0x0010 +#endif +#define EFI_IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 +#define EFI_IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 +#define EFI_IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 +#define EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 +#define EFI_IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +#define EFI_IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +#define EFI_IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +#define EFI_IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 +#define EFI_IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +#define EFI_IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000 +#define EFI_IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 /// /// @attention @@ -303,16 +325,31 @@ // // Section Flags Values // -#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 ///< Reserved. +#define EFI_IMAGE_SCN_RESERVED_00000000 0x00000000 +#define EFI_IMAGE_SCN_RESERVED_00000001 0x00000001 +#define EFI_IMAGE_SCN_RESERVED_00000002 0x00000002 +#define EFI_IMAGE_SCN_RESERVED_00000004 0x00000004 +#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 +#define EFI_IMAGE_SCN_RESERVED_00000010 0x00000010 #define EFI_IMAGE_SCN_CNT_CODE 0x00000020 #define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 #define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 - -#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 ///< Reserved. -#define EFI_IMAGE_SCN_LNK_INFO 0x00000200 ///< Section contains comments or some other type of information. -#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 ///< Section contents will not become part of image. +#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 +#define EFI_IMAGE_SCN_LNK_INFO 0x00000200 +#define EFI_IMAGE_SCN_RESERVED_00000400 0x00000400 +#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 #define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000 - +#define EFI_IMAGE_SCN_RESERVED_00002000 0x00002000 +#define EFI_IMAGE_SCN_RESERVED_00004000 0x00004000 +#define EFI_IMAGE_SCN_GPREL 0x00008000 +/* + * PE 9.3 says both IMAGE_SCN_MEM_PURGEABLE and IMAGE_SCN_MEM_16BIT are + * 0x00020000, but I think it's wrong. --pjones + */ +#define EFI_IMAGE_SCN_MEM_PURGEABLE 0x00010000 // "Reserved for future use." +#define EFI_IMAGE_SCN_MEM_16BIT 0x00020000 // "Reserved for future use." +#define EFI_IMAGE_SCN_MEM_LOCKED 0x00040000 // "Reserved for future use." +#define EFI_IMAGE_SCN_MEM_PRELOAD 0x00080000 // "Reserved for future use." #define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000 #define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000 #define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000 @@ -320,7 +357,14 @@ #define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000 #define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000 #define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000 - +#define EFI_IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define EFI_IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define EFI_IMAGE_SCN_ALIGN_512BYTES 0x00a00000 +#define EFI_IMAGE_SCN_ALIGN_1024BYTES 0x00b00000 +#define EFI_IMAGE_SCN_ALIGN_2048BYTES 0x00c00000 +#define EFI_IMAGE_SCN_ALIGN_4096BYTES 0x00d00000 +#define EFI_IMAGE_SCN_ALIGN_8192BYTES 0x00e00000 +#define EFI_IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 #define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000 #define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000 #define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000 diff -Nru shim-15.4/include/sbat.h shim-15.6/include/sbat.h --- shim-15.4/include/sbat.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/sbat.h 2022-06-01 18:25:48.000000000 +0000 @@ -8,8 +8,35 @@ #define SBAT_VAR_SIG "sbat," #define SBAT_VAR_VERSION "1," -#define SBAT_VAR_DATE "2021030218" -#define SBAT_VAR SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_DATE "\n" +#define SBAT_VAR_ORIGINAL_DATE "2021030218" +#define SBAT_VAR_ORIGINAL \ + SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_ORIGINAL_DATE "\n" + +#if defined(ENABLE_SHIM_DEVEL) +#define SBAT_VAR_PREVIOUS_DATE "2022020101" +#define SBAT_VAR_PREVIOUS_REVOCATIONS "component,2\n" +#define SBAT_VAR_PREVIOUS \ + SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_PREVIOUS_DATE "\n" \ + SBAT_VAR_PREVIOUS_REVOCATIONS + +#define SBAT_VAR_LATEST_DATE "2022050100" +#define SBAT_VAR_LATEST_REVOCATIONS "component,2\nothercomponent,2\n" +#define SBAT_VAR_LATEST \ + SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \ + SBAT_VAR_LATEST_REVOCATIONS +#else /* !ENABLE_SHIM_DEVEL */ +#define SBAT_VAR_PREVIOUS_DATE SBAT_VAR_ORIGINAL_DATE +#define SBAT_VAR_PREVIOUS_REVOCATIONS +#define SBAT_VAR_PREVIOUS \ + SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_PREVIOUS_DATE "\n" \ + SBAT_VAR_PREVIOUS_REVOCATIONS + +#define SBAT_VAR_LATEST_DATE "2022052400" +#define SBAT_VAR_LATEST_REVOCATIONS "shim,2\ngrub,2\n" +#define SBAT_VAR_LATEST \ + SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \ + SBAT_VAR_LATEST_REVOCATIONS +#endif /* ENABLE_SHIM_DEVEL */ #define UEFI_VAR_NV_BS \ (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS) @@ -33,6 +60,13 @@ #define SBAT_VAR_ATTRS UEFI_VAR_NV_BS #endif +#define SBAT_POLICY L"SbatPolicy" +#define SBAT_POLICY8 "SbatPolicy" + +#define SBAT_POLICY_LATEST 1 +#define SBAT_POLICY_PREVIOUS 2 +#define SBAT_POLICY_RESET 3 + extern UINTN _sbat, _esbat; struct sbat_var_entry { @@ -51,7 +85,8 @@ EFI_STATUS parse_sbat_var(list_t *entries); void cleanup_sbat_var(list_t *entries); EFI_STATUS set_sbat_uefi_variable(void); -bool preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes); +bool preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, + UINT32 attributes, char *sbar_var); struct sbat_section_entry { const CHAR8 *component_name; diff -Nru shim-15.4/include/str.h shim-15.6/include/str.h --- shim-15.4/include/str.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/str.h 2022-06-01 18:25:48.000000000 +0000 @@ -72,8 +72,6 @@ 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 diff -Nru shim-15.4/include/system/stdarg.h shim-15.6/include/system/stdarg.h --- shim-15.4/include/system/stdarg.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/system/stdarg.h 2022-06-01 18:25:48.000000000 +0000 @@ -24,7 +24,7 @@ #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 -Nru shim-15.4/include/test-data-efivars-0.h shim-15.6/include/test-data-efivars-0.h --- shim-15.4/include/test-data-efivars-0.h 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/include/test-data-efivars-0.h 2022-06-01 18:25:48.000000000 +0000 @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * test-data-efivars-0.h - test data + * Copyright Peter Jones + */ + +#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 -Nru shim-15.4/include/test-data-efivars-1.h shim-15.6/include/test-data-efivars-1.h --- shim-15.4/include/test-data-efivars-1.h 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/include/test-data-efivars-1.h 2022-06-01 18:25:48.000000000 +0000 @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * test-data-efivars-1.h - test data + * Copyright Peter Jones + */ + +#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 +}; + +static const unsigned char test_data_efivars_1_MokListTrustedRT[] ={ + 0x01 +}; + +#endif /* !TEST_DATA_EFIVARS_1_H_ */ +// vim:fenc=utf-8:tw=75:noet diff -Nru shim-15.4/include/test.h shim-15.6/include/test.h --- shim-15.4/include/test.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/test.h 2022-06-01 18:25:48.000000000 +0000 @@ -8,7 +8,14 @@ #ifndef TEST_H_ #define TEST_H_ +#define _GNU_SOURCE + #include +#include +#include +#include +#include +#include #if defined(__aarch64__) #include @@ -36,17 +43,368 @@ #include -#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 + +#include +#include + +#include #include -#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 : ∅ + const EFI_GUID * const guidb = guid1 ? guid1 : ∅ + + 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 @@ #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 @@ 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 @@ #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 @@ #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 @@ #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 @@ 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 @@ 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_return(cond, status, fmt, ...) \ - ({ \ - int rc_ = assert_as_expr(cond, 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_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 @@ } \ }) +#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__); \ diff -Nru shim-15.4/include/test.mk shim-15.6/include/test.mk --- shim-15.4/include/test.mk 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/test.mk 2022-06-01 18:25:48.000000000 +0000 @@ -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,82 @@ -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) + +# And on Debian also check the multi-arch include path +CFLAGS += -isystem /usr/include/$(shell $(CC) $(ARCH_CFLAGS) -print-multiarch) + +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 diff -Nru shim-15.4/include/ucs2.h shim-15.6/include/ucs2.h --- shim-15.4/include/ucs2.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/include/ucs2.h 2022-06-01 18:25:48.000000000 +0000 @@ -81,31 +81,4 @@ 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 */ diff -Nru shim-15.4/lib/Makefile shim-15.6/lib/Makefile --- shim-15.4/lib/Makefile 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/lib/Makefile 2022-06-01 18:25:48.000000000 +0000 @@ -41,6 +41,10 @@ $(INCLUDES) \ $(DEFINES) +ifneq ($(origin ENABLE_SHIM_DEVEL),undefined) +CFLAGS += -DENABLE_SHIM_DEVEL +endif + lib.a: $(LIBFILES) $(AR) rcs lib.a $(LIBFILES) diff -Nru shim-15.4/lib/console.c shim-15.6/lib/console.c --- shim-15.4/lib/console.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/lib/console.c 2022-06-01 18:25:48.000000000 +0000 @@ -34,8 +34,11 @@ 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 @@ 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); @@ -118,6 +122,30 @@ return ret; } +static struct { + CHAR16 up_left; + CHAR16 up_right; + CHAR16 down_left; + CHAR16 down_right; + CHAR16 horizontal; + CHAR16 vertical; +} boxdraw[2] = { + { + BOXDRAW_UP_LEFT, + BOXDRAW_UP_RIGHT, + BOXDRAW_DOWN_LEFT, + BOXDRAW_DOWN_RIGHT, + BOXDRAW_HORIZONTAL, + BOXDRAW_VERTICAL + }, { + '+', + '+', + '+', + '+', + '-', + '|' + } +}; void console_print_box_at(CHAR16 *str_arr[], int highlight, @@ -129,6 +157,7 @@ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut; UINTN rows, cols; CHAR16 *Line; + bool char_set; if (lines == 0) return; @@ -136,6 +165,9 @@ 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 */ @@ -174,10 +206,16 @@ return; } - SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL); + /* test if boxdraw characters work */ + co->SetCursorPosition(co, start_col, start_row); + Line[0] = boxdraw[0].up_left; + Line[1] = L'\0'; + char_set = co->OutputString(co, Line) == 0 ? 0 : 1; + + SetMem16 (Line, size_cols * 2, boxdraw[char_set].horizontal); - Line[0] = BOXDRAW_DOWN_RIGHT; - Line[size_cols - 1] = BOXDRAW_DOWN_LEFT; + Line[0] = boxdraw[char_set].down_right; + Line[size_cols - 1] = boxdraw[char_set].down_left; Line[size_cols] = L'\0'; co->SetCursorPosition(co, start_col, start_row); co->OutputString(co, Line); @@ -197,8 +235,8 @@ int line = i - start; SetMem16 (Line, size_cols*2, L' '); - Line[0] = BOXDRAW_VERTICAL; - Line[size_cols - 1] = BOXDRAW_VERTICAL; + Line[0] = boxdraw[char_set].vertical; + Line[size_cols - 1] = boxdraw[char_set].vertical; Line[size_cols] = L'\0'; if (line >= 0 && line < lines) { CHAR16 *s = str_arr[line]; @@ -220,9 +258,9 @@ EFI_BACKGROUND_BLUE); } - SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL); - Line[0] = BOXDRAW_UP_RIGHT; - Line[size_cols - 1] = BOXDRAW_UP_LEFT; + SetMem16 (Line, size_cols * 2, boxdraw[char_set].horizontal); + Line[0] = boxdraw[char_set].up_right; + Line[size_cols - 1] = boxdraw[char_set].up_left; Line[size_cols] = L'\0'; co->SetCursorPosition(co, start_col, i); co->OutputString(co, Line); @@ -241,6 +279,9 @@ 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 +315,9 @@ 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 +457,9 @@ 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 +470,9 @@ { SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut; + if (!co) + return; + co->EnableCursor(co, SavedMode->CursorVisible); co->SetCursorPosition(co, SavedMode->CursorColumn, SavedMode->CursorRow); @@ -441,6 +491,9 @@ CHAR16 *titles[2]; int wait = 10000000; + if (!co || !ci) + return -1; + console_save_and_set_mode(&SavedMode); titles[0] = title; @@ -495,9 +548,11 @@ 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 +610,7 @@ 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 +704,25 @@ 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) @@ -665,7 +732,7 @@ UINTN verbose_check_size; verbose_check_size = sizeof(verbose); - efi_status = get_variable(L"SHIM_VERBOSE", &verbose_check_ptr, + efi_status = get_variable(VERBOSE_VAR_NAME, &verbose_check_ptr, &verbose_check_size, SHIM_LOCK_GUID); if (!EFI_ERROR(efi_status)) { verbose = *(__typeof__(verbose) *)verbose_check_ptr; @@ -679,7 +746,7 @@ 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 diff -Nru shim-15.4/lib/execute.c shim-15.6/lib/execute.c --- shim-15.4/lib/execute.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/lib/execute.c 2022-06-01 18:25:48.000000000 +0000 @@ -63,8 +63,8 @@ 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 @@ 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); diff -Nru shim-15.4/lib/guid.c shim-15.6/lib/guid.c --- shim-15.4/lib/guid.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/lib/guid.c 2022-06-01 18:25:48.000000000 +0000 @@ -32,6 +32,6 @@ EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } }; EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; - +EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID = { 0xf4560cf6, 0x40ec, 0x4b4a, {0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89} }; EFI_GUID SHIM_LOCK_GUID = {0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } }; EFI_GUID MOK_VARIABLE_STORE = {0xc451ed2b, 0x9694, 0x45d3, {0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89} }; diff -Nru shim-15.4/lib/security_policy.c shim-15.6/lib/security_policy.c --- shim-15.4/lib/security_policy.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/lib/security_policy.c 2022-06-01 18:25:48.000000000 +0000 @@ -123,7 +123,7 @@ * 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; diff -Nru shim-15.4/lib/shell.c shim-15.6/lib/shell.c --- shim-15.4/lib/shell.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/lib/shell.c 2022-06-01 18:25:48.000000000 +0000 @@ -16,7 +16,7 @@ *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"); diff -Nru shim-15.4/lib/simple_file.c shim-15.6/lib/simple_file.c --- shim-15.4/lib/simple_file.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/lib/simple_file.c 2022-06-01 18:25:48.000000000 +0000 @@ -11,8 +11,8 @@ 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 @@ 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 @@ 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 @@ 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; diff -Nru shim-15.4/lib/variables.c shim-15.6/lib/variables.c --- shim-15.4/lib/variables.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/lib/variables.c 2022-06-01 18:25:48.000000000 +0000 @@ -12,6 +12,10 @@ */ #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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ *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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -Nru shim-15.4/load-options.c shim-15.6/load-options.c --- shim-15.4/load-options.c 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/load-options.c 2022-06-01 18:25:48.000000000 +0000 @@ -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 -Nru shim-15.4/mock-variables.c shim-15.6/mock-variables.c --- shim-15.4/mock-variables.c 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/mock-variables.c 2022-06-01 18:25:48.000000000 +0000 @@ -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 + */ +#include "shim.h" +#include "mock-variables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 = ~((UINT32)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 -Nru shim-15.4/mok.c shim-15.6/mok.c --- shim-15.4/mok.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/mok.c 2022-06-01 18:25:48.000000000 +0000 @@ -16,8 +16,8 @@ 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 @@ #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 @@ 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 @@ 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) { @@ -163,8 +84,9 @@ #define MOK_MIRROR_DELETE_FIRST 0x02 #define MOK_VARIABLE_MEASURE 0x04 #define MOK_VARIABLE_LOG 0x08 +#define MOK_VARIABLE_INVERSE 0x10 -struct mok_state_variable mok_state_variables[] = { +struct mok_state_variable mok_state_variable_data[] = { {.name = L"MokList", .name8 = "MokList", .rtname = L"MokListRT", @@ -176,6 +98,8 @@ .categorize_addend = categorize_authorized, .addend = &vendor_authorized, .addend_size = &vendor_authorized_size, + .user_cert = &user_cert, + .user_cert_size = &user_cert_size, #if defined(ENABLE_SHIM_CERT) .build_cert = &build_cert, .build_cert_size = &build_cert_size, @@ -245,8 +169,38 @@ 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_INVERSE | + MOK_VARIABLE_LOG, + .pcr = 14, + .state = &trust_mok_list, + }, + {.name = L"MokPolicy", + .name8 = "MokPolicy", + .rtname = L"MokPolicyRT", + .rtname8 = "MokPolicyRT", + .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_LOG, + .pcr = 14, + .state = &mok_policy, + }, { 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 +215,9 @@ 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 +227,21 @@ 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 +318,18 @@ 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); @@ -631,7 +603,8 @@ dprint(L"FullDataSize:0x%lx FullData:0x%llx\n", FullDataSize, FullData); } - + if (v->user_cert_size) + FullDataSize += *v->user_cert_size; } /* @@ -745,6 +718,10 @@ dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n", FullDataSize, FullData, p, p-(uintptr_t)FullData); } + if (v->user_cert_size) { + CopyMem(p, *v->user_cert, *v->user_cert_size); + p += *v->user_cert_size; + } } /* @@ -850,7 +827,7 @@ 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 +853,57 @@ 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->flags & MOK_VARIABLE_INVERSE) { + v->data = AllocateZeroPool(4); + if (!v->data) { + perror(L"Out of memory\n"); + return EFI_OUT_OF_RESOURCES; + } + v->data[0] = 0x01; + v->data_size = 1; + } else 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 (v->flags & MOK_VARIABLE_INVERSE) { + FreePool(v->data); + v->data = NULL; + v->data_size = 0; + } } } if (delete == TRUE) { @@ -935,7 +919,9 @@ } 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 +949,7 @@ user_insecure_mode = 0; ignore_db = 0; + trust_mok_list = 0; UINT64 config_sz = 0; UINT8 *config_table = NULL; @@ -1001,10 +988,9 @@ 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 +1010,19 @@ 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"); } diff -Nru shim-15.4/netboot.c shim-15.6/netboot.c --- shim-15.4/netboot.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/netboot.c 2022-06-01 18:25:48.000000000 +0000 @@ -36,8 +36,8 @@ { 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 -Nru shim-15.4/pe.c shim-15.6/pe.c --- shim-15.4/pe.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/pe.c 2022-06-01 18:25:48.000000000 +0000 @@ -298,26 +298,22 @@ */ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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))) { @@ -699,6 +696,7 @@ EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data; unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize; unsigned long FileAlignment = 0; + UINT16 DllFlags; if (datasize < sizeof (PEHdr->Pe32)) { perror(L"Invalid image\n"); @@ -793,13 +791,21 @@ context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint; context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + DllFlags = PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics; } else { context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase; context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint; context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + DllFlags = PEHdr->Pe32.OptionalHeader.DllCharacteristics; } + if ((mok_policy & MOK_POLICY_REQUIRE_NX) && + !(DllFlags & EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT)) { + perror(L"Policy requires NX, but image does not support NX\n"); + return EFI_UNSUPPORTED; + } + context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER)); if (context->ImageSize < context->SizeOfHeaders) { @@ -823,7 +829,7 @@ } EFI_STATUS -handle_sbat(char *SBATBase, size_t SBATSize) +verify_sbat_section(char *SBATBase, size_t SBATSize) { unsigned int i; EFI_STATUS efi_status; @@ -837,7 +843,12 @@ if (SBATBase == NULL || SBATSize == 0) { dprint(L"No .sbat section data\n"); - return EFI_SECURITY_VIOLATION; + /* + * SBAT is mandatory for binaries loaded by shim, but optional + * for binaries loaded outside of shim but verified via the + * protocol. + */ + return in_protocol ? EFI_SUCCESS : EFI_SECURITY_VIOLATION; } sbat_size = SBATSize + 1; @@ -876,6 +887,201 @@ return efi_status; } +static inline uint64_t +shim_mem_attrs_to_uefi_mem_attrs (uint64_t attrs) +{ + uint64_t ret = EFI_MEMORY_RP | + EFI_MEMORY_RO | + EFI_MEMORY_XP; + + if (attrs & MEM_ATTR_R) + ret &= ~EFI_MEMORY_RP; + + if (attrs & MEM_ATTR_W) + ret &= ~EFI_MEMORY_RO; + + if (attrs & MEM_ATTR_X) + ret &= ~EFI_MEMORY_XP; + + return ret; +} + +static inline uint64_t +uefi_mem_attrs_to_shim_mem_attrs (uint64_t attrs) +{ + uint64_t ret = MEM_ATTR_R | + MEM_ATTR_W | + MEM_ATTR_X; + + if (attrs & EFI_MEMORY_RP) + ret &= ~MEM_ATTR_R; + + if (attrs & EFI_MEMORY_RO) + ret &= ~MEM_ATTR_W; + + if (attrs & EFI_MEMORY_XP) + ret &= ~MEM_ATTR_X; + + return ret; +} + +static EFI_STATUS +get_mem_attrs (uintptr_t addr, size_t size, uint64_t *attrs) +{ + EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL; + EFI_PHYSICAL_ADDRESS physaddr = addr; + EFI_STATUS efi_status; + + efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID, + (VOID **)&proto); + if (EFI_ERROR(efi_status) || !proto) + return efi_status; + + if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) { + dprint(L"%a called on 0x%llx-0x%llx and attrs 0x%llx\n", + __func__, (unsigned long long)physaddr, + (unsigned long long)(physaddr+size-1), + attrs); + return EFI_SUCCESS; + } + + efi_status = proto->GetMemoryAttributes(proto, physaddr, size, attrs); + *attrs = uefi_mem_attrs_to_shim_mem_attrs (*attrs); + + return efi_status; +} + +static EFI_STATUS +update_mem_attrs(uintptr_t addr, uint64_t size, + uint64_t set_attrs, uint64_t clear_attrs) +{ + EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL; + EFI_PHYSICAL_ADDRESS physaddr = addr; + EFI_STATUS efi_status, ret; + uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs; + + efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID, + (VOID **)&proto); + if (EFI_ERROR(efi_status) || !proto) + return efi_status; + + efi_status = get_mem_attrs (addr, size, &before); + if (EFI_ERROR(efi_status)) + dprint(L"get_mem_attrs(0x%llx, 0x%llx, 0x%llx) -> 0x%lx\n", + (unsigned long long)addr, (unsigned long long)size, + &before, efi_status); + + if (physaddr & 0xfff || size & 0xfff || size == 0) { + dprint(L"%a called on 0x%llx-0x%llx (size 0x%llx) +%a%a%a -%a%a%a\n", + __func__, (unsigned long long)physaddr, + (unsigned long long)(physaddr + size - 1), + (unsigned long long)size, + (set_attrs & MEM_ATTR_R) ? "r" : "", + (set_attrs & MEM_ATTR_W) ? "w" : "", + (set_attrs & MEM_ATTR_X) ? "x" : "", + (clear_attrs & MEM_ATTR_R) ? "r" : "", + (clear_attrs & MEM_ATTR_W) ? "w" : "", + (clear_attrs & MEM_ATTR_X) ? "x" : ""); + return 0; + } + + uefi_set_attrs = shim_mem_attrs_to_uefi_mem_attrs (set_attrs); + dprint("translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs); + uefi_clear_attrs = shim_mem_attrs_to_uefi_mem_attrs (clear_attrs); + dprint("translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs); + efi_status = EFI_SUCCESS; + if (uefi_set_attrs) + efi_status = proto->SetMemoryAttributes(proto, physaddr, size, uefi_set_attrs); + if (!EFI_ERROR(efi_status) && uefi_clear_attrs) + efi_status = proto->ClearMemoryAttributes(proto, physaddr, size, uefi_clear_attrs); + ret = efi_status; + + efi_status = get_mem_attrs (addr, size, &after); + if (EFI_ERROR(efi_status)) + dprint(L"get_mem_attrs(0x%llx, %llu, 0x%llx) -> 0x%lx\n", + (unsigned long long)addr, (unsigned long long)size, + &after, efi_status); + + dprint(L"set +%a%a%a -%a%a%a on 0x%llx-0x%llx before:%c%c%c after:%c%c%c\n", + (set_attrs & MEM_ATTR_R) ? "r" : "", + (set_attrs & MEM_ATTR_W) ? "w" : "", + (set_attrs & MEM_ATTR_X) ? "x" : "", + (clear_attrs & MEM_ATTR_R) ? "r" : "", + (clear_attrs & MEM_ATTR_W) ? "w" : "", + (clear_attrs & MEM_ATTR_X) ? "x" : "", + (unsigned long long)addr, (unsigned long long)(addr + size - 1), + (before & MEM_ATTR_R) ? 'r' : '-', + (before & MEM_ATTR_W) ? 'w' : '-', + (before & MEM_ATTR_X) ? 'x' : '-', + (after & MEM_ATTR_R) ? 'r' : '-', + (after & MEM_ATTR_W) ? 'w' : '-', + (after & MEM_ATTR_X) ? 'x' : '-'); + + return ret; +} + +EFI_STATUS verify_image(void *data, unsigned int datasize, + EFI_LOADED_IMAGE *li, + PE_COFF_LOADER_IMAGE_CONTEXT *context) +{ + EFI_STATUS efi_status; + UINT8 sha1hash[SHA1_DIGEST_SIZE]; + UINT8 sha256hash[SHA256_DIGEST_SIZE]; + + /* + * The binary header contains relevant context and section pointers + */ + efi_status = read_header(data, datasize, context); + if (EFI_ERROR(efi_status)) { + perror(L"Failed to read header: %r\n", efi_status); + return efi_status; + } + + /* + * Perform the image verification before we start copying data around + * in order to load it. + */ + if (secure_mode()) { + efi_status = verify_buffer(data, datasize, + context, sha256hash, sha1hash); + if (EFI_ERROR(efi_status)) { + if (verbose) + console_print(L"Verification failed: %r\n", efi_status); + else + console_error(L"Verification failed", efi_status); + return efi_status; + } else if (verbose) + console_print(L"Verification succeeded\n"); + } + + /* + * Calculate the hash for the TPM measurement. + * XXX: We're computing these twice in secure boot mode when the + * buffers already contain the previously computed hashes. Also, + * this is only useful for the TPM1.2 case. We should try to fix + * this in a follow-up. + */ + efi_status = generate_hash(data, datasize, context, sha256hash, + sha1hash); + if (EFI_ERROR(efi_status)) + return efi_status; + + /* Measure the binary into the TPM */ +#ifdef REQUIRE_TPM + efi_status = +#endif + tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize, + (EFI_PHYSICAL_ADDRESS)(UINTN)context->ImageAddress, + li->FilePath, sha1hash, 4); +#ifdef REQUIRE_TPM + if (efi_status != EFI_SUCCESS) { + return efi_status; + } +#endif + + return EFI_SUCCESS; +} + /* * Once the image has been loaded it needs to be validated and relocated */ @@ -891,6 +1097,7 @@ int i; EFI_IMAGE_SECTION_HEADER *Section; char *base, *end; + UINT32 size; PE_COFF_LOADER_IMAGE_CONTEXT context; unsigned int alignment, alloc_size; int found_entry_point = 0; @@ -907,7 +1114,31 @@ } /* - * We only need to verify the binary if we're in secure mode + * Perform the image verification before we start copying data around + * in order to load it. + */ + if (secure_mode ()) { + efi_status = verify_buffer(data, datasize, &context, sha256hash, + sha1hash); + + if (EFI_ERROR(efi_status)) { + if (verbose) + console_print(L"Verification failed: %r\n", efi_status); + else + console_error(L"Verification failed", efi_status); + return efi_status; + } else { + if (verbose) + console_print(L"Verification succeeded\n"); + } + } + + /* + * Calculate the hash for the TPM measurement. + * XXX: We're computing these twice in secure boot mode when the + * buffers already contain the previously computed hashes. Also, + * this is only useful for the TPM1.2 case. We should try to fix + * this in a follow-up. */ efi_status = generate_hash(data, datasize, &context, sha256hash, sha1hash); @@ -949,21 +1180,26 @@ 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; } buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment); + dprint(L"Loading 0x%llx bytes at 0x%llx\n", + (unsigned long long)context.ImageSize, + (unsigned long long)(uintptr_t)buffer); + update_mem_attrs((uintptr_t)buffer, alloc_size, MEM_ATTR_R|MEM_ATTR_W, + MEM_ATTR_X); CopyMem(buffer, data, context.SizeOfHeaders); *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; } @@ -983,9 +1219,6 @@ EFI_IMAGE_SECTION_HEADER *RelocSection = NULL; - char *SBATBase = NULL; - size_t SBATSize = 0; - /* * Copy the executable's sections to their desired offsets */ @@ -996,6 +1229,20 @@ !Section->Misc.VirtualSize) continue; + /* + * Skip sections that aren't marked readable. + */ + if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_READ)) + continue; + + if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) && + (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) && + (Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) && + (mok_policy & MOK_POLICY_REQUIRE_NX)) { + perror(L"Section %d is writable and executable\n", i); + return EFI_UNSUPPORTED; + } + base = ImageAddress (buffer, context.ImageSize, Section->VirtualAddress); end = ImageAddress (buffer, context.ImageSize, @@ -1004,7 +1251,7 @@ 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; } @@ -1030,33 +1277,6 @@ RelocBaseEnd == end) { RelocSection = Section; } - } else if (CompareMem(Section->Name, ".sbat\0\0\0", 8) == 0) { - if (SBATBase || SBATSize) { - perror(L"Image has multiple SBAT sections\n"); - return EFI_UNSUPPORTED; - } - - if (Section->NumberOfRelocations != 0 || - Section->PointerToRelocations != 0) { - perror(L"SBAT section has relocations\n"); - return EFI_UNSUPPORTED; - } - - /* The virtual size corresponds to the size of the SBAT - * metadata and isn't necessarily a multiple of the file - * alignment. The on-disk size is a multiple of the file - * alignment and is zero padded. Make sure that the - * on-disk size is at least as large as virtual size, - * and ignore the section if it isn't. */ - if (Section->SizeOfRawData && - Section->SizeOfRawData >= Section->Misc.VirtualSize && - base && end) { - SBATBase = base; - /* +1 because of size vs last byte location */ - SBATSize = end - base + 1; - dprint(L"sbat section base:0x%lx size:0x%lx\n", - SBATBase, SBATSize); - } } if (Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) { @@ -1087,32 +1307,15 @@ return EFI_UNSUPPORTED; } - if (Section->SizeOfRawData > 0) - CopyMem(base, data + Section->PointerToRawData, - Section->SizeOfRawData); - - if (Section->SizeOfRawData < Section->Misc.VirtualSize) - ZeroMem(base + Section->SizeOfRawData, - Section->Misc.VirtualSize - Section->SizeOfRawData); - } - } - - if (secure_mode ()) { - efi_status = handle_sbat(SBATBase, SBATSize); + size = Section->Misc.VirtualSize; + if (size > Section->SizeOfRawData) + size = Section->SizeOfRawData; - if (!EFI_ERROR(efi_status)) - efi_status = verify_buffer(data, datasize, - &context, sha256hash, sha1hash); + if (size > 0) + CopyMem(base, data + Section->PointerToRawData, size); - if (EFI_ERROR(efi_status)) { - if (verbose) - console_print(L"Verification failed: %r\n", efi_status); - else - console_error(L"Verification failed", efi_status); - return efi_status; - } else { - if (verbose) - console_print(L"Verification succeeded\n"); + if (size < Section->Misc.VirtualSize) + ZeroMem(base + size, Section->Misc.VirtualSize - size); } } @@ -1137,6 +1340,50 @@ } /* + * Now set the page permissions appropriately. + */ + Section = context.FirstSection; + for (i = 0; i < context.NumberOfSections; i++, Section++) { + uint64_t set_attrs = MEM_ATTR_R; + uint64_t clear_attrs = MEM_ATTR_W|MEM_ATTR_X; + uintptr_t addr; + uint64_t length; + + /* + * Skip discardable sections with zero size + */ + if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) && + !Section->Misc.VirtualSize) + continue; + + /* + * Skip sections that aren't marked readable. + */ + if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_READ)) + continue; + + base = ImageAddress (buffer, context.ImageSize, + Section->VirtualAddress); + end = ImageAddress (buffer, context.ImageSize, + Section->VirtualAddress + + Section->Misc.VirtualSize - 1); + + addr = (uintptr_t)base; + length = (uintptr_t)end - (uintptr_t)base + 1; + + if (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) { + set_attrs |= MEM_ATTR_W; + clear_attrs &= ~MEM_ATTR_W; + } + if (Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) { + set_attrs |= MEM_ATTR_X; + clear_attrs &= ~MEM_ATTR_X; + } + update_mem_attrs(addr, length, set_attrs, clear_attrs); + } + + + /* * grub needs to know its location and size in memory, so fix up * the loaded image protocol values */ @@ -1144,17 +1391,15 @@ 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 -Nru shim-15.4/post-process-pe.c shim-15.6/post-process-pe.c --- shim-15.4/post-process-pe.c 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/post-process-pe.c 2022-06-01 18:25:48.000000000 +0000 @@ -0,0 +1,547 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * post-process-pe.c - fix up timestamps and checksums in broken PE files + * Copyright Peter Jones + */ + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; \ + }) + +static bool set_nx_compat = false; + +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 %zu", 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, (unsigned long)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 (%ld) * sizeof(EFI_IMAGE_DATA_DIRECTORY) overflows\n", + (unsigned long)ctx->NumberOfRvaAndSizes); + else + debug(ERROR, + "ctx->NumberOfRvaAndSizes (%ld) * sizeof(EFI_IMAGE_DATA_DIRECTORY) = %zu\n", + (unsigned long)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", (size_t)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 +set_dll_characteristics(PE_COFF_LOADER_IMAGE_CONTEXT *ctx) +{ + uint16_t oldflags, newflags; + + if (image_is_64_bit(ctx->PEHdr)) { + oldflags = ctx->PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics; + } else { + oldflags = ctx->PEHdr->Pe32.OptionalHeader.DllCharacteristics; + } + + if (set_nx_compat) + newflags = oldflags | EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT; + else + newflags = oldflags & ~(uint16_t)EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT; + if (oldflags == newflags) + return; + + debug(INFO, "Updating DLL Characteristics from 0x%04hx to 0x%04hx\n", + oldflags, newflags); + if (image_is_64_bit(ctx->PEHdr)) { + ctx->PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics = newflags; + } else { + ctx->PEHdr->Pe32.OptionalHeader.DllCharacteristics = newflags; + } +} + +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); + + set_dll_characteristics(&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; + } + rc = 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, " -N Disable the NX compatibility flag\n"); + fprintf(out, " -n Enable the NX compatibility flag\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 = "disable-nx-compat", + .val = 'N', + }, + {.name = "enable-nx-compat", + .val = 'n', + }, + {.name = "quiet", + .val = 'q', + }, + {.name = "verbose", + .val = 'v', + }, + {.name = ""} + }; + int longindex = -1; + + while ((i = getopt_long(argc, argv, "hNnqv", options, &longindex)) != -1) { + switch (i) { + case 'h': + case '?': + usage(longindex == -1 ? 1 : 0); + break; + case 'N': + set_nx_compat = false; + break; + case 'n': + set_nx_compat = true; + 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 diff -Nru shim-15.4/replacements.c shim-15.6/replacements.c --- shim-15.4/replacements.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/replacements.c 2022-06-01 18:25:48.000000000 +0000 @@ -33,7 +33,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -Nru shim-15.4/sbat.c shim-15.6/sbat.c --- shim-15.4/sbat.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/sbat.c 2022-06-01 18:25:48.000000000 +0000 @@ -113,13 +113,14 @@ } EFI_STATUS -verify_single_entry(struct sbat_section_entry *entry, struct sbat_var_entry *sbat_var_entry) +verify_single_entry(struct sbat_section_entry *entry, struct sbat_var_entry *sbat_var_entry, bool *found) { UINT16 sbat_gen, sbat_var_gen; if (strcmp((const char *)entry->component_name, (const char *)sbat_var_entry->component_name) == 0) { dprint(L"component %a has a matching SBAT variable entry, verifying\n", entry->component_name); + *found = true; /* * atoi returns zero for failed conversion, so essentially @@ -172,10 +173,13 @@ for (i = 0; i < n; i++) { list_for_each(pos, local_sbat_var) { + bool found = false; sbat_var_entry = list_entry(pos, struct sbat_var_entry, list); - efi_status = verify_single_entry(entries[i], sbat_var_entry); + efi_status = verify_single_entry(entries[i], sbat_var_entry, &found); if (EFI_ERROR(efi_status)) goto out; + if (found) + break; } } @@ -285,6 +289,7 @@ UINT8 *data = 0; UINTN datasize; EFI_STATUS efi_status; + list_t *pos = NULL; if (!entries) { dprint(L"entries is NULL\n"); @@ -301,7 +306,20 @@ * We've intentionally made sure there's a NUL byte on all variable * allocations, so use that here. */ - return parse_sbat_var_data(entries, data, datasize+1); + efi_status = parse_sbat_var_data(entries, data, datasize+1); + if (EFI_ERROR(efi_status)) + return efi_status; + + dprint(L"SBAT variable entries:\n"); + list_for_each(pos, entries) { + struct sbat_var_entry *entry; + + entry = list_entry(pos, struct sbat_var_entry, list); + dprint(L"%a, %a, %a\n", entry->component_name, + entry->component_generation, entry->sbat_datestamp); + } + + return efi_status; } static bool @@ -315,12 +333,64 @@ #endif } +static char * +nth_sbat_field(char *str, size_t limit, int n) +{ + size_t i; + for (i = 0; i < limit && str[i] != '\0'; i++) { + if (n == 0) + return &str[i]; + if (str[i] == ',') + n--; + } + return &str[i]; +} + bool -preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes) +preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes, + char *sbat_var) { - return check_sbat_var_attributes(attributes) && - sbatsize >= strlen(SBAT_VAR_SIG "1") && - !strncmp((const char *)sbat, SBAT_VAR_SIG, strlen(SBAT_VAR_SIG)); + char *sbatc = (char *)sbat; + char *current_version, *new_version, + *current_datestamp, *new_datestamp; + int current_version_len, new_version_len; + + /* current metadata is not currupt somehow */ + if (!check_sbat_var_attributes(attributes) || + sbatsize < strlen(SBAT_VAR_ORIGINAL) || + strncmp(sbatc, SBAT_VAR_SIG, strlen(SBAT_VAR_SIG))) + return false; + + /* current metadata version not newer */ + current_version = nth_sbat_field(sbatc, sbatsize, 1); + new_version = nth_sbat_field(sbat_var, strlen(sbat_var)+1, 1); + current_datestamp = nth_sbat_field(sbatc, sbatsize, 2); + new_datestamp = nth_sbat_field(sbat_var, strlen(sbat_var)+1, 2); + + current_version_len = current_datestamp - current_version - 1; + new_version_len = new_datestamp - new_version - 1; + + if (current_version_len > new_version_len || + (current_version_len == new_version_len && + strncmp(current_version, new_version, new_version_len) > 0)) + return true; + + /* current datestamp is not newer or idential */ + if (strncmp(current_datestamp, new_datestamp, + strlen(SBAT_VAR_ORIGINAL_DATE)) >= 0) + return true; + + return false; +} + +static void +clear_sbat_policy() +{ + EFI_STATUS efi_status = EFI_SUCCESS; + + efi_status = del_variable(SBAT_POLICY, SHIM_LOCK_GUID); + if (EFI_ERROR(efi_status)) + console_error(L"Could not reset SBAT Policy", efi_status); } EFI_STATUS @@ -330,7 +400,49 @@ UINT32 attributes = 0; UINT8 *sbat = NULL; + UINT8 *sbat_policy = NULL; UINTN sbatsize = 0; + UINTN sbat_policysize = 0; + + char *sbat_var = NULL; + bool reset_sbat = false; + + efi_status = get_variable_attr(SBAT_POLICY, &sbat_policy, + &sbat_policysize, SHIM_LOCK_GUID, + &attributes); + if (EFI_ERROR(efi_status)) { + dprint("Default sbat policy: previous\n"); + sbat_var = SBAT_VAR_PREVIOUS; + } else { + switch (*sbat_policy) { + case SBAT_POLICY_LATEST: + dprint("Custom sbat policy: latest\n"); + sbat_var = SBAT_VAR_LATEST; + clear_sbat_policy(); + break; + case SBAT_POLICY_PREVIOUS: + dprint("Custom sbat policy: previous\n"); + sbat_var = SBAT_VAR_PREVIOUS; + break; + case SBAT_POLICY_RESET: + if (secure_mode()) { + console_print(L"Cannot reset SBAT policy: Secure Boot is enabled.\n"); + sbat_var = SBAT_VAR_PREVIOUS; + } else { + dprint(L"Custom SBAT policy: reset OK\n"); + reset_sbat = true; + sbat_var = SBAT_VAR_ORIGINAL; + } + clear_sbat_policy(); + break; + default: + console_error(L"SBAT policy state %llu is invalid", + EFI_INVALID_PARAMETER); + sbat_var = SBAT_VAR_PREVIOUS; + clear_sbat_policy(); + break; + } + } efi_status = get_variable_attr(SBAT_VAR_NAME, &sbat, &sbatsize, SHIM_LOCK_GUID, &attributes); @@ -342,8 +454,9 @@ */ if (EFI_ERROR(efi_status)) { dprint(L"SBAT read failed %r\n", efi_status); - } else if (preserve_sbat_uefi_variable(sbat, sbatsize, attributes)) { - dprint(L"%s variable is %d bytes, attributes are 0x%08x\n", + } else if (preserve_sbat_uefi_variable(sbat, sbatsize, attributes, sbat_var) + && !reset_sbat) { + dprint(L"preserving %s variable it is %d bytes, attributes are 0x%08x\n", SBAT_VAR_NAME, sbatsize, attributes); FreePool(sbat); return EFI_SUCCESS; @@ -365,7 +478,7 @@ /* set variable */ efi_status = set_variable(SBAT_VAR_NAME, SHIM_LOCK_GUID, SBAT_VAR_ATTRS, - sizeof(SBAT_VAR)-1, SBAT_VAR); + strlen(sbat_var), sbat_var); if (EFI_ERROR(efi_status)) { dprint(L"%s variable writing failed %r\n", SBAT_VAR_NAME, efi_status); @@ -380,10 +493,10 @@ return efi_status; } - if (sbatsize != strlen(SBAT_VAR) || - strncmp((const char *)sbat, SBAT_VAR, strlen(SBAT_VAR)) != 0) { + if (sbatsize != strlen(sbat_var) || + strncmp((const char *)sbat, sbat_var, strlen(sbat_var)) != 0) { dprint("new sbatsize is %d, expected %d\n", sbatsize, - strlen(SBAT_VAR)); + strlen(sbat_var)); efi_status = EFI_INVALID_PARAMETER; } else { dprint(L"%s variable initialization succeeded\n", SBAT_VAR_NAME); diff -Nru shim-15.4/shim.c shim-15.6/shim.c --- shim-15.4/shim.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/shim.c 2022-06-01 18:25:48.000000000 +0000 @@ -40,10 +40,6 @@ 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 @@ 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 @@ 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 @@ * 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; } @@ -577,9 +559,9 @@ * Check that the signature is valid and matches the binary */ EFI_STATUS -verify_buffer (char *data, int datasize, - PE_COFF_LOADER_IMAGE_CONTEXT *context, - UINT8 *sha256hash, UINT8 *sha1hash) +verify_buffer_authenticode (char *data, int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context, + UINT8 *sha256hash, UINT8 *sha1hash) { EFI_STATUS ret_efi_status; size_t size = datasize; @@ -713,26 +695,78 @@ return ret_efi_status; } +/* + * Check that the binary is permitted to load by SBAT. + */ +EFI_STATUS +verify_buffer_sbat (char *data, int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context) +{ + int i; + EFI_IMAGE_SECTION_HEADER *Section; + char *SBATBase = NULL; + size_t SBATSize = 0; + + Section = context->FirstSection; + for (i = 0; i < context->NumberOfSections; i++, Section++) { + if (CompareMem(Section->Name, ".sbat\0\0\0", 8) != 0) + continue; + + if (SBATBase || SBATSize) { + perror(L"Image has multiple SBAT sections\n"); + return EFI_UNSUPPORTED; + } + + if (Section->NumberOfRelocations != 0 || + Section->PointerToRelocations != 0) { + perror(L"SBAT section has relocations\n"); + return EFI_UNSUPPORTED; + } + + /* The virtual size corresponds to the size of the SBAT + * metadata and isn't necessarily a multiple of the file + * alignment. The on-disk size is a multiple of the file + * alignment and is zero padded. Make sure that the + * on-disk size is at least as large as virtual size, + * and ignore the section if it isn't. */ + if (Section->SizeOfRawData && + Section->SizeOfRawData >= Section->Misc.VirtualSize) { + SBATBase = ImageAddress(data, datasize, + Section->PointerToRawData); + SBATSize = Section->SizeOfRawData; + dprint(L"sbat section base:0x%lx size:0x%lx\n", + SBATBase, SBATSize); + } + } + + return verify_sbat_section(SBATBase, SBATSize); +} + +/* + * Check that the signature is valid and matches the binary and that + * the binary is permitted to load by SBAT. + */ +EFI_STATUS +verify_buffer (char *data, int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context, + UINT8 *sha256hash, UINT8 *sha1hash) +{ + EFI_STATUS efi_status; + + efi_status = verify_buffer_sbat(data, datasize, context); + if (EFI_ERROR(efi_status)) + return efi_status; + + return verify_buffer_authenticode(data, datasize, context, sha256hash, sha1hash); +} + 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 +784,38 @@ 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 +846,9 @@ 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 +868,8 @@ /* * 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; @@ -1085,24 +1053,19 @@ /* * Load and run an EFI executable */ -EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath) +EFI_STATUS read_image(EFI_HANDLE image_handle, CHAR16 *ImagePath, + CHAR16 **PathName, void **data, int *datasize) { EFI_STATUS efi_status; - EFI_IMAGE_ENTRY_POINT entry_point; - EFI_PHYSICAL_ADDRESS alloc_address; - UINTN alloc_pages; - CHAR16 *PathName = NULL; void *sourcebuffer = NULL; UINT64 sourcesize = 0; - void *data = NULL; - int datasize = 0; /* * 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; @@ -1111,11 +1074,11 @@ /* * Build a new path from the existing one plus the executable name */ - efi_status = generate_path_from_image_path(shim_li, ImagePath, &PathName); + efi_status = generate_path_from_image_path(shim_li, ImagePath, PathName); if (EFI_ERROR(efi_status)) { perror(L"Unable to generate path %s: %r\n", ImagePath, efi_status); - goto done; + return efi_status; } if (findNetboot(shim_li->DeviceHandle)) { @@ -1131,8 +1094,8 @@ efi_status); return efi_status; } - data = sourcebuffer; - datasize = sourcesize; + *data = sourcebuffer; + *datasize = sourcesize; } else if (find_httpboot(shim_li->DeviceHandle)) { efi_status = httpboot_fetch_buffer (image_handle, &sourcebuffer, @@ -1142,26 +1105,45 @@ efi_status); return efi_status; } - data = sourcebuffer; - datasize = sourcesize; + *data = sourcebuffer; + *datasize = sourcesize; } else { /* * Read the new executable off disk */ - efi_status = load_image(shim_li, &data, &datasize, PathName); + efi_status = load_image(shim_li, data, datasize, *PathName); if (EFI_ERROR(efi_status)) { perror(L"Failed to load image %s: %r\n", PathName, efi_status); PrintErrors(); ClearErrors(); - goto done; + return efi_status; } } - if (datasize < 0) { + if (*datasize < 0) efi_status = EFI_INVALID_PARAMETER; + + return efi_status; +} + +/* + * Load and run an EFI executable + */ +EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath) +{ + EFI_STATUS efi_status; + EFI_IMAGE_ENTRY_POINT entry_point; + EFI_PHYSICAL_ADDRESS alloc_address; + UINTN alloc_pages; + CHAR16 *PathName = NULL; + void *data = NULL; + int datasize = 0; + + efi_status = read_image(image_handle, ImagePath, &PathName, &data, + &datasize); + if (EFI_ERROR(efi_status)) goto done; - } /* * We need to modify the loaded image protocol entry before running @@ -1233,151 +1215,25 @@ 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 +1243,33 @@ { 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. - */ - +#if defined(DISABLE_REMOVABLE_LOAD_OPTIONS) /* - * Maybe there just aren't any options... + * boot services build very strange load options, and we might misparse them, + * causing boot failures on removable media. */ - 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; - - /* - * 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); - } - - /* - * 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. - */ + if (is_removable_media_path(li)) { + dprint("Invoked from removable media path, ignoring boot options"); return EFI_SUCCESS; } +#endif - /* - * 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 +1348,10 @@ /* * 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 +1377,8 @@ /* * 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; @@ -1721,6 +1392,127 @@ } EFI_STATUS +load_cert_file(EFI_HANDLE image_handle, CHAR16 *filename, CHAR16 *PathName) +{ + EFI_STATUS efi_status; + EFI_LOADED_IMAGE li; + PE_COFF_LOADER_IMAGE_CONTEXT context; + EFI_IMAGE_SECTION_HEADER *Section; + EFI_SIGNATURE_LIST *certlist; + void *pointer; + UINT32 original; + int datasize = 0; + void *data = NULL; + int i; + + efi_status = read_image(image_handle, filename, &PathName, + &data, &datasize); + if (EFI_ERROR(efi_status)) + return efi_status; + + memset(&li, 0, sizeof(li)); + memcpy(&li.FilePath[0], filename, MIN(StrSize(filename), sizeof(li.FilePath))); + + efi_status = verify_image(data, datasize, &li, &context); + if (EFI_ERROR(efi_status)) + return efi_status; + + Section = context.FirstSection; + for (i = 0; i < context.NumberOfSections; i++, Section++) { + if (CompareMem(Section->Name, ".db\0\0\0\0\0", 8) == 0) { + original = user_cert_size; + if (Section->SizeOfRawData < sizeof(EFI_SIGNATURE_LIST)) { + continue; + } + pointer = ImageAddress(data, datasize, + Section->PointerToRawData); + if (!pointer) { + continue; + } + certlist = pointer; + user_cert_size += certlist->SignatureListSize;; + user_cert = ReallocatePool(user_cert, original, + user_cert_size); + memcpy(user_cert + original, pointer, + certlist->SignatureListSize); + } + } + FreePool(data); + return EFI_SUCCESS; +} + +/* Read additional certificates from files (after verifying signatures) */ +EFI_STATUS +load_certs(EFI_HANDLE image_handle) +{ + EFI_STATUS efi_status; + EFI_LOADED_IMAGE *li = NULL; + CHAR16 *PathName = NULL; + EFI_FILE *root, *dir; + EFI_FILE_INFO *info; + EFI_HANDLE device; + EFI_FILE_IO_INTERFACE *drive; + UINTN buffersize = 0; + void *buffer = NULL; + + efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID, + (void **)&li); + if (EFI_ERROR(efi_status)) { + perror(L"Unable to init protocol\n"); + return efi_status; + } + + efi_status = generate_path_from_image_path(li, L"", &PathName); + if (EFI_ERROR(efi_status)) + goto done; + + device = li->DeviceHandle; + efi_status = gBS->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 done; + } + + efi_status = drive->OpenVolume(drive, &root); + if (EFI_ERROR(efi_status)) { + perror(L"Failed to open fs: %r\n", efi_status); + goto done; + } + + efi_status = root->Open(root, &dir, PathName, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(efi_status)) { + perror(L"Failed to open %s - %r\n", PathName, efi_status); + goto done; + } + + while (1) { + int old = buffersize; + efi_status = dir->Read(dir, &buffersize, buffer); + if (efi_status == EFI_BUFFER_TOO_SMALL) { + buffer = ReallocatePool(buffer, old, buffersize); + continue; + } else if (EFI_ERROR(efi_status)) { + perror(L"Failed to read directory %s - %r\n", PathName, + efi_status); + goto done; + } + + info = (EFI_FILE_INFO *)buffer; + if (buffersize == 0 || !info) + goto done; + + if (StrnCaseCmp(info->FileName, L"shim_certificate", 16) == 0) { + load_cert_file(image_handle, info->FileName, PathName); + } + } +done: + FreePool(buffer); + FreePool(PathName); + return efi_status; +} + +EFI_STATUS shim_init(void) { EFI_STATUS efi_status; @@ -1777,12 +1569,6 @@ unhook_exit(); - /* - * Free the space allocated for the alternative 2nd stage loader - */ - if (load_options_size > 0 && second_stage) - FreePool(second_stage); - console_fini(); } @@ -1799,17 +1585,10 @@ register volatile UINTN x = 0; extern char _text, _data; - const CHAR16 * const debug_var_name = -#ifdef ENABLE_SHIM_DEVEL - L"SHIM_DEVEL_DEBUG"; -#else - L"SHIM_DEBUG"; -#endif - if (x) return; - efi_status = get_variable(debug_var_name, &data, &dataSize, + efi_status = get_variable(DEBUG_VAR_NAME, &data, &dataSize, SHIM_LOCK_GUID); if (EFI_ERROR(efi_status)) { return; @@ -1823,7 +1602,7 @@ console_print(L"Pausing for debugger attachment.\n"); console_print(L"To disable this, remove the EFI variable %s-%g .\n", - debug_var_name, &SHIM_LOCK_GUID); + DEBUG_VAR_NAME, &SHIM_LOCK_GUID); x = 1; while (x++) { /* Make this so it can't /totally/ DoS us. */ @@ -1837,7 +1616,7 @@ if (x > 12000) break; #endif - pause(); + wait_for_debug(); } x = 1; } @@ -1867,7 +1646,7 @@ 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 } @@ -1956,7 +1735,7 @@ goto die; } - efi_status = handle_sbat(sbat_start, sbat_end - sbat_start - 1); + efi_status = verify_sbat_section(sbat_start, sbat_end - sbat_start - 1); if (EFI_ERROR(efi_status)) { perror(L"Verifiying shim SBAT data failed: %r\n", efi_status); @@ -1968,15 +1747,25 @@ init_openssl(); + if (secure_mode()) { + efi_status = load_certs(global_image_handle); + if (EFI_ERROR(efi_status)) { + LogError(L"Failed to load addon certificates\n"); + } + } + /* * Before we do anything else, validate our non-volatile, * 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 +1780,8 @@ 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 -Nru shim-15.4/shim.h shim-15.6/shim.h --- shim-15.4/shim.h 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/shim.h 2022-06-01 18:25:48.000000000 +0000 @@ -27,6 +27,10 @@ #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 @@ -167,6 +171,8 @@ #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" @@ -189,6 +195,10 @@ #include "Cryptlib/Include/OpenSslSupport.h" #endif +#define MEM_ATTR_R 4 +#define MEM_ATTR_W 2 +#define MEM_ATTR_X 1 + INTERFACE_DECL(_SHIM_LOCK); typedef @@ -242,6 +252,9 @@ extern UINT32 vendor_deauthorized_size; extern UINT8 *vendor_deauthorized; +extern UINT32 user_cert_size; +extern UINT8 *user_cert; + #if defined(ENABLE_SHIM_CERT) extern UINT32 build_cert_size; extern UINT8 *build_cert; @@ -249,6 +262,9 @@ extern UINT8 user_insecure_mode; extern UINT8 ignore_db; +extern UINT8 trust_mok_list; +extern UINT8 mok_policy; + extern UINT8 in_protocol; extern void *load_options; extern UINT32 load_options_size; @@ -277,6 +293,16 @@ #define LogError(fmt, ...) #endif +#ifdef ENABLE_SHIM_DEVEL +#define FALLBACK_VERBOSE_VAR_NAME L"FALLBACK_DEVEL_VERBOSE" +#define VERBOSE_VAR_NAME L"SHIM_DEVEL_VERBOSE" +#define DEBUG_VAR_NAME L"SHIM_DEVEL_DEBUG" +#else +#define FALLBACK_VERBOSE_VAR_NAME L"FALLBACK_VERBOSE" +#define VERBOSE_VAR_NAME L"SHIM_VERBOSE" +#define DEBUG_VAR_NAME L"SHIM_DEBUG" +#endif + char *translate_slashes(char *out, const char *str); #endif /* SHIM_H_ */ diff -Nru shim-15.4/test-csv.c shim-15.6/test-csv.c --- shim-15.4/test-csv.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/test-csv.c 2022-06-01 18:25:48.000000000 +0000 @@ -338,6 +338,68 @@ } 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) { char csv[] = @@ -456,6 +518,7 @@ 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++) { Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-0/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-0/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-0/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-0/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-0/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-0/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-0/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-0/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-0/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AMD_PBS_SETUP-a339d746-f678-49b3-9fc7-54ce0f9df226 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AMD_RAID-fe26a894-d199-47d4-8afa-070e3d54ba86 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AMITSESetup-c811fa38-42c8-4579-a9bb-60e94eddfb34 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AMITSESetup-c811fa38-42c8-4579-a9bb-60e94eddfb34 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AOD_SETUP-5ed15dc0-edef-4161-9151-6014c4cc630c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AOD_SETUP-5ed15dc0-edef-4161-9151-6014c4cc630c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AmdAcpiVar-79941ecd-ed36-49d0-8124-e4c31ac75cd4 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AmdAcpiVar-79941ecd-ed36-49d0-8124-e4c31ac75cd4 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AmdSetup-3a997502-647a-4c82-998e-52ef9486a247 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AmdSetup-3a997502-647a-4c82-998e-52ef9486a247 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AmiHardwareSignatureSetupUpdateCountVar-81c76078-bfde-4368-9790-570914c01a65 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AmiHardwareSignatureSetupUpdateCountVar-81c76078-bfde-4368-9790-570914c01a65 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/ApSyncFlagNv-ad3f6761-f0a3-46c8-a4cb-19b70ffdb305 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ApSyncFlagNv-ad3f6761-f0a3-46c8-a4cb-19b70ffdb305 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AsbkpInfo-cb825795-feb1-4c0b-894f-cc70f8064395 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsbkpInfo-cb825795-feb1-4c0b-894f-cc70f8064395 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AsusExtFancard-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusExtFancard-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AsusFanSetupFeatures-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusFanSetupFeatures-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AsusHwmSetupOneof-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusHwmSetupOneof-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AsusNodePsu-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusNodePsu-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AsusQFanSetupData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusQFanSetupData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AsusRomLayout-7186d975-2dba-4413-81a8-9f1538faef5e and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusRomLayout-7186d975-2dba-4413-81a8-9f1538faef5e differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AsusSetupDataBackup-1111b056-c5e9-40ca-aba3-ec172533d814 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AsusSetupDataBackup-1111b056-c5e9-40ca-aba3-ec172533d814 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/AutoDetectData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/AutoDetectData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/BiosEventLog-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BiosEventLog-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Boot0004-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0004-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Boot0005-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0005-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Boot0006-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Boot0006-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/BootFromUSB-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BootFromUSB-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/CMOSfailflag-c89dc9c7-5105-472c-a743-b1621e142b41 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/CMOSfailflag-c89dc9c7-5105-472c-a743-b1621e142b41 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/CurrentPolicy-77fa9abd-0359-4d32-bd60-28f4e78f784b and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/CurrentPolicy-77fa9abd-0359-4d32-bd60-28f4e78f784b differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/DefaultBootOrder-45cf35f6-0d6e-4d04-856a-0370a5b16f53 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/DefaultBootOrder-45cf35f6-0d6e-4d04-856a-0370a5b16f53 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/DeploymentModeNv-97e8965f-c761-4f48-b6e4-9ffa9cb2a2d6 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/DeploymentModeNv-97e8965f-c761-4f48-b6e4-9ffa9cb2a2d6 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/DownCoreStatus-29749bad-401b-4f6d-b124-cece8c590c48 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/DownCoreStatus-29749bad-401b-4f6d-b124-cece8c590c48 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/EnWpData-cbab171f-f356-4009-baaa-6628353a0a29 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/EnWpData-cbab171f-f356-4009-baaa-6628353a0a29 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/FPLayoutOrder-4db88a62-6721-47a0-9082-280b00323594 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/FPLayoutOrder-4db88a62-6721-47a0-9082-280b00323594 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/FTMActiveFlag-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/FTMActiveFlag-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/FastBootOption-b540a530-6978-4da7-91cb-7207d764d262 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/FastBootOption-b540a530-6978-4da7-91cb-7207d764d262 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/FirstBootFlag-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/FirstBootFlag-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/HddSmartInfo-a6f44860-b2e8-4fda-bd45-78368994b6ae and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/HddSmartInfo-a6f44860-b2e8-4fda-bd45-78368994b6ae differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/HiiDB-1b838190-4625-4ead-abc9-cd5e6af18fe0 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/HiiDB-1b838190-4625-4ead-abc9-cd5e6af18fe0 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/HwErrRecSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/HwErrRecSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/KEKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/KEKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Kernel_ATPSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_ATPSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Kernel_DriverSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_DriverSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Kernel_RvkSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_RvkSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Kernel_SiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_SiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Kernel_SkuSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_SkuSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Kernel_WinSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Kernel_WinSiStatus-77fa9abd-0359-4d32-bd60-28f4e78f784b differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/LastBoot-b540a530-6978-4da7-91cb-7207d764d262 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/LastBoot-b540a530-6978-4da7-91cb-7207d764d262 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MaximumTableSize-4b3082a3-80c6-4d7e-9cd0-583917265df1 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MaximumTableSize-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MemoryOverwriteRequestControlLock-bb983ccf-151d-40e1-a07b-4a17be168292 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MemoryOverwriteRequestControlLock-bb983ccf-151d-40e1-a07b-4a17be168292 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MokList-605dab50-e046-4300-abb6-3dd810dd8b23 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MokList-605dab50-e046-4300-abb6-3dd810dd8b23 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MokListX-605dab50-e046-4300-abb6-3dd810dd8b23 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MokListX-605dab50-e046-4300-abb6-3dd810dd8b23 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MonotonicCounter-01368881-c4ad-4b1d-b631-d57a8ec8db6b and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MonotonicCounter-01368881-c4ad-4b1d-b631-d57a8ec8db6b differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/MyFav-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/MyFav-4034591c-48ea-4cdc-864f-e7cb61cfd0f2 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/NVRAM_Verify-15a9dd61-e4f8-4a99-80db-353b13d76490 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/NVRAM_Verify-15a9dd61-e4f8-4a99-80db-353b13d76490 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/NetworkStackVar-d1405d16-7afc-4695-bb12-41459d3695a2 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/NetworkStackVar-d1405d16-7afc-4695-bb12-41459d3695a2 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/NvHdd0-e57abcbd-9456-4639-8f65-06aab41d840f and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/NvHdd0-e57abcbd-9456-4639-8f65-06aab41d840f differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/NvHdd8-e57abcbd-9456-4639-8f65-06aab41d840f and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/NvHdd8-e57abcbd-9456-4639-8f65-06aab41d840f differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/OsIndications-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/OsIndications-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/PCI_COMMON-aca9f304-21e2-4852-9875-7ff4881d67a5 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PCI_COMMON-aca9f304-21e2-4852-9875-7ff4881d67a5 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/PcieSataModVar-5e9a565f-cdc0-413b-ad13-1fe8713ffdcd and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PcieSataModVar-5e9a565f-cdc0-413b-ad13-1fe8713ffdcd differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/PreVgaInfo-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/PreVgaInfo-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/RsdpAddr-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/RsdpAddr-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SIDSUPPORT-7d3dceee-cbce-4ea7-8709-6e552f1edbde and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SIDSUPPORT-7d3dceee-cbce-4ea7-8709-6e552f1edbde differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SecureBootSetup-7b59104a-c00d-4158-87ff-f04d6396a915 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SecureBootSetup-7b59104a-c00d-4158-87ff-f04d6396a915 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Setup-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Setup-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SetupLedData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SetupLedData-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SmbiosEntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SmbiosEntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SmbiosScratchBuffer-4b3082a3-80c6-4d7e-9cd0-583917265df1 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SmbiosScratchBuffer-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/SmbiosV3EntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/SmbiosV3EntryPointTable-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/StdDefaults-4599d26f-1a11-49b8-b91f-858745cff824 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/StdDefaults-4599d26f-1a11-49b8-b91f-858745cff824 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/TPMPERBIOSFLAGS-7d3dceee-cbce-4ea7-8709-6e552f1edbde and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/TPMPERBIOSFLAGS-7d3dceee-cbce-4ea7-8709-6e552f1edbde differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/TotalNumberOfRootBridges-fb5703f5-f8a7-f401-18b4-3f108deb2612 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/TotalNumberOfRootBridges-fb5703f5-f8a7-f401-18b4-3f108deb2612 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/TpmServFlags-7d3dceee-cbce-4ea7-8709-6e552f1edbde and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/TpmServFlags-7d3dceee-cbce-4ea7-8709-6e552f1edbde differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/UsbSupport-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/UsbSupport-ec87d643-eba4-4bb5-a1e5-3f3e36b20da9 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/VARSTORE_OCMR_SETTINGS_NAME-c05fba7d-7a92-49e0-bcee-233b14dca803 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/VARSTORE_OCMR_SETTINGS_NAME-c05fba7d-7a92-49e0-bcee-233b14dca803 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/WpBufAddr-cba83c4a-a5fc-48a8-b3a6-d33636166544 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/WpBufAddr-cba83c4a-a5fc-48a8-b3a6-d33636166544 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/WriteOnceStatus-4b3082a3-80c6-4d7e-9cd0-583917265df1 and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/WriteOnceStatus-4b3082a3-80c6-4d7e-9cd0-583917265df1 differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/dbDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f differ Binary files /srv/release.debian.org/tmp/ZIxWlf_GBy/shim-15.4/test-data/efivars-1/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c and /srv/release.debian.org/tmp/ltUclMyKTK/shim-15.6/test-data/efivars-1/dbxDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c differ diff -Nru shim-15.4/test-load-options.c shim-15.6/test-load-options.c --- shim-15.4/test-load-options.c 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/test-load-options.c 2022-06-01 18:25:48.000000000 +0000 @@ -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 +#include +#include + +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 -Nru shim-15.4/test-mock-variables.c shim-15.6/test-mock-variables.c --- shim-15.4/test-mock-variables.c 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/test-mock-variables.c 2022-06-01 18:25:48.000000000 +0000 @@ -0,0 +1,842 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * test-mock-variables.c - test our mock variable implementation (irony) + * Copyright Peter Jones + */ + +#include "shim.h" +#include "mock-variables.h" + +#include +#include +#include +#include +#include + +#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 -Nru shim-15.4/test-mok-mirror.c shim-15.6/test-mok-mirror.c --- shim-15.4/test-mok-mirror.c 1970-01-01 00:00:00.000000000 +0000 +++ shim-15.6/test-mok-mirror.c 2022-06-01 18:25:48.000000000 +0000 @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * test-mok-mirror.c - try to test our mok mirroring code + * Copyright Peter Jones + */ + +#include "shim.h" +#include "mock-variables.h" +#include "test-data-efivars-1.h" + +#include + +#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 = "MokListTrustedRT", + .data_size = sizeof(test_data_efivars_1_MokListTrustedRT), + .data = test_data_efivars_1_MokListTrustedRT + }, + {.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 diff -Nru shim-15.4/test-sbat.c shim-15.6/test-sbat.c --- shim-15.4/test-sbat.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/test-sbat.c 2022-06-01 18:25:48.000000000 +0000 @@ -14,6 +14,11 @@ list_t sbat_var; +BOOLEAN +secure_mode() { + return 1; +} + #if 0 /* * Mock test helpers @@ -965,11 +970,96 @@ int test_preserve_sbat_uefi_variable_good(void) { - char sbat[] = "sbat,1,\ncomponent,2,\n"; + char sbat[] = "sbat,1,2021030218\ncomponent,2,\n"; + char sbatvar[] = "sbat,1,2021030218\ncomponent,2,\n"; + size_t sbat_size = sizeof(sbat); + UINT32 attributes = SBAT_VAR_ATTRS; + + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) + return 0; + else + return -1; +} + +int +test_preserve_sbat_uefi_variable_version_newer(void) +{ + char sbat[] = "sbat,2,2022030218\ncomponent,2,\n"; + char sbatvar[] = "sbat,1,2021030218\ncomponent,2,\n"; + size_t sbat_size = sizeof(sbat); + UINT32 attributes = SBAT_VAR_ATTRS; + + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) + return 0; + else + return -1; +} + +int +test_preserve_sbat_uefi_variable_version_newerlonger(void) +{ + char sbat[] = "sbat,10,2022030218\ncomponent,2,\n"; + char sbatvar[] = "sbat,2,2021030218\ncomponent,2,\n"; + size_t sbat_size = sizeof(sbat); + UINT32 attributes = SBAT_VAR_ATTRS; + + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) + return 0; + else + return -1; +} + +int +test_preserve_sbat_uefi_variable_version_older(void) +{ + char sbat[] = "sbat,1,2021030218\ncomponent,2,\n"; + char sbatvar[] = "sbat,2,2022030218\ncomponent,2,\n"; + size_t sbat_size = sizeof(sbat); + UINT32 attributes = SBAT_VAR_ATTRS; + + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) + return -1; + else + return 0; +} + +int +test_preserve_sbat_uefi_variable_version_olderlonger(void) +{ + char sbat[] = "sbat,2,2021030218\ncomponent,2,\n"; + char sbatvar[] = "sbat,10,2022030218\ncomponent,2,\n"; + size_t sbat_size = sizeof(sbat); + UINT32 attributes = SBAT_VAR_ATTRS; + + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) + return -1; + else + return 0; +} + + +int +test_preserve_sbat_uefi_variable_newer(void) +{ + char sbat[] = "sbat,1,2021030218\ncomponent,2,\n"; + char sbatvar[] = "sbat,1,2025030218\ncomponent,5,\ncomponent,3"; + size_t sbat_size = sizeof(sbat); + UINT32 attributes = SBAT_VAR_ATTRS; + + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) + return -1; + else + return 0; +} +int +test_preserve_sbat_uefi_variable_older(void) +{ + char sbat[] = "sbat,1,2025030218\ncomponent,2,\ncomponent,3"; + char sbatvar[] = "sbat,1,2020030218\ncomponent,1,\n"; size_t sbat_size = sizeof(sbat); UINT32 attributes = SBAT_VAR_ATTRS; - if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes)) + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) return 0; else return -1; @@ -978,11 +1068,12 @@ int test_preserve_sbat_uefi_variable_bad_sig(void) { - char sbat[] = "bad_sig,1,\ncomponent,2,\n"; + char sbat[] = "bad_sig,1,2021030218\ncomponent,2,\n"; + char sbatvar[] = "sbat,1,2021030218\n"; size_t sbat_size = sizeof(sbat); UINT32 attributes = SBAT_VAR_ATTRS; - if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes)) + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) return -1; else return 0; @@ -991,11 +1082,12 @@ int test_preserve_sbat_uefi_variable_bad_attr(void) { - char sbat[] = "sbat,1,\ncomponent,2,\n"; + char sbat[] = "sbat,1,2021030218\ncomponent,2,\n"; + char sbatvar[] = "sbat,1,2021030218\n"; size_t sbat_size = sizeof(sbat); UINT32 attributes = 0; - if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes)) + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) return -1; else return 0; @@ -1005,10 +1097,11 @@ test_preserve_sbat_uefi_variable_bad_short(void) { char sbat[] = "sba"; + char sbatvar[] = "sbat,1,2021030218\n"; size_t sbat_size = sizeof(sbat); UINT32 attributes = SBAT_VAR_ATTRS; - if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes)) + if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar)) return -1; else return 0; @@ -1052,9 +1145,15 @@ test(test_parse_and_verify); test(test_preserve_sbat_uefi_variable_good); + test(test_preserve_sbat_uefi_variable_newer); + test(test_preserve_sbat_uefi_variable_older); test(test_preserve_sbat_uefi_variable_bad_sig); test(test_preserve_sbat_uefi_variable_bad_attr); test(test_preserve_sbat_uefi_variable_bad_short); + test(test_preserve_sbat_uefi_variable_version_newer); + test(test_preserve_sbat_uefi_variable_version_newerlonger); + test(test_preserve_sbat_uefi_variable_version_older); + test(test_preserve_sbat_uefi_variable_version_olderlonger); return 0; } diff -Nru shim-15.4/test-str.c shim-15.6/test-str.c --- shim-15.4/test-str.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/test-str.c 2022-06-01 18:25:48.000000000 +0000 @@ -926,12 +926,15 @@ test_strncpy(void) { char s[] = "0123456789abcdef\0000"; - char s0[4096+4096]; - char *s1 = &s0[4096]; + char s0[4096]; + char s1[4096]; memset(s0, 0, sizeof(s0)); memcpy(s0, s, sizeof(s)); - +#if __GNUC_PREREQ(8, 1) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-truncation" +#endif memset(s1, 0, 4096); assert_equal_return(strncpy(s1, s0, 0), s1, -1, "got %p expected %p\n"); assert_equal_return(strlen(s1), 0, -1, "got %d expected %d\n"); @@ -1030,7 +1033,9 @@ assert_equal_return(s1[16], '\000', -1, "got %#02hhx expected %02hhx\n"); assert_equal_return(s1[17], '0', -1, "got %#02hhx expected %02hhx\n"); assert_equal_return(s1[18], '1', -1, "got %#02hhx expected %02hhx\n"); - +#if __GNUC_PREREQ(8, 1) +# pragma GCC diagnostic pop +#endif return 0; } @@ -1038,12 +1043,12 @@ test_strcat(void) { char s[] = "0123456789abcdef\0000"; - char s0[8192]; - char *s1 = &s0[4096]; + char s0[4096]; + char s1[4096]; char *s2; char s3[] = "0123456789abcdef0123456789abcdef\000\000\000\000\000"; - memset(s0, 0, 8192); + memset(s0, 0, sizeof(s0)); memcpy(s0, s, sizeof(s)); memset(s1, 0, 4096); @@ -1067,7 +1072,7 @@ * 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 -Nru shim-15.4/test.c shim-15.6/test.c --- shim-15.4/test.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/test.c 2022-06-01 18:25:48.000000000 +0000 @@ -4,64 +4,273 @@ * Copyright Peter Jones */ -#ifndef SHIM_UNIT_TEST -#define SHIM_UNIT_TEST -#endif #include "shim.h" +#include +#include +#include + +#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); - - 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_unsupported() +{ + return EFI_UNSUPPORTED; } -INTN -StrnCmp(CONST CHAR16 *s1, CONST CHAR16 *s2, UINTN len) { - assert(s1 != NULL); - assert(s2 != NULL); - - UINTN i; - for (i = 0; i < len && s1[i] && s2[i]; i++) { - if (s1[i] != s2[i]) - return s2[i] - s1[i]; +EFI_STATUS EFIAPI +mock_efi_not_found() +{ + return EFI_NOT_FOUND; +} +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, +}; + +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; +} + +void +console_error(CHAR16 *err, EFI_STATUS efi_status) +{ + return; +} + +#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 -Nru shim-15.4/tpm.c shim-15.6/tpm.c --- shim-15.4/tpm.c 2021-03-30 20:55:03.000000000 +0000 +++ shim-15.6/tpm.c 2022-06-01 18:25:48.000000000 +0000 @@ -10,6 +10,7 @@ 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 @@ 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 @@ (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 @@ 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