未验证 提交 08ddaab4 编写于 作者: P PMheart 提交者: GitHub

Utilities: Advanced ocvalidate for error checking (#169)

上级 0cd067ff
......@@ -56,3 +56,4 @@ Legacy/BinDrivers/X64
Legacy/BinDrivers/IA32
Legacy/BootLoader/bin
Legacy/BootSector/bin
Utilities/ocvalidate/*.plist
......@@ -62,6 +62,10 @@ typedef struct OC_PICKER_CONTEXT_ OC_PICKER_CONTEXT;
#define OC_ATTR_USE_GENERIC_LABEL_IMAGE BIT2
#define OC_ATTR_USE_ALTERNATE_ICONS BIT3
#define OC_ATTR_USE_POINTER_CONTROL BIT4
#define OC_ATTR_ALL_BITS (\
OC_ATTR_USE_VOLUME_ICON | OC_ATTR_USE_DISK_LABEL_FILE | \
OC_ATTR_USE_GENERIC_LABEL_IMAGE | OC_ATTR_USE_ALTERNATE_ICONS | \
OC_ATTR_USE_POINTER_CONTROL)
/**
Default timeout for IDLE timeout during menu picker navigation
......
......@@ -349,6 +349,9 @@
#define OCS_EXPOSE_VERSION_UI 4U
#define OCS_EXPOSE_OEM_INFO 8U
#define OCS_EXPOSE_VERSION (OCS_EXPOSE_VERSION_VAR | OCS_EXPOSE_VERSION_UI)
#define OCS_EXPOSE_ALL_BITS (\
OCS_EXPOSE_BOOT_PATH | OCS_EXPOSE_VERSION_VAR | \
OCS_EXPOSE_VERSION_UI | OCS_EXPOSE_OEM_INFO)
typedef enum {
OcsVaultOptional = 0,
......
......@@ -91,10 +91,22 @@ typedef struct MAC_INFO_DATA_ {
**/
VOID
GetMacInfo (
IN CONST CHAR8 *ProductName,
IN CONST CHAR8 *ProductName,
OUT MAC_INFO_DATA *MacInfo
);
/**
Determine if specified product name is a real Mac model.
@param[in] ProductName Product to check information for.
@retval TRUE if ProductName is a real Mac model.
**/
BOOLEAN
HasMacInfo (
IN CONST CHAR8 *ProductName
);
/**
Determine if specified model and kernel version can
run in 64-bit kernel mode.
......
......@@ -148,11 +148,55 @@ OcAsciiSafeSPrint (
...
);
/**
Compares up to a specified length the contents of two Null-terminated ASCII
strings using case insensitive comparisons, and returns the difference
between the first mismatched ASCII characters.
This function compares the Null-terminated ASCII string FirstString to the
Null-terminated ASCII string SecondString using case insensitive
comparisons. At most, Length ASCII characters will be compared. If Length
is 0, then 0 is returned. If FirstString is identical to SecondString, then 0
is returned. Otherwise, the value returned is the first mismatched upper case
ASCII character in SecondString subtracted from the first mismatched upper
case ASCII character in FirstString.
If Length > 0 and FirstString is NULL, then ASSERT().
If Length > 0 and SecondString is NULL, then ASSERT().
TODO
If PcdMaximumAsciiStringLength is not zero, and Length is greater than
PcdMaximumAsciiStringLength, then ASSERT().
If PcdMaximumAsciiStringLength is not zero, and FirstString contains more
than PcdMaximumAsciiStringLength ASCII characters, not including the
Null-terminator, then ASSERT().
If PcdMaximumAsciiStringLength is not zero, and SecondString contains more
than PcdMaximumAsciiStringLength ASCII characters, not including the
Null-terminator, then ASSERT().
@param FirstString A pointer to a Null-terminated ASCII string.
@param SecondString A pointer to a Null-terminated ASCII string.
@param Length The maximum number of ASCII characters to compare.
@retval ==0 FirstString is identical to SecondString using case
insensitive comparisons.
@retval others FirstString is not identical to SecondString using case
insensitive comparisons.
**/
INTN
EFIAPI
OcAsciiStrniCmp (
IN CONST CHAR8 *FirstString,
IN CONST CHAR8 *SecondString,
IN UINTN Length
);
/** Check if ASCII string ends with another ASCII string.
@param[in] String A pointer to a Null-terminated ASCII string.
@param[in] SearchString A pointer to a Null-terminated ASCII string
to compare against String.
@param[in] String A pointer to a Null-terminated ASCII string.
@param[in] SearchString A pointer to a Null-terminated ASCII string
to compare against String.
@param[in] CaseInsensitiveMatch Perform case-insensitive comparison.
@retval TRUE if String ends with SearchString.
**/
......@@ -160,7 +204,8 @@ BOOLEAN
EFIAPI
OcAsciiEndsWith (
IN CONST CHAR8 *String,
IN CONST CHAR8 *SearchString
IN CONST CHAR8 *SearchString,
IN BOOLEAN CaseInsensitiveMatch
);
/**
......@@ -396,9 +441,10 @@ OcUnicodeSafeSPrint (
/** Check if Unicode string ends with another Unicode string.
@param[in] String A pointer to a Null-terminated Unicode string.
@param[in] SearchString A pointer to a Null-terminated Unicode string
to compare against String.
@param[in] String A pointer to a Null-terminated Unicode string.
@param[in] SearchString A pointer to a Null-terminated Unicode string
to compare against String.
@param[in] CaseInsensitiveMatch Perform case-insensitive comparison.
@retval TRUE if String ends with SearchString.
**/
......@@ -406,7 +452,8 @@ BOOLEAN
EFIAPI
OcUnicodeEndsWith (
IN CONST CHAR16 *String,
IN CONST CHAR16 *SearchString
IN CONST CHAR16 *SearchString,
IN BOOLEAN CaseInsensitiveMatch
);
/**
......
......@@ -33,6 +33,11 @@
#define OC_LOG_VARIABLE BIT4
#define OC_LOG_NONVOLATILE BIT5
#define OC_LOG_FILE BIT6
#define OC_LOG_ALL_BITS (\
OC_LOG_ENABLE | OC_LOG_CONSOLE | \
OC_LOG_DATA_HUB | OC_LOG_SERIAL | \
OC_LOG_VARIABLE | OC_LOG_NONVOLATILE | \
OC_LOG_FILE)
typedef UINT32 OC_LOG_OPTIONS;
......
......@@ -184,7 +184,7 @@ ScanExtensions (
}
if (FileInfoSize > 0) {
if (OcUnicodeEndsWith (FileInfo->FileName, L".kext")) {
if (OcUnicodeEndsWith (FileInfo->FileName, L".kext", FALSE)) {
Status = File->Open (File, &FileKext, FileInfo->FileName, EFI_FILE_MODE_READ, EFI_FILE_DIRECTORY);
if (EFI_ERROR (Status)) {
continue;
......@@ -1391,7 +1391,7 @@ CachelessContextHookBuiltin (
//
// Try to get Info.plist.
//
if (OcUnicodeEndsWith (FileName, L"Info.plist")) {
if (OcUnicodeEndsWith (FileName, L"Info.plist", FALSE)) {
BuiltinKext = LookupBuiltinKextForPlistPath (Context, FileName);
if (BuiltinKext != NULL && BuiltinKext->PatchValidOSBundleRequired) {
DEBUG ((DEBUG_INFO, "OCAK: Processing plist patches for %s\n", FileName));
......
......@@ -84,11 +84,11 @@ LookupInternalEntry (
//
// Even the first element does not match, required due to unsigned End.
//
return &gMacInfoModels[gMacInfoDefaultModel];
return NULL;
}
}
return &gMacInfoModels[gMacInfoDefaultModel];
return NULL;
}
VOID
......@@ -102,6 +102,12 @@ GetMacInfo (
ZeroMem (MacInfo, sizeof (*MacInfo));
InternalEntry = LookupInternalEntry (ProductName);
if (InternalEntry == NULL) {
//
// Fallback to default model if given ProductName is not found.
//
InternalEntry = &gMacInfoModels[gMacInfoDefaultModel];
}
//
// Fill in DataHub values.
......@@ -145,6 +151,18 @@ GetMacInfo (
}
}
BOOLEAN
HasMacInfo (
IN CONST CHAR8 *ProductName
)
{
CONST MAC_INFO_INTERNAL_ENTRY *InternalEntry;
InternalEntry = LookupInternalEntry (ProductName);
return InternalEntry != NULL;
}
BOOLEAN
IsMacModel64BitCompatible (
IN CONST CHAR8 *ProductName,
......
......@@ -202,11 +202,50 @@ OcAsciiSafeSPrint (
return Status;
}
INTN
EFIAPI
OcAsciiStrniCmp (
IN CONST CHAR8 *FirstString,
IN CONST CHAR8 *SecondString,
IN UINTN Length
)
{
CHAR8 UpperFirstString;
CHAR8 UpperSecondString;
if (Length == 0) {
return 0;
}
//
// ASSERT both strings are less long than PcdMaximumAsciiStringLength.
// Length tests are performed inside AsciiStrLen().
//
ASSERT (AsciiStrSize (FirstString) != 0);
ASSERT (AsciiStrSize (SecondString) != 0);
UpperFirstString = AsciiCharToUpper (*FirstString);
UpperSecondString = AsciiCharToUpper (*SecondString);
while ((*FirstString != '\0') &&
(*SecondString != '\0') &&
(UpperFirstString == UpperSecondString) &&
(Length > 1)) {
FirstString++;
SecondString++;
UpperFirstString = AsciiCharToUpper (*FirstString);
UpperSecondString = AsciiCharToUpper (*SecondString);
Length--;
}
return UpperFirstString - UpperSecondString;
}
BOOLEAN
EFIAPI
OcAsciiEndsWith (
IN CONST CHAR8 *String,
IN CONST CHAR8 *SearchString
IN CONST CHAR8 *SearchString,
IN BOOLEAN CaseInsensitiveMatch
)
{
UINTN StringLength;
......@@ -218,6 +257,10 @@ OcAsciiEndsWith (
StringLength = AsciiStrLen (String);
SearchStringLength = AsciiStrLen (SearchString);
if (CaseInsensitiveMatch) {
return StringLength >= SearchStringLength
&& OcAsciiStrniCmp (&String[StringLength - SearchStringLength], SearchString, SearchStringLength) == 0;
}
return StringLength >= SearchStringLength
&& AsciiStrnCmp (&String[StringLength - SearchStringLength], SearchString, SearchStringLength) == 0;
}
......
......@@ -38,9 +38,6 @@
OpenCorePkg/OpenCorePkg.dec
MdePkg/MdePkg.dec
[Pcd]
gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength ## SOMETIMES_CONSUMES
[LibraryClasses]
BaseLib
BaseMemoryLib
......
......@@ -71,11 +71,7 @@ OcStrniCmp (
//
ASSERT (StrSize (FirstString) != 0);
ASSERT (StrSize (SecondString) != 0);
if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) {
ASSERT (Length <= PcdGet32 (PcdMaximumUnicodeStringLength));
}
UpperFirstString = CharToUpper (*FirstString);
UpperSecondString = CharToUpper (*SecondString);
while ((*FirstString != L'\0') &&
......@@ -360,7 +356,8 @@ BOOLEAN
EFIAPI
OcUnicodeEndsWith (
IN CONST CHAR16 *String,
IN CONST CHAR16 *SearchString
IN CONST CHAR16 *SearchString,
IN BOOLEAN CaseInsensitiveMatch
)
{
UINTN StringLength;
......@@ -372,6 +369,10 @@ OcUnicodeEndsWith (
StringLength = StrLen (String);
SearchStringLength = StrLen (SearchString);
if (CaseInsensitiveMatch) {
return StringLength >= SearchStringLength
&& OcStrniCmp (&String[StringLength - SearchStringLength], SearchString, SearchStringLength) == 0;
}
return StringLength >= SearchStringLength
&& StrnCmp (&String[StringLength - SearchStringLength], SearchString, SearchStringLength) == 0;
}
......
......@@ -155,7 +155,11 @@ ifneq ($(STANDALONE),1)
#
# OcMiscLib targets.
#
OBJS += Math.o ProtocolSupport.o
OBJS += Math.o ProtocolSupport.o DataPatcher.o
#
# OcAppleKernelLib targets.
#
OBJS += KernelVersion.o
#
# Add source searchpath for transparent compilation.
......@@ -183,7 +187,8 @@ ifneq ($(STANDALONE),1)
../../Library/OcMachoLib:$\
../../Library/OcAppleKeysLib:$\
../../Library/OcCpuLib:$\
../../Library/OcMiscLib
../../Library/OcMiscLib:$\
../../Library/OcAppleKernelLib
endif
#
......
......@@ -8,7 +8,6 @@ PRODUCT = $(PROJECT)$(SUFFIX)
OBJS = $(PROJECT).o \
CommonPatches.o \
CpuidPatches.o \
KernelVersion.o \
KextPatcher.o \
KxldState.o \
PrelinkedKext.o \
......@@ -18,7 +17,6 @@ OBJS = $(PROJECT).o \
Link.o \
KernelReader.o \
KernelCollection.o \
DataPatcher.o \
lzss.o \
lzvn.o \
adler32.o \
......@@ -33,7 +31,6 @@ OBJS = $(PROJECT).o \
uncompr.o \
zlib_uefi.o
VPATH = ../../Library/OcAppleKernelLib:$\
../../Library/OcMiscLib:$\
../../Library/OcCompressionLib/lzss:$\
../../Library/OcCompressionLib/lzvn:$\
../../Library/OcCompressionLib/zlib
......
ocvalidate Checklist
=====================
As of commit [TODO_DONT_CLICK](TODO), ocvalidate performs the following checks:
## Global Rules
- For all strings (fields with plist `String` format) throughout the whole config, only ASCII printable characters are accepted at most. Stricter rules may apply. For instance, some fields only accept specified values, as indicated in [Configuration.pdf](https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/Configuration.pdf).
- For all patches, excluding section `Kernel->Patch` (where `Base` is not empty), their `Find`, `Replace`, `Mask`, and `ReplaceMask` must have identical size in most cases. Also, `Find` requires `Mask` (or `Replace` requires `ReplaceMask`) to be active (set to non-zero) for corresponding bits.
- For all `MinKernel` and `MaxKernel` settings, they should follow the conventions indicated in [Configuration.pdf](https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/Configuration.pdf). (TODO: Bring decent checks for this)
- For all entries taking file system path only `0-9, A-Z, a-z, '_', '-', '.', '/', and '\'` are accepted.
- For all Device Paths (e.g. `PciRoot(0x0)/Pci(0x1b,0x0)`) only strings in canonic string format are accepted.
- For all paths of UEFI Drivers, only `0-9, A-Z, a-z, '_', '-', '.', and '/'` are accepted.
- For all entries requiring bitwise operations (e.g. `ConsoleAttributes`, `PickerAttributes`, or `ScanPolicy`), only known bits can be set.
- For all entries involving GUID (mainly at Section `NVRAM`), correct format must be ensured.
## ACPI
#### Add
- Entry[N]->Path: Only `.aml` and `.bin` filename suffix are accepted.
- Entry[N]->Path: If a customised DSDT is added and enabled, `RebaseRegions` in `Quirks` should be enabled.
## Booter
#### MmioWhitelist
- Entry[N]->Enabled: When at least one entry is enabled, `DevirtualiseMmio` in `Quirks` should be enabled.
#### Patch
- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted.
- Entry[N]->Identifier: Only `Any`, `Apple`, or a specified bootloader with `.efi` sufffix, are accepted.
#### Quirks
- When `AllowRelocationBlock` is enabled, `ProvideCustomSlide` should be enabled altogether.
- When `EnableSafeModeSlide` is enabled, `ProvideCustomSlide` should be enabled altogether.
- If `ProvideMaxSlide` is set to a number greater than zero (i.e. is enabled), `ProvideCustomSlide` should be enabled altogether.
- When `DisableVariableWrite`, `EnableWriteUnprotector`, or `ProvideCustomSlide` is enabled, `OpenRuntime.efi` should be loaded under `UEFI->Drivers`.
## DeviceProperties
- Check requirements for Device Paths in Section Global Rules.
## Kernel
#### Add
- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted.
- Entry[N]->BundlePath: Filename should have `.kext` suffix.
- Entry[N]->PlistPath: Filename should have `.plist` suffix.
- Entry[N]: If `Lilu.kext` is used, `DisableLinkeditJettison` should be enabled at `Kernel->Quirks`.
- For some known kexts, their `BundlePath`, `ExecutablePath`, and `PlistPath` must match against each other. Current list of rules can be found [here](https://github.com/PMheart/OpenCorePkg/blob/master/Utilities/ocvalidate/ValidateKernel.c). (TODO: Change to Acidanthera link once merged)
- Known [Lilu plugins](https://github.com/acidanthera/Lilu/blob/master/KnownPlugins.md) must have proper `Add` precedence. That is to say, plugins must be placed after `Lilu.kext`.
#### Delete
- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted.
- Entry[N]->Identifier: At least one dot (`.`) should exist, because any identifier looks like a domain sequence (`vendor.product`).
#### Quirks
- `CustomSMBIOSGuid` requires `UpdateSMBIOSMode` at `PlatformInfo` set to `Custom`.
#### Scheme
- KernelArch: Only `Auto`, `i386`, `i386-user32`, or `x86_64` are accepted.
- KernelCache: Only `Auto`, `Cacheless`, `Mkext`, or `Prelinked` are accepted.
## Misc
#### Boot
- HibernateMode: Only `None`, `Auto`, `RTC`, or `NVRAM` are accepted.
- PickerMode: Only `Builtin`, `External`, or `Apple` are accepted.
#### Security
- BootProtect: Only `None`, `Bootstrap`, or `BootstrapShort` are accepted. When set to `Bootstrap` or `BootstrapShort`, `RequestBootVarRouting` should be enabled at `UEFI->Quirks`.
- DmgLoading: Only `Disabled`, `Signed`, or `Any` are accepted.
- Vault: Only `Optional`, `Basic`, or `Secure` are accepted.
- SecureBootModel: Only `Default`, `Disabled`, `j137`, `j680`, `j132`, `j174`, `j140k`, `j780`, `j213`, `j140a`, `j152f`, `j160`, `j230k`, `j214k`, `j223`, `j215`, `j185`, `j185f`, or `x86legacy` are accepted.
## NVRAM
- Check requirements for GUID in Section Global Rules.
## PlatformInfo
- UpdateSMBIOSMode: Only `TryOverwrite`, `Create`, `Overwrite`, or `Custom` are accepted.
#### Generic
- SystemProductName: Only real Mac models are accepted.
- SystemMemoryStatus: Only `Auto`, `Upgradable`, or `Soldered` are accepted.
## UEFI
#### APFS
- When `EnableJumpstart` is enabled, `ScanPolicy` at `Misc->Security` should have `OC_SCAN_ALLOW_FS_APFS` (bit 8) set, or `ScanPolicy` should be `0` (failsafe value).
#### Quirks
- When `RequestBootVarRouting` is enabled, `OpenRuntime.efi` should be loaded under `UEFI->Drivers`.
#### Drivers
- No drivers should be loaded more than once (i.e. there should NOT be any duplicated entries in this section).
- When `OpenUsbKbDxe.efi` is in use, `KeySupport` at `UEFI->Input` should NEVER be enabled altogether.
- When `Ps2KeyboardDxe.efi` is in use, `KeySupport` at `UEFI->Input` should be enabled altogether.
- `OpenUsbKbDxe.efi` and `Ps2KeyboardDxe.efi` should never co-exist.
#### Input
- The value of `KeySupportMode` can only be `Auto`, `V1`, `V2`, or `AMI`.
- When `PointerSupport` is enabled, the value of `PointerSupportMode` should only be `ASUS`.
#### Output
- `ClearScreenOnModeSwitch`, `IgnoreTextInGraphics`, `ReplaceTabWithSpace`, and `SanitiseClearScreen` only apply to `System` TextRenderer
- `Resolution` should match `NUMBERxNUMBER` or `NUMBERxNUMBER@NUMBER` sequences (unless it is an `Empty string` or is set to `Max`).
......@@ -5,7 +5,21 @@
PROJECT = ocvalidate
PRODUCT = $(PROJECT)$(SUFFIX)
OBJS = $(PROJECT).o \
OcConfigurationLib.o
VPATH = ../../Library/OcConfigurationLib
OBJS = $(PROJECT).o OcValidateLib.o ValidateAcpi.o ValidateBooter.o ValidateDeviceProperties.o ValidateKernel.o ValidateMisc.o ValidateNVRAM.o ValidatePlatformInfo.o ValidateUEFI.o
#
# OcConfigurationLib targets.
#
OBJS += OcConfigurationLib.o
#
# OcConsoleLib targets.
#
OBJS += ResolutionParsing.o
#
# OcMacInfoLib targets.
#
OBJS += OcMacInfoLib.o AutoGenerated.o
VPATH = ../../Library/OcConfigurationLib \
../../Library/OcConsoleLib \
../../Library/OcMacInfoLib
include ../../User/Makefile
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
INT64
GetCurrentTimestamp (
VOID
)
{
struct timeval Time;
//
// Get current time.
//
gettimeofday (&Time, NULL);
//
// Return milliseconds.
//
return Time.tv_sec * 1000LL + Time.tv_usec / 1000LL;
}
BOOLEAN
AsciiFileSystemPathIsLegal (
IN CONST CHAR8 *Path
)
{
UINTN Index;
UINTN PathLength;
PathLength = AsciiStrLen (Path);
for (Index = 0; Index < PathLength; ++Index) {
//
// Skip allowed characters (0-9, A-Z, a-z, '_', '-', '.', '/', and '\').
//
if (IsAsciiNumber (Path[Index])
|| IsAsciiAlpha (Path[Index])
|| Path[Index] == '_'
|| Path[Index] == '-'
|| Path[Index] == '.'
|| Path[Index] == '/'
|| Path[Index] == '\\') {
continue;
}
//
// Disallowed characters matched.
//
return FALSE;
}
return TRUE;
}
BOOLEAN
AsciiCommentIsLegal (
IN CONST CHAR8 *Comment
)
{
UINTN Index;
UINTN CommentLength;
CommentLength = AsciiStrLen (Comment);
for (Index = 0; Index < CommentLength; ++Index) {
//
// Unprintable characters matched.
//
if (IsAsciiPrint (Comment[Index]) == 0) {
return FALSE;
}
}
return TRUE;
}
BOOLEAN
AsciiIdentifierIsLegal (
IN CONST CHAR8 *Identifier,
IN BOOLEAN IsKernelIdentifier
)
{
UINTN Index;
UINTN IdentifierLength;
if (IsKernelIdentifier) {
//
// Kernel patch only requires Kernel->Patch->Identifier set to kernel.
//
if (AsciiStrCmp (Identifier, "kernel") == 0) {
return TRUE;
}
} else {
//
// Any and Apple are two fixed values accepted by Booter->Patch.
// TODO: Drop empty string support in OC.
//
if (AsciiStrCmp (Identifier, "Any") == 0
|| AsciiStrCmp (Identifier, "Apple") == 0) {
return TRUE;
}
//
// For customised bootloader, it must have .efi suffix.
//
if (!OcAsciiEndsWith (Identifier, ".efi", TRUE)) {
return FALSE;
}
}
//
// There must be a dot for a sane Identifier.
//
if (OcAsciiStrChr (Identifier, '.') == NULL) {
return FALSE;
}
IdentifierLength = AsciiStrLen (Identifier);
for (Index = 0; Index < IdentifierLength; ++Index) {
//
// Skip allowed characters (0-9, A-Z, a-z, '_', '-', and '.').
// FIXME: Discuss what exactly is legal for identifiers, or update the allowed list on request.
//
if (IsAsciiNumber (Identifier[Index])
|| IsAsciiAlpha (Identifier[Index])
|| Identifier[Index] == '_'
|| Identifier[Index] == '-'
|| Identifier[Index] == '.') {
continue;
}
//
// Disallowed characters matched.
//
return FALSE;
}
return TRUE;
}
BOOLEAN
AsciiArchIsLegal (
IN CONST CHAR8 *Arch,
IN BOOLEAN IsKernelArch
)
{
//
// Special mode for Kernel->Scheme->KernelArch.
//
if (IsKernelArch) {
//
// Auto and i386-user32 are two special values allowed in KernelArch.
//
if (AsciiStrCmp (Arch, "Auto") == 0
|| AsciiStrCmp (Arch, "i386-user32") == 0) {
return TRUE;
}
} else {
//
// Any is only allowed in non-KernelArch mode.
//
if (AsciiStrCmp (Arch, "Any") == 0) {
return TRUE;
}
}
//
// i386 and x86_64 are allowed in both modes.
// TODO: Do not allow empty string in OC.
//
if (AsciiStrCmp (Arch, "i386") != 0
&& AsciiStrCmp (Arch, "x86_64") != 0) {
return FALSE;
}
return TRUE;
}
BOOLEAN
AsciiPropertyIsLegal (
IN CONST CHAR8 *Property
)
{
//
// Like comments, properties can be anything printable.
// Calling sanitiser for comments to reduce code duplication.
//
return AsciiCommentIsLegal (Property);
}
BOOLEAN
AsciiUefiDriverIsLegal (
IN CONST CHAR8 *Driver
)
{
UINTN Index;
UINTN DriverLength;
//
// If an EFI driver does not contain .efi suffix,
// then it must be illegal.
//
if (!OcAsciiEndsWith (Driver, ".efi", TRUE)) {
return FALSE;
}
DriverLength = AsciiStrLen (Driver);
for (Index = 0; Index < DriverLength; ++Index) {
//
// NOTE: Skip '#' as it is treated as comments and thus is legal.
//
if (Driver[0] == '#') {
continue;
}
//
// Skip allowed characters (0-9, A-Z, a-z, '_', '-', '.', '/').
//
if (IsAsciiNumber (Driver[Index])
|| IsAsciiAlpha (Driver[Index])
|| Driver[Index] == '_'
|| Driver[Index] == '-'
|| Driver[Index] == '.'
|| Driver[Index] == '/') {
continue;
}
//
// Disallowed characters matched.
//
return FALSE;
}
return TRUE;
}
BOOLEAN
AsciiDevicePathIsLegal (
IN CONST CHAR8 *AsciiDevicePath
)
{
BOOLEAN RetVal;
CHAR16 *UnicodeDevicePath;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
CHAR16 *TextualDevicePath;
RetVal = TRUE;
//
// Convert ASCII device path to Unicode format.
//
UnicodeDevicePath = AsciiStrCopyToUnicode (AsciiDevicePath, 0);
if (UnicodeDevicePath != NULL) {
//
// Firstly, convert Unicode device path to binary.
//
DevicePath = ConvertTextToDevicePath (UnicodeDevicePath);
if (DevicePath != NULL) {
//
// Secondly, convert binary back to Unicode device path.
//
TextualDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
if (TextualDevicePath != NULL) {
//
// If the results before and after conversion do not match,
// then the original device path is borked.
//
if (OcStriCmp (UnicodeDevicePath, TextualDevicePath) != 0) {
DEBUG ((
DEBUG_WARN,
"Original path: %s\nPath after internal conversion: %s\n\n",
UnicodeDevicePath,
TextualDevicePath
));
//
// Do not return immediately in order to free properly.
//
RetVal = FALSE;
}
FreePool (TextualDevicePath);
}
FreePool (DevicePath);
}
FreePool (UnicodeDevicePath);
}
return RetVal;
}
BOOLEAN
DataHasProperMasking (
IN CONST VOID *Data,
IN CONST VOID *Mask,
IN UINTN Size
)
{
CONST UINT8 *ByteData;
CONST UINT8 *ByteMask;
UINTN Index;
ByteData = Data;
ByteMask = Mask;
for (Index = 0; Index < Size; ++Index) {
if ((ByteData[Index] & ~ByteMask[Index]) != 0) {
return FALSE;
}
}
return TRUE;
}
UINT32
ValidatePatch (
IN CONST CHAR8 *PatchSection,
IN UINT32 PatchIndex,
IN BOOLEAN FindSizeCanBeZero,
IN CONST UINT8 *Find,
IN UINT32 FindSize,
IN CONST UINT8 *Replace,
IN UINT32 ReplaceSize,
IN CONST UINT8 *Mask,
IN UINT32 MaskSize,
IN CONST UINT8 *ReplaceMask,
IN UINT32 ReplaceMaskSize
)
{
UINT32 ErrorCount;
ErrorCount = 0;
if (!FindSizeCanBeZero && FindSize != ReplaceSize) {
DEBUG ((
DEBUG_WARN,
"%a[%u] has different Find and Replace size (%u vs %u)!\n",
PatchSection,
PatchIndex,
FindSize,
ReplaceSize
));
++ErrorCount;
}
if (MaskSize > 0) {
if (MaskSize != FindSize) {
DEBUG ((
DEBUG_WARN,
"%a[%u] has Mask set but its size is different from Find (%u vs %u)!\n",
PatchSection,
PatchIndex,
MaskSize,
FindSize
));
++ErrorCount;
} else if (!DataHasProperMasking (Find, Mask, FindSize)) {
DEBUG ((
DEBUG_WARN,
"%a[%u]->Find requires Mask to be active for corresponding bits!\n",
PatchSection,
PatchIndex
));
++ErrorCount;
}
}
if (ReplaceMaskSize > 0) {
if (ReplaceMaskSize != ReplaceSize) {
DEBUG ((
DEBUG_WARN,
"%a[%u] has ReplaceMask set but its size is different from Replace (%u vs %u)!\n",
PatchSection,
PatchIndex,
ReplaceMaskSize,
ReplaceSize
));
++ErrorCount;
} else if (!DataHasProperMasking (Replace, ReplaceMask, ReplaceSize)) {
DEBUG ((
DEBUG_WARN,
"%a[%u]->Replace requires ReplaceMask to be active for corresponding bits!\n",
PatchSection,
PatchIndex
));
++ErrorCount;
}
}
return ErrorCount;
}
UINT32
ReportError (
IN CONST CHAR8 *FuncName,
IN UINT32 ErrorCount
)
{
if (ErrorCount != 0) {
DEBUG ((DEBUG_WARN, "%a returns %u %a!\n", FuncName, ErrorCount, ErrorCount > 1 ? "errors" : "error"));
} else {
DEBUG ((DEBUG_VERBOSE, "%a returns no errors!\n", FuncName));
}
return ErrorCount;
}
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef OC_USER_UTILITIES_OCVALIDATELIB_H
#define OC_USER_UTILITIES_OCVALIDATELIB_H
#include <sys/time.h>
#include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
/**
Get current timestamp in milliseconds.
@return Current timestamp in milliseconds.
**/
INT64
GetCurrentTimestamp (
VOID
);
/**
Check if a filesystem path contains only legal characters.
@param[in] Path Filesystem path to be checked.
@retval TRUE If Path only contains 0-9, A-Z, a-z, '_', '-', '.', '/', and '\'.
**/
BOOLEAN
AsciiFileSystemPathIsLegal (
IN CONST CHAR8 *Path
);
/**
Check if an OpenCore Configuration Comment contains only ASCII printable characters.
@param[in] Comment Comment to be checked.
@retval TRUE If Comment only contains ASCII printable characters.
**/
BOOLEAN
AsciiCommentIsLegal (
IN CONST CHAR8 *Comment
);
/**
Check if an OpenCore Configuration Identifier matches specific conventions.
@param[in] Identifier Identifier to be checked.
@param[in] IsKernelPatchIdentifier TRUE to perform special checks for Kernel->Patch->Identifier.
@retval TRUE If Identifier matches conventions.
**/
BOOLEAN
AsciiIdentifierIsLegal (
IN CONST CHAR8 *Identifier,
IN BOOLEAN IsKernelIdentifier
);
/**
Check if an OpenCore Configuration Arch matches specific conventions.
@param[in] Arch Arch to be checked.
@param[in] IsKernelArch Whether to perform special checks for Kernel->Scheme->KernelArch.
@retval TRUE If Arch matches conventions.
**/
BOOLEAN
AsciiArchIsLegal (
IN CONST CHAR8 *Arch,
IN BOOLEAN IsKernelArch
);
/**
Check if an OpenCore Configuration Property contains only ASCII printable characters. Mainly used in device properties and NVRAM properties.
@param[in] Property Property to be checked.
@retval TRUE If Property only contains ASCII printable characters.
**/
BOOLEAN
AsciiPropertyIsLegal (
IN CONST CHAR8 *Property
);
/**
Check if a UEFI Driver matches specific conventions.
@param[in] Driver Driver to be checked.
@retval TRUE If path of Driver contains .efi suffix, and only contains 0-9, A-Z, a-z, '_', '-', '.', and '/'.
**/
BOOLEAN
AsciiUefiDriverIsLegal (
IN CONST CHAR8 *Driver
);
/**
Check if a device path in ASCII is valid.
@param[in] AsciiDevicePath Device path to be checked.
@retval TRUE If AsciiDevicePath is valid.
**/
BOOLEAN
AsciiDevicePathIsLegal (
IN CONST CHAR8 *AsciiDevicePath
);
/**
Check if a set of data has proper masking set.
This function assumes identical sizes of Data and Mask, which must be ensured before calling.
@param[in] Data Data to be checked.
@param[in] Mask Mask to be paired with Data.
@param[in] Size Size of Data and Mask.
@retval TRUE If corresponding bits of Mask to Data are active (set to non-zero).
**/
BOOLEAN
DataHasProperMasking (
IN CONST VOID *Data,
IN CONST VOID *Mask,
IN UINTN Size
);
/**
Check if an OpenCore binary patch is valid.
If size of Find pattern cannot be zero, and size of Find pattern is different from that of Replace pattern, it is an error.
If Mask/ReplaceMask is used, but its size is different from that of Find/Replace, it is an error.
If Mask/ReplaceMask is used without corresponding bits being active for Find/Replace pattern, it is an error.
@param[in] PatchSection Patch section to which the patch to be checked belongs.
@param[in] PatchIndex Index of the patch to be checked.
@param[in] FindSizeCanBeZero Whether size of Find pattern can be zero. Set to TRUE only when Kernel->Patch->Base is used and Find is empty.
@param[in] Find Find pattern to be checked.
@param[in] FindSize Size of Find pattern to be checked.
@param[in] Replace Replace pattern to be checked.
@param[in] ReplaceSize Size of Replace pattern to be checked.
@param[in] Mask Mask pattern to be checked.
@param[in] MaskSize Size of Mask pattern to be checked.
@param[in] ReplaceMask ReplaceMask pattern to be checked.
@param[in] ReplaceMaskSize Size of ReplaceMask pattern to be checked.
@return Number of errors detected.
**/
UINT32
ValidatePatch (
IN CONST CHAR8 *PatchSection,
IN UINT32 PatchIndex,
IN BOOLEAN FindSizeCanBeZero,
IN CONST UINT8 *Find,
IN UINT32 FindSize,
IN CONST UINT8 *Replace,
IN UINT32 ReplaceSize,
IN CONST UINT8 *Mask,
IN UINT32 MaskSize,
IN CONST UINT8 *ReplaceMask,
IN UINT32 ReplaceMaskSize
);
/**
Report status of errors in the end of each checker functions.
@param[in] FuncName Checker function name. (__func__)
@param[in] ErrorCount Number of errors to be returned.
@return Number of errors detected in one checker.
**/
UINT32
ReportError (
IN CONST CHAR8 *FuncName,
IN UINT32 ErrorCount
);
#endif // OC_USER_UTILITIES_OCVALIDATELIB_H
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
UINT32
CheckACPI (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
UINT32 Index;
OC_ACPI_CONFIG *UserAcpi;
CONST CHAR8 *Path;
CONST CHAR8 *Comment;
CONST UINT8 *Find;
UINT32 FindSize;
CONST UINT8 *Replace;
UINT32 ReplaceSize;
CONST UINT8 *Mask;
UINT32 MaskSize;
CONST UINT8 *ReplaceMask;
UINT32 ReplaceMaskSize;
BOOLEAN HasCustomDSDT;
DEBUG ((DEBUG_VERBOSE, "config loaded into ACPI checker!\n"));
ErrorCount = 0;
UserAcpi = &Config->Acpi;
HasCustomDSDT = FALSE;
for (Index = 0; Index < UserAcpi->Add.Count; ++Index) {
Path = OC_BLOB_GET (&UserAcpi->Add.Values[Index]->Path);
Comment = OC_BLOB_GET (&UserAcpi->Add.Values[Index]->Comment);
//
// Sanitise strings.
//
if (!AsciiFileSystemPathIsLegal (Path)) {
DEBUG ((DEBUG_WARN, "ACPI->Add[%u]->Path contains illegal character!\n", Index));
++ErrorCount;
continue;
}
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "ACPI->Add[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
if (!OcAsciiEndsWith (Path, ".aml", TRUE) && !OcAsciiEndsWith (Path, ".bin", TRUE)) {
DEBUG ((DEBUG_WARN, "ACPI->Add[%u]->Path has filename suffix other than .aml and .bin!\n", Index));
++ErrorCount;
}
if (OcAsciiStriStr (Path, "DSDT") != NULL && UserAcpi->Add.Values[Index]->Enabled) {
HasCustomDSDT = TRUE;
}
}
for (Index = 0; Index < UserAcpi->Delete.Count; ++Index) {
Comment = OC_BLOB_GET (&UserAcpi->Delete.Values[Index]->Comment);
//
// Sanitise strings.
//
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "ACPI->Delete[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
//
// Size of OemTableId and TableSignature cannot be checked,
// as serialisation kills it.
//
}
for (Index = 0; Index < UserAcpi->Patch.Count; ++Index) {
Comment = OC_BLOB_GET (&UserAcpi->Patch.Values[Index]->Comment);
Find = OC_BLOB_GET (&UserAcpi->Patch.Values[Index]->Find);
FindSize = UserAcpi->Patch.Values[Index]->Find.Size;
Replace = OC_BLOB_GET (&UserAcpi->Patch.Values[Index]->Replace);
ReplaceSize = UserAcpi->Patch.Values[Index]->Replace.Size;
Mask = OC_BLOB_GET (&UserAcpi->Patch.Values[Index]->Mask);
MaskSize = UserAcpi->Patch.Values[Index]->Mask.Size;
ReplaceMask = OC_BLOB_GET (&UserAcpi->Patch.Values[Index]->ReplaceMask);
ReplaceMaskSize = UserAcpi->Patch.Values[Index]->ReplaceMask.Size;
//
// Sanitise strings.
//
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "ACPI->Patch[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
//
// Size of OemTableId and TableSignature cannot be checked,
// as serialisation kills it.
//
//
// Checks for size.
//
ErrorCount += ValidatePatch (
"ACPI->Patch",
Index,
FALSE,
Find,
FindSize,
Replace,
ReplaceSize,
Mask,
MaskSize,
ReplaceMask,
ReplaceMaskSize
);
}
//
// Check for RebaseRegions when using customised DSDT.
//
if (HasCustomDSDT && !UserAcpi->Quirks.RebaseRegions) {
DEBUG ((DEBUG_WARN, "ACPI->Quirks->RebaseRegions is not enabled when customised DSDT table is in use!\n"));
++ErrorCount;
}
return ReportError (__func__, ErrorCount);
}
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
UINT32
CheckBooter (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
UINT32 Index;
OC_BOOTER_CONFIG *UserBooter;
OC_UEFI_CONFIG *UserUefi;
CONST CHAR8 *Comment;
CONST CHAR8 *Arch;
CONST CHAR8 *Identifier;
CONST CHAR8 *Driver;
CONST UINT8 *Find;
UINT32 FindSize;
CONST UINT8 *Replace;
UINT32 ReplaceSize;
CONST UINT8 *Mask;
UINT32 MaskSize;
CONST UINT8 *ReplaceMask;
UINT32 ReplaceMaskSize;
UINT8 MaxSlide;
BOOLEAN IsMmioWhitelistEnabled;
BOOLEAN ShouldEnableDevirtualiseMmio;
BOOLEAN IsDevirtualiseMmioEnabled;
BOOLEAN IsAllowRelocationBlockEnabled;
BOOLEAN IsProvideCustomSlideEnabled;
BOOLEAN IsEnableSafeModeSlideEnabled;
BOOLEAN IsDisableVariableWriteEnabled;
BOOLEAN IsEnableWriteUnprotectorEnabled;
BOOLEAN HasOpenRuntimeEfiDriver;
DEBUG ((DEBUG_VERBOSE, "config loaded into Booter checker!\n"));
ErrorCount = 0;
UserBooter = &Config->Booter;
UserUefi = &Config->Uefi;
IsMmioWhitelistEnabled = FALSE;
ShouldEnableDevirtualiseMmio = FALSE;
IsDevirtualiseMmioEnabled = UserBooter->Quirks.DevirtualiseMmio;
IsAllowRelocationBlockEnabled = UserBooter->Quirks.AllowRelocationBlock;
IsProvideCustomSlideEnabled = UserBooter->Quirks.ProvideCustomSlide;
IsEnableSafeModeSlideEnabled = UserBooter->Quirks.EnableSafeModeSlide;
IsDisableVariableWriteEnabled = UserBooter->Quirks.DisableVariableWrite;
IsEnableWriteUnprotectorEnabled = UserBooter->Quirks.EnableWriteUnprotector;
HasOpenRuntimeEfiDriver = FALSE;
MaxSlide = UserBooter->Quirks.ProvideMaxSlide;
for (Index = 0; Index < UserBooter->MmioWhitelist.Count; ++Index) {
Comment = OC_BLOB_GET (&UserBooter->MmioWhitelist.Values[Index]->Comment);
IsMmioWhitelistEnabled = UserBooter->MmioWhitelist.Values[Index]->Enabled;
//
// Sanitise strings.
//
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "Booter->MmioWhitelist[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
if (IsMmioWhitelistEnabled) {
ShouldEnableDevirtualiseMmio = TRUE;
}
}
for (Index = 0; Index < UserBooter->Patch.Count; ++Index) {
Comment = OC_BLOB_GET (&UserBooter->Patch.Values[Index]->Comment);
Arch = OC_BLOB_GET (&UserBooter->Patch.Values[Index]->Arch);
Identifier = OC_BLOB_GET (&UserBooter->Patch.Values[Index]->Identifier);
Find = OC_BLOB_GET (&UserBooter->Patch.Values[Index]->Find);
FindSize = UserBooter->Patch.Values[Index]->Find.Size;
Replace = OC_BLOB_GET (&UserBooter->Patch.Values[Index]->Replace);
ReplaceSize = UserBooter->Patch.Values[Index]->Replace.Size;
Mask = OC_BLOB_GET (&UserBooter->Patch.Values[Index]->Mask);
MaskSize = UserBooter->Patch.Values[Index]->Mask.Size;
ReplaceMask = OC_BLOB_GET (&UserBooter->Patch.Values[Index]->ReplaceMask);
ReplaceMaskSize = UserBooter->Patch.Values[Index]->ReplaceMask.Size;
//
// Sanitise strings.
//
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "Booter->Patch[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
if (!AsciiArchIsLegal (Arch, FALSE)) {
DEBUG ((DEBUG_WARN, "Booter->Patch[%u]->Arch is borked (Can only be Any, i386, and x86_64)!\n", Index));
++ErrorCount;
}
if (!AsciiIdentifierIsLegal (Identifier, FALSE)) {
DEBUG ((DEBUG_WARN, "Booter->Patch[%u]->Identifier contains illegal character!\n", Index));
++ErrorCount;
}
//
// Checks for size.
//
ErrorCount += ValidatePatch (
"Booter->Patch",
Index,
FALSE,
Find,
FindSize,
Replace,
ReplaceSize,
Mask,
MaskSize,
ReplaceMask,
ReplaceMaskSize
);
}
for (Index = 0; Index < UserUefi->Drivers.Count; ++Index) {
Driver = OC_BLOB_GET (UserUefi->Drivers.Values[Index]);
//
// Skip sanitising UEFI->Drivers as it will be performed when checking UEFI section.
//
if (AsciiStrCmp (Driver, "OpenRuntime.efi") == 0) {
HasOpenRuntimeEfiDriver = TRUE;
}
}
if (ShouldEnableDevirtualiseMmio && !IsDevirtualiseMmioEnabled) {
DEBUG ((DEBUG_WARN, "There are enabled entries under Booter->MmioWhitelist, but DevirtualiseMmio is not enabled!\n"));
++ErrorCount;
}
if (!HasOpenRuntimeEfiDriver) {
if (IsProvideCustomSlideEnabled) {
DEBUG ((DEBUG_WARN, "Booter->Quirks->ProvideCustomSlide is enabled, but OpenRuntime.efi is not loaded at UEFI->Drivers!\n"));
++ErrorCount;
}
if (IsDisableVariableWriteEnabled) {
DEBUG ((DEBUG_WARN, "Booter->Quirks->DisableVariableWrite is enabled, but OpenRuntime.efi is not loaded at UEFI->Drivers!\n"));
++ErrorCount;
}
if (IsEnableWriteUnprotectorEnabled) {
DEBUG ((DEBUG_WARN, "Booter->Quirks->EnableWriteUnprotector is enabled, but OpenRuntime.efi is not loaded at UEFI->Drivers!\n"));
++ErrorCount;
}
}
if (!IsProvideCustomSlideEnabled) {
if (IsAllowRelocationBlockEnabled) {
DEBUG ((DEBUG_WARN, "Booter->Quirks->AllowRelocationBlock is enabled, but ProvideCustomSlide is not enabled altogether!\n"));
++ErrorCount;
}
if (IsEnableSafeModeSlideEnabled) {
DEBUG ((DEBUG_WARN, "Booter->Quirks->EnableSafeModeSlide is enabled, but ProvideCustomSlide is not enabled altogether!\n"));
++ErrorCount;
}
if (MaxSlide > 0) {
DEBUG ((DEBUG_WARN, "Booter->Quirks->ProvideMaxSlide is set to %u, but ProvideCustomSlide is not enabled altogether!\n", MaxSlide));
++ErrorCount;
}
}
return ReportError (__func__, ErrorCount);
}
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
UINT32
CheckDeviceProperties (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
UINT32 DeviceIndex;
UINT32 PropertyIndex;
OC_DEV_PROP_CONFIG *UserDevProp;
CONST CHAR8 *AsciiDevicePath;
CONST CHAR8 *AsciiProperty;
OC_ASSOC *PropertyMap;
DEBUG ((DEBUG_VERBOSE, "config loaded into DeviceProperties checker!\n"));
ErrorCount = 0;
UserDevProp = &Config->DeviceProperties;
for (DeviceIndex = 0; DeviceIndex < UserDevProp->Delete.Count; ++DeviceIndex) {
AsciiDevicePath = OC_BLOB_GET (UserDevProp->Delete.Keys[DeviceIndex]);
if (!AsciiDevicePathIsLegal (AsciiDevicePath)) {
DEBUG ((DEBUG_WARN, "DeviceProperties->Delete[%u]->DevicePath is borked! Please check the information above!\n", DeviceIndex));
++ErrorCount;
}
for (PropertyIndex = 0; PropertyIndex < UserDevProp->Delete.Values[DeviceIndex]->Count; ++PropertyIndex) {
AsciiProperty = OC_BLOB_GET (UserDevProp->Delete.Values[DeviceIndex]->Values[PropertyIndex]);
//
// Sanitise strings.
//
if (!AsciiPropertyIsLegal (AsciiProperty)) {
DEBUG ((
DEBUG_WARN,
"DeviceProperties->Delete[%u]->Property[%u] contains illegal character!\n",
DeviceIndex,
PropertyIndex
));
++ErrorCount;
}
}
}
for (DeviceIndex = 0; DeviceIndex < UserDevProp->Add.Count; ++DeviceIndex) {
PropertyMap = UserDevProp->Add.Values[DeviceIndex];
AsciiDevicePath = OC_BLOB_GET (UserDevProp->Add.Keys[DeviceIndex]);
if (!AsciiDevicePathIsLegal (AsciiDevicePath)) {
DEBUG ((DEBUG_WARN, "DeviceProperties->Add[%u]->DevicePath is borked! Please check the information above!\n", DeviceIndex));
++ErrorCount;
}
for (PropertyIndex = 0; PropertyIndex < PropertyMap->Count; ++PropertyIndex) {
AsciiProperty = OC_BLOB_GET (PropertyMap->Keys[PropertyIndex]);
//
// Sanitise strings.
//
if (!AsciiPropertyIsLegal (AsciiProperty)) {
DEBUG ((
DEBUG_WARN,
"DeviceProperties->Add[%u]->Property[%u] contains illegal character!\n",
DeviceIndex,
PropertyIndex
));
++ErrorCount;
}
}
}
return ReportError (__func__, ErrorCount);
}
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
#include <Library/OcAppleKernelLib.h>
#define INDEX_KEXT_LILU 0U
typedef struct KEXT_PRECEDENCE_ {
CONST CHAR8 *Child;
CONST CHAR8 *Parent;
} KEXT_PRECEDENCE;
typedef struct KEXT_INFO_ {
CONST CHAR8 *KextBundlePath;
CONST CHAR8 *KextExecutablePath;
CONST CHAR8 *KextPlistPath;
} KEXT_INFO;
STATIC KEXT_PRECEDENCE mKextPrecedence[] = {
{ "VirtualSMC.kext", "Lilu.kext" },
{ "WhateverGreen.kext", "Lilu.kext" },
//
// TODO: Add more kexts here...
//
};
STATIC UINTN mKextPrecedenceSize = ARRAY_SIZE (mKextPrecedence);
STATIC KEXT_INFO mKextInfo[] = {
//
// NOTE: Index of Lilu should always be 0. Please add entries after this if necessary.
//
{ "Lilu.kext", "Contents/MacOS/Lilu", "Contents/Info.plist" },
{ "VirtualSMC.kext", "Contents/MacOS/VirtualSMC", "Contents/Info.plist" },
{ "WhateverGreen.kext", "Contents/MacOS/WhateverGreen", "Contents/Info.plist" },
//
// TODO: Add more kexts here...
//
};
STATIC UINTN mKextInfoSize = ARRAY_SIZE (mKextInfo);
UINT32
CheckKernel (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
UINT32 Index;
OC_KERNEL_CONFIG *UserKernel;
OC_PLATFORM_CONFIG *UserPlatformInfo;
CONST CHAR8 *Arch;
CONST CHAR8 *BundlePath;
CONST CHAR8 *Comment;
CONST CHAR8 *ExecutablePath;
CONST CHAR8 *MaxKernel;
CONST CHAR8 *MinKernel;
CONST CHAR8 *PlistPath;
CONST CHAR8 *Identifier;
BOOLEAN IsDisableLinkeditJettisonEnabled;
BOOLEAN IsCustomSMBIOSGuidEnabled;
CONST CHAR8 *UpdateSMBIOSMode;
CONST CHAR8 *Base;
CONST UINT8 *Find;
UINT32 FindSize;
CONST UINT8 *Replace;
UINT32 ReplaceSize;
CONST UINT8 *Mask;
UINT32 MaskSize;
CONST UINT8 *ReplaceMask;
UINT32 ReplaceMaskSize;
CONST CHAR8 *KernelCache;
UINTN IndexKextInfo;
UINTN IndexKextPrecedence;
BOOLEAN HasParent;
CONST CHAR8 *CurrentKext;
CONST CHAR8 *ParentKext;
CONST CHAR8 *ChildKext;
DEBUG ((DEBUG_VERBOSE, "config loaded into Kernel checker!\n"));
//
// Ensure Lilu to be always placed where it is supposed to be.
//
ASSERT (AsciiStrCmp (mKextInfo[INDEX_KEXT_LILU].KextBundlePath, "Lilu.kext") == 0);
ASSERT (AsciiStrCmp (mKextInfo[INDEX_KEXT_LILU].KextExecutablePath, "Contents/MacOS/Lilu") == 0);
ASSERT (AsciiStrCmp (mKextInfo[INDEX_KEXT_LILU].KextPlistPath, "Contents/Info.plist") == 0);
ErrorCount = 0;
UserKernel = &Config->Kernel;
UserPlatformInfo = &Config->PlatformInfo;
IsDisableLinkeditJettisonEnabled = UserKernel->Quirks.DisableLinkeditJettison;
IsCustomSMBIOSGuidEnabled = UserKernel->Quirks.CustomSmbiosGuid;
UpdateSMBIOSMode = OC_BLOB_GET (&UserPlatformInfo->UpdateSmbiosMode);
KernelCache = OC_BLOB_GET (&UserKernel->Scheme.KernelCache);
for (Index = 0; Index < UserKernel->Add.Count; ++Index) {
Arch = OC_BLOB_GET (&UserKernel->Add.Values[Index]->Arch);
BundlePath = OC_BLOB_GET (&UserKernel->Add.Values[Index]->BundlePath);
Comment = OC_BLOB_GET (&UserKernel->Add.Values[Index]->Comment);
ExecutablePath = OC_BLOB_GET (&UserKernel->Add.Values[Index]->ExecutablePath);
MaxKernel = OC_BLOB_GET (&UserKernel->Add.Values[Index]->MaxKernel);
MinKernel = OC_BLOB_GET (&UserKernel->Add.Values[Index]->MinKernel);
PlistPath = OC_BLOB_GET (&UserKernel->Add.Values[Index]->PlistPath);
//
// Sanitise strings.
//
if (!AsciiArchIsLegal (Arch, FALSE)) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->Arch is borked (Can only be Any, i386, and x86_64)!\n", Index));
++ErrorCount;
}
if (!AsciiFileSystemPathIsLegal (BundlePath)) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->BundlePath contains illegal character!\n", Index));
++ErrorCount;
continue;
}
//
// Valid BundlePath must contain .kext suffix.
//
if (!OcAsciiEndsWith (BundlePath, ".kext", TRUE)) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->BundlePath does NOT contain .kext suffix!\n", Index));
++ErrorCount;
}
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
if (!AsciiFileSystemPathIsLegal (ExecutablePath)) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->ExecutablePath contains illegal character!\n", Index));
++ErrorCount;
continue;
}
if (!AsciiFileSystemPathIsLegal (PlistPath)) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->PlistPath contains illegal character!\n", Index));
++ErrorCount;
continue;
}
//
// Valid PlistPath must contain .plist suffix.
//
if (!OcAsciiEndsWith (PlistPath, ".plist", TRUE)) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->PlistPath does NOT contain .plist suffix!\n", Index));
++ErrorCount;
}
//
// FIXME: Handle correct kernel version checking.
//
if (MaxKernel[0] != '\0' && OcParseDarwinVersion (MaxKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->MaxKernel (currently set to %a) is borked!\n", Index, MaxKernel));
++ErrorCount;
}
if (MinKernel[0] != '\0' && OcParseDarwinVersion (MinKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u]->MinKernel (currently set to %a) is borked!\n", Index, MinKernel));
++ErrorCount;
}
for (IndexKextInfo = 0; IndexKextInfo < mKextInfoSize; ++IndexKextInfo) {
if (AsciiStrCmp (BundlePath, mKextInfo[IndexKextInfo].KextBundlePath) == 0) {
//
// BundlePath matched. Continue checking ExecutablePath and PlistPath.
//
if (AsciiStrCmp (ExecutablePath, mKextInfo[IndexKextInfo].KextExecutablePath) == 0
&& AsciiStrCmp (PlistPath, mKextInfo[IndexKextInfo].KextPlistPath) == 0) {
//
// Special check for Lilu and Quirks->DisableLinkeditJettison.
//
if (IndexKextInfo == INDEX_KEXT_LILU) {
if (!IsDisableLinkeditJettisonEnabled) {
DEBUG ((DEBUG_WARN, "Lilu.kext is loaded at Kernel->Add[%u], but DisableLinkeditJettison is not enabled at Kernel->Quirks!\n", Index));
++ErrorCount;
}
}
} else {
DEBUG ((
DEBUG_WARN,
"Kernel->Add[%u] discovers %a, but its ExecutablePath (%a) or PlistPath (%a) is borked!\n",
IndexKextInfo,
BundlePath,
ExecutablePath,
PlistPath
));
++ErrorCount;
}
}
}
}
//
// Special checks for kext precedence from Acidanthera.
//
for (IndexKextPrecedence = 0; IndexKextPrecedence < mKextPrecedenceSize; ++IndexKextPrecedence) {
HasParent = FALSE;
for (Index = 0; Index < UserKernel->Add.Count; ++Index) {
CurrentKext = OC_BLOB_GET (&UserKernel->Add.Values[Index]->BundlePath);
ParentKext = mKextPrecedence[IndexKextPrecedence].Parent;
ChildKext = mKextPrecedence[IndexKextPrecedence].Child;
if (AsciiStrCmp (CurrentKext, ParentKext) == 0) {
HasParent = TRUE;
} else if (AsciiStrCmp (CurrentKext, ChildKext) == 0) {
if (!HasParent) {
DEBUG ((DEBUG_WARN, "Kernel->Add[%u] discovers %a, but its Parent (%a) is either placed after it or is missing!\n", Index, CurrentKext, ParentKext));
++ErrorCount;
}
//
// Parent is already found before Child. Done.
//
break;
}
}
}
for (Index = 0; Index < UserKernel->Block.Count; ++Index) {
Arch = OC_BLOB_GET (&UserKernel->Block.Values[Index]->Arch);
Comment = OC_BLOB_GET (&UserKernel->Block.Values[Index]->Comment);
Identifier = OC_BLOB_GET (&UserKernel->Block.Values[Index]->Identifier);
MaxKernel = OC_BLOB_GET (&UserKernel->Block.Values[Index]->MaxKernel);
MinKernel = OC_BLOB_GET (&UserKernel->Block.Values[Index]->MinKernel);
//
// Sanitise strings.
//
if (!AsciiArchIsLegal (Arch, FALSE)) {
DEBUG ((DEBUG_WARN, "Kernel->Block[%u]->Arch is borked (Can only be Any, i386, and x86_64)!\n", Index));
++ErrorCount;
}
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "Kernel->Block[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
if (!AsciiIdentifierIsLegal (Identifier, TRUE)) {
DEBUG ((DEBUG_WARN, "Kernel->Block[%u]->Identifier contains illegal character!\n", Index));
++ErrorCount;
}
//
// FIXME: Handle correct kernel version checking.
//
if (MaxKernel[0] != '\0' && OcParseDarwinVersion (MaxKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Block[%u]->MaxKernel (currently set to %a) is borked!\n", Index, MaxKernel));
++ErrorCount;
}
if (MinKernel[0] != '\0' && OcParseDarwinVersion (MinKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Block[%u]->MinKernel (currently set to %a) is borked!\n", Index, MinKernel));
++ErrorCount;
}
}
//
// FIXME: Handle correct kernel version checking.
//
MaxKernel = OC_BLOB_GET (&UserKernel->Emulate.MaxKernel);
MinKernel = OC_BLOB_GET (&UserKernel->Emulate.MinKernel);
if (MaxKernel[0] != '\0' && OcParseDarwinVersion (MaxKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Emulate->MaxKernel (currently set to %a) is borked!\n", MaxKernel));
++ErrorCount;
}
if (MinKernel[0] != '\0' && OcParseDarwinVersion (MinKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Emulate->MinKernel (currently set to %a) is borked!\n", MinKernel));
++ErrorCount;
}
if (!DataHasProperMasking (UserKernel->Emulate.Cpuid1Data, UserKernel->Emulate.Cpuid1Mask, sizeof (UserKernel->Emulate.Cpuid1Data))) {
DEBUG ((DEBUG_WARN, "Kernel->Emulate->Cpuid1Data requires Cpuid1Mask to be active for replaced bits!\n"));
++ErrorCount;
}
for (Index = 0; Index < UserKernel->Force.Count; ++Index) {
Arch = OC_BLOB_GET (&UserKernel->Force.Values[Index]->Arch);
BundlePath = OC_BLOB_GET (&UserKernel->Force.Values[Index]->BundlePath);
Comment = OC_BLOB_GET (&UserKernel->Force.Values[Index]->Comment);
ExecutablePath = OC_BLOB_GET (&UserKernel->Force.Values[Index]->ExecutablePath);
Identifier = OC_BLOB_GET (&UserKernel->Force.Values[Index]->Identifier);
MaxKernel = OC_BLOB_GET (&UserKernel->Force.Values[Index]->MaxKernel);
MinKernel = OC_BLOB_GET (&UserKernel->Force.Values[Index]->MinKernel);
PlistPath = OC_BLOB_GET (&UserKernel->Force.Values[Index]->PlistPath);
//
// Sanitise strings.
//
if (!AsciiArchIsLegal (Arch, FALSE)) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->Arch is borked (Can only be Any, i386, and x86_64)!\n", Index));
++ErrorCount;
}
if (!AsciiIdentifierIsLegal (Identifier, TRUE)) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->Identifier contains illegal character!\n", Index));
++ErrorCount;
}
if (!AsciiFileSystemPathIsLegal (BundlePath)) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->BundlePath contains illegal character!\n", Index));
++ErrorCount;
continue;
}
//
// Valid BundlePath must contain .kext suffix.
//
if (!OcAsciiEndsWith (BundlePath, ".kext", TRUE)) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->BundlePath does NOT contain .kext suffix!\n", Index));
++ErrorCount;
}
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
if (!AsciiFileSystemPathIsLegal (ExecutablePath)) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->ExecutablePath contains illegal character!\n", Index));
++ErrorCount;
continue;
}
if (!AsciiFileSystemPathIsLegal (PlistPath)) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->PlistPath contains illegal character!\n", Index));
++ErrorCount;
continue;
}
//
// Valid PlistPath must contain .plist suffix.
//
if (!OcAsciiEndsWith (PlistPath, ".plist", TRUE)) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->PlistPath does NOT contain .plist suffix!\n", Index));
++ErrorCount;
}
//
// FIXME: Handle correct kernel version checking.
//
if (MaxKernel[0] != '\0' && OcParseDarwinVersion (MaxKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->MaxKernel (currently set to %a) is borked!\n", Index, MaxKernel));
++ErrorCount;
}
if (MinKernel[0] != '\0' && OcParseDarwinVersion (MinKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Force[%u]->MinKernel (currently set to %a) is borked!\n", Index, MinKernel));
++ErrorCount;
}
}
for (Index = 0; Index < UserKernel->Patch.Count; ++Index) {
Base = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->Base);
Comment = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->Comment);
Arch = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->Arch);
Identifier = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->Identifier);
Find = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->Find);
FindSize = UserKernel->Patch.Values[Index]->Find.Size;
Replace = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->Replace);
ReplaceSize = UserKernel->Patch.Values[Index]->Replace.Size;
Mask = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->Mask);
MaskSize = UserKernel->Patch.Values[Index]->Mask.Size;
ReplaceMask = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->ReplaceMask);
ReplaceMaskSize = UserKernel->Patch.Values[Index]->ReplaceMask.Size;
MaxKernel = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->MaxKernel);
MinKernel = OC_BLOB_GET (&UserKernel->Patch.Values[Index]->MinKernel);
//
// Sanitise strings.
//
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "Kernel->Patch[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
if (!AsciiArchIsLegal (Arch, FALSE)) {
DEBUG ((DEBUG_WARN, "Kernel->Patch[%u]->Arch is borked (Can only be Any, i386, and x86_64)!\n", Index));
++ErrorCount;
}
if (!AsciiIdentifierIsLegal (Identifier, TRUE)) {
DEBUG ((DEBUG_WARN, "Kernel->Patch[%u]->Identifier contains illegal character!\n", Index));
++ErrorCount;
}
//
// FIXME: Handle correct kernel version checking.
//
if (MaxKernel[0] != '\0' && OcParseDarwinVersion (MaxKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Patch[%u]->MaxKernel (currently set to %a) is borked!\n", Index, MaxKernel));
++ErrorCount;
}
if (MinKernel[0] != '\0' && OcParseDarwinVersion (MinKernel) == 0) {
DEBUG ((DEBUG_WARN, "Kernel->Patch[%u]->MinKernel (currently set to %a) is borked!\n", Index, MinKernel));
++ErrorCount;
}
//
// Checks for size.
//
ErrorCount += ValidatePatch (
"Kernel->Patch",
Index,
Base[0] != '\0' && FindSize == 0,
Find,
FindSize,
Replace,
ReplaceSize,
Mask,
MaskSize,
ReplaceMask,
ReplaceMaskSize
);
}
//
// Sanitise Kernel->Scheme keys.
//
Arch = OC_BLOB_GET (&UserKernel->Scheme.KernelArch);
if (!AsciiArchIsLegal (Arch, TRUE)) {
DEBUG ((DEBUG_WARN, "Kernel->Scheme->KernelArch is borked (Can only be Auto, i386, i386-user32, or x86_64)!\n"));
++ErrorCount;
}
if (AsciiStrCmp (KernelCache, "Auto") != 0
&& AsciiStrCmp (KernelCache, "Cacheless") != 0
&& AsciiStrCmp (KernelCache, "Mkext") != 0
&& AsciiStrCmp (KernelCache, "Prelinked") != 0) {
DEBUG ((DEBUG_WARN, "Kernel->Scheme->KernelCache is borked (Can only be Auto, Cacheless, Mkext, or Prelinked)!\n"));
++ErrorCount;
}
//
// CustomSMBIOSGuid quirk requires UpdateSMBIOSMode at PlatformInfo set to Custom.
//
if (IsCustomSMBIOSGuidEnabled && AsciiStrCmp (UpdateSMBIOSMode, "Custom") != 0) {
DEBUG ((DEBUG_WARN, "Kernel->Quirks->CustomSMBIOSGuid is enabled, but PlatformInfo->UpdateSMBIOSMode is not set to Custom!\n"));
++ErrorCount;
}
return ReportError (__func__, ErrorCount);
}
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
#include <Library/OcBootManagementLib.h>
#include <Library/OcConfigurationLib.h>
#include <Protocol/OcLog.h>
/**
Validate if SecureBootModel has allowed value.
@param[in] SecureBootModel SecureBootModel retrieved from user config.
@retval TRUE If SecureBootModel is valid.
**/
STATIC
BOOLEAN
ValidateSecureBootModel (
IN CONST CHAR8 *SecureBootModel
)
{
UINT32 Index;
CONST CHAR8 *AllowedSecureBootModel[] = {
"Default", "Disabled",
"j137", "j680", "j132", "j174", "j140k",
"j780", "j213", "j140a", "j152f", "j160",
"j230k", "j214k", "j223", "j215", "j185", "j185f",
"x86legacy"
};
for (Index = 0; Index < ARRAY_SIZE (AllowedSecureBootModel); ++Index) {
if (AsciiStrCmp (SecureBootModel, AllowedSecureBootModel[Index]) == 0) {
return TRUE;
}
}
return FALSE;
}
UINT32
CheckMisc (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
UINT32 Index;
OC_MISC_CONFIG *UserMisc;
OC_UEFI_CONFIG *UserUefi;
UINT32 ConsoleAttributes;
CONST CHAR8 *HibernateMode;
UINT32 PickerAttributes;
CONST CHAR8 *PickerMode;
UINT64 DisplayLevel;
UINT64 AllowedDisplayLevel;
UINT64 HaltLevel;
UINT64 AllowedHaltLevel;
UINT32 Target;
CONST CHAR8 *BootProtect;
BOOLEAN IsRequestBootVarRoutingEnabled;
CONST CHAR8 *AsciiDmgLoading;
UINT32 ExposeSensitiveData;
CONST CHAR8 *AsciiVault;
UINT32 ScanPolicy;
UINT32 AllowedScanPolicy;
CONST CHAR8 *SecureBootModel;
CONST CHAR8 *Arguments;
CONST CHAR8 *Comment;
CONST CHAR8 *AsciiName;
CONST CHAR16 *UnicodeName;
CONST CHAR8 *Path;
DEBUG ((DEBUG_VERBOSE, "config loaded into Misc checker!\n"));
ErrorCount = 0;
UserMisc = &Config->Misc;
UserUefi = &Config->Uefi;
ConsoleAttributes = UserMisc->Boot.ConsoleAttributes;
HibernateMode = OC_BLOB_GET (&UserMisc->Boot.HibernateMode);
PickerAttributes = UserMisc->Boot.PickerAttributes;
PickerMode = OC_BLOB_GET (&UserMisc->Boot.PickerMode);
DisplayLevel = UserMisc->Debug.DisplayLevel;
AllowedDisplayLevel = DEBUG_WARN | DEBUG_INFO | DEBUG_VERBOSE | DEBUG_ERROR;
HaltLevel = DisplayLevel;
AllowedHaltLevel = AllowedDisplayLevel;
Target = UserMisc->Debug.Target;
BootProtect = OC_BLOB_GET (&UserMisc->Security.BootProtect);
IsRequestBootVarRoutingEnabled = UserUefi->Quirks.RequestBootVarRouting;
AsciiDmgLoading = OC_BLOB_GET (&UserMisc->Security.DmgLoading);
ExposeSensitiveData = UserMisc->Security.ExposeSensitiveData;
AsciiVault = OC_BLOB_GET (&UserMisc->Security.Vault);
ScanPolicy = UserMisc->Security.ScanPolicy;
AllowedScanPolicy = OC_SCAN_FILE_SYSTEM_LOCK | OC_SCAN_DEVICE_LOCK | OC_SCAN_DEVICE_BITS | OC_SCAN_FILE_SYSTEM_BITS;
SecureBootModel = OC_BLOB_GET (&UserMisc->Security.SecureBootModel);
if ((ConsoleAttributes & ~0x7FU) != 0) {
DEBUG ((DEBUG_WARN, "Misc->Boot->ConsoleAttributes has unknown bits set!\n"));
++ErrorCount;
}
if (AsciiStrCmp (HibernateMode, "None") != 0
&& AsciiStrCmp (HibernateMode, "Auto") != 0
&& AsciiStrCmp (HibernateMode, "RTC") != 0
&& AsciiStrCmp (HibernateMode, "NVRAM") != 0) {
DEBUG ((DEBUG_WARN, "Misc->Boot->HibernateMode is borked (Can only be None, Auto, RTC, or NVRAM)!\n"));
++ErrorCount;
}
if ((PickerAttributes & ~OC_ATTR_ALL_BITS) != 0) {
DEBUG ((DEBUG_WARN, "Misc->Boot->PickerAttributes is has unknown bits set!\n"));
++ErrorCount;
}
//
// FIXME: Is OpenCanopy.efi mandatory if set to External? Or is this just a suggestion?
//
if (AsciiStrCmp (PickerMode, "Builtin") != 0
&& AsciiStrCmp (PickerMode, "External") != 0
&& AsciiStrCmp (PickerMode, "Apple") != 0) {
DEBUG ((DEBUG_WARN, "Misc->Boot->PickerMode is borked (Can only be Builtin, External, or Apple)!\n"));
++ErrorCount;
}
//
// FIXME: Check whether DisplayLevel only supports values within AllowedDisplayLevel, or all possible levels in DebugLib.h?
//
if ((DisplayLevel & ~AllowedDisplayLevel) != 0) {
DEBUG ((DEBUG_WARN, "Misc->Debug->DisplayLevel is has unknown bits set!\n"));
++ErrorCount;
}
if ((HaltLevel & ~AllowedHaltLevel) != 0) {
DEBUG ((DEBUG_WARN, "Misc->Security->HaltLevel has unknown bits set!\n"));
++ErrorCount;
}
if ((Target & ~OC_LOG_ALL_BITS) != 0) {
DEBUG ((DEBUG_WARN, "Misc->Debug->Target has unknown bits set!\n"));
++ErrorCount;
}
//
// TODO: Check requirements of Security->AuthRestart.
//
if (AsciiStrCmp (BootProtect, "None") != 0
&& AsciiStrCmp (BootProtect, "Bootstrap") != 0
&& AsciiStrCmp (BootProtect, "BootstrapShort") != 0) {
DEBUG ((DEBUG_WARN, "Misc->Security->BootProtect is borked (Can only be None, Bootstrap, or BootstrapShort)!\n"));
++ErrorCount;
} else if (AsciiStrCmp (BootProtect, "Bootstrap") == 0
|| AsciiStrCmp (BootProtect, "BootstrapShort") == 0) {
if (!IsRequestBootVarRoutingEnabled) {
DEBUG ((DEBUG_WARN, "Misc->Security->BootProtect is set to %a which requires UEFI->Quirks->RequestBootVarRouting to be enabled!\n", BootProtect));
++ErrorCount;
}
//
// NOTE: RequestBootVarRouting requires OpenRuntime.efi, which will be checked in UEFI checker.
//
}
if (AsciiStrCmp (AsciiDmgLoading, "Disabled") != 0
&& AsciiStrCmp (AsciiDmgLoading, "Signed") != 0
&& AsciiStrCmp (AsciiDmgLoading, "Any") != 0) {
DEBUG ((DEBUG_WARN, "Misc->Security->DmgLoading is borked (Can only be Disabled, Signed, or Any)!\n"));
++ErrorCount;
}
if ((ExposeSensitiveData & ~OCS_EXPOSE_ALL_BITS) != 0) {
DEBUG ((DEBUG_WARN, "Misc->Security->ExposeSensitiveData has unknown bits set!\n"));
++ErrorCount;
}
if (AsciiStrCmp (AsciiVault, "Optional") != 0
&& AsciiStrCmp (AsciiVault, "Basic") != 0
&& AsciiStrCmp (AsciiVault, "Secure") != 0) {
DEBUG ((DEBUG_WARN, "Misc->Security->Vault is borked (Can only be Optional, Basic, or Secure)!\n"));
++ErrorCount;
}
//
// ScanPolicy can be zero (failsafe value).
//
if (ScanPolicy != 0) {
if ((ScanPolicy & ~AllowedScanPolicy) != 0) {
DEBUG ((DEBUG_WARN, "Misc->Security->ScanPolicy has unknown bits set!\n"));
++ErrorCount;
}
if ((ScanPolicy & OC_SCAN_FILE_SYSTEM_BITS) != 0 && (ScanPolicy & OC_SCAN_FILE_SYSTEM_LOCK) == 0) {
DEBUG ((DEBUG_WARN, "Misc->Security->ScanPolicy requests scanning filesystem, but OC_SCAN_FILE_SYSTEM_LOCK (bit 0) is not set!\n"));
++ErrorCount;
}
if ((ScanPolicy & OC_SCAN_DEVICE_BITS) != 0 && (ScanPolicy & OC_SCAN_DEVICE_LOCK) == 0) {
DEBUG ((DEBUG_WARN, "Misc->Security->ScanPolicy requests scanning devices, but OC_SCAN_DEVICE_LOCK (bit 1) is not set!\n"));
++ErrorCount;
}
}
//
// Validate SecureBootModel.
//
if (!ValidateSecureBootModel (SecureBootModel)) {
DEBUG ((DEBUG_WARN, "Misc->Security->SecureBootModel is borked!\n"));
++ErrorCount;
}
for (Index = 0; Index < UserMisc->Entries.Count; ++Index) {
Arguments = OC_BLOB_GET (&UserMisc->Entries.Values[Index]->Arguments);
Comment = OC_BLOB_GET (&UserMisc->Entries.Values[Index]->Comment);
AsciiName = OC_BLOB_GET (&UserMisc->Entries.Values[Index]->Name);
Path = OC_BLOB_GET (&UserMisc->Entries.Values[Index]->Path);
//
// Sanitise strings.
//
// NOTE: As Arguments takes identical requirements of Comment,
// we use Comment sanitiser here.
//
if (!AsciiCommentIsLegal (Arguments)) {
DEBUG ((DEBUG_WARN, "Misc->Entries[%u]->Arguments contains illegal character!\n", Index));
++ErrorCount;
}
if (!AsciiCommentIsLegal (Comment)) {
DEBUG ((DEBUG_WARN, "Misc->Entries[%u]->Comment contains illegal character!\n", Index));
++ErrorCount;
}
UnicodeName = AsciiStrCopyToUnicode (AsciiName, 0);
if (UnicodeName != NULL) {
if (!UnicodeIsFilteredString (UnicodeName, TRUE)) {
DEBUG ((DEBUG_WARN, "Misc->Entries[%u]->Name contains illegal character!\n", Index));
++ErrorCount;
}
FreePool ((VOID *) UnicodeName);
}
//
// FIXME: Properly sanitise Path.
//
if (!AsciiCommentIsLegal (Path)) {
DEBUG ((DEBUG_WARN, "Misc->Entries[%u]->Path contains illegal character!\n", Index));
++ErrorCount;
}
}
return ReportError (__func__, ErrorCount);
}
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
UINT32
CheckNVRAM (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
EFI_STATUS Status;
UINT32 GuidIndex;
UINT32 VariableIndex;
OC_NVRAM_CONFIG *UserNVRAM;
CONST CHAR8 *AsciiGuid;
CONST CHAR8 *AsciiNVRAMKey;
GUID VariableGuid;
OC_ASSOC *VariableMap;
DEBUG ((DEBUG_VERBOSE, "config loaded into NVRAM checker!\n"));
ErrorCount = 0;
UserNVRAM = &Config->Nvram;
for (GuidIndex = 0; GuidIndex < UserNVRAM->Add.Count; ++GuidIndex) {
AsciiGuid = OC_BLOB_GET (UserNVRAM->Add.Keys[GuidIndex]);
Status = AsciiStrToGuid (AsciiGuid, &VariableGuid);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "NVRAM->Add[%u] has borked GUID!\n", GuidIndex));
++ErrorCount;
}
VariableMap = UserNVRAM->Add.Values[GuidIndex];
for (VariableIndex = 0; VariableIndex < VariableMap->Count; ++VariableIndex) {
AsciiNVRAMKey = OC_BLOB_GET (VariableMap->Keys[VariableIndex]);
//
// Sanitise strings.
//
if (!AsciiPropertyIsLegal (AsciiNVRAMKey)) {
DEBUG ((
DEBUG_WARN,
"NVRAM->Add[%u]->Key[%u] contains illegal character!\n",
GuidIndex,
VariableIndex
));
++ErrorCount;
}
}
}
for (GuidIndex = 0; GuidIndex < UserNVRAM->Delete.Count; ++GuidIndex) {
AsciiGuid = OC_BLOB_GET (UserNVRAM->Delete.Keys[GuidIndex]);
Status = AsciiStrToGuid (AsciiGuid, &VariableGuid);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "NVRAM->Delete[%u] has borked GUID!\n", GuidIndex));
++ErrorCount;
}
for (VariableIndex = 0; VariableIndex < UserNVRAM->Delete.Values[GuidIndex]->Count; ++VariableIndex) {
AsciiNVRAMKey = OC_BLOB_GET (UserNVRAM->Delete.Values[GuidIndex]->Values[VariableIndex]);
//
// Sanitise strings.
//
if (!AsciiPropertyIsLegal (AsciiNVRAMKey)) {
DEBUG ((
DEBUG_WARN,
"NVRAM->Delete[%u]->Key[%u] contains illegal character!\n",
GuidIndex,
VariableIndex
));
++ErrorCount;
}
}
}
for (GuidIndex = 0; GuidIndex < UserNVRAM->Legacy.Count; ++GuidIndex) {
AsciiGuid = OC_BLOB_GET (UserNVRAM->Legacy.Keys[GuidIndex]);
Status = AsciiStrToGuid (AsciiGuid, &VariableGuid);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "NVRAM->LegacySchema[%u] has borked GUID!\n", GuidIndex));
++ErrorCount;
}
for (VariableIndex = 0; VariableIndex < UserNVRAM->Legacy.Values[GuidIndex]->Count; ++VariableIndex) {
AsciiNVRAMKey = OC_BLOB_GET (UserNVRAM->Legacy.Values[GuidIndex]->Values[VariableIndex]);
//
// Sanitise strings.
//
if (!AsciiPropertyIsLegal (AsciiNVRAMKey)) {
DEBUG ((
DEBUG_WARN,
"NVRAM->LegacySchema[%u]->Key[%u] contains illegal character!\n",
GuidIndex,
VariableIndex
));
++ErrorCount;
}
}
}
return ReportError (__func__, ErrorCount);
}
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
#include <Library/OcMacInfoLib.h>
//
// NOTE: Only PlatformInfo->Generic is checked here. The rest is ignored.
//
UINT32
CheckPlatformInfo (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
EFI_STATUS Status;
OC_PLATFORM_CONFIG *UserPlatformInfo;
BOOLEAN IsAutomaticEnabled;
CONST CHAR8 *UpdateSMBIOSMode;
CONST CHAR8 *SystemProductName;
CONST CHAR8 *SystemMemoryStatus;
CONST CHAR8 *AsciiSystemUUID;
GUID Guid;
DEBUG ((DEBUG_VERBOSE, "config loaded into PlatformInfo checker!\n"));
ErrorCount = 0;
UserPlatformInfo = &Config->PlatformInfo;
IsAutomaticEnabled = UserPlatformInfo->Automatic;
UpdateSMBIOSMode = OC_BLOB_GET (&UserPlatformInfo->UpdateSmbiosMode);
SystemProductName = OC_BLOB_GET (&UserPlatformInfo->Generic.SystemProductName);
SystemMemoryStatus = OC_BLOB_GET (&UserPlatformInfo->Generic.SystemMemoryStatus);
AsciiSystemUUID = OC_BLOB_GET (&UserPlatformInfo->Generic.SystemUuid);
if (AsciiStrCmp (UpdateSMBIOSMode, "TryOverwrite") != 0
&& AsciiStrCmp (UpdateSMBIOSMode, "Create") != 0
&& AsciiStrCmp (UpdateSMBIOSMode, "Overwrite") != 0
&& AsciiStrCmp (UpdateSMBIOSMode, "Custom") != 0) {
DEBUG ((DEBUG_WARN, "PlatformInfo->UpdateSMBIOSMode is borked (Can only be TryOverwrite, Create, Overwrite, or Custom)!\n"));
++ErrorCount;
}
if (!IsAutomaticEnabled) {
//
// This is not an error, but we need to stop checking further.
//
return ReportError (__func__, ErrorCount);
}
if (!HasMacInfo (SystemProductName)) {
DEBUG ((DEBUG_WARN, "PlatformInfo->Generic->SystemProductName has unknown model set!\n"));
++ErrorCount;
}
if (AsciiStrCmp (SystemMemoryStatus, "Auto") != 0
&& AsciiStrCmp (SystemMemoryStatus, "Upgradable") != 0
&& AsciiStrCmp (SystemMemoryStatus, "Soldered") != 0) {
DEBUG ((DEBUG_WARN, "PlatformInfo->Generic->SystemMemoryStatus is borked (Can only be Auto, Upgradable, or Soldered)!\n"));
++ErrorCount;
}
Status = AsciiStrToGuid (AsciiSystemUUID, &Guid);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "PlatformInfo->Generic->SystemUUID is borked!\n"));
++ErrorCount;
}
//
// TODO: Sanitise MLB, ProcessorType, and SystemSerialNumber if possible...
//
return ReportError (__func__, ErrorCount);
}
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "ocvalidate.h"
#include "OcValidateLib.h"
#include <Library/OcConsoleLib.h>
UINT32
CheckUEFI (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
UINT32 Index;
UINT32 Index2;
UINT32 IndexOpenUsbKbDxeEfiDriver;
UINT32 IndexPs2KeyboardDxeEfiDriver;
OC_UEFI_CONFIG *UserUefi;
OC_MISC_CONFIG *UserMisc;
CONST CHAR8 *Driver;
CONST CHAR8 *TextRenderer;
CONST CHAR8 *ConsoleMode;
CONST CHAR8 *PointerSupportMode;
CONST CHAR8 *KeySupportMode;
BOOLEAN HasOpenRuntimeEfiDriver;
BOOLEAN HasOpenUsbKbDxeEfiDriver;
BOOLEAN HasPs2KeyboardDxeEfiDriver;
BOOLEAN IsRequestBootVarRoutingEnabled;
BOOLEAN IsKeySupportEnabled;
BOOLEAN IsTextRendererSystem;
BOOLEAN IsClearScreenOnModeSwitchEnabled;
BOOLEAN IsIgnoreTextInGraphicsEnabled;
BOOLEAN IsReplaceTabWithSpaceEnabled;
BOOLEAN IsSanitiseClearScreenEnabled;
BOOLEAN IsPointerSupportEnabled;
CONST CHAR8 *Resolution;
UINT32 UserWidth;
UINT32 UserHeight;
UINT32 UserBpp;
BOOLEAN UserSetMax;
CONST CHAR8 *AsciiAudioDevicePath;
DEBUG ((DEBUG_VERBOSE, "config loaded into UEFI checker!\n"));
ErrorCount = 0;
IndexOpenUsbKbDxeEfiDriver = 0;
IndexPs2KeyboardDxeEfiDriver = 0;
UserUefi = &Config->Uefi;
UserMisc = &Config->Misc;
HasOpenRuntimeEfiDriver = FALSE;
HasOpenUsbKbDxeEfiDriver = FALSE;
HasPs2KeyboardDxeEfiDriver = FALSE;
IsRequestBootVarRoutingEnabled = UserUefi->Quirks.RequestBootVarRouting;
IsKeySupportEnabled = UserUefi->Input.KeySupport;
IsPointerSupportEnabled = UserUefi->Input.PointerSupport;
PointerSupportMode = OC_BLOB_GET (&UserUefi->Input.PointerSupportMode);
KeySupportMode = OC_BLOB_GET (&UserUefi->Input.KeySupportMode);
IsClearScreenOnModeSwitchEnabled = UserUefi->Output.ClearScreenOnModeSwitch;
IsIgnoreTextInGraphicsEnabled = UserUefi->Output.IgnoreTextInGraphics;
IsReplaceTabWithSpaceEnabled = UserUefi->Output.ReplaceTabWithSpace;
IsSanitiseClearScreenEnabled = UserUefi->Output.SanitiseClearScreen;
TextRenderer = OC_BLOB_GET (&UserUefi->Output.TextRenderer);
IsTextRendererSystem = FALSE;
ConsoleMode = OC_BLOB_GET (&UserUefi->Output.ConsoleMode);
Resolution = OC_BLOB_GET (&UserUefi->Output.Resolution);
AsciiAudioDevicePath = OC_BLOB_GET (&UserUefi->Audio.AudioDevice);
//
// Sanitise strings.
//
if (AsciiStrCmp (TextRenderer, "BuiltinGraphics") != 0
&& AsciiStrCmp (TextRenderer, "BuiltinText") != 0
&& AsciiStrCmp (TextRenderer, "SystemGraphics") != 0
&& AsciiStrCmp (TextRenderer, "SystemText") != 0
&& AsciiStrCmp (TextRenderer, "SystemGeneric") != 0) {
DEBUG ((DEBUG_WARN, "UEFI->Output->TextRenderer is illegal (Can only be BuiltinGraphics, BuiltinText, SystemGraphics, SystemText, or SystemGeneric)!\n"));
++ErrorCount;
} else if (AsciiStrnCmp (TextRenderer, "System", L_STR_LEN ("System")) == 0) {
//
// Check whether TextRenderer has System prefix.
//
IsTextRendererSystem = TRUE;
}
//
// If FS restrictions is enabled but APFS FS scanning is disabled, it is an error.
//
if (UserUefi->Apfs.EnableJumpstart
&& (UserMisc->Security.ScanPolicy & OC_SCAN_FILE_SYSTEM_LOCK) != 0
&& (UserMisc->Security.ScanPolicy & OC_SCAN_ALLOW_FS_APFS) == 0) {
DEBUG ((DEBUG_WARN, "UEFI->APFS->EnableJumpstart is enabled, but Misc->Security->ScanPolicy does not allow APFS scanning!\n"));
++ErrorCount;
}
if (AsciiAudioDevicePath[0] != '\0' && !AsciiDevicePathIsLegal (AsciiAudioDevicePath)) {
DEBUG ((DEBUG_WARN, "UEFI->Audio->AudioDevice is borked! Please check the information above!\n"));
++ErrorCount;
}
for (Index = 0; Index < UserUefi->Drivers.Count; ++Index) {
Driver = OC_BLOB_GET (UserUefi->Drivers.Values[Index]);
//
// Sanitise strings.
//
if (!AsciiUefiDriverIsLegal (Driver)) {
DEBUG ((DEBUG_WARN, "UEFI->Drivers[%u] contains illegal character!\n", Index));
++ErrorCount;
continue;
}
//
// Brute-force to check duplicated Drivers.
//
for (Index2 = Index + 1; Index2 < UserUefi->Drivers.Count; ++Index2) {
if (AsciiStrCmp (Driver, OC_BLOB_GET (UserUefi->Drivers.Values[Index2])) == 0) {
DEBUG ((
DEBUG_WARN,
"UEFI->Drivers[%u] and UEFI->Drivers[%u] (%a) are duplicated!\n",
Index,
Index2,
Driver
));
++ErrorCount;
}
}
if (AsciiStrCmp (Driver, "OpenRuntime.efi") == 0) {
HasOpenRuntimeEfiDriver = TRUE;
}
if (AsciiStrCmp (Driver, "OpenUsbKbDxe.efi") == 0) {
HasOpenUsbKbDxeEfiDriver = TRUE;
IndexOpenUsbKbDxeEfiDriver = Index;
}
if (AsciiStrCmp (Driver, "Ps2KeyboardDxe.efi") == 0) {
HasPs2KeyboardDxeEfiDriver = TRUE;
IndexPs2KeyboardDxeEfiDriver = Index;
}
}
if (IsPointerSupportEnabled && AsciiStrCmp (PointerSupportMode, "ASUS") != 0) {
DEBUG ((DEBUG_WARN, "UEFI->Input->PointerSupport is enabled, but PointerSupportMode is not ASUS!\n"));
++ErrorCount;
}
if (AsciiStrCmp (KeySupportMode, "Auto") != 0
&& AsciiStrCmp (KeySupportMode, "V1") != 0
&& AsciiStrCmp (KeySupportMode, "V2") != 0
&& AsciiStrCmp (KeySupportMode, "AMI") != 0) {
DEBUG ((DEBUG_WARN, "UEFI->Input->KeySupportMode is illegal (Can only be Auto, V1, V2, AMI)!\n"));
++ErrorCount;
}
if (IsRequestBootVarRoutingEnabled) {
if (!HasOpenRuntimeEfiDriver) {
DEBUG ((DEBUG_WARN, "UEFI->Quirks->RequestBootVarRouting is enabled, but OpenRuntime.efi is not loaded at UEFI->Drivers!\n"));
++ErrorCount;
}
}
if (IsKeySupportEnabled) {
if (HasOpenUsbKbDxeEfiDriver) {
DEBUG ((DEBUG_WARN, "OpenUsbKbDxe.efi at UEFI->Drivers[%u] should NEVER be used together with UEFI->Input->KeySupport!\n", IndexOpenUsbKbDxeEfiDriver));
++ErrorCount;
}
} else {
if (HasPs2KeyboardDxeEfiDriver) {
DEBUG ((DEBUG_WARN, "UEFI->Input->KeySupport should be enabled when Ps2KeyboardDxe.efi is in use!\n"));
++ErrorCount;
}
}
if (HasOpenUsbKbDxeEfiDriver && HasPs2KeyboardDxeEfiDriver) {
DEBUG ((
DEBUG_WARN,
"OpenUsbKbDxe.efi at UEFI->Drivers[%u], and Ps2KeyboardDxe.efi at UEFI->Drivers[%u], should NEVER co-exist!\n",
IndexOpenUsbKbDxeEfiDriver,
IndexPs2KeyboardDxeEfiDriver
));
++ErrorCount;
}
if (!IsTextRendererSystem) {
if (IsClearScreenOnModeSwitchEnabled) {
DEBUG ((DEBUG_WARN, "UEFI->Output->ClearScreenOnModeSwitch is enabled on non-System TextRenderer (currently %a)!\n", TextRenderer));
++ErrorCount;
}
if (IsIgnoreTextInGraphicsEnabled) {
DEBUG ((DEBUG_WARN, "UEFI->Output->IgnoreTextInGraphics is enabled on non-System TextRenderer (currently %a)!\n", TextRenderer));
++ErrorCount;
}
if (IsReplaceTabWithSpaceEnabled) {
DEBUG ((DEBUG_WARN, "UEFI->Output->ReplaceTabWithSpace is enabled on non-System TextRenderer (currently %a)!\n", TextRenderer));
++ErrorCount;
}
if (IsSanitiseClearScreenEnabled) {
DEBUG ((DEBUG_WARN, "UEFI->Output->SanitiseClearScreen is enabled on non-System TextRenderer (currently %a)!\n", TextRenderer));
++ErrorCount;
}
}
//
// Parse Output->ConsoleMode by calling OpenCore libraries.
//
OcParseConsoleMode (
ConsoleMode,
&UserWidth,
&UserHeight,
&UserSetMax
);
if (ConsoleMode[0] != '\0'
&& !UserSetMax
&& (UserWidth == 0 || UserHeight == 0)) {
DEBUG ((DEBUG_WARN, "UEFI->Output->ConsoleMode is borked, please check Configurations.pdf!\n"));
++ErrorCount;
}
//
// Parse Output->Resolution by calling OpenCore libraries.
//
OcParseScreenResolution (
Resolution,
&UserWidth,
&UserHeight,
&UserBpp,
&UserSetMax
);
if (Resolution[0] != '\0'
&& !UserSetMax
&& (UserWidth == 0 || UserHeight == 0)) {
DEBUG ((DEBUG_WARN, "UEFI->Output->Resolution is borked, please check Configurations.pdf!\n"));
++ErrorCount;
}
return ReportError (__func__, ErrorCount);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ACPI</key>
<dict>
<key>CleanHeaders</key>
<true/>
</dict>
<key>DeviceProperties</key>
<dict>
<key>DeviceName1</key>
<dict>
<key>Prop1</key>
<string>Val1</string>
<key>Prop2</key>
<string>Val2</string>
</dict>
<key>DeviceName2</key>
<dict>
<key>Prop21</key>
<string>Val21</string>
<key>Prop22</key>
<string>Val22</string>
</dict>
</dict>
<key>Misc</key>
<dict>
<key>DataFix</key>
<data>ESIz</data>
<key>DataVar</key>
<data>RFVm</data>
<key>DataMeta</key>
<string>123</string>
<key>DataMetaVar</key>
<data>MTIzAA==</data>
<key>DataMeta3</key>
<true/>
<key>DataMeta4</key>
<integer>65535</integer>
<key>Test32</key>
<integer>123456</integer>
</dict>
<key>Mods</key>
<dict>
<key>Kext</key>
<array>
<dict>
<key>Identifier</key>
<string>Hello</string>
</dict>
<dict>
<key>Identifier</key>
<string>Idt</string>
</dict>
</array>
</dict>
<key>NVRAM</key>
<dict>
<key>COOL:boot-args</key>
<string>nopasaran=1 debug=1</string>
<key>HACK:booter</key>
<string>#something</string>
</dict>
<key>SMBIOS</key>
<dict>
<key>ProductName</key>
<string>Computer2,1</string>
</dict>
</dict>
</plist>
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
......@@ -12,19 +13,10 @@
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcTemplateLib.h>
#include <Library/OcSerializeLib.h>
#include <Library/OcMiscLib.h>
#include <Library/OcConfigurationLib.h>
#include "ocvalidate.h"
#include "OcValidateLib.h"
#include <File.h>
#include <sys/time.h>
/*
for fuzzing (TODO):
......@@ -34,41 +26,97 @@
rm -rf ConfigValidty.dSYM DICT fuzz*.log ConfigValidty
*/
long long current_timestamp() {
struct timeval te;
gettimeofday(&te, NULL); // get current time
long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // calculate milliseconds
// printf("milliseconds: %lld\n", milliseconds);
return milliseconds;
}
int main(int argc, char** argv) {
uint32_t f;
uint8_t *b;
if ((b = readFile(argc > 1 ? argv[1] : "config.plist", &f)) == NULL) {
printf("Read fail\n");
return -1;
UINT32
CheckConfig (
IN OC_GLOBAL_CONFIG *Config
)
{
UINT32 ErrorCount;
UINTN Index;
STATIC CONFIG_CHECK ConfigCheckers[] = {
&CheckACPI,
&CheckBooter,
&CheckDeviceProperties,
&CheckKernel,
&CheckMisc,
&CheckNVRAM,
&CheckPlatformInfo,
&CheckUEFI
};
ErrorCount = 0;
//
// Pass config structure to all checkers.
//
for (Index = 0; Index < ARRAY_SIZE (ConfigCheckers); ++Index) {
ErrorCount += ConfigCheckers[Index] (Config);
}
long long a = current_timestamp();
PcdGet8 (PcdDebugPropertyMask) |= DEBUG_PROPERTY_DEBUG_CODE_ENABLED;
return ErrorCount;
}
int main(int argc, const char *argv[]) {
UINT8 *ConfigFileBuffer;
UINT32 ConfigFileSize;
CONST CHAR8 *ConfigFileName;
INT64 ExecTimeStart;
OC_GLOBAL_CONFIG Config;
EFI_STATUS Status;
Status = OcConfigurationInit (&Config, b, f);
UINT32 ErrorCount;
//
// Enable PCD debug logging.
//
PcdGet8 (PcdDebugPropertyMask) |= DEBUG_PROPERTY_DEBUG_CODE_ENABLED;
PcdGet32 (PcdFixedDebugPrintErrorLevel) |= DEBUG_INFO;
PcdGet32 (PcdDebugPrintErrorLevel) |= DEBUG_INFO;
//
// Read config file.
//
ConfigFileName = argc > 1 ? argv[1] : "config.plist";
ConfigFileBuffer = readFile (ConfigFileName, &ConfigFileSize);
if (ConfigFileBuffer == NULL) {
DEBUG ((DEBUG_ERROR, "Failed to read %a\n", ConfigFileName));
return -1;
}
if (Status != EFI_SUCCESS) {
printf("Invalid config\n");
//
// Record the current time when action starts.
//
ExecTimeStart = GetCurrentTimestamp ();
//
// Initialise config structure to be checked, and exit on error.
//
Status = OcConfigurationInit (&Config, ConfigFileBuffer, ConfigFileSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Invalid config\n"));
return -1;
}
DEBUG ((DEBUG_ERROR, "Done checking %a in %llu ms\n", argc > 1 ? argv[1] : "./config.plist", current_timestamp() - a));
ErrorCount = CheckConfig (&Config);
if (ErrorCount == 0) {
DEBUG ((
DEBUG_ERROR,
"Done checking %a in %llu ms\n",
ConfigFileName,
GetCurrentTimestamp () - ExecTimeStart
));
} else {
DEBUG ((
DEBUG_ERROR,
"Done checking %a in %llu ms, but it has %u %a to be fixed\n",
ConfigFileName,
GetCurrentTimestamp () - ExecTimeStart,
ErrorCount,
ErrorCount > 1 ? "errors" : "error"
));
}
OcConfigurationFree (&Config);
free(b);
free (ConfigFileBuffer);
return 0;
}
......
/** @file
Copyright (C) 2018, vit9696. All rights reserved.
Copyright (C) 2020, PMheart. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef OC_USER_UTILITIES_OCVALIDATE_H
#define OC_USER_UTILITIES_OCVALIDATE_H
#include <Library/OcConfigurationLib.h>
/**
Validate OpenCore Configuration.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
typedef
UINT32
(*CONFIG_CHECK) (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration ACPI Section.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckACPI (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration Booter Section.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckBooter (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration DeviceProperties Section.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckDeviceProperties (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration Kernel Section.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckKernel (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration Misc Section.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckMisc (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration NVRAM Section.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckNVRAM (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration PlatformInfo Section.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckPlatformInfo (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration UEFI Section.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckUEFI (
IN OC_GLOBAL_CONFIG *Config
);
/**
Validate OpenCore Configuration overall, by calling each checker above.
@param[in] Config Configuration structure.
@return Number of errors detected.
**/
UINT32
CheckConfig (
IN OC_GLOBAL_CONFIG *Config
);
#endif // OC_USER_UTILITIES_OCVALIDATE_H
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册