Fix the boot issue with old UEFI version firmware when secure boot is disabled.

This commit is contained in:
longpanda
2026-06-25 19:23:48 +08:00
parent 31648a0d4b
commit 475de1dada
5 changed files with 241 additions and 84 deletions

View File

@@ -35,14 +35,16 @@
#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_GUID gShimLockGUID = SHIM_LOCK_GUID;
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 SHIM_LOCK gShimLock;
STATIC EFI_EXIT_BOOT_SERVICES gSysExitBootServices = NULL;
STATIC EFI_GET_VARIABLE gSysGetVariable = NULL;
STATIC VOID EFIAPI VtoyLog(CONST CHAR16 *Format, ...)
{
@@ -66,7 +68,7 @@ STATIC VOID EFIAPI DumpDevicePath(const EFI_DEVICE_PATH_PROTOCOL *DevicePath)
{
CHAR16 *DPStr = NULL;
DPStr = gDpToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);
DPStr = ConvertDevicePathToText(DevicePath, TRUE, TRUE);
if (DPStr)
{
vLog(L"%s", DPStr);
@@ -95,8 +97,11 @@ STATIC VOID EFIAPI ShowSBWarning(BOOLEAN Reboot, const EFI_DEVICE_PATH_PROTOCOL
if (Reboot)
{
vLog(L"\r\n###### Press Enter to reboot... ######");
gST->ConIn->Reset(gST->ConIn, FALSE);
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index);
if (gST->ConIn)
{
gST->ConIn->Reset(gST->ConIn, FALSE);
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index);
}
gRT->ResetSystem(EfiResetWarm, EFI_SECURITY_VIOLATION, 0, NULL);
}
else
@@ -129,7 +134,6 @@ STATIC VOID * EFIAPI FindShimFuncAddr(UINT64 FuncOffset)
}
}
EFI_STATUS EFIAPI LaunchRealGrub(EFI_HANDLE ImageHandle, CONST CHAR16 *FileName)
{
EFI_STATUS Status;
@@ -156,7 +160,7 @@ EFI_STATUS EFIAPI LaunchRealGrub(EFI_HANDLE ImageHandle, CONST CHAR16 *FileName)
goto END;
}
DevDpStr = gDpToText->ConvertDevicePathToText(DeviceDP, FALSE, TRUE);
DevDpStr = ConvertDevicePathToText(DeviceDP, FALSE, TRUE);
if (!DevDpStr)
{
vLog(L"Failed to convert device path to text");
@@ -175,7 +179,7 @@ EFI_STATUS EFIAPI LaunchRealGrub(EFI_HANDLE ImageHandle, CONST CHAR16 *FileName)
UnicodeSPrint(NewDpStr, BufferSize, L"%s/EFI/BOOT/%s", DevDpStr, FileName);
TargetDp = gTextToDp->ConvertTextToDevicePath(NewDpStr);
TargetDp = ConvertTextToDevicePath(NewDpStr);
if (!TargetDp)
{
vLog(L"Failed to convert new text <%s> to device path", NewDpStr);
@@ -200,9 +204,9 @@ EFI_STATUS EFIAPI LaunchRealGrub(EFI_HANDLE ImageHandle, CONST CHAR16 *FileName)
END:
CheckBSFreePool(DevDpStr);
CheckFreePool(DevDpStr);
CheckFreePool(NewDpStr);
CheckBSFreePool(TargetDp);
CheckFreePool(TargetDp);
return Status;
}
@@ -243,7 +247,7 @@ STATIC EFI_STATUS EFIAPI ReadAuthFile
goto END;
}
DpStr = gDpToText->ConvertDevicePathToText(DevPath, FALSE, TRUE);
DpStr = ConvertDevicePathToText(DevPath, FALSE, TRUE);
if (!DpStr)
{
Status = EFI_OUT_OF_RESOURCES;
@@ -311,7 +315,7 @@ END:
}
CheckFreePool(TmpPath);
CheckBSFreePool(DpStr);
CheckFreePool(DpStr);
if (EFI_ERROR(Status))
{
@@ -332,7 +336,7 @@ 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 (Size > sizeof(EFI_IMAGE_DOS_HEADER) && DosHead->e_magic == 0x5A4D)
{
if (CompareMem(DosHead->e_res2, &gVtoySbatGUID, 16) == 0)
{
@@ -386,12 +390,12 @@ STATIC EFI_STATUS EFIAPI SecurityPolicyAuth
* 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 (gShimLock.Verify)
{
Status = ReadAuthFile(DevicePathConst, &Buffer, &Size);
if (!EFI_ERROR(Status))
{
Status = gShimLock->Verify(Buffer, Size);
Status = gShimLock.Verify(Buffer, Size);
if (!EFI_ERROR(Status))
{
bRevokeChkOK = VtoyCheckRevoke(Buffer, Size);
@@ -448,11 +452,11 @@ STATIC EFI_STATUS EFIAPI Security2PolicyAuth
* 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 (gShimLock.Verify)
{
if (FileBuffer && FileSize > 0 && FileSize < 0xFFFFFFFFUL)
{
Status = gShimLock->Verify(FileBuffer, (UINT32)FileSize);
Status = gShimLock.Verify(FileBuffer, (UINT32)FileSize);
if (!EFI_ERROR(Status))
{
bRevokeChkOK = VtoyCheckRevoke(FileBuffer, FileSize);
@@ -522,13 +526,13 @@ STATIC VOID EFIAPI UnHookSecurityPolicy(VOID)
return;
}
if (Security2 && gSysSec2FileAuth)
if (Security2 && gSysSec2FileAuth && Security2->FileAuthentication == Security2PolicyAuth)
{
Security2->FileAuthentication = gSysSec2FileAuth;
gSysSec2FileAuth = NULL;
}
if (Security && gSysSecFileAuth)
if (Security && gSysSecFileAuth && Security->FileAuthenticationState == SecurityPolicyAuth)
{
Security->FileAuthenticationState = gSysSecFileAuth;
gSysSecFileAuth = NULL;
@@ -599,47 +603,38 @@ STATIC BOOLEAN EFIAPI IsSecureBootEnabled(VOID)
return SecureBoot ? TRUE : FALSE;
}
STATIC EFI_STATUS EFIAPI EnvInit(VOID)
STATIC BOOLEAN EFIAPI IsSetupMode(VOID)
{
EFI_STATUS Status;
UINT8 SetupMode = 0;
UINTN DataSize;
EFI_STATUS Status;
Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&gDpToText);
if (EFI_ERROR(Status) || !gDpToText || !gDpToText->ConvertDevicePathToText)
DataSize = sizeof(SetupMode);
Status = gST->RuntimeServices->GetVariable(L"SetupMode", &gEfiGlobalVariableGuid, NULL,
&DataSize, &SetupMode);
if (EFI_ERROR(Status))
{
vLog(L"Failed to locate PathToText Protocol %lx", Status);
return Status;
return FALSE;
}
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;
}
return EFI_SUCCESS;
return SetupMode ? TRUE : FALSE;
}
EFI_STATUS EFIAPI VtoyShimEfiMain
STATIC EFI_STATUS EFIAPI ShimEfiMain
(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
IN EFI_SYSTEM_TABLE *SystemTable,
IN BOOLEAN IsSecureBoot,
IN BOOLEAN IsSetup
)
{
EFI_STATUS Status;
EFI_GUID Guid = SHIM_LOCK_GUID;
unhook_system_services_pf Func = NULL;
SHIM_LOCK *ShimLock = NULL;
shim_void_func_pf Func1 = NULL;
shim_void_func_pf Func2 = NULL;
Status = EnvInit();
if (EFI_ERROR(Status))
{
vErr(L"Failed to prepare env");
return Status;
}
/* If secure boot is not enabled, nothing needed, just launch Ventoy grub */
if (!IsSecureBootEnabled())
/* If secure boot is not enabled or in SetupMode, nothing needed, just launch Ventoy grub */
if (!IsSecureBoot || IsSetup)
{
Status = LaunchRealGrub(ImageHandle, REAL_GRUB_FILE);
if (EFI_ERROR(Status))
@@ -649,13 +644,18 @@ EFI_STATUS EFIAPI VtoyShimEfiMain
return Status;
}
Status = gBS->LocateProtocol(&Guid, NULL, (VOID**)&gShimLock);
if (EFI_ERROR(Status) || !gShimLock)
/* We must be launched by shim */
Status = gBS->LocateProtocol(&gShimLockGUID, NULL, (VOID**)&ShimLock);
if (EFI_ERROR(Status) || !ShimLock)
{
vErr(L"Failed to locate SHIM LOCK Protocol %lx", Status);
return Status;
}
/* Backup shim Lock because we will remove it later */
gShimLock.Verify = ShimLock->Verify;
gShimLock.Hash = ShimLock->Hash;
gShimLock.Context = ShimLock->Context;
Status = InstallVtoyShimProtocol();
if (EFI_ERROR(Status))
@@ -679,15 +679,17 @@ EFI_STATUS EFIAPI VtoyShimEfiMain
* It may break in future versions of shim, and a better approach may exist.
*
*/
Func = FindShimFuncAddr(NM_UNHOOK_SYSTEM_SERVICES_OFFSET);
if (!Func)
Func1 = FindShimFuncAddr(NM_UNHOOK_SYSTEM_SERVICES_OFFSET);
Func2 = FindShimFuncAddr(NM_UNINSTALL_SHIM_PROTOCOLS_OFFSET);
if (!Func1 || !Func2)
{
vErr(L"Can not find shim unhook_system_services");
vErr(L"Can not find shim func %p %p", Func1, Func2);
Status = EFI_NOT_FOUND;
goto END;
}
Func(); /* call shim unhook_system_services() */
Func1(); /* call shim unhook_system_services() */
Func2(); /* call shim uninstall_shim_protocols() */
/* Hook the system security policy */
@@ -716,3 +718,83 @@ END:
return Status;
}
STATIC EFI_STATUS EFIAPI VtoyExitBootServices
(
IN EFI_HANDLE ImageHandle,
IN UINTN MapKey
)
{
UnHookSecurityPolicy();
UnInstallVtoyShimProtocol();
gST->RuntimeServices->GetVariable = gSysGetVariable;
gBS->ExitBootServices = gSysExitBootServices;
return gSysExitBootServices(ImageHandle, MapKey);
}
EFI_STATUS EFIAPI VtoyGetVariable
(
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
OUT UINT32 *Attributes, OPTIONAL
IN OUT UINTN *DataSize,
OUT VOID *Data OPTIONAL
)
{
BOOLEAN bChk = FALSE;
EFI_STATUS Status;
if (gVtoyByPassSB && VariableName && VendorGuid && DataSize && Data && (*DataSize) > 0)
{
bChk = TRUE;
}
Status = gSysGetVariable(VariableName, VendorGuid, Attributes, DataSize, Data);
if (bChk && (!EFI_ERROR(Status)))
{
if (CompareMem(&gShimLockGUID, VendorGuid, 16) == 0 &&
StrCmp(VariableName, L"MokSBState") == 0)
{
*(UINT8 *)Data = 1;
}
}
return Status;
}
EFI_STATUS EFIAPI VtoyShimEfiMain
(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
BOOLEAN IsSetup = FALSE;
BOOLEAN IsSecureBoot = FALSE;
EFI_STATUS Status;
IsSetup = IsSetupMode();
IsSecureBoot = IsSecureBootEnabled();
if (!IsSecureBoot || IsSetup)
{
Status = ShimEfiMain(ImageHandle, SystemTable, IsSecureBoot, IsSetup);
}
else
{
gSysExitBootServices = gBS->ExitBootServices;
gBS->ExitBootServices = VtoyExitBootServices;
gSysGetVariable = gST->RuntimeServices->GetVariable;
gST->RuntimeServices->GetVariable = VtoyGetVariable;
Status = ShimEfiMain(ImageHandle, SystemTable, IsSecureBoot, IsSetup);
gBS->ExitBootServices = gSysExitBootServices;
gST->RuntimeServices->GetVariable = gSysGetVariable;
}
return Status;
}