Ventoy Secure Boot Policy Update

- Add Ventoy Preload module.
This commit is contained in:
longpanda
2026-06-23 21:02:56 +08:00
parent 25369d5884
commit 26a394ce84
13 changed files with 1071 additions and 15 deletions

View File

@@ -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));

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,709 @@
/******************************************************************************
* VtoyShim.c
*
* Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
*/
#include <Uefi.h>
#include <Library/DebugLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/PeCoffLib.h>
#include <Protocol/LoadedImage.h>
#include <Guid/FileInfo.h>
#include <Guid/FileSystemInfo.h>
#include <Protocol/BlockIo.h>
#include <Protocol/RamDisk.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/DevicePathToText.h>
#include <Protocol/DevicePathFromText.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/Security.h>
#include <Protocol/Security2.h>
#include <IndustryStandard/PeImage.h>
#include <VtoyShim.h>
#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;
}

View File

@@ -0,0 +1,121 @@
/******************************************************************************
* VtoyShim.h
*
* Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
* 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

View File

@@ -0,0 +1,83 @@
#************************************************************************************
# Copyright (c) 2026, longpanda <admin@ventoy.net>
#
# 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 <http://www.gnu.org/licenses/>.
#
#************************************************************************************
[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

View File

@@ -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/
1 sbat 1 SBAT Version sbat 1 https://github.com/rhboot/shim/blob/main/SBAT.md
2 ventoy-shim 1 Ventoy ventoy-shim 1.0 https://www.ventoy.net/

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
@@ -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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
*/
#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;

View File

@@ -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

View File

@@ -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