From 26a394ce8466f431d1bf1085e6f91b3380f683af Mon Sep 17 00:00:00 2001 From: longpanda Date: Tue, 23 Jun 2026 21:02:56 +0800 Subject: [PATCH] Ventoy Secure Boot Policy Update - Add Ventoy Preload module. --- EDK2/build_shim.sh | 55 ++ EDK2/buildedk.sh | 4 + .../MdeModulePkg/Application/Ventoy/Ventoy.c | 35 + .../MdeModulePkg/Application/Ventoy/Ventoy.h | 2 + .../Application/Ventoy/Ventoy.inf | 4 + .../Application/VtoyShim/VtoyShim.c | 709 ++++++++++++++++++ .../Application/VtoyShim/VtoyShim.h | 121 +++ .../Application/VtoyShim/VtoyShim.inf | 83 ++ .../Application/VtoyShim/sbat.csv | 2 + .../Application/VtoyUtil/VtoyUtil.c | 53 +- .../Application/VtoyUtil/VtoyUtil.h | 12 +- .../Application/VtoyUtil/VtoyUtil.inf | 5 +- .../MdeModulePkg/MdeModulePkg.dsc | 1 + 13 files changed, 1071 insertions(+), 15 deletions(-) create mode 100644 EDK2/build_shim.sh create mode 100644 EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.c create mode 100644 EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.h create mode 100644 EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.inf create mode 100644 EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/sbat.csv diff --git a/EDK2/build_shim.sh b/EDK2/build_shim.sh new file mode 100644 index 00000000..edefa4d2 --- /dev/null +++ b/EDK2/build_shim.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +if [ -z "$1" ]; then + EDKARCH=X64 + postfix=x64 +elif [ "$1" = "ia32" ]; then + EDKARCH=IA32 + postfix=ia32 + shift +elif [ "$1" = "aa64" ]; then + EDKARCH=AARCH64 + postfix=aa64 + shift +fi + +cd edk2-edk2-stable201911 + +rm -rf ./Conf/.cache +rm -f ./Conf/.AutoGenIdFile.txt + +VTEFI_PATH=Build/MdeModule/RELEASE_GCC48/$EDKARCH/MdeModulePkg/Application/VtoyShim/VtoyShim/OUTPUT/VtoyShim.efi +DST_PATH=../../INSTALL/EFI/BOOT/fb${postfix}.efi + + +rm -f $VTEFI_PATH +rm -f $DST_PATH + +unset WORKSPACE +source ./edksetup.sh + +if [ "$EDKARCH" = "AARCH64" ]; then + PATH=$PATH:/opt/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu/bin \ + GCC48_AARCH64_PREFIX=aarch64-linux-gnu- \ + build -p MdeModulePkg/MdeModulePkg.dsc -a $EDKARCH -b RELEASE -t GCC48 -m MdeModulePkg/Application/VtoyShim/VtoyShim.inf +else + build -p MdeModulePkg/MdeModulePkg.dsc -a $EDKARCH -b RELEASE -t GCC48 -m MdeModulePkg/Application/VtoyShim/VtoyShim.inf +fi + +if [ -e $VTEFI_PATH ]; then + objcopy \ + --add-section .sbat="MdeModulePkg/Application/VtoyShim/sbat.csv" \ + --set-section-flags .sbat=alloc,load,readonly,data \ + "$VTEFI_PATH" "$DST_PATH" + + objcopy --adjust-section-vma .sbat=0x1000 "$DST_PATH" + + echo -e '\n\n====================== SUCCESS ========================\n\n' + + cd .. +else + echo -e '\n\n====================== FAILED ========================\n\n' + cd .. + exit 1 +fi + diff --git a/EDK2/buildedk.sh b/EDK2/buildedk.sh index e001303b..14823c07 100644 --- a/EDK2/buildedk.sh +++ b/EDK2/buildedk.sh @@ -19,3 +19,7 @@ sh ./build.sh aa64 || exit 1 echo '======== build EDK2 for x86_64-efi ===============' sh ./build.sh || exit 1 + +echo '======== build EDK2 for x86_64-efi ===============' +sh ./build_shim.sh || exit 1 + diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c index 65342013..3ca80f62 100644 --- a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c @@ -1231,6 +1231,32 @@ EFI_STATUS EFIAPI ventoy_boot(IN EFI_HANDLE ImageHandle) return EFI_SUCCESS; } +#if defined (MDE_CPU_X64) +STATIC BOOLEAN EFIAPI CheckVtoyShim(VOID) +{ + UINT8 SecureBoot = 0; + UINTN DataSize; + EFI_STATUS Status; + EFI_GUID Guid = VTOY_SHIM_POLICY_GUID; + VOID *Prot = NULL; + + DataSize = sizeof(SecureBoot); + Status = gST->RuntimeServices->GetVariable(L"SecureBoot", &gEfiGlobalVariableGuid, NULL, + &DataSize, &SecureBoot); + if (!EFI_ERROR(Status) && SecureBoot) + { + Status = gBS->LocateProtocol(&Guid, NULL, (VOID**)&Prot); + if (EFI_ERROR(Status)) + { + VtoyDebug("Failed to locate Vtoy Shim Protocol %lx\r\n", Status); + return FALSE; + } + } + + return TRUE; +} +#endif + EFI_STATUS EFIAPI VentoyEfiMain ( IN EFI_HANDLE ImageHandle, @@ -1240,6 +1266,15 @@ EFI_STATUS EFIAPI VentoyEfiMain EFI_STATUS Status = EFI_SUCCESS; EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *Protocol; +#if defined (MDE_CPU_X64) + /* check that Ventoy Shim must exist */ + if (!CheckVtoyShim()) + { + sleep(5); + return EFI_NOT_FOUND; + } +#endif + g_sector_flag_num = 512; /* initial value */ g_sector_flag = AllocatePool(g_sector_flag_num * sizeof(ventoy_sector_flag)); diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h index 40ba6b13..35fd5e45 100644 --- a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h @@ -23,6 +23,8 @@ #define COMPILE_ASSERT(expr) extern char __compile_assert[(expr) ? 1 : -1] +#define VTOY_SHIM_POLICY_GUID {0x90a29d14, 0x3968, 0x48fe, { 0x85, 0x81, 0x6b, 0x7f, 0x7d, 0xc4, 0x70, 0x55 }}; + #define VENTOY_GUID { 0x77772020, 0x2e77, 0x6576, { 0x6e, 0x74, 0x6f, 0x79, 0x2e, 0x6e, 0x65, 0x74 }} typedef enum ventoy_chain_type diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.inf b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.inf index 374efdd7..36ec0ab0 100644 --- a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.inf +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.inf @@ -24,6 +24,10 @@ VERSION_STRING = 1.0 ENTRY_POINT = VentoyEfiMain + +[BuildOptions] + # Force standard GNU ld to pack and align ELF segments to 4KB page boundaries + GCC:*_*_*_DLINK_FLAGS = -Wl,-z,common-page-size=0x1000 -Wl,-z,max-page-size=0x1000 [Sources] Ventoy.h diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.c b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.c new file mode 100644 index 00000000..88476d68 --- /dev/null +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.c @@ -0,0 +1,709 @@ +/****************************************************************************** + * VtoyShim.c + * + * Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: BSD-2-Clause-Patent + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CUR_SBAT_VER 1 + +STATIC EFI_GUID gVtoySbatGUID = { 0xf755068a, 0xe04f, 0x452b, { 0x9d, 0x6d, 0x7c, 0x55, 0x96, 0xb3, 0xc0, 0x7d }}; +STATIC EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *gDpToText = NULL; +STATIC EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *gTextToDp = NULL; +STATIC EFI_SECURITY_FILE_AUTHENTICATION_STATE gSysSecFileAuth = NULL; +STATIC EFI_SECURITY2_FILE_AUTHENTICATION gSysSec2FileAuth = NULL; +STATIC BOOLEAN gVtoyByPassSB = FALSE; /* must be FALSE by default for revoke */ +STATIC VTOY_SHIM gVtoyShimProtocol; +STATIC EFI_HANDLE gVtoyShimProtHandle; +STATIC SHIM_LOCK *gShimLock = NULL; + +STATIC VOID EFIAPI VtoyLog(CONST CHAR16 *Format, ...) +{ + VA_LIST Marker; + CHAR16 Buffer[512]; + UINTN BufLen = 0; + + Buffer[0] = 0; + VA_START(Marker, Format); + BufLen = UnicodeVSPrint(Buffer, sizeof(Buffer), Format, Marker); + VA_END(Marker); + + if (gST->ConOut && gST->ConOut->OutputString) + { + gST->ConOut->OutputString(gST->ConOut, Buffer); + } +} + + +STATIC VOID EFIAPI DumpDevicePath(const EFI_DEVICE_PATH_PROTOCOL *DevicePath) +{ + CHAR16 *DPStr = NULL; + + DPStr = gDpToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE); + if (DPStr) + { + vLog(L"%s", DPStr); + gBS->FreePool(DPStr); + } + else + { + vLog(L"NULL"); + } +} + +STATIC VOID EFIAPI ShowSBWarning(BOOLEAN Reboot, const EFI_DEVICE_PATH_PROTOCOL *DevicePath) +{ + UINTN Index = 0; + + vLog(L"\r\n======================================================="); + vLog(L"=======================================================\r\n"); + + DumpDevicePath(DevicePath); + + vLog(L"\r\n####### Security Boot Violation ##########\r\n"); + + vLog(L"======================================================="); + vLog(L"======================================================="); + + if (Reboot) + { + vLog(L"\r\n###### Press Enter to reboot... ######"); + gST->ConIn->Reset(gST->ConIn, FALSE); + gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index); + gRT->ResetSystem(EfiResetWarm, EFI_SECURITY_VIOLATION, 0, NULL); + } + else + { + VtoySleep(5); + } +} + + +STATIC VOID * EFIAPI FindShimFuncAddr(UINT64 FuncOffset) +{ + EFI_STATUS Status; + SHIM_IMAGE_LOADER *ImgLoader = NULL; + EFI_GUID ShimImgLoaderGuid = SHIM_IMAGE_LOADER_GUID; + + Status = gBS->LocateProtocol(&ShimImgLoaderGuid, NULL, (VOID **)&ImgLoader); + if (EFI_ERROR(Status) || !ImgLoader || !ImgLoader->LoadImage) + { + vLog(L"Failed to locate shim image loader protocol %lx %p", Status, ImgLoader); + return NULL; + } + + if (NM_SHIM_LOAD_IMAGE_OFFSET > FuncOffset) + { + return (UINT8 *)ImgLoader->LoadImage - (NM_SHIM_LOAD_IMAGE_OFFSET - FuncOffset); + } + else + { + return (UINT8 *)ImgLoader->LoadImage + (FuncOffset - NM_SHIM_LOAD_IMAGE_OFFSET); + } +} + + +EFI_STATUS EFIAPI LaunchRealGrub(EFI_HANDLE ImageHandle, CONST CHAR16 *FileName) +{ + EFI_STATUS Status; + UINTN BufferSize = 0; + CHAR16 *DevDpStr = NULL; + CHAR16 *NewDpStr = NULL; + EFI_HANDLE ChildHandle = NULL; + EFI_LOADED_IMAGE_PROTOCOL *Li = NULL; + EFI_DEVICE_PATH_PROTOCOL *DeviceDP = NULL; + EFI_DEVICE_PATH_PROTOCOL *TargetDp = NULL; + + Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID**)&Li); + if (EFI_ERROR(Status)) + { + vLog(L"Failed to locate loaded image protocol %lx", Status); + return Status; + } + + DeviceDP = DevicePathFromHandle(Li->DeviceHandle); + if (!DeviceDP || !IsDevicePathValid(DeviceDP, 0)) + { + vLog(L"Failed to get device path of device handle %p", Li->DeviceHandle); + Status = EFI_NOT_FOUND; + goto END; + } + + DevDpStr = gDpToText->ConvertDevicePathToText(DeviceDP, FALSE, TRUE); + if (!DevDpStr) + { + vLog(L"Failed to convert device path to text"); + Status = EFI_OUT_OF_RESOURCES; + goto END; + } + + BufferSize = (StrLen(DevDpStr) + 64) * sizeof(CHAR16); + NewDpStr = (CHAR16 *)AllocatePool(BufferSize); + if (!NewDpStr) + { + vLog(L"Failed to alloc new device path string buffer size:%lu", BufferSize); + Status = EFI_OUT_OF_RESOURCES; + goto END; + } + + UnicodeSPrint(NewDpStr, BufferSize, L"%s/EFI/BOOT/%s", DevDpStr, FileName); + + TargetDp = gTextToDp->ConvertTextToDevicePath(NewDpStr); + if (!TargetDp) + { + vLog(L"Failed to convert new text <%s> to device path", NewDpStr); + Status = EFI_NOT_FOUND; + goto END; + } + + Status = gBS->LoadImage(FALSE, ImageHandle, TargetDp, NULL, 0, &ChildHandle); + if (EFI_ERROR(Status)) + { + vLog(L"Failed to LoadImage %lx", Status); + goto END; + } + + + Status = gBS->StartImage(ChildHandle, NULL, NULL); + if (EFI_ERROR(Status)) + { + vLog(L"Failed to StartImage %lx", Status); + gBS->UnloadImage(ChildHandle); + goto END; + } + + +END: + + CheckBSFreePool(DevDpStr); + CheckFreePool(NewDpStr); + CheckBSFreePool(TargetDp); + + return Status; +} + + + +STATIC EFI_STATUS EFIAPI ReadAuthFile +( + const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst, + VOID **Buffer, + UINT32 *Size +) +{ + EFI_STATUS Status; + UINTN TmpSize = 0; + CHAR16 *DpStr = NULL; + EFI_HANDLE Handle = NULL; + EFI_DEVICE_PATH *DevPath = NULL; + EFI_DEVICE_PATH *TmpPath = NULL; + EFI_FILE_IO_INTERFACE *FileIO = NULL; + EFI_FILE *File = NULL; + EFI_FILE *Root = NULL; + UINT8 *FileData = NULL; + EFI_FILE_INFO *FInfo = NULL; + UINT8 Buf[1024]; + + DevPath = TmpPath = DuplicateDevicePath(DevicePathConst); + if (!DevPath) + { + Status = EFI_OUT_OF_RESOURCES; + goto END; + } + + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevPath, &Handle); + if (EFI_ERROR(Status)) + { + vLog(L"Failed to locate simple file protocol %lx", Status); + goto END; + } + + DpStr = gDpToText->ConvertDevicePathToText(DevPath, FALSE, TRUE); + if (!DpStr) + { + Status = EFI_OUT_OF_RESOURCES; + goto END; + } + + Status = gBS->HandleProtocol(Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileIO); + if (EFI_ERROR(Status)) + { + vLog(L"Failed to handle simple file protocol %lx", Status); + goto END; + } + + Status = FileIO->OpenVolume(Handle, &Root); + if (EFI_ERROR(Status)) + { + vLog(L"Failed to open drive volume (%lx)\n", Status); + goto END; + } + + Status = Root->Open(Root, &File, DpStr, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) + { + vLog(L"Failed to open file (%s) (%lx)\n", DpStr, Status); + goto END; + } + + FInfo = (EFI_FILE_INFO *)Buf; + TmpSize = sizeof(Buf); + ZeroMem(FInfo, sizeof(EFI_FILE_INFO)); + + Status = File->GetInfo(File, &gEfiFileInfoGuid, &TmpSize, FInfo); + if (EFI_ERROR(Status) || FInfo->FileSize == 0 || FInfo->FileSize >= 0xFFFFFFFFUL) + { + vLog(L"Failed to open file (%s) (%lx) Size(%ld)\n", DpStr, Status, (UINTN)FInfo->FileSize); + goto END; + } + + FileData = AllocatePool(FInfo->FileSize); + if (!FileData) + { + Status = EFI_OUT_OF_RESOURCES; + goto END; + } + + TmpSize = FInfo->FileSize; + Status = File->Read(File, &TmpSize, FileData); + if (EFI_ERROR(Status) || TmpSize != (UINTN)FInfo->FileSize) + { + vLog(L"Failed to read file (%lx) Read:%ld Size:%ld\n", Status, TmpSize, (UINTN)FInfo->FileSize); + goto END; + } + + +END: + + if (File) + { + File->Close(File); + } + + if (Root) + { + Root->Close(Root); + } + + CheckFreePool(TmpPath); + CheckBSFreePool(DpStr); + + if (EFI_ERROR(Status)) + { + CheckFreePool(FileData); + } + else + { + *Buffer = FileData; + *Size = (UINT32)FInfo->FileSize; + } + + return Status; +} + + +STATIC BOOLEAN VtoyCheckRevoke(VOID *Buffer, UINTN Size) +{ + UINT32 uiVer = 0; + EFI_IMAGE_DOS_HEADER *DosHead = (EFI_IMAGE_DOS_HEADER *)Buffer; + + if (Size > sizeof(EFI_IMAGE_DOS_HEADER)) + { + if (CompareMem(DosHead->e_res2, &gVtoySbatGUID, 16) == 0) + { + CopyMem(&uiVer, DosHead->e_res2 + 8, 4); + if (uiVer < CUR_SBAT_VER) + { + vLog(L"Ventoy EFI file revoke (%u < %u)", uiVer, CUR_SBAT_VER); + return FALSE; + } + } + } + + return TRUE; +} + +STATIC EFI_STATUS EFIAPI SecurityPolicyAuth +( + const EFI_SECURITY_ARCH_PROTOCOL *This, + UINT32 AuthenticationStatus, + const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst +) +{ + EFI_STATUS Status; + BOOLEAN bRevokeChkOK = TRUE; + UINT32 Size = 0; + VOID *Buffer = NULL; + + /* Just return OK if the user choose to bypass SB */ + if (gVtoyByPassSB) + { + return EFI_SUCCESS; + } + + /* + * Step 1: + * Use original UEFI firmware auth API. + * If it's OK, it may be signed with Microsoft UEFI CA. (e.g. bootmgr/shim/...) + */ + if (gSysSecFileAuth) + { + Status = gSysSecFileAuth(This, AuthenticationStatus, DevicePathConst); + if (!EFI_ERROR(Status)) + { + return EFI_SUCCESS; + } + } + + + /* + * Step 2: + * Use shim verify API. + * If it's OK, it may be signed with a MOK key. (e.g. Ventoy EFI files) + */ + if (gShimLock && gShimLock->Verify) + { + Status = ReadAuthFile(DevicePathConst, &Buffer, &Size); + if (!EFI_ERROR(Status)) + { + Status = gShimLock->Verify(Buffer, Size); + if (!EFI_ERROR(Status)) + { + bRevokeChkOK = VtoyCheckRevoke(Buffer, Size); + if (bRevokeChkOK) + { + FreePool(Buffer); + return EFI_SUCCESS; + } + } + FreePool(Buffer); + } + } + + ShowSBWarning(!bRevokeChkOK, DevicePathConst); + + return EFI_SECURITY_VIOLATION; +} + +STATIC EFI_STATUS EFIAPI Security2PolicyAuth +( + const EFI_SECURITY2_ARCH_PROTOCOL *This, + const EFI_DEVICE_PATH_PROTOCOL *DevicePath, + VOID *FileBuffer, + UINTN FileSize, + BOOLEAN BootPolicy +) +{ + EFI_STATUS Status; + BOOLEAN bRevokeChkOK = TRUE; + + /* Just return OK if the user choose to bypass SB */ + if (gVtoyByPassSB) + { + return EFI_SUCCESS; + } + + /* + * Step 1: + * Use original UEFI firmware auth API. + * If it's OK, it may be signed with Microsoft UEFI CA. (e.g. bootmgr/shim/...) + */ + if (gSysSec2FileAuth) + { + Status = gSysSec2FileAuth(This, DevicePath, FileBuffer, FileSize, BootPolicy); + if (!EFI_ERROR(Status)) + { + return EFI_SUCCESS; + } + } + + + /* + * Step 2: + * Use shim verify API. + * If it's OK, it may be signed with a MOK key. (e.g. Ventoy EFI files) + */ + if (gShimLock && gShimLock->Verify) + { + if (FileBuffer && FileSize > 0 && FileSize < 0xFFFFFFFFUL) + { + Status = gShimLock->Verify(FileBuffer, (UINT32)FileSize); + if (!EFI_ERROR(Status)) + { + bRevokeChkOK = VtoyCheckRevoke(FileBuffer, FileSize); + if (bRevokeChkOK) + { + return EFI_SUCCESS; + } + } + } + } + + ShowSBWarning(!bRevokeChkOK, DevicePath); + + return EFI_SECURITY_VIOLATION; +} + + +STATIC EFI_STATUS EFIAPI HookSecurityPolicy(VOID) +{ + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_SECURITY_ARCH_PROTOCOL *Security = NULL; + EFI_SECURITY2_ARCH_PROTOCOL *Security2 = NULL; + + Status = gBS->LocateProtocol(&gEfiSecurityArchProtocolGuid, NULL, (VOID **)&Security); + Status2 = gBS->LocateProtocol(&gEfiSecurity2ArchProtocolGuid, NULL, (VOID **)&Security2); + if (EFI_ERROR(Status) && EFI_ERROR(Status2)) + { + vLog(L"Failed to locate security or security2 protocol. %lx %lx %p %p", + Status, Status2, Security, Security2); + return EFI_NOT_FOUND; + } + + if (Security2) + { + gSysSec2FileAuth = Security2->FileAuthentication; + Security2->FileAuthentication = Security2PolicyAuth; + } + + if (Security) + { + gSysSecFileAuth = Security->FileAuthenticationState; + Security->FileAuthenticationState = SecurityPolicyAuth; + } + + return EFI_SUCCESS; +} + +STATIC VOID EFIAPI UnHookSecurityPolicy(VOID) +{ + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_SECURITY_ARCH_PROTOCOL *Security = NULL; + EFI_SECURITY2_ARCH_PROTOCOL *Security2 = NULL; + + if (!gSysSec2FileAuth && !gSysSecFileAuth) + { + return; + } + + Status = gBS->LocateProtocol(&gEfiSecurityArchProtocolGuid, NULL, (VOID **)&Security); + Status2 = gBS->LocateProtocol(&gEfiSecurity2ArchProtocolGuid, NULL, (VOID **)&Security2); + if (EFI_ERROR(Status) && EFI_ERROR(Status2)) + { + vLog(L"Failed to locate security or security2 protocol. %lx %lx %p %p", + Status, Status2, Security, Security2); + return; + } + + if (Security2 && gSysSec2FileAuth) + { + Security2->FileAuthentication = gSysSec2FileAuth; + gSysSec2FileAuth = NULL; + } + + if (Security && gSysSecFileAuth) + { + Security->FileAuthenticationState = gSysSecFileAuth; + gSysSecFileAuth = NULL; + } +} + +STATIC VOID EFIAPI VtoyByPassSB(VOID) +{ + gVtoyByPassSB = TRUE; +} + +STATIC VOID EFIAPI VtoyCheckSB(VOID) +{ + gVtoyByPassSB = FALSE; +} + +STATIC VOID EFIAPI UnInstallVtoyShimProtocol(VOID) +{ + EFI_GUID Guid = VTOY_SHIM_POLICY_GUID; + + if (gVtoyShimProtHandle) + { + gBS->UninstallProtocolInterface(gVtoyShimProtHandle, &Guid, &gVtoyShimProtocol); + gVtoyShimProtHandle = NULL; + } +} + +STATIC EFI_STATUS EFIAPI InstallVtoyShimProtocol(VOID) +{ + EFI_STATUS Status; + EFI_GUID Guid = VTOY_SHIM_POLICY_GUID; + VTOY_SHIM *Prot = NULL; + + gVtoyShimProtocol.ByPassSB = VtoyByPassSB; + gVtoyShimProtocol.CheckSB = VtoyCheckSB; + + Status = gBS->LocateProtocol(&Guid, NULL, (VOID**)&Prot); + if (!EFI_ERROR(Status)) + { + vLog(L"Ventoy shim already loaded, cannot be nested."); + return EFI_ALREADY_STARTED; + } + + Status = gBS->InstallProtocolInterface(&gVtoyShimProtHandle, &Guid, + EFI_NATIVE_INTERFACE, &gVtoyShimProtocol); + if (EFI_ERROR(Status)) + { + vLog(L"Failed to install protocol %lx", Status); + } + + return Status; +} + +STATIC BOOLEAN EFIAPI IsSecureBootEnabled(VOID) +{ + UINT8 SecureBoot = 0; + UINTN DataSize; + EFI_STATUS Status; + + DataSize = sizeof(SecureBoot); + Status = gST->RuntimeServices->GetVariable(L"SecureBoot", &gEfiGlobalVariableGuid, NULL, + &DataSize, &SecureBoot); + if (EFI_ERROR(Status)) + { + return FALSE; + } + + return SecureBoot ? TRUE : FALSE; +} + +STATIC EFI_STATUS EFIAPI EnvInit(VOID) +{ + EFI_STATUS Status; + EFI_GUID Guid = SHIM_LOCK_GUID; + + Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&gDpToText); + if (EFI_ERROR(Status) || !gDpToText || !gDpToText->ConvertDevicePathToText) + { + vLog(L"Failed to locate PathToText Protocol %lx", Status); + return Status; + } + + Status = gBS->LocateProtocol(&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID**)&gTextToDp); + if (EFI_ERROR(Status) || !gTextToDp || !gTextToDp->ConvertTextToDevicePath) + { + vLog(L"Failed to locate PathFromText Protocol %lx", Status); + return Status; + } + + Status = gBS->LocateProtocol(&Guid, NULL, (VOID**)&gShimLock); + if (EFI_ERROR(Status) || !gShimLock) + { + vLog(L"Failed to locate SHIM LOCK Protocol %lx", Status); + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS EFIAPI VtoyShimEfiMain +( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + unhook_system_services_pf Func = NULL; + + /* If secure boot is not enabled, nothing needed, just launch Ventoy grub */ + if (!IsSecureBootEnabled()) + { + return LaunchRealGrub(ImageHandle, REAL_GRUB_FILE); + } + + Status = EnvInit(); + if (EFI_ERROR(Status)) + { + vErr(L"Failed to prepare env"); + return Status; + } + + Status = InstallVtoyShimProtocol(); + if (EFI_ERROR(Status)) + { + vErr(L"Failed to install ventoy shim protocol"); + return Status; + } + + + /* + * IMPORTANT: All recent shim implementations hook the UEFI Boot Services + * (e.g. LoadImage, StartImage) to enforce signature verification. + * + * We must restore the original system service pointers here. If we fail to do this, + * we will be unable to launch Ventoy-signed EFI binaries or any other unsigned + * EFI applications later, even when the user has explicitly opted to disable + * all Secure Boot validation checks. + * + * To the best of my knowledge, there is no official way to remove these hooks. + * This is a tricky hack that relies on shim's internal implementation details. + * It may break in future versions of shim, and a better approach may exist. + * + */ + Func = FindShimFuncAddr(NM_UNHOOK_SYSTEM_SERVICES_OFFSET); + if (!Func) + { + vErr(L"Can not find shim unhook_system_services"); + Status = EFI_NOT_FOUND; + goto END; + } + + Func(); /* call shim unhook_system_services() */ + + + /* Hook the system security policy */ + Status = HookSecurityPolicy(); + if (EFI_ERROR(Status)) + { + vErr(L"Failed to hook system security policy"); + goto END; + } + + /* Finally launch Ventoy grub */ + Status = LaunchRealGrub(ImageHandle, REAL_GRUB_FILE); + +END: + + /* UnHook system security policy */ + UnHookSecurityPolicy(); + + UnInstallVtoyShimProtocol(); + + return Status; +} + diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.h b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.h new file mode 100644 index 00000000..052cbd5f --- /dev/null +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.h @@ -0,0 +1,121 @@ +/****************************************************************************** + * VtoyShim.h + * + * Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: BSD-2-Clause-Patent + * + */ + +#ifndef __VTOYSHIM_H__ +#define __VTOYSHIM_H__ + +#if defined (MDE_CPU_IA32) +#define REAL_GRUB_FILE L"grubia32_real.efi" +#elif defined (MDE_CPU_X64) +#define REAL_GRUB_FILE L"grubx64_real.efi" +#elif defined (MDE_CPU_AARCH64) +#define REAL_GRUB_FILE L"grubaa64_real.efi" +#else +#error "Not supported now" +#endif + + +/* The following definations are copied from shim source code */ + +#define SHIM_LOCK_GUID {0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } }; + +typedef +EFI_STATUS +(*EFI_SHIM_LOCK_VERIFY) ( + IN VOID *buffer, + IN UINT32 size + ); + +typedef +EFI_STATUS +(*EFI_SHIM_LOCK_HASH) ( + IN char *data, + IN int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context, + UINT8 *sha256hash, + UINT8 *sha1hash + ); + +typedef +EFI_STATUS +(*EFI_SHIM_LOCK_CONTEXT) ( + IN VOID *data, + IN unsigned int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context + ); + +typedef struct _SHIM_LOCK { + EFI_SHIM_LOCK_VERIFY Verify; + EFI_SHIM_LOCK_HASH Hash; + EFI_SHIM_LOCK_CONTEXT Context; +} SHIM_LOCK; + + + +#define SHIM_IMAGE_LOADER_GUID {0x1f492041, 0xfadb, 0x4e59, {0x9e, 0x57, 0x7c, 0xaf, 0xe7, 0x3a, 0x55, 0xab } } + +typedef struct _SHIM_IMAGE_LOADER { + EFI_IMAGE_LOAD LoadImage; + EFI_IMAGE_START StartImage; + EFI_EXIT Exit; + EFI_IMAGE_UNLOAD UnloadImage; +} SHIM_IMAGE_LOADER; + +typedef VOID (*unhook_system_services_pf)(VOID); + + +/* + * The two offset here are extract from the shim file which used in Ventoy. + * nm BOOTX64.EFI | grep shim_load_image + * nm BOOTX64.EFI | grep unhook_system_services + * + * It means that they must be updated every time Ventoy update the shim file. + * + */ +#define NM_SHIM_LOAD_IMAGE_OFFSET 0x2dc12 +#define NM_UNHOOK_SYSTEM_SERVICES_OFFSET 0x2e278 + + + + +#define VtoySleep(sec) gBS->Stall(1000000 * (sec)) +#define vLog(fmt, ...) VtoyLog(fmt "\r\n", ##__VA_ARGS__) +#define vErr(fmt, ...) VtoyLog(fmt "\r\n", ##__VA_ARGS__); VtoySleep(5) + +#define CheckFreePool(p) \ +do { \ + if (p) { \ + FreePool(p); \ + (p) = NULL; \ + }\ +} while (0) + +#define CheckBSFreePool(p) \ +do { \ + if (p) { \ + gBS->FreePool(p); \ + (p) = NULL; \ + }\ +} while (0) + + + +#define VTOY_SHIM_POLICY_GUID {0x90a29d14, 0x3968, 0x48fe, { 0x85, 0x81, 0x6b, 0x7f, 0x7d, 0xc4, 0x70, 0x55 }}; + + +typedef VOID (EFIAPI *VTOY_BYPASS_SB)(VOID); +typedef VOID (EFIAPI *VTOY_CHECK_SB)(VOID); +typedef struct _VTOY_SHIM{ + VTOY_BYPASS_SB ByPassSB; + VTOY_BYPASS_SB CheckSB; +} VTOY_SHIM; + +CONST UINT8 * ventoy_get_der_data(UINT32 *Len); + +#endif + diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.inf b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.inf new file mode 100644 index 00000000..5ed232bb --- /dev/null +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/VtoyShim.inf @@ -0,0 +1,83 @@ +#************************************************************************************ +# Copyright (c) 2026, longpanda +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +#************************************************************************************ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VtoyShim + FILE_GUID = 6d7c7406-b32c-461f-8454-ddaa5243d93d + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = VtoyShimEfiMain + +[BuildOptions] + # Force standard GNU ld to pack and align ELF segments to 4KB page boundaries + GCC:*_*_*_DLINK_FLAGS = -Wl,-z,common-page-size=0x1000 -Wl,-z,max-page-size=0x1000 + +[Sources] + VtoyShim.h + VtoyShim.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + DevicePathLib + DebugLib + +[Guids] + gEfiGlobalVariableGuid + gShellVariableGuid + gEfiVirtualCdGuid + gEfiFileInfoGuid + +[Protocols] + gEfiSecurityArchProtocolGuid + gEfiSecurity2ArchProtocolGuid + gEfiLoadedImageProtocolGuid + gEfiBlockIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiDevicePathToTextProtocolGuid + gEfiDevicePathFromTextProtocolGuid + gEfiSimpleFileSystemProtocolGuid + gEfiRamDiskProtocolGuid + gEfiAbsolutePointerProtocolGuid + gEfiAcpiTableProtocolGuid + gEfiBlockIo2ProtocolGuid + gEfiBusSpecificDriverOverrideProtocolGuid + gEfiComponentNameProtocolGuid + gEfiComponentName2ProtocolGuid + gEfiDriverBindingProtocolGuid + gEfiDiskIoProtocolGuid + gEfiDiskIo2ProtocolGuid + gEfiGraphicsOutputProtocolGuid + gEfiHiiConfigAccessProtocolGuid + gEfiHiiFontProtocolGuid + gEfiLoadFileProtocolGuid + gEfiLoadFile2ProtocolGuid + gEfiLoadedImageProtocolGuid + gEfiLoadedImageDevicePathProtocolGuid + gEfiPciIoProtocolGuid + gEfiSerialIoProtocolGuid + gEfiSimpleTextInProtocolGuid + gEfiSimpleTextInputExProtocolGuid + gEfiSimpleTextOutProtocolGuid + diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/sbat.csv b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/sbat.csv new file mode 100644 index 00000000..6f07aa04 --- /dev/null +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyShim/sbat.csv @@ -0,0 +1,2 @@ +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +ventoy-shim,1,Ventoy,ventoy-shim,1.0,https://www.ventoy.net/ \ No newline at end of file diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.c b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.c index 65212c23..f5ff0066 100644 --- a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.c +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.c @@ -7,12 +7,12 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * @@ -41,7 +41,7 @@ STATIC CONST CHAR16 *gCurFeature= NULL; STATIC CHAR16 *gCmdLine = NULL; STATIC grub_env_printf_pf g_env_printf = NULL; -STATIC VtoyUtilFeature gFeatureList[] = +STATIC VtoyUtilFeature gFeatureList[] = { { L"fix_windows_mmap", FixWindowsMemhole }, { L"show_efi_drivers", ShowEfiDrivers }, @@ -93,7 +93,7 @@ VOID EFIAPI VtoyUtilDebug(IN CONST CHAR8 *Format, ...) } STATIC EFI_STATUS ParseCmdline(IN EFI_HANDLE ImageHandle) -{ +{ CHAR16 *pPos = NULL; CHAR16 *pCmdLine = NULL; EFI_STATUS Status = EFI_SUCCESS; @@ -117,7 +117,7 @@ STATIC EFI_STATUS ParseCmdline(IN EFI_HANDLE ImageHandle) gST->ConOut->OutputString(gST->ConOut, L"\r\n##########################"); return EFI_SUCCESS; } - + if (StrStr(pCmdLine, L"debug")) { gVtoyDebugPrint = TRUE; @@ -139,12 +139,38 @@ STATIC EFI_STATUS ParseCmdline(IN EFI_HANDLE ImageHandle) } gCurFeature = pPos + StrLen(L"feature="); - + gCmdLine = pCmdLine; - + return EFI_SUCCESS; } +#if defined (MDE_CPU_X64) +STATIC BOOLEAN EFIAPI CheckVtoyShim(VOID) +{ + UINT8 SecureBoot = 0; + UINTN DataSize; + EFI_STATUS Status; + EFI_GUID Guid = VTOY_SHIM_POLICY_GUID; + VOID *Prot = NULL; + + DataSize = sizeof(SecureBoot); + Status = gST->RuntimeServices->GetVariable(L"SecureBoot", &gEfiGlobalVariableGuid, NULL, + &DataSize, &SecureBoot); + if (!EFI_ERROR(Status) && SecureBoot) + { + Status = gBS->LocateProtocol(&Guid, NULL, (VOID**)&Prot); + if (EFI_ERROR(Status)) + { + gST->ConOut->OutputString(gST->ConOut, L"Can not locate Vtoy Shim\r\n"); + return FALSE; + } + } + + return TRUE; +} +#endif + EFI_STATUS EFIAPI VtoyUtilEfiMain ( IN EFI_HANDLE ImageHandle, @@ -153,7 +179,16 @@ EFI_STATUS EFIAPI VtoyUtilEfiMain { UINTN i; UINTN Len; - + +#if defined (MDE_CPU_X64) + /* check that Ventoy Shim must exist */ + if (!CheckVtoyShim()) + { + gBS->Stall(5 * 1000000); + return EFI_NOT_FOUND; + } +#endif + ParseCmdline(ImageHandle); for (i = 0; gCurFeature && i < ARRAY_SIZE(gFeatureList); i++) @@ -170,7 +205,7 @@ EFI_STATUS EFIAPI VtoyUtilEfiMain if (gCmdLine) { FreePool(gCmdLine); - gCmdLine = NULL; + gCmdLine = NULL; } return EFI_SUCCESS; diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.h b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.h index f0c9b258..5e228be8 100644 --- a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.h +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.h @@ -7,20 +7,22 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * */ - + #ifndef __VTOYUTIL_H__ #define __VTOYUTIL_H__ +#define VTOY_SHIM_POLICY_GUID {0x90a29d14, 0x3968, 0x48fe, { 0x85, 0x81, 0x6b, 0x7f, 0x7d, 0xc4, 0x70, 0x55 }}; + #pragma pack(1) typedef EFI_STATUS (*VTOY_UTIL_PROC_PF)(IN EFI_HANDLE ImageHandle, IN CONST CHAR16 *CmdLine); @@ -44,14 +46,14 @@ typedef struct ventoy_grub_param grub_env_set_pf grub_env_set; ventoy_grub_param_file_replace file_replace; ventoy_grub_param_file_replace img_replace[VTOY_MAX_CONF_REPLACE]; - grub_env_printf_pf grub_env_printf; + grub_env_printf_pf grub_env_printf; }ventoy_grub_param; #pragma pack() typedef struct VtoyUtilFeature { - CONST CHAR16 *Cmd; + CONST CHAR16 *Cmd; VTOY_UTIL_PROC_PF MainProc; }VtoyUtilFeature; diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.inf b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.inf index c422b7d1..1100c758 100644 --- a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.inf +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.inf @@ -23,7 +23,10 @@ MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 1.0 ENTRY_POINT = VtoyUtilEfiMain - + +[BuildOptions] + # Force standard GNU ld to pack and align ELF segments to 4KB page boundaries + GCC:*_*_*_DLINK_FLAGS = -Wl,-z,common-page-size=0x1000 -Wl,-z,max-page-size=0x1000 [Sources] VtoyUtil.h diff --git a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/MdeModulePkg.dsc b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/MdeModulePkg.dsc index c27b6d17..66172f2d 100644 --- a/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/MdeModulePkg.dsc +++ b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/MdeModulePkg.dsc @@ -205,6 +205,7 @@ [Components] MdeModulePkg/Application/Ventoy/Ventoy.inf MdeModulePkg/Application/VtoyUtil/VtoyUtil.inf + MdeModulePkg/Application/VtoyShim/VtoyShim.inf MdeModulePkg/Application/VDiskChain/VDiskChain.inf MdeModulePkg/Application/HelloWorld/HelloWorld.inf MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf