New upstream version 15.5

This commit is contained in:
Steve McIntyre 2022-04-27 22:41:59 +01:00
parent 8119f7183f
commit 8529e0f7f7
179 changed files with 6660 additions and 1082 deletions

9
.gitignore vendored
View File

@ -14,7 +14,10 @@ Make.local
*.efi.debug *.efi.debug
*.efi.signed *.efi.signed
*.esl *.esl
*.gdbinit *.gdb*
*.gcda
*.gcno
*.gcov
*.hash *.hash
*.key *.key
*.key *.key
@ -27,8 +30,11 @@ Make.local
*.sw? *.sw?
*.tar.* *.tar.*
/build*/ /build*/
/.cache/
/certdb/ /certdb/
/compile_commands.json
/cov-int/ /cov-int/
/post-process-pe
/random.bin /random.bin
/sbat.*.csv /sbat.*.csv
/scan-results/ /scan-results/
@ -36,5 +42,6 @@ Make.local
shim_cert.h shim_cert.h
/test-* /test-*
!/test-*.c !/test-*.c
!/test-data/
/test-random.h /test-random.h
version.c version.c

2
.gitmodules vendored
View File

@ -1,4 +1,4 @@
[submodule "gnu-efi"] [submodule "gnu-efi"]
path = gnu-efi path = gnu-efi
url = https://github.com/rhboot/gnu-efi.git url = https://github.com/rhboot/gnu-efi.git
branch = shim-15.3 branch = shim-15.5

View File

@ -45,6 +45,12 @@ Variables you could set to customize the build:
shim has already verified the kernel when shim loaded the kernel as the shim has already verified the kernel when shim loaded the kernel as the
second stage loader. In such a case, and only in this case, you should second stage loader. In such a case, and only in this case, you should
use DISABLE_EBS_PROTECTION=y to build. use DISABLE_EBS_PROTECTION=y to build.
- DISABLE_REMOVABLE_LOAD_OPTIONS
Do not parse load options when invoked as boot*.efi. This prevents boot
failures because of unexpected data in boot entries automatically generated
by firmware. It breaks loading non-default second-stage loaders when invoked
via that path, and requires using a binary named shim*.efi (or really anything
else).
- REQUIRE_TPM - REQUIRE_TPM
if tpm logging or extends return an error code, treat that as a fatal error. if tpm logging or extends return an error code, treat that as a fatal error.
- ARCH - ARCH

View File

@ -93,7 +93,7 @@ Md5Duplicate (
return FALSE; return FALSE;
} }
CopyMem (NewMd5Context, Md5Context, sizeof (MD5_CTX)); CopyMem (NewMd5Context, (void *)Md5Context, sizeof (MD5_CTX));
return TRUE; return TRUE;
} }

View File

@ -92,7 +92,7 @@ Sha1Duplicate (
return FALSE; return FALSE;
} }
CopyMem (NewSha1Context, Sha1Context, sizeof (SHA_CTX)); CopyMem (NewSha1Context, (void *)Sha1Context, sizeof (SHA_CTX));
return TRUE; return TRUE;
} }

View File

@ -91,7 +91,7 @@ Sha256Duplicate (
return FALSE; return FALSE;
} }
CopyMem (NewSha256Context, Sha256Context, sizeof (SHA256_CTX)); CopyMem (NewSha256Context, (void *)Sha256Context, sizeof (SHA256_CTX));
return TRUE; return TRUE;
} }

View File

@ -93,7 +93,7 @@ Sha384Duplicate (
return FALSE; return FALSE;
} }
CopyMem (NewSha384Context, Sha384Context, sizeof (SHA512_CTX)); CopyMem (NewSha384Context, (void *)Sha384Context, sizeof (SHA512_CTX));
return TRUE; return TRUE;
} }
@ -308,7 +308,7 @@ Sha512Duplicate (
return FALSE; return FALSE;
} }
CopyMem (NewSha512Context, Sha512Context, sizeof (SHA512_CTX)); CopyMem (NewSha512Context, (void *)Sha512Context, sizeof (SHA512_CTX));
return TRUE; return TRUE;
} }

View File

@ -262,11 +262,11 @@ extern FILE *stdout;
// //
// Macros that directly map functions to BaseLib, BaseMemoryLib, and DebugLib functions // Macros that directly map functions to BaseLib, BaseMemoryLib, and DebugLib functions
// //
#define memcpy(dest,source,count) ( {CopyMem(dest,source,(UINTN)(count)); dest; }) #define memcpy(dest,source,count) ( {CopyMem(dest,(void *)source,(UINTN)(count)); dest; })
#define memset(dest,ch,count) SetMem(dest,(UINTN)(count),(UINT8)(ch)) #define memset(dest,ch,count) SetMem(dest,(UINTN)(count),(UINT8)(ch))
#define memchr(buf,ch,count) ScanMem8((CHAR8 *)buf,(UINTN)(count),ch) #define memchr(buf,ch,count) ScanMem8((CHAR8 *)buf,(UINTN)(count),ch)
#define memcmp(buf1,buf2,count) (int)(CompareMem(buf1,buf2,(UINTN)(count))) #define memcmp(buf1,buf2,count) (int)(CompareMem(buf1,buf2,(UINTN)(count)))
#define memmove(dest,source,count) CopyMem(dest,source,(UINTN)(count)) #define memmove(dest,source,count) CopyMem(dest,(void *)source,(UINTN)(count))
#define localtime(timer) NULL #define localtime(timer) NULL
#define assert(expression) #define assert(expression)
#define atoi(nptr) AsciiStrDecimalToUintn((const CHAR8 *)nptr) #define atoi(nptr) AsciiStrDecimalToUintn((const CHAR8 *)nptr)

View File

@ -216,7 +216,7 @@ WrapPkcs7Data (
// //
// Part7: P7Data. // Part7: P7Data.
// //
CopyMem (SignedData + 19, P7Data, P7Length); CopyMem (SignedData + 19, (void *)P7Data, P7Length);
} }
*WrapFlag = Wrapped; *WrapFlag = Wrapped;

View File

@ -52,7 +52,11 @@ override EFI_INCLUDES := $(EFI_INCLUDES)
EFI_CRT_OBJS = $(LOCAL_EFI_PATH)/crt0-efi-$(ARCH_GNUEFI).o EFI_CRT_OBJS = $(LOCAL_EFI_PATH)/crt0-efi-$(ARCH_GNUEFI).o
EFI_LDS = $(TOPDIR)/elf_$(ARCH)_efi.lds EFI_LDS = $(TOPDIR)/elf_$(ARCH)_efi.lds
CLANG_BUGS = $(if $(findstring gcc,$(CC)),-maccumulate-outgoing-args,) CLANG_WARNINGS = -Wno-pointer-bool-conversion \
-Wno-unknown-attributes
CLANG_BUGS = $(if $(findstring gcc,$(CC)),-maccumulate-outgoing-args,) \
$(if $(findstring clang,$(CC)),$(CLANG_WARNINGS))
COMMIT_ID ?= $(shell if [ -e .git ] ; then git log -1 --pretty=format:%H ; elif [ -f commit ]; then cat commit ; else echo master; fi) COMMIT_ID ?= $(shell if [ -e .git ] ; then git log -1 --pretty=format:%H ; elif [ -f commit ]; then cat commit ; else echo master; fi)
@ -64,7 +68,6 @@ ifeq ($(ARCH),x86_64)
ARCH_SUFFIX ?= x64 ARCH_SUFFIX ?= x64
ARCH_SUFFIX_UPPER ?= X64 ARCH_SUFFIX_UPPER ?= X64
ARCH_LDFLAGS ?= ARCH_LDFLAGS ?=
TIMESTAMP_LOCATION := 136
endif endif
ifeq ($(ARCH),ia32) ifeq ($(ARCH),ia32)
ARCH_CFLAGS ?= -mno-mmx -mno-sse -mno-red-zone -nostdinc \ ARCH_CFLAGS ?= -mno-mmx -mno-sse -mno-red-zone -nostdinc \
@ -75,7 +78,6 @@ ifeq ($(ARCH),ia32)
ARCH_SUFFIX_UPPER ?= IA32 ARCH_SUFFIX_UPPER ?= IA32
ARCH_LDFLAGS ?= ARCH_LDFLAGS ?=
ARCH_CFLAGS ?= -m32 ARCH_CFLAGS ?= -m32
TIMESTAMP_LOCATION := 136
endif endif
ifeq ($(ARCH),aarch64) ifeq ($(ARCH),aarch64)
ARCH_CFLAGS ?= -DMDE_CPU_AARCH64 -DPAGE_SIZE=4096 -mstrict-align ARCH_CFLAGS ?= -DMDE_CPU_AARCH64 -DPAGE_SIZE=4096 -mstrict-align
@ -86,7 +88,6 @@ ifeq ($(ARCH),aarch64)
SUBSYSTEM := 0xa SUBSYSTEM := 0xa
ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM) ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
ARCH_CFLAGS ?= ARCH_CFLAGS ?=
TIMESTAMP_LOCATION := 72
endif endif
ifeq ($(ARCH),arm) ifeq ($(ARCH),arm)
ARCH_CFLAGS ?= -DMDE_CPU_ARM -DPAGE_SIZE=4096 -mno-unaligned-access ARCH_CFLAGS ?= -DMDE_CPU_ARM -DPAGE_SIZE=4096 -mno-unaligned-access
@ -96,7 +97,6 @@ ifeq ($(ARCH),arm)
FORMAT := -O binary FORMAT := -O binary
SUBSYSTEM := 0xa SUBSYSTEM := 0xa
ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM) ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
TIMESTAMP_LOCATION := 72
endif endif
DEFINES = -DDEFAULT_LOADER='L"$(DEFAULT_LOADER)"' \ DEFINES = -DDEFAULT_LOADER='L"$(DEFAULT_LOADER)"' \
@ -135,6 +135,7 @@ $(call update-variable,WERRFLAGS)
CFLAGS = $(FEATUREFLAGS) \ CFLAGS = $(FEATUREFLAGS) \
$(OPTIMIZATIONS) \ $(OPTIMIZATIONS) \
$(WARNFLAGS) \ $(WARNFLAGS) \
$(if $(findstring clang,$(CC)),$(CLANG_WARNINGS)) \
$(ARCH_CFLAGS) \ $(ARCH_CFLAGS) \
$(WERRFLAGS) \ $(WERRFLAGS) \
$(INCLUDES) \ $(INCLUDES) \
@ -152,6 +153,10 @@ ifneq ($(origin DISABLE_EBS_PROTECTION), undefined)
DEFINES += -DDISABLE_EBS_PROTECTION DEFINES += -DDISABLE_EBS_PROTECTION
endif endif
ifneq ($(origin DISABLE_REMOVABLE_LOAD_OPTIONS), undefined)
DEFINES += -DDISABLE_REMOVABLE_LOAD_OPTIONS
endif
LIB_GCC = $(shell $(CC) $(ARCH_CFLAGS) -print-libgcc-file-name) LIB_GCC = $(shell $(CC) $(ARCH_CFLAGS) -print-libgcc-file-name)
EFI_LIBS = -lefi -lgnuefi --start-group Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a --end-group $(LIB_GCC) EFI_LIBS = -lefi -lgnuefi --start-group Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a --end-group $(LIB_GCC)
FORMAT ?= --target efi-app-$(ARCH) FORMAT ?= --target efi-app-$(ARCH)

View File

@ -1,7 +1,7 @@
default : all default : all
NAME = shim NAME = shim
VERSION = 15.4 VERSION = 15.5
ifneq ($(origin RELEASE),undefined) ifneq ($(origin RELEASE),undefined)
DASHRELEASE ?= -$(RELEASE) DASHRELEASE ?= -$(RELEASE)
else else
@ -38,12 +38,12 @@ CFLAGS += -DENABLE_SHIM_CERT
else else
TARGETS += $(MMNAME) $(FBNAME) TARGETS += $(MMNAME) $(FBNAME)
endif endif
OBJS = shim.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o sbat.o sbat_data.o pe.o httpboot.o csv.o OBJS = shim.o globals.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o sbat.o sbat_data.o pe.o httpboot.o csv.o load-options.o
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
ORIG_SOURCES = shim.c mok.c netboot.c replacements.c tpm.c errlog.c sbat.c pe.c httpboot.c shim.h version.h $(wildcard include/*.h) ORIG_SOURCES = shim.c globals.c mok.c netboot.c replacements.c tpm.c errlog.c sbat.c pe.c httpboot.c shim.h version.h $(wildcard include/*.h)
MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o errlog.o sbat_data.o MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o errlog.o sbat_data.o globals.o
ORIG_MOK_SOURCES = MokManager.c PasswordCrypt.c crypt_blowfish.c shim.h $(wildcard include/*.h) ORIG_MOK_SOURCES = MokManager.c PasswordCrypt.c crypt_blowfish.c shim.h $(wildcard include/*.h)
FALLBACK_OBJS = fallback.o tpm.o errlog.o sbat_data.o FALLBACK_OBJS = fallback.o tpm.o errlog.o sbat_data.o globals.o
ORIG_FALLBACK_SRCS = fallback.c ORIG_FALLBACK_SRCS = fallback.c
SBATPATH = $(TOPDIR)/data/sbat.csv SBATPATH = $(TOPDIR)/data/sbat.csv
@ -61,6 +61,10 @@ ifneq ($(origin FALLBACK_VERBOSE), undefined)
CFLAGS += -DFALLBACK_VERBOSE CFLAGS += -DFALLBACK_VERBOSE
endif endif
ifneq ($(origin FALLBACK_NONINTERACTIVE), undefined)
CFLAGS += -DFALLBACK_NONINTERACTIVE
endif
ifneq ($(origin FALLBACK_VERBOSE_WAIT), undefined) ifneq ($(origin FALLBACK_VERBOSE_WAIT), undefined)
CFLAGS += -DFALLBACK_VERBOSE_WAIT=$(FALLBACK_VERBOSE_WAIT) CFLAGS += -DFALLBACK_VERBOSE_WAIT=$(FALLBACK_VERBOSE_WAIT)
endif endif
@ -121,9 +125,10 @@ sbat_data.o : /dev/null
$@ $@
$(foreach vs,$(VENDOR_SBATS),$(call add-vendor-sbat,$(vs),$@)) $(foreach vs,$(VENDOR_SBATS),$(call add-vendor-sbat,$(vs),$@))
$(SHIMNAME) : $(SHIMSONAME) $(SHIMNAME) : $(SHIMSONAME) post-process-pe
$(MMNAME) : $(MMSONAME) $(MMNAME) : $(MMSONAME) post-process-pe
$(FBNAME) : $(FBSONAME) $(FBNAME) : $(FBSONAME) post-process-pe
$(SHIMNAME) $(MMNAME) $(FBNAME) : | post-process-pe
LIBS = Cryptlib/libcryptlib.a \ LIBS = Cryptlib/libcryptlib.a \
Cryptlib/OpenSSL/libopenssl.a \ Cryptlib/OpenSSL/libopenssl.a \
@ -148,7 +153,10 @@ gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a: C
gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a: gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a:
mkdir -p gnu-efi/lib gnu-efi/gnuefi mkdir -p gnu-efi/lib gnu-efi/gnuefi
$(MAKE) -C gnu-efi \ $(MAKE) -C gnu-efi \
ARCH=$(ARCH_GNUEFI) TOPDIR=$(TOPDIR)/gnu-efi \ COMPILER="$(COMPILER)" \
CC="$(CC)" \
ARCH=$(ARCH_GNUEFI) \
TOPDIR=$(TOPDIR)/gnu-efi \
-f $(TOPDIR)/gnu-efi/Makefile \ -f $(TOPDIR)/gnu-efi/Makefile \
lib gnuefi inc lib gnuefi inc
@ -164,6 +172,9 @@ lib/lib.a: | $(TOPDIR)/lib/Makefile $(wildcard $(TOPDIR)/include/*.[ch])
mkdir -p lib mkdir -p lib
$(MAKE) VPATH=$(TOPDIR)/lib TOPDIR=$(TOPDIR) -C lib -f $(TOPDIR)/lib/Makefile $(MAKE) VPATH=$(TOPDIR)/lib TOPDIR=$(TOPDIR) -C lib -f $(TOPDIR)/lib/Makefile
post-process-pe : $(TOPDIR)/post-process-pe.c
$(HOSTCC) -std=gnu11 -Og -g3 -Wall -Wextra -Wno-missing-field-initializers -Werror -o $@ $<
buildid : $(TOPDIR)/buildid.c buildid : $(TOPDIR)/buildid.c
$(HOSTCC) -I/usr/include -Og -g3 -Wall -Werror -Wextra -o $@ $< -lelf $(HOSTCC) -I/usr/include -Og -g3 -Wall -Werror -Wextra -o $@ $< -lelf
@ -243,11 +254,10 @@ ifneq ($(OBJCOPY_GTE224),1)
endif endif
$(OBJCOPY) -D -j .text -j .sdata -j .data -j .data.ident \ $(OBJCOPY) -D -j .text -j .sdata -j .data -j .data.ident \
-j .dynamic -j .rodata -j .rel* \ -j .dynamic -j .rodata -j .rel* \
-j .rela* -j .reloc -j .eh_frame \ -j .rela* -j .dyn -j .reloc -j .eh_frame \
-j .vendor_cert -j .sbat \ -j .vendor_cert -j .sbat \
$(FORMAT) $< $@ $(FORMAT) $< $@
# I am tired of wasting my time fighting binutils timestamp code. ./post-process-pe -vv $@
dd conv=notrunc bs=1 count=4 seek=$(TIMESTAMP_LOCATION) if=/dev/zero of=$@
ifneq ($(origin ENABLE_SHIM_HASH),undefined) ifneq ($(origin ENABLE_SHIM_HASH),undefined)
%.hash : %.efi %.hash : %.efi
@ -260,7 +270,7 @@ ifneq ($(OBJCOPY_GTE224),1)
endif endif
$(OBJCOPY) -D -j .text -j .sdata -j .data \ $(OBJCOPY) -D -j .text -j .sdata -j .data \
-j .dynamic -j .rodata -j .rel* \ -j .dynamic -j .rodata -j .rel* \
-j .rela* -j .reloc -j .eh_frame -j .sbat \ -j .rela* -j .dyn -j .reloc -j .eh_frame -j .sbat \
-j .debug_info -j .debug_abbrev -j .debug_aranges \ -j .debug_info -j .debug_abbrev -j .debug_aranges \
-j .debug_line -j .debug_str -j .debug_ranges \ -j .debug_line -j .debug_str -j .debug_ranges \
-j .note.gnu.build-id \ -j .note.gnu.build-id \
@ -277,8 +287,14 @@ else
$(PESIGN) -n certdb -i $< -c "shim" -s -o $@ -f $(PESIGN) -n certdb -i $< -c "shim" -s -o $@ -f
endif endif
test : test test-clean test-coverage test-lto :
@make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" all @make -f $(TOPDIR)/include/test.mk \
COMPILER="$(COMPILER)" \
CROSS_COMPILE="$(CROSS_COMPILE)" \
CLANG_WARNINGS="$(CLANG_WARNINGS)" \
ARCH_DEFINES="$(ARCH_DEFINES)" \
EFI_INCLUDES="$(EFI_INCLUDES)" \
test-clean $@
$(patsubst %.c,%,$(wildcard test-*.c)) : $(patsubst %.c,%,$(wildcard test-*.c)) :
@make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" $@ @make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" $@
@ -291,7 +307,11 @@ clean-test-objs:
clean-gnu-efi: clean-gnu-efi:
@if [ -d gnu-efi ] ; then \ @if [ -d gnu-efi ] ; then \
$(MAKE) -C gnu-efi \ $(MAKE) -C gnu-efi \
ARCH=$(ARCH_GNUEFI) TOPDIR=$(TOPDIR)/gnu-efi \ CC="$(CC)" \
HOSTCC="$(HOSTCC)" \
COMPILER="$(COMPILER)" \
ARCH=$(ARCH_GNUEFI) \
TOPDIR=$(TOPDIR)/gnu-efi \
-f $(TOPDIR)/gnu-efi/Makefile \ -f $(TOPDIR)/gnu-efi/Makefile \
clean ; \ clean ; \
fi fi
@ -303,7 +323,7 @@ clean-lib-objs:
clean-shim-objs: clean-shim-objs:
@rm -rvf $(TARGET) *.o $(SHIM_OBJS) $(MOK_OBJS) $(FALLBACK_OBJS) $(KEYS) certdb $(BOOTCSVNAME) @rm -rvf $(TARGET) *.o $(SHIM_OBJS) $(MOK_OBJS) $(FALLBACK_OBJS) $(KEYS) certdb $(BOOTCSVNAME)
@rm -vf *.debug *.so *.efi *.efi.* *.tar.* version.c buildid @rm -vf *.debug *.so *.efi *.efi.* *.tar.* version.c buildid post-process-pe
@rm -vf Cryptlib/*.[oa] Cryptlib/*/*.[oa] @rm -vf Cryptlib/*.[oa] Cryptlib/*/*.[oa]
@if [ -d .git ] ; then git clean -f -d -e 'Cryptlib/OpenSSL/*'; fi @if [ -d .git ] ; then git clean -f -d -e 'Cryptlib/OpenSSL/*'; fi

View File

@ -40,6 +40,12 @@ typedef struct {
CHAR16 Password[SB_PASSWORD_LEN]; CHAR16 Password[SB_PASSWORD_LEN];
} __attribute__ ((packed)) MokDBvar; } __attribute__ ((packed)) MokDBvar;
typedef struct {
UINT32 MokTMLState;
UINT32 PWLen;
CHAR16 Password[SB_PASSWORD_LEN];
} __attribute__ ((packed)) MokTMLvar;
typedef struct { typedef struct {
INT32 Timeout; INT32 Timeout;
} __attribute__ ((packed)) MokTimeoutvar; } __attribute__ ((packed)) MokTimeoutvar;
@ -333,6 +339,7 @@ static void show_x509_info(X509 * X509Cert, UINT8 * hash)
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
CatPrint(&serial_string, L"%02x:", hexbuf[i]); CatPrint(&serial_string, L"%02x:", hexbuf[i]);
} }
BN_free(bnser);
} }
if (serial_string.str) if (serial_string.str)
@ -735,7 +742,7 @@ done:
static INTN reset_system() static INTN reset_system()
{ {
gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL); RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
console_notify(L"Failed to reboot\n"); console_notify(L"Failed to reboot\n");
return -1; return -1;
} }
@ -883,7 +890,7 @@ static EFI_STATUS write_db(CHAR16 * db_name, void *MokNew, UINTN MokNewSize)
CopyMem(new_data, old_data, old_size); CopyMem(new_data, old_data, old_size);
CopyMem(new_data + old_size, MokNew, MokNewSize); CopyMem(new_data + old_size, MokNew, MokNewSize);
efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID, efi_status = RT->SetVariable(db_name, &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
new_size, new_data); new_size, new_data);
@ -918,7 +925,7 @@ static EFI_STATUS store_keys(void *MokNew, UINTN MokNewSize, int authenticate,
} }
if (authenticate) { if (authenticate) {
efi_status = gRT->GetVariable(auth_name, &SHIM_LOCK_GUID, efi_status = RT->GetVariable(auth_name, &SHIM_LOCK_GUID,
&attributes, &auth_size, auth); &attributes, &auth_size, auth);
if (EFI_ERROR(efi_status) || if (EFI_ERROR(efi_status) ||
(auth_size != SHA256_DIGEST_SIZE && (auth_size != SHA256_DIGEST_SIZE &&
@ -945,7 +952,7 @@ static EFI_STATUS store_keys(void *MokNew, UINTN MokNewSize, int authenticate,
if (!MokNewSize) { if (!MokNewSize) {
/* Delete MOK */ /* Delete MOK */
efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID, efi_status = RT->SetVariable(db_name, &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
0, NULL); 0, NULL);
@ -1005,7 +1012,7 @@ static EFI_STATUS mok_reset_prompt(BOOLEAN MokX)
EFI_STATUS efi_status; EFI_STATUS efi_status;
CHAR16 *prompt[] = { NULL, NULL }; CHAR16 *prompt[] = { NULL, NULL };
ST->ConOut->ClearScreen(ST->ConOut); clear_screen();
if (MokX) if (MokX)
prompt[0] = L"Erase all stored keys in MokListX?"; prompt[0] = L"Erase all stored keys in MokListX?";
@ -1064,7 +1071,7 @@ static EFI_STATUS write_back_mok_list(MokListNode * list, INTN key_num,
} }
if (DataSize == 0) { if (DataSize == 0) {
dprint(L"DataSize = 0; deleting variable %s\n", db_name); dprint(L"DataSize = 0; deleting variable %s\n", db_name);
efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID, efi_status = RT->SetVariable(db_name, &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
DataSize, Data); DataSize, Data);
@ -1109,7 +1116,7 @@ static EFI_STATUS write_back_mok_list(MokListNode * list, INTN key_num,
ptr = (uint8_t *) ptr + CertList->SignatureListSize; ptr = (uint8_t *) ptr + CertList->SignatureListSize;
} }
efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID, efi_status = RT->SetVariable(db_name, &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
DataSize, Data); DataSize, Data);
@ -1262,7 +1269,7 @@ static EFI_STATUS delete_keys(void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
auth_name = L"MokDelAuth"; auth_name = L"MokDelAuth";
} }
efi_status = gRT->GetVariable(auth_name, &SHIM_LOCK_GUID, &attributes, efi_status = RT->GetVariable(auth_name, &SHIM_LOCK_GUID, &attributes,
&auth_size, auth); &auth_size, auth);
if (EFI_ERROR(efi_status) || if (EFI_ERROR(efi_status) ||
(auth_size != SHA256_DIGEST_SIZE (auth_size != SHA256_DIGEST_SIZE
@ -1305,7 +1312,7 @@ static EFI_STATUS delete_keys(void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
err_strs[1] = L"Erase all keys in MokList!"; err_strs[1] = L"Erase all keys in MokList!";
} }
console_alertbox(err_strs); console_alertbox(err_strs);
gRT->SetVariable(db_name, &SHIM_LOCK_GUID, RT->SetVariable(db_name, &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL); EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
efi_status = EFI_ACCESS_DENIED; efi_status = EFI_ACCESS_DENIED;
@ -1327,7 +1334,7 @@ static EFI_STATUS delete_keys(void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
err_strs[1] = L"Reset MokList!"; err_strs[1] = L"Reset MokList!";
} }
console_alertbox(err_strs); console_alertbox(err_strs);
gRT->SetVariable(db_name, &SHIM_LOCK_GUID, RT->SetVariable(db_name, &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL); EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
efi_status = EFI_ABORTED; efi_status = EFI_ABORTED;
@ -1468,7 +1475,7 @@ static EFI_STATUS mok_sb_prompt(void *MokSB, UINTN MokSBSize)
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
ST->ConOut->ClearScreen(ST->ConOut); clear_screen();
message[0] = L"Change Secure Boot state"; message[0] = L"Change Secure Boot state";
message[1] = NULL; message[1] = NULL;
@ -1541,7 +1548,7 @@ static EFI_STATUS mok_sb_prompt(void *MokSB, UINTN MokSBSize)
} }
if (var->MokSBState == 0) { if (var->MokSBState == 0) {
efi_status = gRT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID, efi_status = RT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
1, &sbval); 1, &sbval);
@ -1550,7 +1557,7 @@ static EFI_STATUS mok_sb_prompt(void *MokSB, UINTN MokSBSize)
return efi_status; return efi_status;
} }
} else { } else {
efi_status = gRT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID, efi_status = RT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
0, NULL); 0, NULL);
@ -1583,7 +1590,7 @@ static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize)
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
ST->ConOut->ClearScreen(ST->ConOut); clear_screen();
message[0] = L"Change DB state"; message[0] = L"Change DB state";
message[1] = NULL; message[1] = NULL;
@ -1656,7 +1663,7 @@ static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize)
} }
if (var->MokDBState == 0) { if (var->MokDBState == 0) {
efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID, efi_status = RT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
1, &dbval); 1, &dbval);
@ -1665,7 +1672,7 @@ static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize)
return efi_status; return efi_status;
} }
} else { } else {
efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID, efi_status = RT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
0, NULL); 0, NULL);
@ -1678,6 +1685,121 @@ static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
static EFI_STATUS mok_tml_prompt(void *MokTML, UINTN MokTMLSize)
{
EFI_STATUS efi_status;
SIMPLE_TEXT_OUTPUT_MODE SavedMode;
MokTMLvar *var = MokTML;
CHAR16 *message[4];
CHAR16 pass1, pass2, pass3;
CHAR16 *str;
UINT8 fail_count = 0;
UINT8 dbval = 1;
UINT8 pos1, pos2, pos3;
int ret;
CHAR16 *untrust_tml[] = { L"Do not trust the MOK list", NULL };
CHAR16 *trust_tml[] = { L"Trust the MOK list", NULL };
if (MokTMLSize != sizeof(MokTMLvar)) {
console_notify(L"Invalid MokTML variable contents");
return EFI_INVALID_PARAMETER;
}
clear_screen();
message[0] = L"Change Trusted MOK List Keyring state";
message[1] = NULL;
console_save_and_set_mode(&SavedMode);
console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
console_restore_mode(&SavedMode);
while (fail_count < 3) {
RandomBytes(&pos1, sizeof(pos1));
pos1 = (pos1 % var->PWLen);
do {
RandomBytes(&pos2, sizeof(pos2));
pos2 = (pos2 % var->PWLen);
} while (pos2 == pos1);
do {
RandomBytes(&pos3, sizeof(pos3));
pos3 = (pos3 % var->PWLen);
} while (pos3 == pos2 || pos3 == pos1);
str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
if (!str) {
console_errorbox(L"Failed to allocate buffer");
return EFI_OUT_OF_RESOURCES;
}
pass1 = get_password_charater(str);
FreePool(str);
str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
if (!str) {
console_errorbox(L"Failed to allocate buffer");
return EFI_OUT_OF_RESOURCES;
}
pass2 = get_password_charater(str);
FreePool(str);
str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
if (!str) {
console_errorbox(L"Failed to allocate buffer");
return EFI_OUT_OF_RESOURCES;
}
pass3 = get_password_charater(str);
FreePool(str);
if (pass1 != var->Password[pos1] ||
pass2 != var->Password[pos2] ||
pass3 != var->Password[pos3]) {
console_print(L"Invalid character\n");
fail_count++;
} else {
break;
}
}
if (fail_count >= 3) {
console_notify(L"Password limit reached");
return EFI_ACCESS_DENIED;
}
if (var->MokTMLState == 0)
ret = console_yes_no(trust_tml);
else
ret = console_yes_no(untrust_tml);
if (ret == 0) {
LibDeleteVariable(L"MokListTrustedNew", &SHIM_LOCK_GUID);
return EFI_ABORTED;
}
if (var->MokTMLState == 0) {
efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS,
1, &dbval);
if (EFI_ERROR(efi_status)) {
console_notify(L"Failed to set MokListTrusted state");
return efi_status;
}
} else {
efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS,
0, NULL);
if (EFI_ERROR(efi_status)) {
console_notify(L"Failed to delete MokListTrusted state");
return efi_status;
}
}
return EFI_SUCCESS;
}
static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize) static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
{ {
EFI_STATUS efi_status; EFI_STATUS efi_status;
@ -1691,7 +1813,7 @@ static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
ST->ConOut->ClearScreen(ST->ConOut); clear_screen();
SetMem(hash, PASSWORD_CRYPT_SIZE, 0); SetMem(hash, PASSWORD_CRYPT_SIZE, 0);
@ -1707,7 +1829,7 @@ static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
if (console_yes_no(clear_p) == 0) if (console_yes_no(clear_p) == 0)
return EFI_ABORTED; return EFI_ABORTED;
gRT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID, RT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL); EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
goto mokpw_done; goto mokpw_done;
@ -1729,7 +1851,7 @@ static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
if (console_yes_no(set_p) == 0) if (console_yes_no(set_p) == 0)
return EFI_ABORTED; return EFI_ABORTED;
efi_status = gRT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID, efi_status = RT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
MokPWSize, MokPW); MokPWSize, MokPW);
@ -1994,7 +2116,7 @@ static BOOLEAN verify_pw(BOOLEAN * protected)
*protected = FALSE; *protected = FALSE;
efi_status = gRT->GetVariable(L"MokPWStore", &SHIM_LOCK_GUID, &attributes, efi_status = RT->GetVariable(L"MokPWStore", &SHIM_LOCK_GUID, &attributes,
&size, pwhash); &size, pwhash);
/* /*
* If anything can attack the password it could just set it to a * If anything can attack the password it could just set it to a
@ -2008,7 +2130,7 @@ static BOOLEAN verify_pw(BOOLEAN * protected)
if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
return TRUE; return TRUE;
ST->ConOut->ClearScreen(ST->ConOut); clear_screen();
/* Draw the background */ /* Draw the background */
console_save_and_set_mode(&SavedMode); console_save_and_set_mode(&SavedMode);
@ -2076,7 +2198,8 @@ typedef enum {
MOK_SET_PW, MOK_SET_PW,
MOK_CHANGE_DB, MOK_CHANGE_DB,
MOK_KEY_ENROLL, MOK_KEY_ENROLL,
MOK_HASH_ENROLL MOK_HASH_ENROLL,
MOK_CHANGE_TML
} mok_menu_item; } mok_menu_item;
static void free_menu(mok_menu_item * menu_item, CHAR16 ** menu_strings) static void free_menu(mok_menu_item * menu_item, CHAR16 ** menu_strings)
@ -2095,7 +2218,8 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
void *MokPW, UINTN MokPWSize, void *MokPW, UINTN MokPWSize,
void *MokDB, UINTN MokDBSize, void *MokDB, UINTN MokDBSize,
void *MokXNew, UINTN MokXNewSize, void *MokXNew, UINTN MokXNewSize,
void *MokXDel, UINTN MokXDelSize) void *MokXDel, UINTN MokXDelSize,
void *MokTML, UINTN MokTMLSize)
{ {
CHAR16 **menu_strings = NULL; CHAR16 **menu_strings = NULL;
mok_menu_item *menu_item = NULL; mok_menu_item *menu_item = NULL;
@ -2122,28 +2246,28 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
UINT32 MokXAuth = 0; UINT32 MokXAuth = 0;
UINT32 MokXDelAuth = 0; UINT32 MokXDelAuth = 0;
efi_status = gRT->GetVariable(L"MokAuth", &SHIM_LOCK_GUID, efi_status = RT->GetVariable(L"MokAuth", &SHIM_LOCK_GUID,
&attributes, &auth_size, auth); &attributes, &auth_size, auth);
if (!EFI_ERROR(efi_status) && if (!EFI_ERROR(efi_status) &&
(auth_size == SHA256_DIGEST_SIZE || (auth_size == SHA256_DIGEST_SIZE ||
auth_size == PASSWORD_CRYPT_SIZE)) auth_size == PASSWORD_CRYPT_SIZE))
MokAuth = 1; MokAuth = 1;
efi_status = gRT->GetVariable(L"MokDelAuth", &SHIM_LOCK_GUID, efi_status = RT->GetVariable(L"MokDelAuth", &SHIM_LOCK_GUID,
&attributes, &auth_size, auth); &attributes, &auth_size, auth);
if (!EFI_ERROR(efi_status) && if (!EFI_ERROR(efi_status) &&
(auth_size == SHA256_DIGEST_SIZE || (auth_size == SHA256_DIGEST_SIZE ||
auth_size == PASSWORD_CRYPT_SIZE)) auth_size == PASSWORD_CRYPT_SIZE))
MokDelAuth = 1; MokDelAuth = 1;
efi_status = gRT->GetVariable(L"MokXAuth", &SHIM_LOCK_GUID, efi_status = RT->GetVariable(L"MokXAuth", &SHIM_LOCK_GUID,
&attributes, &auth_size, auth); &attributes, &auth_size, auth);
if (!EFI_ERROR(efi_status) && if (!EFI_ERROR(efi_status) &&
(auth_size == SHA256_DIGEST_SIZE || (auth_size == SHA256_DIGEST_SIZE ||
auth_size == PASSWORD_CRYPT_SIZE)) auth_size == PASSWORD_CRYPT_SIZE))
MokXAuth = 1; MokXAuth = 1;
efi_status = gRT->GetVariable(L"MokXDelAuth", &SHIM_LOCK_GUID, efi_status = RT->GetVariable(L"MokXDelAuth", &SHIM_LOCK_GUID,
&attributes, &auth_size, auth); &attributes, &auth_size, auth);
if (!EFI_ERROR(efi_status) && if (!EFI_ERROR(efi_status) &&
(auth_size == SHA256_DIGEST_SIZE || (auth_size == SHA256_DIGEST_SIZE ||
@ -2171,6 +2295,9 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
if (MokDB) if (MokDB)
menucount++; menucount++;
if (MokTML)
menucount++;
menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * menu_strings = AllocateZeroPool(sizeof(CHAR16 *) *
(menucount + 1)); (menucount + 1));
if (!menu_strings) if (!menu_strings)
@ -2242,6 +2369,12 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
i++; i++;
} }
if (MokTML) {
menu_strings[i] = L"Change MOK List Trusted State";
menu_item[i] = MOK_CHANGE_TML;
i++;
}
menu_strings[i] = L"Enroll key from disk"; menu_strings[i] = L"Enroll key from disk";
menu_item[i] = MOK_KEY_ENROLL; menu_item[i] = MOK_KEY_ENROLL;
i++; i++;
@ -2352,6 +2485,17 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED,
case MOK_HASH_ENROLL: case MOK_HASH_ENROLL:
efi_status = mok_hash_enroll(); efi_status = mok_hash_enroll();
break; break;
case MOK_CHANGE_TML:
if (!MokTML) {
console_print(L"MokManager: internal error: %s",
L"MokListTrusted was ! NULL bs is now NULL\n");
ret = EFI_ABORTED;
goto out;
}
efi_status = mok_tml_prompt(MokTML, MokTMLSize);
if (!EFI_ERROR(efi_status))
MokTML = NULL;
break;
} }
if (!EFI_ERROR(efi_status)) if (!EFI_ERROR(efi_status))
@ -2376,7 +2520,7 @@ out:
static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
{ {
UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0; UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0; UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0, MokTMLSize = 0;
void *MokNew = NULL; void *MokNew = NULL;
void *MokDel = NULL; void *MokDel = NULL;
void *MokSB = NULL; void *MokSB = NULL;
@ -2384,6 +2528,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
void *MokDB = NULL; void *MokDB = NULL;
void *MokXNew = NULL; void *MokXNew = NULL;
void *MokXDel = NULL; void *MokXDel = NULL;
void *MokTML = NULL;
EFI_STATUS efi_status; EFI_STATUS efi_status;
efi_status = get_variable(L"MokNew", (UINT8 **) & MokNew, &MokNewSize, efi_status = get_variable(L"MokNew", (UINT8 **) & MokNew, &MokNewSize,
@ -2436,6 +2581,18 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
console_error(L"Could not retrieve MokDB", efi_status); console_error(L"Could not retrieve MokDB", efi_status);
} }
efi_status = get_variable(L"MokListTrustedNew", (UINT8 **) & MokTML,
&MokTMLSize, SHIM_LOCK_GUID);
if (!EFI_ERROR(efi_status)) {
efi_status = LibDeleteVariable(L"MokListTrustedNew",
&SHIM_LOCK_GUID);
if (EFI_ERROR(efi_status))
console_notify(L"Failed to delete MokListTrustedNew");
} else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
console_error(L"Could not retrieve MokListTrustedNew",
efi_status);
}
efi_status = get_variable(L"MokXNew", (UINT8 **) & MokXNew, efi_status = get_variable(L"MokXNew", (UINT8 **) & MokXNew,
&MokXNewSize, SHIM_LOCK_GUID); &MokXNewSize, SHIM_LOCK_GUID);
if (!EFI_ERROR(efi_status)) { if (!EFI_ERROR(efi_status)) {
@ -2458,7 +2615,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize, enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize, MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize,
MokXNew, MokXNewSize, MokXDel, MokXDelSize); MokXNew, MokXNewSize, MokXDel, MokXDelSize, MokTML, MokTMLSize);
if (MokNew) if (MokNew)
FreePool(MokNew); FreePool(MokNew);
@ -2481,6 +2638,9 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
if (MokXDel) if (MokXDel)
FreePool(MokXDel); FreePool(MokXDel);
if (MokTML)
FreePool(MokTML);
LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID); LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID); LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID);
LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID); LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
@ -2496,7 +2656,7 @@ static EFI_STATUS setup_rand(void)
UINT64 seed; UINT64 seed;
BOOLEAN status; BOOLEAN status;
efi_status = gRT->GetTime(&time, NULL); efi_status = RT->GetTime(&time, NULL);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return efi_status; return efi_status;

View File

@ -77,3 +77,9 @@ or not to import DB certs for its own verification purposes.
MokPWStore: A SHA-256 representation of the password set by the user MokPWStore: A SHA-256 representation of the password set by the user
via MokPW. The user will be prompted to enter this password in order via MokPW. The user will be prompted to enter this password in order
to interact with MokManager. to interact with MokManager.
MokListTrusted: An 8-bit unsigned integer. If 1, it signifies to Linux
to trust CA keys in the MokList. BS,NV
MokListTrustedRT: A copy of MokListTrusted made available to the kernel
at runtime. RT

View File

@ -16,7 +16,7 @@ the `.sbat` section has the following fields:
`SBAT` EFI variable `SBAT` EFI variable
----------------- -----------------
The SBAT EFI variable (`SBAT-605dab50-e046-4300-abb6-3dd810dd8b23`) is structured as a series ASCII CSV records: The SBAT EFI variable (`SbatLevel-605dab50-e046-4300-abb6-3dd810dd8b23`) is structured as a series ASCII CSV records:
``` ```
sbat,1 sbat,1
@ -192,7 +192,7 @@ Debian discovers that they actually shipped bug 0 as well (woops). They
produce a new build which fixes it and has the following in `.sbat`: produce a new build which fixes it and has the following in `.sbat`:
``` ```
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
grub,1,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/ grub,2,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
grub.debian,2,Debian,grub2,2.04-13,https://packages.debian.org/source/sid/grub2 grub.debian,2,Debian,grub2,2.04-13,https://packages.debian.org/source/sid/grub2
``` ```

48
SBAT.md
View File

@ -6,7 +6,7 @@ In the PC ecosystem, [UEFI Secure Boot](https://docs.microsoft.com/en-us/windows
is typically configured to trust 2 authorities for signing UEFI boot code, the is typically configured to trust 2 authorities for signing UEFI boot code, the
Microsoft UEFI Certificate Authority (CA) and Windows CA. When malicious or Microsoft UEFI Certificate Authority (CA) and Windows CA. When malicious or
security compromised code is detected, 2 revocation mechanisms are provided by security compromised code is detected, 2 revocation mechanisms are provided by
compatible UEFI implementations, signing certificate or image hash. The UEFI compatible UEFI implementations: signing certificate or image hash. The UEFI
Specification does not provides any well tested additional revocation Specification does not provides any well tested additional revocation
mechanisms. mechanisms.
@ -140,21 +140,29 @@ value associated with the data currently stored in that variable.
#### Generation-Based Revocation Scenarios #### Generation-Based Revocation Scenarios
Products (**not** vendors, a vendor can have multiple products or even pass a **Products** (**not** vendors, a vendor can have multiple products or even pass a
product from one vendor to another over time) are assigned a name. Product product from one vendor to another over time) are assigned a name. Product
names can specify a specific version or refer to the entire product family. For names can specify a specific version or refer to the entire product family. For
example mydistro and mydistro,12. example mydistro and mydistro,12.
Components that are used as a link in the UEFI Secure Boot chain of trust are **Components** that are used as a link in the UEFI Secure Boot chain of trust are
assigned names. Examples of components are shim, GRUB, kernel, hypervisors, etc. assigned names. Examples of components are shim, GRUB, kernel, hypervisors, etc.
Below is an example of a product and component, both in the same `sbat.csv` file. `sbat`
defines the version of the format of the revocation metadata itself.
`grub.acme` is an example of a product name.
```
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
grub.acme,1,Acme Corporation,grub,1.96-8191,https://acme.arpa/packages/grub
```
We could conceivably support sub-components, but it's hard to conceive of a We could conceivably support sub-components, but it's hard to conceive of a
scenario that would trigger a UEFI variable update that wouldn't justify a scenario that would trigger a UEFI variable update that wouldn't justify a
hypervisor or kernel re-release to enforce that sub-component level from there. hypervisor or kernel re-release to enforce that sub-component level from there.
Something like a "level 1.5 hypervisor" that can exist between different kernel Something like a "level 1.5 hypervisor" that can exist between different kernel
generations can be considered its own component. generations can be considered its own component.
Each component is assigned a minimum global generation number. Vendors signing Each component is assigned a **minimum global generation number**. Vendors signing
component binary artifacts with a specific global generation number are component binary artifacts with a specific global generation number are
required to include fixes for any public or pre-disclosed issue required for required to include fixes for any public or pre-disclosed issue required for
that generation. Additionally, in the event that a bypass only manifests in a that generation. Additionally, in the event that a bypass only manifests in a
@ -162,7 +170,9 @@ specific product's component, vendors may ask for a product-specific generation
number to be published for one of their product's components. This avoids number to be published for one of their product's components. This avoids
triggering an industry wide re-publishing of otherwise safe components. triggering an industry wide re-publishing of otherwise safe components.
A product-specific minimum generation number only applies to the instance of In the example above, 1 is sbat's minimum global generation number.
A **product-specific minimum generation number** only applies to the instance of
that component that is signed with that product name. Another product's that component that is signed with that product name. Another product's
instance of the same component may be installed on the same system and would instance of the same component may be installed on the same system and would
not be subject to the other product's product-specific minimum generation not be subject to the other product's product-specific minimum generation
@ -174,6 +184,8 @@ entire industry that uses that component re-release, just that product's
minimum generation number would be incremented and that product's component minimum generation number would be incremented and that product's component
re-released along with a UEFI variable update specifying that requirement. re-released along with a UEFI variable update specifying that requirement.
In the example above, 1 is grub.acme's product-specific minimum generation number.
The global and product-specific generation number name spaces are not tied to The global and product-specific generation number name spaces are not tied to
each other. The global number is managed externally, and the vast majority of each other. The global number is managed externally, and the vast majority of
products will never publish a minimum product-specific generation number for products will never publish a minimum product-specific generation number for
@ -232,8 +244,8 @@ number, this product-specific number can be dropped from the UEFI revocation
variable. variable.
If this same Vendor C has a similar event after the global number is If this same Vendor C has a similar event after the global number is
incremented, they would again set their product-specific or version-specific incremented, they would again set their product-specific or **version-specific
number to 1. If they have a second event on with the same component, they would number** to 1. If they have a second event on the same component, they would
set their product-specific or version-specific number to 2. set their product-specific or version-specific number to 2.
In such an event, a vendor would set the product-specific or version-specific In such an event, a vendor would set the product-specific or version-specific
@ -242,15 +254,17 @@ branches or in just a subset of them. The goal is generally to limit end
customer impact with as few re-releases as possible, while not creating an customer impact with as few re-releases as possible, while not creating an
unnecessarily large UEFI revocation variable payload. unnecessarily large UEFI revocation variable payload.
| | prior to<br>disclosure | after<br>disclosure | after Vendor C's<br>first update | after Vendor C's<br>second update | after next global<br>disclosure | | | prior to<br>disclosure\* | after<br>disclosure | after Vendor C's<br>first update | after Vendor C's<br>second update | after next global<br>disclosure |
|--------------------------------------------------------------------------------------|------------------------|---------------------|----------------------------------|----------------------------------|---------------------------------| |--------------------------------------------------------------------------------------|------------------------|---------------------|----------------------------------|----------------------------------|---------------------------------|
| GRUB global<br>generation number in<br>artifacts .sbat section | 3 | 4 | 4 | 4 | 5 | | GRUB global<br>generation number in<br>artifacts .sbat section | 3 | 4 | 4 | 4 | 5 |
| Vendor C's product-specific<br>generation number in artifact's<br>.sbat section | 1 | 1 | 5 | 6 | 1 | | Vendor C's product-specific<br>generation number in artifact's<br>.sbat section | 1 | 1 | 2 | 3 | 1 |
| GRUB global<br>generation number in<br>UEFI SBAT revocation variable | 3 | 4 | 4 | 4 | 5 | | GRUB global<br>generation number in<br>UEFI SBAT revocation variable | 3 | 4 | 4 | 4 | 5 |
| Vendor C's product-specific<br>generation number in<br>UEFI SBAT revocation variable | not set | not set | 5 | 6 | not set | | Vendor C's product-specific<br>generation number in<br>UEFI SBAT revocation variable | not set | not set | 2 | 3 | not set |
\* A disclosure is the event/date where a CVE and fixes for it are made public.
The product-specific generation number does not reset and continues to The product-specific generation number does not reset and continues to
monotonically increase over the course of these events. Continuity of more monotonically increase over the course of these non-global events. Continuity of more
specific generation numbers must be maintained in this way in order to satisfy specific generation numbers must be maintained in this way in order to satisfy
checks against older revocation data. checks against older revocation data.
@ -258,6 +272,10 @@ The variable payload will be stored publicly in the shim source base and
identify the global generation associated with a product or version-specific identify the global generation associated with a product or version-specific
one. The payload is also built into shim to additionally limit exposure. one. The payload is also built into shim to additionally limit exposure.
At this time of writing, all version-numbers are set to 1. Presumably at some point,
updated numbers will be published on the respective websites of the associated vendors
and components.
#### Retiring Signed Releases #### Retiring Signed Releases
Products that have reached the end of their support life by definition no Products that have reached the end of their support life by definition no
@ -269,7 +287,7 @@ that the global generation numbers will eventually move forward and exclude
those products from booting on a UEFI Secure Boot enabled system. However a those products from booting on a UEFI Secure Boot enabled system. However a
product made up of GRUB and a closed source kernel is just as conceivable. In product made up of GRUB and a closed source kernel is just as conceivable. In
that case the kernel version may never move forward once the product reaches that case the kernel version may never move forward once the product reaches
its end of support. Therefor it is recommended that the product-specific its end of support. Therefore it is recommended that the product-specific
generation number be incremented past the latest one shown in any binary for generation number be incremented past the latest one shown in any binary for
that product, effectively disabling that product on UEFI Secure Boot enabled that product, effectively disabling that product on UEFI Secure Boot enabled
systems. systems.
@ -309,8 +327,8 @@ compromise.
The initial SBAT implementation will add SBAT metadata to Shim and GRUB and The initial SBAT implementation will add SBAT metadata to Shim and GRUB and
enforce SBAT on all components labeled with it. Until a component (e.g. the enforce SBAT on all components labeled with it. Until a component (e.g. the
Linux kernel gains SBAT metadata) it can not be revoked via SBAT, but only by Linux kernel) gains SBAT metadata it can not be revoked via SBAT, but only by
revoking the keys signing that component. These keys will should live in revoking the keys signing that component. These keys will live in
separate, product-specific signed PE files that contain **only** the separate, product-specific signed PE files that contain **only** the
certificate and SBAT metadata for the key files. These key files can then be certificate and SBAT metadata for the key files. These key files can then be
revoked via SBAT in order to invalidate and replace a specific key. While revoked via SBAT in order to invalidate and replace a specific key. While
@ -346,7 +364,7 @@ Adding a .sbat section containing the SBAT metadata structure to PE images.
| vendor_url | url to look stuff up, contact, whatever. | vendor_url | url to look stuff up, contact, whatever.
The format of this .sbat section is comma separated values, or more The format of this .sbat section is comma separated values, or more
specifically UTF-8 encoded strings. specifically ASCII encoded strings.
## Example sbat sections ## Example sbat sections

2
commit
View File

@ -1 +1 @@
20e4d9486fcae54ee44d2323ae342ffe68c920e6 f2c598bb2218da966872ba3e0c6e7e830dca6ef0

14
csv.c
View File

@ -15,6 +15,7 @@ parse_csv_line(char * line, size_t max, size_t *n_columns, const char *columns[]
char *token = NULL; char *token = NULL;
bool valid = true; bool valid = true;
for (n = 0; n < *n_columns; n++) { for (n = 0; n < *n_columns; n++) {
if (valid) { if (valid) {
@ -62,19 +63,21 @@ parse_csv_data(char *data, char *data_end, size_t n_columns, list_t *list)
} }
max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0); max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
if (is_utf8_bom(line, max))
if (line && is_utf8_bom(line, max))
line += UTF8_BOM_SIZE; line += UTF8_BOM_SIZE;
while (line && line <= data_end) { while (line <= data_end && *line) {
size_t entrysz = sizeof(char *) * n_columns + sizeof(struct csv_row); size_t entrysz = sizeof(char *) * n_columns + sizeof(struct csv_row);
struct csv_row *entry; struct csv_row *entry;
size_t m_columns = n_columns; size_t m_columns = n_columns;
char *delim; char *delim;
bool found = true; bool found = true;
bool eof = false;
end = data_end; end = data_end;
max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0); max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
/* Skip the delimiter(s) of the previous line */
while (max && found) { while (max && found) {
found = false; found = false;
for (delim = &delims[0]; max && *delim; delim++) { for (delim = &delims[0]; max && *delim; delim++) {
@ -85,12 +88,16 @@ parse_csv_data(char *data, char *data_end, size_t n_columns, list_t *list)
} }
} }
} }
/* Find the first delimiter of the current line */
for (delim = &delims[0]; *delim; delim++) { for (delim = &delims[0]; *delim; delim++) {
char *tmp = strnchrnul(line, max, *delim); char *tmp = strnchrnul(line, max, *delim);
if (tmp < end) if (tmp < end)
end = tmp; end = tmp;
} }
max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0); max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
if (!*end)
eof = true;
*end = '\0'; *end = '\0';
if (line == data_end || max == 0) { if (line == data_end || max == 0) {
@ -115,6 +122,9 @@ parse_csv_data(char *data, char *data_end, size_t n_columns, list_t *list)
parse_csv_line(line, max, &m_columns, (const char **)entry->columns); parse_csv_line(line, max, &m_columns, (const char **)entry->columns);
entry->n_columns = m_columns; entry->n_columns = m_columns;
if (eof)
break;
line = end + 1; line = end + 1;
} }

View File

@ -70,21 +70,29 @@ SECTIONS
.rodata : .rodata :
{ {
_rodata = .; _rodata = .;
*(.rela.dyn)
*(.rela.plt)
*(.rela.got)
*(.rela.data)
*(.rela.data*)
*(.rodata*) *(.rodata*)
*(.srodata) *(.srodata)
*(.dynsym)
*(.dynstr)
. = ALIGN(16); . = ALIGN(16);
*(.note.gnu.build-id) *(.note.gnu.build-id)
. = ALIGN(4096); . = ALIGN(4096);
*(.vendor_cert) *(.vendor_cert)
*(.data.ident) *(.data.ident)
. = ALIGN(4096);
}
. = ALIGN(4096);
.rela :
{
*(.rela.dyn)
*(.rela.plt)
*(.rela.got)
*(.rela.data)
*(.rela.data*)
}
. = ALIGN(4096);
.dyn :
{
*(.dynsym)
*(.dynstr)
_evrodata = .; _evrodata = .;
. = ALIGN(4096); . = ALIGN(4096);
} }

View File

@ -70,21 +70,29 @@ SECTIONS
.rodata : .rodata :
{ {
_rodata = .; _rodata = .;
*(.rel.dyn)
*(.rel.plt)
*(.rel.got)
*(.rel.data)
*(.rel.data*)
*(.rodata*) *(.rodata*)
*(.srodata) *(.srodata)
*(.dynsym)
*(.dynstr)
. = ALIGN(16); . = ALIGN(16);
*(.note.gnu.build-id) *(.note.gnu.build-id)
. = ALIGN(4096); . = ALIGN(4096);
*(.vendor_cert) *(.vendor_cert)
*(.data.ident) *(.data.ident)
. = ALIGN(4096);
}
. = ALIGN(4096);
.rela :
{
*(.rela.dyn)
*(.rela.plt)
*(.rela.got)
*(.rela.data)
*(.rela.data*)
}
. = ALIGN(4096);
.dyn :
{
*(.dynsym)
*(.dynstr)
_evrodata = .; _evrodata = .;
. = ALIGN(4096); . = ALIGN(4096);
} }

View File

@ -15,6 +15,7 @@ SECTIONS
*(.gnu.linkonce.t.*) *(.gnu.linkonce.t.*)
_etext = .; _etext = .;
} }
. = ALIGN(4096);
.reloc : .reloc :
{ {
*(.reloc) *(.reloc)

View File

@ -158,7 +158,7 @@ read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
} }
b = AllocateZeroPool(len + 2); b = AllocateZeroPool(len + 2);
if (!buffer) { if (!b) {
console_print(L"Could not allocate memory\n"); console_print(L"Could not allocate memory\n");
fh2->Close(fh2); fh2->Close(fh2);
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
@ -166,7 +166,7 @@ read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
efi_status = fh->Read(fh, &len, b); efi_status = fh->Read(fh, &len, b);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
FreePool(buffer); FreePool(b);
fh2->Close(fh2); fh2->Close(fh2);
console_print(L"Could not read file: %r\n", efi_status); console_print(L"Could not read file: %r\n", efi_status);
return efi_status; return efi_status;
@ -230,8 +230,11 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
StrLen(label)*2 + 2 + DevicePathSize(hddp) + StrLen(label)*2 + 2 + DevicePathSize(hddp) +
StrLen(arguments) * 2; StrLen(arguments) * 2;
CHAR8 *data = AllocateZeroPool(size + 2); CHAR8 *data, *cursor;
CHAR8 *cursor = data; cursor = data = AllocateZeroPool(size + 2);
if (!data)
return EFI_OUT_OF_RESOURCES;
*(UINT32 *)cursor = LOAD_OPTION_ACTIVE; *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
cursor += sizeof (UINT32); cursor += sizeof (UINT32);
*(UINT16 *)cursor = DevicePathSize(hddp); *(UINT16 *)cursor = DevicePathSize(hddp);
@ -248,11 +251,11 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
if (!first_new_option) { if (!first_new_option) {
first_new_option = DuplicateDevicePath(fulldp); first_new_option = DuplicateDevicePath(fulldp);
first_new_option_args = arguments; first_new_option_args = StrDuplicate(arguments);
first_new_option_size = StrLen(arguments) * sizeof (CHAR16); first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
} }
efi_status = gRT->SetVariable(varname, &GV_GUID, efi_status = RT->SetVariable(varname, &GV_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS, EFI_VARIABLE_RUNTIME_ACCESS,
@ -415,9 +418,12 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
cursor += DevicePathSize(dp); cursor += DevicePathSize(dp);
StrCpy((CHAR16 *)cursor, arguments); StrCpy((CHAR16 *)cursor, arguments);
CHAR16 varname[256];
EFI_STATUS efi_status; EFI_STATUS efi_status;
EFI_GUID vendor_guid = NullGuid; EFI_GUID vendor_guid = NullGuid;
UINTN buffer_size = 256 * sizeof(CHAR16);
CHAR16 *varname = AllocateZeroPool(buffer_size);
if (!varname)
return EFI_OUT_OF_RESOURCES;
UINTN max_candidate_size = calc_masked_boot_option_size(size); UINTN max_candidate_size = calc_masked_boot_option_size(size);
CHAR8 *candidate = AllocateZeroPool(max_candidate_size); CHAR8 *candidate = AllocateZeroPool(max_candidate_size);
@ -426,13 +432,34 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
varname[0] = 0;
while (1) { while (1) {
UINTN varname_size = sizeof(varname); UINTN varname_size = buffer_size;
efi_status = gRT->GetNextVariableName(&varname_size, varname, efi_status = RT->GetNextVariableName(&varname_size, varname,
&vendor_guid); &vendor_guid);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status)) {
if (efi_status == EFI_BUFFER_TOO_SMALL) {
VerbosePrint(L"Buffer too small for next variable name, re-allocating it to be %d bytes and retrying\n",
varname_size);
varname = ReallocatePool(varname,
buffer_size,
varname_size);
if (!varname)
return EFI_OUT_OF_RESOURCES;
buffer_size = varname_size;
continue;
}
if (efi_status == EFI_DEVICE_ERROR)
VerbosePrint(L"The next variable name could not be retrieved due to a hardware error\n");
if (efi_status == EFI_INVALID_PARAMETER)
VerbosePrint(L"Invalid parameter to GetNextVariableName: varname_size=%d, varname=%s\n",
varname_size, varname);
/* EFI_NOT_FOUND means we listed all variables */
VerbosePrint(L"Checked all boot entries\n");
break; break;
}
if (StrLen(varname) != 8 || StrnCmp(varname, L"Boot", 4) || if (StrLen(varname) != 8 || StrnCmp(varname, L"Boot", 4) ||
!isxdigit(varname[4]) || !isxdigit(varname[5]) || !isxdigit(varname[4]) || !isxdigit(varname[5]) ||
@ -440,7 +467,7 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
continue; continue;
UINTN candidate_size = max_candidate_size; UINTN candidate_size = max_candidate_size;
efi_status = gRT->GetVariable(varname, &GV_GUID, NULL, efi_status = RT->GetVariable(varname, &GV_GUID, NULL,
&candidate_size, candidate); &candidate_size, candidate);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
continue; continue;
@ -458,7 +485,7 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
/* at this point, we have duplicate data. */ /* at this point, we have duplicate data. */
if (!first_new_option) { if (!first_new_option) {
first_new_option = DuplicateDevicePath(fulldp); first_new_option = DuplicateDevicePath(fulldp);
first_new_option_args = arguments; first_new_option_args = StrDuplicate(arguments);
first_new_option_size = StrLen(arguments) * sizeof (CHAR16); first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
} }
@ -469,7 +496,8 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
} }
FreePool(candidate); FreePool(candidate);
FreePool(data); FreePool(data);
return EFI_NOT_FOUND; FreePool(varname);
return efi_status;
} }
EFI_STATUS EFI_STATUS
@ -513,11 +541,11 @@ update_boot_order(void)
for (j = 0 ; j < size / sizeof (CHAR16); j++) for (j = 0 ; j < size / sizeof (CHAR16); j++)
VerbosePrintUnprefixed(L"%04x ", newbootorder[j]); VerbosePrintUnprefixed(L"%04x ", newbootorder[j]);
VerbosePrintUnprefixed(L"\n"); VerbosePrintUnprefixed(L"\n");
efi_status = gRT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL); efi_status = RT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL);
if (efi_status == EFI_BUFFER_TOO_SMALL) if (efi_status == EFI_BUFFER_TOO_SMALL)
LibDeleteVariable(L"BootOrder", &GV_GUID); LibDeleteVariable(L"BootOrder", &GV_GUID);
efi_status = gRT->SetVariable(L"BootOrder", &GV_GUID, efi_status = RT->SetVariable(L"BootOrder", &GV_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS, EFI_VARIABLE_RUNTIME_ACCESS,
@ -544,7 +572,7 @@ add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *argum
full_device_path = FileDevicePath(this_image->DeviceHandle, fullpath); full_device_path = FileDevicePath(this_image->DeviceHandle, fullpath);
if (!full_device_path) { if (!full_device_path) {
efi_status = EFI_OUT_OF_RESOURCES; efi_status = EFI_OUT_OF_RESOURCES;
goto err; goto done;
} }
dps = DevicePathToStr(full_device_path); dps = DevicePathToStr(full_device_path);
VerbosePrint(L"file DP: %s\n", dps); VerbosePrint(L"file DP: %s\n", dps);
@ -558,7 +586,7 @@ add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *argum
dp = full_device_path; dp = full_device_path;
} else { } else {
efi_status = EFI_OUT_OF_RESOURCES; efi_status = EFI_OUT_OF_RESOURCES;
goto err; goto done;
} }
} }
@ -587,21 +615,53 @@ add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *argum
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
add_boot_option(dp, full_device_path, fullpath, label, add_boot_option(dp, full_device_path, fullpath, label,
arguments); arguments);
} else if (option != 0) { goto done;
CHAR16 *newbootorder; }
newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder);
if (!newbootorder)
return EFI_OUT_OF_RESOURCES;
newbootorder[0] = bootorder[option]; UINT16 bootnum;
CopyMem(newbootorder + 1, bootorder, sizeof (CHAR16) * option); CHAR16 *newbootorder;
CopyMem(newbootorder + option + 1, bootorder + option + 1, /* Search for the option in the current bootorder */
sizeof (CHAR16) * (nbootorder - option - 1)); for (bootnum = 0; bootnum < nbootorder; bootnum++)
if (bootorder[bootnum] == option)
break;
if (bootnum == nbootorder) {
/* Option not found, prepend option and copy the rest */
newbootorder = AllocateZeroPool(sizeof(CHAR16)
* (nbootorder + 1));
if (!newbootorder) {
efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
newbootorder[0] = option;
CopyMem(newbootorder + 1, bootorder,
sizeof(CHAR16) * nbootorder);
FreePool(bootorder);
bootorder = newbootorder;
nbootorder += 1;
} else {
/* Option found, put first and slice the rest */
newbootorder = AllocateZeroPool(
sizeof(CHAR16) * nbootorder);
if (!newbootorder) {
efi_status = EFI_OUT_OF_RESOURCES;
goto done;
}
newbootorder[0] = option;
CopyMem(newbootorder + 1, bootorder,
sizeof(CHAR16) * bootnum);
CopyMem(newbootorder + 1 + bootnum,
bootorder + bootnum + 1,
sizeof(CHAR16) * (nbootorder - bootnum - 1));
FreePool(bootorder); FreePool(bootorder);
bootorder = newbootorder; bootorder = newbootorder;
} }
VerbosePrint(L"New nbootorder: %d\nBootOrder: ",
nbootorder);
for (int i = 0 ; i < nbootorder ; i++)
VerbosePrintUnprefixed(L"%04x ", bootorder[i]);
VerbosePrintUnprefixed(L"\n");
err: done:
if (full_device_path) if (full_device_path)
FreePool(full_device_path); FreePool(full_device_path);
if (dp && dp != full_device_path) if (dp && dp != full_device_path)
@ -832,7 +892,7 @@ find_boot_options(EFI_HANDLE device)
EFI_STATUS efi_status; EFI_STATUS efi_status;
EFI_FILE_IO_INTERFACE *fio = NULL; EFI_FILE_IO_INTERFACE *fio = NULL;
efi_status = gBS->HandleProtocol(device, &FileSystemProtocol, efi_status = BS->HandleProtocol(device, &FileSystemProtocol,
(void **) &fio); (void **) &fio);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_print(L"Couldn't find file system: %r\n", efi_status); console_print(L"Couldn't find file system: %r\n", efi_status);
@ -960,7 +1020,7 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
efi_status = gBS->LoadImage(0, parent_image_handle, first_new_option, efi_status = BS->LoadImage(0, parent_image_handle, first_new_option,
NULL, 0, &image_handle); NULL, 0, &image_handle);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
CHAR16 *dps = DevicePathToStr(first_new_option); CHAR16 *dps = DevicePathToStr(first_new_option);
@ -981,14 +1041,14 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
} }
EFI_LOADED_IMAGE *image; EFI_LOADED_IMAGE *image;
efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol, efi_status = BS->HandleProtocol(image_handle, &LoadedImageProtocol,
(void *) &image); (void *) &image);
if (!EFI_ERROR(efi_status)) { if (!EFI_ERROR(efi_status)) {
image->LoadOptions = first_new_option_args; image->LoadOptions = first_new_option_args;
image->LoadOptionsSize = first_new_option_size; image->LoadOptionsSize = first_new_option_size;
} }
efi_status = gBS->StartImage(image_handle, NULL, NULL); efi_status = BS->StartImage(image_handle, NULL, NULL);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_print(L"StartImage failed: %r\n", efi_status); console_print(L"StartImage failed: %r\n", efi_status);
msleep(500000000); msleep(500000000);
@ -1003,7 +1063,7 @@ get_fallback_no_reboot(void)
UINT32 no_reboot; UINT32 no_reboot;
UINTN size = sizeof(UINT32); UINTN size = sizeof(UINT32);
efi_status = gRT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID, efi_status = RT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
NULL, &size, &no_reboot); NULL, &size, &no_reboot);
if (!EFI_ERROR(efi_status)) { if (!EFI_ERROR(efi_status)) {
return no_reboot; return no_reboot;
@ -1011,15 +1071,16 @@ get_fallback_no_reboot(void)
return 0; return 0;
} }
#ifndef FALLBACK_NONINTERACTIVE
static EFI_STATUS static EFI_STATUS
set_fallback_no_reboot(void) set_fallback_no_reboot(void)
{ {
EFI_STATUS efi_status; EFI_STATUS efi_status;
UINT32 no_reboot = 1; UINT32 no_reboot = 1;
efi_status = gRT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID, efi_status = RT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE EFI_VARIABLE_NON_VOLATILE |
| EFI_VARIABLE_BOOTSERVICE_ACCESS EFI_VARIABLE_BOOTSERVICE_ACCESS |
| EFI_VARIABLE_RUNTIME_ACCESS, EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(UINT32), &no_reboot); sizeof(UINT32), &no_reboot);
return efi_status; return efi_status;
} }
@ -1054,6 +1115,7 @@ get_user_choice(void)
return choice; return choice;
} }
#endif
extern EFI_STATUS extern EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab); efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
@ -1097,7 +1159,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
*/ */
debug_hook(); debug_hook();
efi_status = gBS->HandleProtocol(image, &LoadedImageProtocol, efi_status = BS->HandleProtocol(image, &LoadedImageProtocol,
(void *) &this_image); (void *) &this_image);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_print(L"Error: could not find loaded image: %r\n", console_print(L"Error: could not find loaded image: %r\n",
@ -1126,6 +1188,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
try_start_first_option(image); try_start_first_option(image);
} }
#ifndef FALLBACK_NONINTERACTIVE
int timeout = draw_countdown(); int timeout = draw_countdown();
if (timeout == 0) if (timeout == 0)
goto reset; goto reset;
@ -1141,6 +1204,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
VerbosePrint(L"tpm present, starting the first image\n"); VerbosePrint(L"tpm present, starting the first image\n");
try_start_first_option(image); try_start_first_option(image);
reset: reset:
#endif
VerbosePrint(L"tpm present, resetting system\n"); VerbosePrint(L"tpm present, resetting system\n");
} }
@ -1157,7 +1221,7 @@ reset:
msleep(fallback_verbose_wait); msleep(fallback_verbose_wait);
} }
gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
return EFI_SUCCESS; return EFI_SUCCESS;
} }

32
globals.c Normal file
View File

@ -0,0 +1,32 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* globals.c - global shim state
* Copyright Peter Jones <pjones@redhat.com>
*/
#include "shim.h"
UINT32 vendor_authorized_size = 0;
UINT8 *vendor_authorized = NULL;
UINT32 vendor_deauthorized_size = 0;
UINT8 *vendor_deauthorized = NULL;
#if defined(ENABLE_SHIM_CERT)
UINT32 build_cert_size;
UINT8 *build_cert;
#endif /* defined(ENABLE_SHIM_CERT) */
/*
* indicator of how an image has been verified
*/
verification_method_t verification_method;
int loader_is_participating;
UINT8 user_insecure_mode;
UINT8 ignore_db;
UINT8 trust_mok_list;
UINT32 verbose = 0;
// vim:fenc=utf-8:tw=75:noet

View File

@ -124,10 +124,10 @@ ifeq ($(ARCH),x86_64)
|| ( [ $(GCCVERSION) -eq "4" ] \ || ( [ $(GCCVERSION) -eq "4" ] \
&& [ $(GCCMINOR) -ge "7" ] ) ) \ && [ $(GCCMINOR) -ge "7" ] ) ) \
&& echo 1) && echo 1)
ifeq ($(GCCNEWENOUGH),1) ifeq ($(USING_CLANG),clang)
CPPFLAGS += -DGNU_EFI_USE_MS_ABI -DGNU_EFI_USE_EXTERNAL_STDARG -maccumulate-outgoing-args --std=c11
else ifeq ($(USING_CLANG),clang)
CPPFLAGS += -DGNU_EFI_USE_MS_ABI -DGNU_EFI_USE_EXTERNAL_STDARG --std=c11 CPPFLAGS += -DGNU_EFI_USE_MS_ABI -DGNU_EFI_USE_EXTERNAL_STDARG --std=c11
else ifeq ($(GCCNEWENOUGH),1)
CPPFLAGS += -DGNU_EFI_USE_MS_ABI -DGNU_EFI_USE_EXTERNAL_STDARG -maccumulate-outgoing-args --std=c11
endif endif
CFLAGS += -mno-red-zone CFLAGS += -mno-red-zone
@ -193,6 +193,7 @@ CFLAGS += $(ARCH3264) $(OPTIMIZATIONS) \
-fshort-wchar -fno-strict-aliasing \ -fshort-wchar -fno-strict-aliasing \
-ffreestanding -fno-stack-protector \ -ffreestanding -fno-stack-protector \
-fno-stack-check -nostdinc \ -fno-stack-check -nostdinc \
$(CFLAGS_LTO) $(CFLAGS_GCOV) \
-isystem $(TOPDIR)/../include/system \ -isystem $(TOPDIR)/../include/system \
-isystem $(shell $(CC) $(ARCH3264) -print-file-name=include) \ -isystem $(shell $(CC) $(ARCH3264) -print-file-name=include) \
$(if $(findstring gcc,$(CC)),-fno-merge-all-constants,) $(if $(findstring gcc,$(CC)),-fno-merge-all-constants,)

View File

@ -229,6 +229,7 @@ VOID
#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
#define EFI_VARIABLE_APPEND_WRITE 0x00000040 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
#define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS 0x00000080
// Variable size limitation // Variable size limitation
#define EFI_MAXIMUM_VARIABLE_SIZE 1024 #define EFI_MAXIMUM_VARIABLE_SIZE 1024
@ -751,6 +752,8 @@ typedef struct _EFI_TABLE_HEADER {
// //
#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552 #define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552
#define EFI_1_10_RUNTIME_SERVICES_REVISION ((1<<16) | (10))
#define EFI_2_00_RUNTIME_SERVICES_REVISION ((2<<16) | (0))
#define EFI_RUNTIME_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) #define EFI_RUNTIME_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)
typedef struct { typedef struct {
@ -798,6 +801,8 @@ typedef struct {
// //
#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 #define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42
#define EFI_1_10_BOOT_SERVICES_REVISION ((1<<16) | (10))
#define EFI_2_00_BOOT_SERVICES_REVISION ((2<<16) | (0))
#define EFI_BOOT_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) #define EFI_BOOT_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)
typedef struct _EFI_BOOT_SERVICES { typedef struct _EFI_BOOT_SERVICES {
@ -938,6 +943,9 @@ typedef struct _EFI_CONFIGURATION_TABLE {
#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 #define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249
#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | (02))
#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | (10))
#define EFI_2_00_SYSTEM_TABLE_REVISION ((2<<16) | (0))
#define EFI_SYSTEM_TABLE_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) #define EFI_SYSTEM_TABLE_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)
typedef struct _EFI_SYSTEM_TABLE { typedef struct _EFI_SYSTEM_TABLE {

View File

@ -272,17 +272,17 @@ ZeroMem (
IN UINTN Size IN UINTN Size
); );
VOID VOID EFIAPI
SetMem ( SetMem (
IN VOID *Buffer, IN VOID *Buffer,
IN UINTN Size, IN UINTN Size,
IN UINT8 Value IN UINT8 Value
); );
VOID VOID EFIAPI
CopyMem ( CopyMem (
IN VOID *Dest, IN VOID *Dest,
IN CONST VOID *Src, IN VOID *Src,
IN UINTN len IN UINTN len
); );

View File

@ -98,7 +98,7 @@ ZeroMem (
RtZeroMem (Buffer, Size); RtZeroMem (Buffer, Size);
} }
VOID VOID EFIAPI
SetMem ( SetMem (
IN VOID *Buffer, IN VOID *Buffer,
IN UINTN Size, IN UINTN Size,
@ -108,10 +108,10 @@ SetMem (
RtSetMem (Buffer, Size, Value); RtSetMem (Buffer, Size, Value);
} }
VOID VOID EFIAPI
CopyMem ( CopyMem (
IN VOID *Dest, IN VOID *Dest,
IN CONST VOID *Src, IN VOID *Src,
IN UINTN len IN UINTN len
) )
{ {

View File

@ -211,7 +211,7 @@ StrDuplicate (
Size = StrSize(Src); Size = StrSize(Src);
Dest = AllocatePool (Size); Dest = AllocatePool (Size);
if (Dest) { if (Dest) {
CopyMem (Dest, Src, Size); CopyMem (Dest, (void *)Src, Size);
} }
return Dest; return Dest;
} }

View File

@ -179,8 +179,8 @@ generate_next_uri (CONST CHAR8 *current_uri, CONST CHAR8 *next_loader,
if (!*uri) if (!*uri)
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
CopyMem(*uri, current_uri, path_len); CopyMem(*uri, (void *)current_uri, path_len);
CopyMem(*uri + path_len, next_loader, next_len); CopyMem(*uri + path_len, (void *)next_loader, next_len);
(*uri)[path_len + next_len] = '\0'; (*uri)[path_len + next_len] = '\0';
return EFI_SUCCESS; return EFI_SUCCESS;
@ -209,7 +209,7 @@ extract_hostname (CONST CHAR8 *url, CHAR8 **hostname)
if (!*hostname) if (!*hostname)
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
CopyMem(*hostname, start, host_len); CopyMem(*hostname, (void *)start, host_len);
(*hostname)[host_len] = '\0'; (*hostname)[host_len] = '\0';
return EFI_SUCCESS; return EFI_SUCCESS;
@ -232,7 +232,7 @@ get_nic_handle (EFI_MAC_ADDRESS *mac)
/* Get the list of handles that support the HTTP service binding /* Get the list of handles that support the HTTP service binding
protocol */ protocol */
efi_status = gBS->LocateHandleBuffer(ByProtocol, efi_status = BS->LocateHandleBuffer(ByProtocol,
&EFI_HTTP_BINDING_GUID, &EFI_HTTP_BINDING_GUID,
NULL, &NoHandles, &buffer); NULL, &NoHandles, &buffer);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
@ -306,7 +306,7 @@ set_ip6(EFI_HANDLE *nic, IPv6_DEVICE_PATH *ip6node)
EFI_IPv6_ADDRESS gateway; EFI_IPv6_ADDRESS gateway;
EFI_STATUS efi_status; EFI_STATUS efi_status;
efi_status = gBS->HandleProtocol(nic, &EFI_IP6_CONFIG_GUID, efi_status = BS->HandleProtocol(nic, &EFI_IP6_CONFIG_GUID,
(VOID **)&ip6cfg); (VOID **)&ip6cfg);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return efi_status; return efi_status;
@ -367,7 +367,7 @@ set_ip4(EFI_HANDLE *nic, IPv4_DEVICE_PATH *ip4node)
EFI_IPv4_ADDRESS gateway; EFI_IPv4_ADDRESS gateway;
EFI_STATUS efi_status; EFI_STATUS efi_status;
efi_status = gBS->HandleProtocol(nic, &EFI_IP4_CONFIG2_GUID, efi_status = BS->HandleProtocol(nic, &EFI_IP4_CONFIG2_GUID,
(VOID **)&ip4cfg2); (VOID **)&ip4cfg2);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return efi_status; return efi_status;
@ -470,7 +470,7 @@ send_http_request (EFI_HTTP_PROTOCOL *http, CHAR8 *hostname, CHAR8 *uri)
tx_token.Message = &tx_message; tx_token.Message = &tx_message;
tx_token.Event = NULL; tx_token.Event = NULL;
request_done = FALSE; request_done = FALSE;
efi_status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY, efi_status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
httpnotify, &request_done, httpnotify, &request_done,
&tx_token.Event); &tx_token.Event);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
@ -496,7 +496,7 @@ send_http_request (EFI_HTTP_PROTOCOL *http, CHAR8 *hostname, CHAR8 *uri)
} }
error: error:
event_status = gBS->CloseEvent(tx_token.Event); event_status = BS->CloseEvent(tx_token.Event);
if (EFI_ERROR(event_status)) { if (EFI_ERROR(event_status)) {
perror(L"Failed to close Event for HTTP request: %r\n", perror(L"Failed to close Event for HTTP request: %r\n",
event_status); event_status);
@ -534,7 +534,7 @@ receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINT64 *buf_size)
rx_token.Message = &rx_message; rx_token.Message = &rx_message;
rx_token.Event = NULL; rx_token.Event = NULL;
response_done = FALSE; response_done = FALSE;
efi_status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY, efi_status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
httpnotify, &response_done, httpnotify, &response_done,
&rx_token.Event); &rx_token.Event);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
@ -571,7 +571,8 @@ receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINT64 *buf_size)
/* Check the length of the file */ /* Check the length of the file */
for (i = 0; i < rx_message.HeaderCount; i++) { for (i = 0; i < rx_message.HeaderCount; i++) {
if (!strcmp(rx_message.Headers[i].FieldName, (CHAR8 *)"Content-Length")) { if (!strcasecmp(rx_message.Headers[i].FieldName,
(CHAR8 *)"Content-Length")) {
*buf_size = ascii_to_int(rx_message.Headers[i].FieldValue); *buf_size = ascii_to_int(rx_message.Headers[i].FieldValue);
} }
} }
@ -631,7 +632,7 @@ receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINT64 *buf_size)
} }
error: error:
event_status = gBS->CloseEvent(rx_token.Event); event_status = BS->CloseEvent(rx_token.Event);
if (EFI_ERROR(event_status)) { if (EFI_ERROR(event_status)) {
perror(L"Failed to close Event for HTTP response: %r\n", perror(L"Failed to close Event for HTTP response: %r\n",
event_status); event_status);
@ -659,7 +660,7 @@ http_fetch (EFI_HANDLE image, EFI_HANDLE device,
*buf_size = 0; *buf_size = 0;
/* Open HTTP Service Binding Protocol */ /* Open HTTP Service Binding Protocol */
efi_status = gBS->OpenProtocol(device, &EFI_HTTP_BINDING_GUID, efi_status = BS->OpenProtocol(device, &EFI_HTTP_BINDING_GUID,
(VOID **) &service, image, NULL, (VOID **) &service, image, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL); EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
@ -675,7 +676,7 @@ http_fetch (EFI_HANDLE image, EFI_HANDLE device,
} }
/* Get the http protocol */ /* Get the http protocol */
efi_status = gBS->HandleProtocol(http_handle, &EFI_HTTP_PROTOCOL_GUID, efi_status = BS->HandleProtocol(http_handle, &EFI_HTTP_PROTOCOL_GUID,
(VOID **) &http); (VOID **) &http);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Failed to get http\n"); perror(L"Failed to get http\n");

View File

@ -26,17 +26,17 @@ static inline uint64_t read_counter(void)
} }
#if defined(__x86_64__) || defined(__i386__) || defined(__i686__) #if defined(__x86_64__) || defined(__i386__) || defined(__i686__)
static inline void pause(void) static inline void wait_for_debug(void)
{ {
__asm__ __volatile__("pause"); __asm__ __volatile__("pause");
} }
#elif defined(__aarch64__) #elif defined(__aarch64__)
static inline void pause(void) static inline void wait_for_debug(void)
{ {
__asm__ __volatile__("wfi"); __asm__ __volatile__("wfi");
} }
#else #else
static inline void pause(void) static inline void wait_for_debug(void)
{ {
uint64_t a, b; uint64_t a, b;
int x; int x;

View File

@ -50,6 +50,9 @@ void
console_reset(void); console_reset(void);
void void
console_mode_handle(void); console_mode_handle(void);
void
clear_screen(void);
#define NOSEL 0x7fffffff #define NOSEL 0x7fffffff
typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL;
@ -109,8 +112,12 @@ extern UINT32 verbose;
extern EFI_STATUS EFIAPI vdprint_(const CHAR16 *fmt, const char *file, int line, extern EFI_STATUS EFIAPI vdprint_(const CHAR16 *fmt, const char *file, int line,
const char *func, ms_va_list args); const char *func, ms_va_list args);
#if defined(SHIM_UNIT_TEST)
#define vdprint(fmt, ...)
#else
#define vdprint(fmt, ...) \ #define vdprint(fmt, ...) \
vdprint_(fmt, __FILE__, __LINE__ - 1, __func__, ##__VA_ARGS__) vdprint_(fmt, __FILE__, __LINE__ - 1, __func__, ##__VA_ARGS__)
#endif
extern EFI_STATUS print_crypto_errors(EFI_STATUS rc, char *file, const char *func, int line); extern EFI_STATUS print_crypto_errors(EFI_STATUS rc, char *file, const char *func, int line);
#define crypterr(rc) print_crypto_errors((rc), __FILE__, __func__, __LINE__) #define crypterr(rc) print_crypto_errors((rc), __FILE__, __func__, __LINE__)

View File

@ -124,9 +124,15 @@ typedef struct {
/* /*
* Attributes of Authenticated Variable * Attributes of Authenticated Variable
*/ */
#ifndef EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
#endif
#ifndef EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
#endif
#ifndef EFI_VARIABLE_APPEND_WRITE
#define EFI_VARIABLE_APPEND_WRITE 0x00000040 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
#endif
/* /*
* AuthInfo is a WIN_CERTIFICATE using the wCertificateType * AuthInfo is a WIN_CERTIFICATE using the wCertificateType

View File

@ -71,7 +71,7 @@ prepare_text(const void *data, size_t size, char *buf, unsigned int position)
else else
buf[offset++] = '.'; buf[offset++] = '.';
} }
buf[offset++] = size > 0 ? '|' : 'X'; buf[offset++] = '|';
buf[offset] = '\0'; buf[offset] = '\0';
} }
@ -89,6 +89,11 @@ vhexdumpf(const char *file, int line, const char *func, const CHAR16 *const fmt,
if (verbose == 0) if (verbose == 0)
return; return;
if (!data || !size) {
dprint(L"hexdump of a NULL pointer!\n");
return;
}
while (offset < size) { while (offset < size) {
char hexbuf[49]; char hexbuf[49];
char txtbuf[19]; char txtbuf[19];
@ -137,12 +142,19 @@ hexdumpat(const char *file, int line, const char *func, const void *data, unsign
hexdumpf(file, line, func, L"", data, size, at); hexdumpf(file, line, func, L"", data, size, at);
} }
#if defined(SHIM_UNIT_TEST)
#define LogHexDump(data, ...)
#define dhexdump(data, ...)
#define dhexdumpat(data, ...)
#define dhexdumpf(fmt, ...)
#else
#define LogHexdump(data, sz) LogHexdump_(__FILE__, __LINE__, __func__, data, sz) #define LogHexdump(data, sz) LogHexdump_(__FILE__, __LINE__, __func__, data, sz)
#define dhexdump(data, sz) hexdump(__FILE__, __LINE__, __func__, data, sz) #define dhexdump(data, sz) hexdump(__FILE__, __LINE__, __func__, data, sz)
#define dhexdumpat(data, sz, at) \ #define dhexdumpat(data, sz, at) \
hexdumpat(__FILE__, __LINE__ - 1, __func__, data, sz, at) hexdumpat(__FILE__, __LINE__ - 1, __func__, data, sz, at)
#define dhexdumpf(fmt, data, sz, at, ...) \ #define dhexdumpf(fmt, data, sz, at, ...) \
hexdumpf(__FILE__, __LINE__ - 1, __func__, fmt, data, sz, at, ##__VA_ARGS__) hexdumpf(__FILE__, __LINE__ - 1, __func__, fmt, data, sz, at, ##__VA_ARGS__)
#endif
#endif /* STATIC_HEXDUMP_H */ #endif /* STATIC_HEXDUMP_H */
// vim:fenc=utf-8:tw=75:noet // vim:fenc=utf-8:tw=75:noet

20
include/load-options.h Normal file
View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* load-options.h - all the stuff we need to parse the load options
*/
#ifndef SHIM_ARGV_H_
#define SHIM_ARGV_H_
EFI_STATUS generate_path_from_image_path(EFI_LOADED_IMAGE *li,
CHAR16 *ImagePath,
CHAR16 **PathName);
EFI_STATUS parse_load_options(EFI_LOADED_IMAGE *li);
extern CHAR16 *second_stage;
extern void *load_options;
extern UINT32 load_options_size;
#endif /* !SHIM_ARGV_H_ */
// vim:fenc=utf-8:tw=75:noet

199
include/mock-variables.h Normal file
View File

@ -0,0 +1,199 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* mock-variables.h - a mock GetVariable/SetVariable/GNVN/etc
* implementation for testing.
* Copyright Peter Jones <pjones@redhat.com>
*/
#ifndef SHIM_MOCK_VARIABLES_H_
#define SHIM_MOCK_VARIABLES_H_
#include "test.h"
EFI_STATUS EFIAPI mock_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs,
UINTN *size, VOID *data);
EFI_STATUS EFIAPI mock_get_next_variable_name(UINTN *size, CHAR16 *name,
EFI_GUID *guid);
EFI_STATUS EFIAPI mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
UINTN size, VOID *data);
EFI_STATUS EFIAPI mock_query_variable_info(UINT32 attrs,
UINT64 *max_var_storage,
UINT64 *remaining_var_storage,
UINT64 *max_var_size);
EFI_STATUS EFIAPI mock_install_configuration_table(EFI_GUID *guid, VOID *table);
struct mock_variable_limits {
UINT32 attrs;
UINT64 *max_var_storage;
UINT64 *remaining_var_storage;
UINT64 *max_var_size;
EFI_STATUS status;
list_t list;
};
typedef enum {
MOCK_SORT_DESCENDING,
MOCK_SORT_PREPEND,
MOCK_SORT_APPEND,
MOCK_SORT_ASCENDING,
MOCK_SORT_MAX_SENTINEL
} mock_sort_policy_t;
extern mock_sort_policy_t mock_variable_sort_policy;
extern mock_sort_policy_t mock_config_table_sort_policy;
#define MOCK_VAR_DELETE_ATTR_ALLOW_ZERO 0x01
#define MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH 0x02
extern UINT32 mock_variable_delete_attr_policy;
extern list_t mock_default_variable_limits;
extern list_t *mock_qvi_limits;
extern list_t *mock_sv_limits;
struct mock_variable {
CHAR16 *name;
EFI_GUID guid;
void *data;
size_t size;
uint32_t attrs;
list_t list;
};
extern list_t mock_variables;
static inline void
dump_mock_variables(const char * const file,
const int line,
const char * const func)
{
list_t *pos = NULL;
printf("%s:%d:%s(): dumping variables\n", file, line, func);
list_for_each(pos, &mock_variables) {
struct mock_variable *var;
var = list_entry(pos, struct mock_variable, list);
printf("%s:%d:%s(): "GUID_FMT"-%s\n", file, line, func,
GUID_ARGS(var->guid), Str2str(var->name));
}
}
static inline void
dump_mock_variables_if_wrong(const char * const file,
const int line,
const char * const func,
EFI_GUID *guid, CHAR16 *first)
{
UINTN size = 0;
CHAR16 buf[8192] = { 0, };
EFI_STATUS status;
size = sizeof(buf);
buf[0] = L'\0';
status = RT->GetNextVariableName(&size, buf, guid);
if (EFI_ERROR(status)) {
printf("%s:%d:%s() Can't dump variables: %lx\n",
__FILE__, __LINE__, __func__,
(unsigned long)status);
return;
}
buf[size] = L'\0';
if (StrCmp(buf, first) == 0)
return;
printf("%s:%d:%s():expected \"%s\" but got \"%s\". Variables:\n",
file, line, func, Str2str(first), Str2str(buf));
dump_mock_variables(file, line, func);
}
void mock_load_variables(const char *const dirname, const char *filters[],
bool filter_out);
void mock_install_query_variable_info(void);
void mock_uninstall_query_variable_info(void);
void mock_reset_variables(void);
void mock_reset_config_table(void);
void mock_finalize_vars_and_configs(void);
typedef enum {
NONE = 0,
CREATE,
DELETE,
APPEND,
REPLACE,
GET,
} mock_variable_op_t;
static inline const char *
format_var_op(mock_variable_op_t op)
{
static const char *var_op_names[] = {
"NONE",
"CREATE",
"DELETE",
"APPEND",
"REPLACE",
"GET",
NULL
};
return var_op_names[op];
}
typedef EFI_STATUS (mock_set_variable_pre_hook_t)(CHAR16 *name, EFI_GUID *guid,
UINT32 attrs, UINTN size,
VOID *data);
extern mock_set_variable_pre_hook_t *mock_set_variable_pre_hook;
typedef void (mock_set_variable_post_hook_t)(CHAR16 *name, EFI_GUID *guid,
UINT32 attrs, UINTN size,
VOID *data, EFI_STATUS *status,
mock_variable_op_t op,
const char * const file,
const int line,
const char * const func);
extern mock_set_variable_post_hook_t *mock_set_variable_post_hook;
typedef EFI_STATUS (mock_get_variable_pre_hook_t)(CHAR16 *name, EFI_GUID *guid,
UINT32 *attrs, UINTN *size,
VOID *data);
extern mock_get_variable_pre_hook_t *mock_get_variable_pre_hook;
typedef void (mock_get_variable_post_hook_t)(CHAR16 *name, EFI_GUID *guid,
UINT32 *attrs, UINTN *size,
VOID *data, EFI_STATUS *status,
const char * const file,
const int line,
const char * const func);
extern mock_get_variable_post_hook_t *mock_get_variable_post_hook;
typedef EFI_STATUS (mock_get_next_variable_name_pre_hook_t)(UINTN *size,
CHAR16 *name,
EFI_GUID *guid);
extern mock_get_next_variable_name_pre_hook_t
*mock_get_next_variable_name_pre_hook;
typedef void (mock_get_next_variable_name_post_hook_t)(
UINTN *size, CHAR16 *name, EFI_GUID *guid,
EFI_STATUS *status, const char * const file,
const int line, const char * const func);
extern mock_get_next_variable_name_post_hook_t
*mock_get_next_variable_name_post_hook;
typedef EFI_STATUS (mock_query_variable_info_pre_hook_t)(
UINT32 attrs, UINT64 *max_var_storage,
UINT64 *remaining_var_storage, UINT64 *max_var_size);
extern mock_query_variable_info_pre_hook_t *mock_query_variable_info_pre_hook;
typedef void (mock_query_variable_info_post_hook_t)(
UINT32 attrs, UINT64 *max_var_storage, UINT64 *remaining_var_storage,
UINT64 *max_var_size, EFI_STATUS *status, const char * const file,
const int line, const char * const func);
extern mock_query_variable_info_post_hook_t *mock_query_variable_info_post_hook;
#define MOCK_CONFIG_TABLE_ENTRIES 1024
extern EFI_CONFIGURATION_TABLE mock_config_table[MOCK_CONFIG_TABLE_ENTRIES];
#endif /* !SHIM_MOCK_VARIABLES_H_ */
// vim:fenc=utf-8:tw=75:noet

101
include/mok.h Normal file
View File

@ -0,0 +1,101 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* mok.h - structs for MoK data
* Copyright Peter Jones <pjones@redhat.com>
*/
#ifndef SHIM_MOK_H_
#define SHIM_MOK_H_
#include "shim.h"
typedef enum {
VENDOR_ADDEND_DB,
VENDOR_ADDEND_X509,
VENDOR_ADDEND_NONE,
} vendor_addend_category_t;
struct mok_state_variable;
typedef vendor_addend_category_t (vendor_addend_categorizer_t)(struct mok_state_variable *);
/*
* MoK variables that need to have their storage validated.
*
* The order here is important, since this is where we measure for the
* tpm as well.
*/
struct mok_state_variable {
CHAR16 *name; /* UCS-2 BS|NV variable name */
char *name8; /* UTF-8 BS|NV variable name */
CHAR16 *rtname; /* UCS-2 RT variable name */
char *rtname8; /* UTF-8 RT variable name */
EFI_GUID *guid; /* variable GUID */
/*
* these are used during processing, they shouldn't be filled out
* in the static table below.
*/
UINT8 *data;
UINTN data_size;
/*
* addend are added to the input variable, as part of the runtime
* variable, so that they're visible to the kernel. These are
* where we put vendor_cert / vendor_db / vendor_dbx
*
* These are indirect pointers just to make initialization saner...
*/
vendor_addend_categorizer_t *categorize_addend; /* determines format */
/*
* we call categorize_addend() and it determines what kind of thing
* this is. That is, if this shim was built with VENDOR_CERT, for
* the DB entry it'll return VENDOR_ADDEND_X509; if you used
* VENDOR_DB instead, it'll return VENDOR_ADDEND_DB. If you used
* neither, it'll do VENDOR_ADDEND_NONE.
*
* The existing categorizers are for db and dbx; they differ
* because we don't currently support a CERT for dbx.
*/
UINT8 **addend;
UINT32 *addend_size;
/*
* build_cert is our build-time cert. Like addend, this is added
* to the input variable, as part of the runtime variable, so that
* they're visible to the kernel. This is the ephemeral cert used
* for signing MokManager.efi and fallback.efi.
*
* These are indirect pointers just to make initialization saner...
*/
UINT8 **build_cert;
UINT32 *build_cert_size;
UINT32 yes_attr; /* var attrs that must be set */
UINT32 no_attr; /* var attrs that must not be set */
UINT32 flags; /* flags on what and how to mirror */
/*
* MOK_MIRROR_KEYDB mirror this as a key database
* MOK_MIRROR_DELETE_FIRST delete any existing variable first
* MOK_VARIABLE_MEASURE extend PCR 7 and log the hash change
* MOK_VARIABLE_LOG measure into whatever .pcr says and log
*/
UINTN pcr; /* PCR to measure and hash to */
/*
* if this is a state value, a pointer to our internal state to be
* mirrored.
*/
UINT8 *state;
};
extern size_t n_mok_state_variables;
extern struct mok_state_variable *mok_state_variables;
struct mok_variable_config_entry {
CHAR8 name[256];
UINT64 data_size;
UINT8 data[];
};
#endif /* !SHIM_MOK_H_ */
// vim:fenc=utf-8:tw=75:noet

View File

@ -25,7 +25,7 @@ handle_image (void *data, unsigned int datasize,
UINTN *alloc_pages); UINTN *alloc_pages);
EFI_STATUS EFI_STATUS
generate_hash (char *data, unsigned int datasize_in, generate_hash (char *data, unsigned int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context, PE_COFF_LOADER_IMAGE_CONTEXT *context,
UINT8 *sha256hash, UINT8 *sha1hash); UINT8 *sha256hash, UINT8 *sha1hash);

View File

@ -72,8 +72,6 @@ strntoken(char *str, size_t max, const char *delims, char **token, char *state)
return 0; return 0;
tokend = &str[max-1]; tokend = &str[max-1];
if (!str || max == 0 || !delims || !token)
return 0;
/* /*
* the very special case of "" with max=1, where we have no prior * the very special case of "" with max=1, where we have no prior

View File

@ -24,7 +24,7 @@ typedef __builtin_va_list __builtin_sysv_va_list;
#endif #endif
#if defined(__aarch64__) || defined(__arm__) || defined(__i386__) || \ #if defined(__aarch64__) || defined(__arm__) || defined(__i386__) || \
defined(__i486__) || defined(__i686__) defined(__i486__) || defined(__i686__) || defined(__COVERITY__)
typedef __builtin_va_list ms_va_list; typedef __builtin_va_list ms_va_list;
typedef __builtin_va_list __builtin_ms_va_list; typedef __builtin_va_list __builtin_ms_va_list;

View File

@ -0,0 +1,554 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* test-data-efivars-0.h - test data
* Copyright Peter Jones <pjones@redhat.com>
*/
#ifndef TEST_DATA_EFIVARS_0_H_
#define TEST_DATA_EFIVARS_0_H_
static const unsigned char test_data_efivars_0_Boot0000[] = {
0x01, 0x00, 0x00, 0x00, 0x62, 0x00, 0x46, 0x00, 0x65, 0x00, 0x64, 0x00,
0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x00, 0x00, 0x04, 0x01, 0x2a, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x58, 0x7f, 0x92,
0x54, 0xdc, 0xf4, 0x4f, 0x82, 0x1c, 0xd2, 0x9b, 0x59, 0xc4, 0x8a, 0xb1,
0x02, 0x02, 0x04, 0x04, 0x34, 0x00, 0x5c, 0x00, 0x45, 0x00, 0x46, 0x00,
0x49, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x45, 0x00, 0x44, 0x00, 0x4f, 0x00,
0x52, 0x00, 0x41, 0x00, 0x5c, 0x00, 0x53, 0x00, 0x48, 0x00, 0x49, 0x00,
0x4d, 0x00, 0x58, 0x00, 0x36, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x45, 0x00,
0x46, 0x00, 0x49, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x04, 0x00
};
static const unsigned char test_data_efivars_0_dbDefault[] = {
0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15,
0x5c, 0x2b, 0xf0, 0x72, 0x82, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x03, 0x00, 0x00, 0x91, 0x30, 0x05, 0x3b, 0x9f, 0x6c, 0xcc, 0x04,
0xb1, 0xac, 0xe2, 0xa5, 0x1e, 0x3b, 0xe5, 0xf5, 0x30, 0x82, 0x03, 0x52,
0x30, 0x82, 0x02, 0x3a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xda,
0x83, 0xb9, 0x90, 0x42, 0x2e, 0xbc, 0x8c, 0x44, 0x1f, 0x8d, 0x8b, 0x03,
0x9a, 0x65, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d,
0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x41, 0x53, 0x55, 0x53, 0x54,
0x65, 0x4b, 0x20, 0x4d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x61,
0x72, 0x64, 0x20, 0x53, 0x57, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x1e, 0x17,
0x0d, 0x31, 0x31, 0x31, 0x32, 0x32, 0x36, 0x32, 0x33, 0x33, 0x35, 0x30,
0x35, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x31, 0x32, 0x32, 0x36, 0x32, 0x33,
0x33, 0x35, 0x30, 0x34, 0x5a, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, 0x06,
0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65,
0x4b, 0x20, 0x4d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x61, 0x72,
0x64, 0x20, 0x53, 0x57, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65, 0x72,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x82, 0x01, 0x22,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
0x02, 0x82, 0x01, 0x01, 0x00, 0x8c, 0xf6, 0xa6, 0xeb, 0x77, 0xfc, 0x83,
0x8a, 0xa4, 0x9f, 0xd5, 0xf8, 0xcf, 0x3f, 0x37, 0xf2, 0x6e, 0x2d, 0x0a,
0x62, 0xc5, 0xd8, 0x9b, 0x1d, 0x16, 0x0b, 0x22, 0x7f, 0x29, 0x5f, 0x3a,
0x26, 0xdf, 0x53, 0x97, 0x8c, 0x78, 0x94, 0x19, 0x90, 0x42, 0x73, 0x0f,
0x85, 0xc2, 0xff, 0xa4, 0x85, 0x7c, 0x81, 0x2e, 0x0b, 0x51, 0xba, 0x56,
0x23, 0x27, 0x92, 0x3d, 0xa3, 0xf2, 0xdc, 0xe2, 0x77, 0x84, 0x9e, 0x50,
0xbe, 0x8a, 0xeb, 0x51, 0x34, 0xa4, 0xf8, 0xef, 0x5d, 0xd7, 0x51, 0xfe,
0x70, 0x42, 0x4c, 0x42, 0x06, 0xef, 0x69, 0x2c, 0xa2, 0xd3, 0x25, 0xe1,
0x26, 0x57, 0x23, 0x85, 0x6d, 0xd0, 0xa7, 0x7b, 0xc0, 0x45, 0x28, 0x7e,
0x89, 0xd5, 0xb4, 0x0a, 0xeb, 0xaf, 0x41, 0x79, 0x21, 0xd2, 0xd7, 0x00,
0xec, 0x48, 0xf9, 0x44, 0xf6, 0x5b, 0xbe, 0xb6, 0x25, 0x24, 0xf0, 0x8e,
0x2e, 0xb4, 0x52, 0x3e, 0xe1, 0x0e, 0xc1, 0xa4, 0x67, 0xea, 0xfe, 0xe5,
0x93, 0xcc, 0xb9, 0xc4, 0x36, 0x21, 0xcb, 0x54, 0xfa, 0xaf, 0x9d, 0x9c,
0x85, 0x78, 0xcc, 0xe5, 0x88, 0xf3, 0x84, 0x0c, 0x67, 0xdb, 0x26, 0x69,
0x58, 0xca, 0xde, 0x47, 0x34, 0xec, 0xcf, 0x2f, 0xb6, 0x49, 0x59, 0xb5,
0x56, 0xdb, 0x58, 0x45, 0x7b, 0x21, 0x9d, 0x99, 0x0b, 0x5f, 0xde, 0x57,
0x16, 0xa6, 0xab, 0xc8, 0x79, 0x3f, 0x9d, 0x76, 0x89, 0xe2, 0x09, 0xf9,
0x8d, 0xe2, 0x63, 0x37, 0xfc, 0x74, 0xea, 0x73, 0x7e, 0x70, 0xac, 0x15,
0x16, 0xa5, 0xed, 0x88, 0x60, 0x5f, 0x33, 0xed, 0x94, 0x9e, 0x0a, 0x05,
0xde, 0xc7, 0x85, 0xc3, 0xc1, 0x7a, 0x54, 0xfb, 0x4e, 0xcb, 0xcb, 0xe8,
0x5e, 0x44, 0x7c, 0x39, 0xdb, 0x2d, 0xb2, 0xb7, 0x6c, 0xce, 0xca, 0x2f,
0x63, 0x9d, 0x16, 0x4e, 0xa6, 0xe5, 0xef, 0xd6, 0xcf, 0x02, 0x03, 0x01,
0x00, 0x01, 0xa3, 0x66, 0x30, 0x64, 0x30, 0x62, 0x06, 0x03, 0x55, 0x1d,
0x01, 0x04, 0x5b, 0x30, 0x59, 0x80, 0x10, 0x56, 0xb0, 0x8b, 0x2a, 0xa7,
0xfe, 0xcc, 0xf1, 0x0c, 0xed, 0x87, 0x62, 0xdc, 0xd5, 0x1d, 0xc3, 0xa1,
0x33, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x26, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65, 0x4b, 0x20, 0x4d, 0x6f,
0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x53, 0x57,
0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x82, 0x10, 0xda, 0x83, 0xb9, 0x90, 0x42, 0x2e,
0xbc, 0x8c, 0x44, 0x1f, 0x8d, 0x8b, 0x03, 0x9a, 0x65, 0xa2, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x02, 0xcf, 0x52, 0x6f, 0x0b, 0x91,
0xeb, 0xe4, 0x3b, 0xb2, 0x70, 0x0c, 0x07, 0x2d, 0x79, 0x80, 0x01, 0x9e,
0x4b, 0x4d, 0x92, 0xbb, 0xdc, 0x9e, 0xe5, 0xe5, 0x31, 0x85, 0xe3, 0x9a,
0x75, 0xed, 0xca, 0xde, 0x8c, 0xee, 0x28, 0x34, 0x01, 0x83, 0x14, 0x47,
0x9e, 0x3a, 0xd4, 0x43, 0x5b, 0x2c, 0xc4, 0x41, 0xc8, 0x40, 0x7d, 0xb5,
0x08, 0x76, 0x86, 0x80, 0x2b, 0xa8, 0x00, 0x9f, 0xb7, 0xd3, 0xb1, 0xe6,
0x60, 0x5c, 0x32, 0xb0, 0xa0, 0x01, 0x0f, 0xba, 0x36, 0x8b, 0xb7, 0xb5,
0x4e, 0x87, 0xd5, 0xb7, 0x0a, 0x2c, 0xbd, 0xbc, 0x6a, 0x43, 0x3c, 0xee,
0x76, 0x7c, 0x76, 0x20, 0xed, 0x39, 0x91, 0xa8, 0xbf, 0x70, 0x1e, 0xd6,
0xa8, 0x1a, 0x3e, 0x81, 0x36, 0x6b, 0x7d, 0x1d, 0x8d, 0xf6, 0xf8, 0xaf,
0x5b, 0x38, 0x53, 0x6a, 0x04, 0x0d, 0x7e, 0xae, 0x4d, 0xee, 0xab, 0x02,
0xd4, 0xa4, 0xa2, 0xa9, 0xcf, 0xb6, 0xe3, 0x66, 0xa3, 0xca, 0x4d, 0x5d,
0xd4, 0x18, 0x61, 0x4d, 0xda, 0x83, 0x28, 0x4e, 0xaa, 0x2a, 0xaf, 0xda,
0xeb, 0xdf, 0x2a, 0x20, 0xbd, 0x78, 0x80, 0xef, 0xd1, 0xb0, 0xdd, 0x9b,
0x77, 0xdb, 0xc9, 0x25, 0x39, 0x4b, 0xcf, 0xa2, 0x86, 0x1a, 0xac, 0xcc,
0x32, 0xe7, 0x87, 0xd4, 0x59, 0xb2, 0x03, 0xc4, 0x69, 0x02, 0x8f, 0x17,
0xc9, 0xde, 0x52, 0xcb, 0xe7, 0xab, 0xb8, 0x35, 0xc5, 0xf8, 0x33, 0x06,
0x03, 0x93, 0x52, 0xcf, 0xb3, 0x68, 0xd2, 0xb3, 0x5c, 0x1c, 0xe8, 0x19,
0xfe, 0x75, 0x26, 0xed, 0xd1, 0x65, 0x72, 0x13, 0x4d, 0x69, 0x34, 0x5a,
0x9b, 0x0c, 0xb4, 0xe3, 0x56, 0x53, 0x3c, 0xb4, 0x67, 0x27, 0xf8, 0xfa,
0xd3, 0x20, 0xda, 0x37, 0x58, 0xf6, 0xad, 0xe2, 0x82, 0x59, 0xa2, 0xb8,
0x22, 0x2f, 0x9e, 0x56, 0xfe, 0xbc, 0x17, 0x49, 0x1d, 0xaf, 0xa1, 0x59,
0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b,
0xf0, 0x72, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x03,
0x00, 0x00, 0x91, 0x30, 0x05, 0x3b, 0x9f, 0x6c, 0xcc, 0x04, 0xb1, 0xac,
0xe2, 0xa5, 0x1e, 0x3b, 0xe5, 0xf5, 0x30, 0x82, 0x03, 0x49, 0x30, 0x82,
0x02, 0x31, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xb8, 0xe5, 0x81,
0xe4, 0xdf, 0x77, 0xa5, 0xbb, 0x42, 0x82, 0xd5, 0xcc, 0xfc, 0x00, 0xc0,
0x71, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x0b, 0x05, 0x00, 0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03,
0x55, 0x04, 0x03, 0x13, 0x23, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65, 0x4b,
0x20, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x20, 0x53, 0x57,
0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x31, 0x32,
0x32, 0x37, 0x30, 0x30, 0x31, 0x38, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x33,
0x31, 0x31, 0x32, 0x32, 0x37, 0x30, 0x30, 0x31, 0x38, 0x35, 0x32, 0x5a,
0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
0x23, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65, 0x4b, 0x20, 0x4e, 0x6f, 0x74,
0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x20, 0x53, 0x57, 0x20, 0x4b, 0x65, 0x79,
0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9e, 0x61, 0xfa,
0x74, 0x2c, 0x2a, 0x88, 0x17, 0xc4, 0xbd, 0x77, 0x19, 0x0d, 0xb3, 0x33,
0x27, 0x0c, 0x0e, 0x94, 0xec, 0xb0, 0x8b, 0x71, 0xb3, 0x08, 0x77, 0xb7,
0xd2, 0x08, 0x9d, 0x32, 0x4f, 0x5c, 0xf7, 0x0c, 0xcf, 0xe0, 0x29, 0x53,
0x56, 0xed, 0x24, 0x91, 0xd8, 0xbd, 0x53, 0x2a, 0x89, 0x89, 0x8c, 0x74,
0x28, 0xab, 0x16, 0x2d, 0x4f, 0x9b, 0x65, 0xfc, 0x63, 0x7d, 0xed, 0x23,
0xb6, 0x97, 0x5c, 0x6d, 0x04, 0xe4, 0x15, 0x7f, 0xdc, 0xf8, 0xba, 0x6b,
0x08, 0xcc, 0xc9, 0x21, 0xe9, 0xb5, 0xde, 0x8e, 0x03, 0x28, 0x12, 0x63,
0xf0, 0x6a, 0xb6, 0xe5, 0xdf, 0x1d, 0x72, 0x28, 0xcc, 0x64, 0xd6, 0x63,
0x66, 0x2f, 0x04, 0x52, 0x6a, 0x1d, 0x25, 0x7d, 0xc7, 0xbd, 0xe0, 0x78,
0xfb, 0x0c, 0xb7, 0x37, 0xe5, 0xae, 0xf7, 0x0d, 0xd6, 0xb5, 0xb4, 0xbf,
0xf5, 0xf1, 0xc6, 0x82, 0x56, 0x78, 0x5c, 0xa8, 0xf3, 0x53, 0x2e, 0xf5,
0xec, 0x15, 0x3f, 0x12, 0x62, 0x2f, 0xeb, 0xb6, 0x79, 0x79, 0x86, 0xac,
0x76, 0xff, 0xb6, 0x66, 0x45, 0xf5, 0x33, 0xda, 0xdd, 0x25, 0xd6, 0xa7,
0xbf, 0xf8, 0xd9, 0xdb, 0xd3, 0xf1, 0xfa, 0xce, 0x0e, 0x22, 0x30, 0xd7,
0xd4, 0x80, 0x02, 0xbd, 0xd3, 0x2c, 0x1e, 0xec, 0x46, 0x2e, 0x2f, 0xca,
0x0f, 0x7a, 0xfa, 0xb9, 0x5c, 0xff, 0x2b, 0x16, 0xc6, 0x6a, 0x6b, 0x8d,
0x94, 0x64, 0x92, 0x7e, 0xf9, 0x55, 0xee, 0x96, 0x00, 0x4d, 0x04, 0x2e,
0x4b, 0x15, 0xed, 0xf1, 0x08, 0x49, 0x6a, 0x07, 0x86, 0x69, 0xc8, 0xc5,
0x64, 0xfa, 0xad, 0x2c, 0x4f, 0x02, 0x50, 0xe4, 0x1f, 0x83, 0xc7, 0x2f,
0x19, 0x9f, 0xe8, 0xa5, 0x62, 0xd9, 0x51, 0x32, 0x18, 0xb6, 0x83, 0xca,
0x08, 0x0a, 0xa1, 0xab, 0xa7, 0x65, 0x70, 0x9c, 0x1e, 0x48, 0xc3, 0x0f,
0x49, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x5f,
0x06, 0x03, 0x55, 0x1d, 0x01, 0x04, 0x58, 0x30, 0x56, 0x80, 0x10, 0x00,
0x65, 0x11, 0xe3, 0xca, 0x0f, 0x96, 0xe8, 0x8d, 0x5b, 0x04, 0xa4, 0xe7,
0xfe, 0xce, 0xaa, 0xa1, 0x30, 0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a, 0x06,
0x03, 0x55, 0x04, 0x03, 0x13, 0x23, 0x41, 0x53, 0x55, 0x53, 0x54, 0x65,
0x4b, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x20, 0x53,
0x57, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
0x69, 0x63, 0x61, 0x74, 0x65, 0x82, 0x10, 0xb8, 0xe5, 0x81, 0xe4, 0xdf,
0x77, 0xa5, 0xbb, 0x42, 0x82, 0xd5, 0xcc, 0xfc, 0x00, 0xc0, 0x71, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x31, 0x18, 0xf4, 0xee, 0xe3,
0x72, 0xba, 0xbe, 0x33, 0x44, 0x61, 0x74, 0x19, 0x1f, 0x66, 0xac, 0x5c,
0xfd, 0x1d, 0x9a, 0x26, 0x75, 0xd0, 0x14, 0xcd, 0x68, 0x38, 0xb3, 0xa8,
0x3f, 0x4f, 0xb4, 0x4a, 0xe9, 0x1e, 0x21, 0xf2, 0xc9, 0xee, 0x37, 0x96,
0x26, 0xbe, 0x1d, 0x58, 0x9b, 0xad, 0x21, 0xce, 0x58, 0x79, 0x53, 0xd3,
0xff, 0x38, 0xef, 0x8f, 0x22, 0xcd, 0x90, 0x0e, 0xc6, 0x32, 0x21, 0x75,
0x9b, 0x5a, 0xab, 0xaf, 0x08, 0xff, 0x05, 0xcd, 0x2b, 0xf8, 0x8c, 0xe7,
0x97, 0x47, 0xbb, 0x78, 0xe4, 0x5f, 0x56, 0x47, 0xd2, 0xbc, 0xc8, 0xa5,
0x95, 0xcb, 0x76, 0x89, 0x5c, 0x65, 0x24, 0x02, 0x18, 0x06, 0x9c, 0x12,
0x5f, 0xef, 0xe0, 0x5c, 0x19, 0x45, 0x38, 0x96, 0xdf, 0x7a, 0x60, 0x5d,
0x61, 0xba, 0x4d, 0xc8, 0x7b, 0x6e, 0x8d, 0x8c, 0x6e, 0x1d, 0xa9, 0xe5,
0x92, 0x35, 0xa2, 0x4f, 0x36, 0xd3, 0x40, 0xad, 0xd7, 0x40, 0x12, 0xab,
0x6c, 0x48, 0x8d, 0x18, 0x92, 0xe4, 0x00, 0x52, 0x03, 0xdf, 0x14, 0xac,
0x66, 0x3f, 0x6a, 0xae, 0x42, 0x3a, 0x06, 0x50, 0xaa, 0xa5, 0x0d, 0x40,
0xa7, 0x7b, 0xeb, 0xfd, 0x41, 0x49, 0xff, 0xeb, 0xa3, 0xb4, 0x50, 0x4f,
0xf7, 0x54, 0x13, 0x3b, 0x1f, 0x8e, 0xb4, 0x45, 0x04, 0x20, 0x42, 0x74,
0xfe, 0x78, 0x3d, 0xbe, 0x7c, 0xdb, 0xa7, 0x2a, 0x2a, 0x9d, 0x06, 0x48,
0xc0, 0x9a, 0x02, 0x23, 0xaf, 0xf2, 0x98, 0x07, 0x95, 0xde, 0x3b, 0x30,
0x73, 0xec, 0x3e, 0x73, 0x58, 0x8f, 0x07, 0x53, 0x40, 0x96, 0xd8, 0x24,
0xd9, 0x66, 0x80, 0x7a, 0x75, 0x8d, 0xb7, 0x39, 0x27, 0x10, 0x89, 0x7a,
0xb4, 0x53, 0xbf, 0x3b, 0xc2, 0xe2, 0x97, 0x93, 0x37, 0x8a, 0x9d, 0x4d,
0x23, 0x6e, 0xac, 0xeb, 0x0d, 0x53, 0x21, 0x4d, 0x0b, 0x34, 0x13, 0xa1,
0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, 0x5c,
0x2b, 0xf0, 0x72, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
0x06, 0x00, 0x00, 0xbd, 0x9a, 0xfa, 0x77, 0x59, 0x03, 0x32, 0x4d, 0xbd,
0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b, 0x30, 0x82, 0x06, 0x10, 0x30,
0x82, 0x03, 0xf8, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x61, 0x08,
0xd3, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
0x81, 0x91, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e,
0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52,
0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
0x32, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43,
0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x54,
0x68, 0x69, 0x72, 0x64, 0x20, 0x50, 0x61, 0x72, 0x74, 0x79, 0x20, 0x4d,
0x61, 0x72, 0x6b, 0x65, 0x74, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x52,
0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x36, 0x32,
0x37, 0x32, 0x31, 0x32, 0x32, 0x34, 0x35, 0x5a, 0x17, 0x0d, 0x32, 0x36,
0x30, 0x36, 0x32, 0x37, 0x32, 0x31, 0x33, 0x32, 0x34, 0x35, 0x5a, 0x30,
0x81, 0x81, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e,
0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52,
0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
0x22, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43,
0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x55,
0x45, 0x46, 0x49, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x31, 0x30,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x08, 0x6c, 0x4c,
0xc7, 0x45, 0x09, 0x6a, 0x4b, 0x0c, 0xa4, 0xc0, 0x87, 0x7f, 0x06, 0x75,
0x0c, 0x43, 0x01, 0x54, 0x64, 0xe0, 0x16, 0x7f, 0x07, 0xed, 0x92, 0x7d,
0x0b, 0xb2, 0x73, 0xbf, 0x0c, 0x0a, 0xc6, 0x4a, 0x45, 0x61, 0xa0, 0xc5,
0x16, 0x2d, 0x96, 0xd3, 0xf5, 0x2b, 0xa0, 0xfb, 0x4d, 0x49, 0x9b, 0x41,
0x80, 0x90, 0x3c, 0xb9, 0x54, 0xfd, 0xe6, 0xbc, 0xd1, 0x9d, 0xc4, 0xa4,
0x18, 0x8a, 0x7f, 0x41, 0x8a, 0x5c, 0x59, 0x83, 0x68, 0x32, 0xbb, 0x8c,
0x47, 0xc9, 0xee, 0x71, 0xbc, 0x21, 0x4f, 0x9a, 0x8a, 0x7c, 0xff, 0x44,
0x3f, 0x8d, 0x8f, 0x32, 0xb2, 0x26, 0x48, 0xae, 0x75, 0xb5, 0xee, 0xc9,
0x4c, 0x1e, 0x4a, 0x19, 0x7e, 0xe4, 0x82, 0x9a, 0x1d, 0x78, 0x77, 0x4d,
0x0c, 0xb0, 0xbd, 0xf6, 0x0f, 0xd3, 0x16, 0xd3, 0xbc, 0xfa, 0x2b, 0xa5,
0x51, 0x38, 0x5d, 0xf5, 0xfb, 0xba, 0xdb, 0x78, 0x02, 0xdb, 0xff, 0xec,
0x0a, 0x1b, 0x96, 0xd5, 0x83, 0xb8, 0x19, 0x13, 0xe9, 0xb6, 0xc0, 0x7b,
0x40, 0x7b, 0xe1, 0x1f, 0x28, 0x27, 0xc9, 0xfa, 0xef, 0x56, 0x5e, 0x1c,
0xe6, 0x7e, 0x94, 0x7e, 0xc0, 0xf0, 0x44, 0xb2, 0x79, 0x39, 0xe5, 0xda,
0xb2, 0x62, 0x8b, 0x4d, 0xbf, 0x38, 0x70, 0xe2, 0x68, 0x24, 0x14, 0xc9,
0x33, 0xa4, 0x08, 0x37, 0xd5, 0x58, 0x69, 0x5e, 0xd3, 0x7c, 0xed, 0xc1,
0x04, 0x53, 0x08, 0xe7, 0x4e, 0xb0, 0x2a, 0x87, 0x63, 0x08, 0x61, 0x6f,
0x63, 0x15, 0x59, 0xea, 0xb2, 0x2b, 0x79, 0xd7, 0x0c, 0x61, 0x67, 0x8a,
0x5b, 0xfd, 0x5e, 0xad, 0x87, 0x7f, 0xba, 0x86, 0x67, 0x4f, 0x71, 0x58,
0x12, 0x22, 0x04, 0x22, 0x22, 0xce, 0x8b, 0xef, 0x54, 0x71, 0x00, 0xce,
0x50, 0x35, 0x58, 0x76, 0x95, 0x08, 0xee, 0x6a, 0xb1, 0xa2, 0x01, 0xd5,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x76, 0x30, 0x82, 0x01,
0x72, 0x30, 0x12, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37,
0x15, 0x01, 0x04, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x23, 0x06,
0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x02, 0x04, 0x16,
0x04, 0x14, 0xf8, 0xc1, 0x6b, 0xb7, 0x7f, 0x77, 0x53, 0x4a, 0xf3, 0x25,
0x37, 0x1d, 0x4e, 0xa1, 0x26, 0x7b, 0x0f, 0x20, 0x70, 0x80, 0x30, 0x1d,
0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x13, 0xad, 0xbf,
0x43, 0x09, 0xbd, 0x82, 0x70, 0x9c, 0x8c, 0xd5, 0x4f, 0x31, 0x6e, 0xd5,
0x22, 0x98, 0x8a, 0x1b, 0xd4, 0x30, 0x19, 0x06, 0x09, 0x2b, 0x06, 0x01,
0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x04, 0x0c, 0x1e, 0x0a, 0x00, 0x53,
0x00, 0x75, 0x00, 0x62, 0x00, 0x43, 0x00, 0x41, 0x30, 0x0b, 0x06, 0x03,
0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
0x16, 0x80, 0x14, 0x45, 0x66, 0x52, 0x43, 0xe1, 0x7e, 0x58, 0x11, 0xbf,
0xd6, 0x4e, 0x9e, 0x23, 0x55, 0x08, 0x3b, 0x3a, 0x22, 0x6a, 0xa8, 0x30,
0x5c, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x55, 0x30, 0x53, 0x30, 0x51,
0xa0, 0x4f, 0xa0, 0x4d, 0x86, 0x4b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x2f, 0x63,
0x72, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2f,
0x4d, 0x69, 0x63, 0x43, 0x6f, 0x72, 0x54, 0x68, 0x69, 0x50, 0x61, 0x72,
0x4d, 0x61, 0x72, 0x52, 0x6f, 0x6f, 0x5f, 0x32, 0x30, 0x31, 0x30, 0x2d,
0x31, 0x30, 0x2d, 0x30, 0x35, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x60, 0x06,
0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x54, 0x30,
0x52, 0x30, 0x50, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30,
0x02, 0x86, 0x44, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77,
0x77, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x2f, 0x63, 0x65, 0x72, 0x74,
0x73, 0x2f, 0x4d, 0x69, 0x63, 0x43, 0x6f, 0x72, 0x54, 0x68, 0x69, 0x50,
0x61, 0x72, 0x4d, 0x61, 0x72, 0x52, 0x6f, 0x6f, 0x5f, 0x32, 0x30, 0x31,
0x30, 0x2d, 0x31, 0x30, 0x2d, 0x30, 0x35, 0x2e, 0x63, 0x72, 0x74, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x35, 0x08, 0x42, 0xff, 0x30,
0xcc, 0xce, 0xf7, 0x76, 0x0c, 0xad, 0x10, 0x68, 0x58, 0x35, 0x29, 0x46,
0x32, 0x76, 0x27, 0x7c, 0xef, 0x12, 0x41, 0x27, 0x42, 0x1b, 0x4a, 0xaa,
0x6d, 0x81, 0x38, 0x48, 0x59, 0x13, 0x55, 0xf3, 0xe9, 0x58, 0x34, 0xa6,
0x16, 0x0b, 0x82, 0xaa, 0x5d, 0xad, 0x82, 0xda, 0x80, 0x83, 0x41, 0x06,
0x8f, 0xb4, 0x1d, 0xf2, 0x03, 0xb9, 0xf3, 0x1a, 0x5d, 0x1b, 0xf1, 0x50,
0x90, 0xf9, 0xb3, 0x55, 0x84, 0x42, 0x28, 0x1c, 0x20, 0xbd, 0xb2, 0xae,
0x51, 0x14, 0xc5, 0xc0, 0xac, 0x97, 0x95, 0x21, 0x1c, 0x90, 0xdb, 0x0f,
0xfc, 0x77, 0x9e, 0x95, 0x73, 0x91, 0x88, 0xca, 0xbd, 0xbd, 0x52, 0xb9,
0x05, 0x50, 0x0d, 0xdf, 0x57, 0x9e, 0xa0, 0x61, 0xed, 0x0d, 0xe5, 0x6d,
0x25, 0xd9, 0x40, 0x0f, 0x17, 0x40, 0xc8, 0xce, 0xa3, 0x4a, 0xc2, 0x4d,
0xaf, 0x9a, 0x12, 0x1d, 0x08, 0x54, 0x8f, 0xbd, 0xc7, 0xbc, 0xb9, 0x2b,
0x3d, 0x49, 0x2b, 0x1f, 0x32, 0xfc, 0x6a, 0x21, 0x69, 0x4f, 0x9b, 0xc8,
0x7e, 0x42, 0x34, 0xfc, 0x36, 0x06, 0x17, 0x8b, 0x8f, 0x20, 0x40, 0xc0,
0xb3, 0x9a, 0x25, 0x75, 0x27, 0xcd, 0xc9, 0x03, 0xa3, 0xf6, 0x5d, 0xd1,
0xe7, 0x36, 0x54, 0x7a, 0xb9, 0x50, 0xb5, 0xd3, 0x12, 0xd1, 0x07, 0xbf,
0xbb, 0x74, 0xdf, 0xdc, 0x1e, 0x8f, 0x80, 0xd5, 0xed, 0x18, 0xf4, 0x2f,
0x14, 0x16, 0x6b, 0x2f, 0xde, 0x66, 0x8c, 0xb0, 0x23, 0xe5, 0xc7, 0x84,
0xd8, 0xed, 0xea, 0xc1, 0x33, 0x82, 0xad, 0x56, 0x4b, 0x18, 0x2d, 0xf1,
0x68, 0x95, 0x07, 0xcd, 0xcf, 0xf0, 0x72, 0xf0, 0xae, 0xbb, 0xdd, 0x86,
0x85, 0x98, 0x2c, 0x21, 0x4c, 0x33, 0x2b, 0xf0, 0x0f, 0x4a, 0xf0, 0x68,
0x87, 0xb5, 0x92, 0x55, 0x32, 0x75, 0xa1, 0x6a, 0x82, 0x6a, 0x3c, 0xa3,
0x25, 0x11, 0xa4, 0xed, 0xad, 0xd7, 0x04, 0xae, 0xcb, 0xd8, 0x40, 0x59,
0xa0, 0x84, 0xd1, 0x95, 0x4c, 0x62, 0x91, 0x22, 0x1a, 0x74, 0x1d, 0x8c,
0x3d, 0x47, 0x0e, 0x44, 0xa6, 0xe4, 0xb0, 0x9b, 0x34, 0x35, 0xb1, 0xfa,
0xb6, 0x53, 0xa8, 0x2c, 0x81, 0xec, 0xa4, 0x05, 0x71, 0xc8, 0x9d, 0xb8,
0xba, 0xe8, 0x1b, 0x44, 0x66, 0xe4, 0x47, 0x54, 0x0e, 0x8e, 0x56, 0x7f,
0xb3, 0x9f, 0x16, 0x98, 0xb2, 0x86, 0xd0, 0x68, 0x3e, 0x90, 0x23, 0xb5,
0x2f, 0x5e, 0x8f, 0x50, 0x85, 0x8d, 0xc6, 0x8d, 0x82, 0x5f, 0x41, 0xa1,
0xf4, 0x2e, 0x0d, 0xe0, 0x99, 0xd2, 0x6c, 0x75, 0xe4, 0xb6, 0x69, 0xb5,
0x21, 0x86, 0xfa, 0x07, 0xd1, 0xf6, 0xe2, 0x4d, 0xd1, 0xda, 0xad, 0x2c,
0x77, 0x53, 0x1e, 0x25, 0x32, 0x37, 0xc7, 0x6c, 0x52, 0x72, 0x95, 0x86,
0xb0, 0xf1, 0x35, 0x61, 0x6a, 0x19, 0xf5, 0xb2, 0x3b, 0x81, 0x50, 0x56,
0xa6, 0x32, 0x2d, 0xfe, 0xa2, 0x89, 0xf9, 0x42, 0x86, 0x27, 0x18, 0x55,
0xa1, 0x82, 0xca, 0x5a, 0x9b, 0xf8, 0x30, 0x98, 0x54, 0x14, 0xa6, 0x47,
0x96, 0x25, 0x2f, 0xc8, 0x26, 0xe4, 0x41, 0x94, 0x1a, 0x5c, 0x02, 0x3f,
0xe5, 0x96, 0xe3, 0x85, 0x5b, 0x3c, 0x3e, 0x3f, 0xbb, 0x47, 0x16, 0x72,
0x55, 0xe2, 0x25, 0x22, 0xb1, 0xd9, 0x7b, 0xe7, 0x03, 0x06, 0x2a, 0xa3,
0xf7, 0x1e, 0x90, 0x46, 0xc3, 0x00, 0x0d, 0xd6, 0x19, 0x89, 0xe3, 0x0e,
0x35, 0x27, 0x62, 0x03, 0x71, 0x15, 0xa6, 0xef, 0xd0, 0x27, 0xa0, 0xa0,
0x59, 0x37, 0x60, 0xf8, 0x38, 0x94, 0xb8, 0xe0, 0x78, 0x70, 0xf8, 0xba,
0x4c, 0x86, 0x87, 0x94, 0xf6, 0xe0, 0xae, 0x02, 0x45, 0xee, 0x65, 0xc2,
0xb6, 0xa3, 0x7e, 0x69, 0x16, 0x75, 0x07, 0x92, 0x9b, 0xf5, 0xa6, 0xbc,
0x59, 0x83, 0x58, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87,
0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x07, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xeb, 0x05, 0x00, 0x00, 0xbd, 0x9a, 0xfa, 0x77, 0x59,
0x03, 0x32, 0x4d, 0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b, 0x30,
0x82, 0x05, 0xd7, 0x30, 0x82, 0x03, 0xbf, 0xa0, 0x03, 0x02, 0x01, 0x02,
0x02, 0x0a, 0x61, 0x07, 0x76, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x0b, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
0x07, 0x13, 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e,
0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63,
0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03,
0x55, 0x04, 0x03, 0x13, 0x29, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
0x66, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x32, 0x30, 0x31, 0x30, 0x30, 0x1e,
0x17, 0x0d, 0x31, 0x31, 0x31, 0x30, 0x31, 0x39, 0x31, 0x38, 0x34, 0x31,
0x34, 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x31, 0x30, 0x31, 0x39, 0x31,
0x38, 0x35, 0x31, 0x34, 0x32, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73,
0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06,
0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e,
0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15,
0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f,
0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x2e, 0x30,
0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x4d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77,
0x73, 0x20, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x50, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x31, 0x30, 0x82, 0x01,
0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdd, 0x0c, 0xbb, 0xa2, 0xe4, 0x2e,
0x09, 0xe3, 0xe7, 0xc5, 0xf7, 0x96, 0x69, 0xbc, 0x00, 0x21, 0xbd, 0x69,
0x33, 0x33, 0xef, 0xad, 0x04, 0xcb, 0x54, 0x80, 0xee, 0x06, 0x83, 0xbb,
0xc5, 0x20, 0x84, 0xd9, 0xf7, 0xd2, 0x8b, 0xf3, 0x38, 0xb0, 0xab, 0xa4,
0xad, 0x2d, 0x7c, 0x62, 0x79, 0x05, 0xff, 0xe3, 0x4a, 0x3f, 0x04, 0x35,
0x20, 0x70, 0xe3, 0xc4, 0xe7, 0x6b, 0xe0, 0x9c, 0xc0, 0x36, 0x75, 0xe9,
0x8a, 0x31, 0xdd, 0x8d, 0x70, 0xe5, 0xdc, 0x37, 0xb5, 0x74, 0x46, 0x96,
0x28, 0x5b, 0x87, 0x60, 0x23, 0x2c, 0xbf, 0xdc, 0x47, 0xa5, 0x67, 0xf7,
0x51, 0x27, 0x9e, 0x72, 0xeb, 0x07, 0xa6, 0xc9, 0xb9, 0x1e, 0x3b, 0x53,
0x35, 0x7c, 0xe5, 0xd3, 0xec, 0x27, 0xb9, 0x87, 0x1c, 0xfe, 0xb9, 0xc9,
0x23, 0x09, 0x6f, 0xa8, 0x46, 0x91, 0xc1, 0x6e, 0x96, 0x3c, 0x41, 0xd3,
0xcb, 0xa3, 0x3f, 0x5d, 0x02, 0x6a, 0x4d, 0xec, 0x69, 0x1f, 0x25, 0x28,
0x5c, 0x36, 0xff, 0xfd, 0x43, 0x15, 0x0a, 0x94, 0xe0, 0x19, 0xb4, 0xcf,
0xdf, 0xc2, 0x12, 0xe2, 0xc2, 0x5b, 0x27, 0xee, 0x27, 0x78, 0x30, 0x8b,
0x5b, 0x2a, 0x09, 0x6b, 0x22, 0x89, 0x53, 0x60, 0x16, 0x2c, 0xc0, 0x68,
0x1d, 0x53, 0xba, 0xec, 0x49, 0xf3, 0x9d, 0x61, 0x8c, 0x85, 0x68, 0x09,
0x73, 0x44, 0x5d, 0x7d, 0xa2, 0x54, 0x2b, 0xdd, 0x79, 0xf7, 0x15, 0xcf,
0x35, 0x5d, 0x6c, 0x1c, 0x2b, 0x5c, 0xce, 0xbc, 0x9c, 0x23, 0x8b, 0x6f,
0x6e, 0xb5, 0x26, 0xd9, 0x36, 0x13, 0xc3, 0x4f, 0xd6, 0x27, 0xae, 0xb9,
0x32, 0x3b, 0x41, 0x92, 0x2c, 0xe1, 0xc7, 0xcd, 0x77, 0xe8, 0xaa, 0x54,
0x4e, 0xf7, 0x5c, 0x0b, 0x04, 0x87, 0x65, 0xb4, 0x43, 0x18, 0xa8, 0xb2,
0xe0, 0x6d, 0x19, 0x77, 0xec, 0x5a, 0x24, 0xfa, 0x48, 0x03, 0x02, 0x03,
0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x43, 0x30, 0x82, 0x01, 0x3f, 0x30,
0x10, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01,
0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
0x04, 0x16, 0x04, 0x14, 0xa9, 0x29, 0x02, 0x39, 0x8e, 0x16, 0xc4, 0x97,
0x78, 0xcd, 0x90, 0xf9, 0x9e, 0x4f, 0x9a, 0xe1, 0x7c, 0x55, 0xaf, 0x53,
0x30, 0x19, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14,
0x02, 0x04, 0x0c, 0x1e, 0x0a, 0x00, 0x53, 0x00, 0x75, 0x00, 0x62, 0x00,
0x43, 0x00, 0x41, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06,
0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xd5, 0xf6,
0x56, 0xcb, 0x8f, 0xe8, 0xa2, 0x5c, 0x62, 0x68, 0xd1, 0x3d, 0x94, 0x90,
0x5b, 0xd7, 0xce, 0x9a, 0x18, 0xc4, 0x30, 0x56, 0x06, 0x03, 0x55, 0x1d,
0x1f, 0x04, 0x4f, 0x30, 0x4d, 0x30, 0x4b, 0xa0, 0x49, 0xa0, 0x47, 0x86,
0x45, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x70, 0x72,
0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2f, 0x4d, 0x69, 0x63, 0x52, 0x6f,
0x6f, 0x43, 0x65, 0x72, 0x41, 0x75, 0x74, 0x5f, 0x32, 0x30, 0x31, 0x30,
0x2d, 0x30, 0x36, 0x2d, 0x32, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x5a,
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x4e,
0x30, 0x4c, 0x30, 0x4a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
0x30, 0x02, 0x86, 0x3e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x2f, 0x63, 0x65, 0x72,
0x74, 0x73, 0x2f, 0x4d, 0x69, 0x63, 0x52, 0x6f, 0x6f, 0x43, 0x65, 0x72,
0x41, 0x75, 0x74, 0x5f, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x30, 0x36, 0x2d,
0x32, 0x33, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
0x01, 0x00, 0x14, 0xfc, 0x7c, 0x71, 0x51, 0xa5, 0x79, 0xc2, 0x6e, 0xb2,
0xef, 0x39, 0x3e, 0xbc, 0x3c, 0x52, 0x0f, 0x6e, 0x2b, 0x3f, 0x10, 0x13,
0x73, 0xfe, 0xa8, 0x68, 0xd0, 0x48, 0xa6, 0x34, 0x4d, 0x8a, 0x96, 0x05,
0x26, 0xee, 0x31, 0x46, 0x90, 0x61, 0x79, 0xd6, 0xff, 0x38, 0x2e, 0x45,
0x6b, 0xf4, 0xc0, 0xe5, 0x28, 0xb8, 0xda, 0x1d, 0x8f, 0x8a, 0xdb, 0x09,
0xd7, 0x1a, 0xc7, 0x4c, 0x0a, 0x36, 0x66, 0x6a, 0x8c, 0xec, 0x1b, 0xd7,
0x04, 0x90, 0xa8, 0x18, 0x17, 0xa4, 0x9b, 0xb9, 0xe2, 0x40, 0x32, 0x36,
0x76, 0xc4, 0xc1, 0x5a, 0xc6, 0xbf, 0xe4, 0x04, 0xc0, 0xea, 0x16, 0xd3,
0xac, 0xc3, 0x68, 0xef, 0x62, 0xac, 0xdd, 0x54, 0x6c, 0x50, 0x30, 0x58,
0xa6, 0xeb, 0x7c, 0xfe, 0x94, 0xa7, 0x4e, 0x8e, 0xf4, 0xec, 0x7c, 0x86,
0x73, 0x57, 0xc2, 0x52, 0x21, 0x73, 0x34, 0x5a, 0xf3, 0xa3, 0x8a, 0x56,
0xc8, 0x04, 0xda, 0x07, 0x09, 0xed, 0xf8, 0x8b, 0xe3, 0xce, 0xf4, 0x7e,
0x8e, 0xae, 0xf0, 0xf6, 0x0b, 0x8a, 0x08, 0xfb, 0x3f, 0xc9, 0x1d, 0x72,
0x7f, 0x53, 0xb8, 0xeb, 0xbe, 0x63, 0xe0, 0xe3, 0x3d, 0x31, 0x65, 0xb0,
0x81, 0xe5, 0xf2, 0xac, 0xcd, 0x16, 0xa4, 0x9f, 0x3d, 0xa8, 0xb1, 0x9b,
0xc2, 0x42, 0xd0, 0x90, 0x84, 0x5f, 0x54, 0x1d, 0xff, 0x89, 0xea, 0xba,
0x1d, 0x47, 0x90, 0x6f, 0xb0, 0x73, 0x4e, 0x41, 0x9f, 0x40, 0x9f, 0x5f,
0xe5, 0xa1, 0x2a, 0xb2, 0x11, 0x91, 0x73, 0x8a, 0x21, 0x28, 0xf0, 0xce,
0xde, 0x73, 0x39, 0x5f, 0x3e, 0xab, 0x5c, 0x60, 0xec, 0xdf, 0x03, 0x10,
0xa8, 0xd3, 0x09, 0xe9, 0xf4, 0xf6, 0x96, 0x85, 0xb6, 0x7f, 0x51, 0x88,
0x66, 0x47, 0x19, 0x8d, 0xa2, 0xb0, 0x12, 0x3d, 0x81, 0x2a, 0x68, 0x05,
0x77, 0xbb, 0x91, 0x4c, 0x62, 0x7b, 0xb6, 0xc1, 0x07, 0xc7, 0xba, 0x7a,
0x87, 0x34, 0x03, 0x0e, 0x4b, 0x62, 0x7a, 0x99, 0xe9, 0xca, 0xfc, 0xce,
0x4a, 0x37, 0xc9, 0x2d, 0xa4, 0x57, 0x7c, 0x1c, 0xfe, 0x3d, 0xdc, 0xb8,
0x0f, 0x5a, 0xfa, 0xd6, 0xc4, 0xb3, 0x02, 0x85, 0x02, 0x3a, 0xea, 0xb3,
0xd9, 0x6e, 0xe4, 0x69, 0x21, 0x37, 0xde, 0x81, 0xd1, 0xf6, 0x75, 0x19,
0x05, 0x67, 0xd3, 0x93, 0x57, 0x5e, 0x29, 0x1b, 0x39, 0xc8, 0xee, 0x2d,
0xe1, 0xcd, 0xe4, 0x45, 0x73, 0x5b, 0xd0, 0xd2, 0xce, 0x7a, 0xab, 0x16,
0x19, 0x82, 0x46, 0x58, 0xd0, 0x5e, 0x9d, 0x81, 0xb3, 0x67, 0xaf, 0x6c,
0x35, 0xf2, 0xbc, 0xe5, 0x3f, 0x24, 0xe2, 0x35, 0xa2, 0x0a, 0x75, 0x06,
0xf6, 0x18, 0x56, 0x99, 0xd4, 0x78, 0x2c, 0xd1, 0x05, 0x1b, 0xeb, 0xd0,
0x88, 0x01, 0x9d, 0xaa, 0x10, 0xf1, 0x05, 0xdf, 0xba, 0x7e, 0x2c, 0x63,
0xb7, 0x06, 0x9b, 0x23, 0x21, 0xc4, 0xf9, 0x78, 0x6c, 0xe2, 0x58, 0x17,
0x06, 0x36, 0x2b, 0x91, 0x12, 0x03, 0xcc, 0xa4, 0xd9, 0xf2, 0x2d, 0xba,
0xf9, 0x94, 0x9d, 0x40, 0xed, 0x18, 0x45, 0xf1, 0xce, 0x8a, 0x5c, 0x6b,
0x3e, 0xab, 0x03, 0xd3, 0x70, 0x18, 0x2a, 0x0a, 0x6a, 0xe0, 0x5f, 0x47,
0xd1, 0xd5, 0x63, 0x0a, 0x32, 0xf2, 0xaf, 0xd7, 0x36, 0x1f, 0x2a, 0x70,
0x5a, 0xe5, 0x42, 0x59, 0x08, 0x71, 0x4b, 0x57, 0xba, 0x7e, 0x83, 0x81,
0xf0, 0x21, 0x3c, 0xf4, 0x1c, 0xc1, 0xc5, 0xb9, 0x90, 0x93, 0x0e, 0x88,
0x45, 0x93, 0x86, 0xe9, 0xb1, 0x20, 0x99, 0xbe, 0x98, 0xcb, 0xc5, 0x95,
0xa4, 0x5d, 0x62, 0xd6, 0xa0, 0x63, 0x08, 0x20, 0xbd, 0x75, 0x10, 0x77,
0x7d, 0x3d, 0xf3, 0x45, 0xb9, 0x9f, 0x97, 0x9f, 0xcb, 0x57, 0x80, 0x6f,
0x33, 0xa9, 0x04, 0xcf, 0x77, 0xa4, 0x62, 0x1c, 0x59, 0x7e, 0xa1, 0x59,
0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b,
0xf0, 0x72, 0x64, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x04,
0x00, 0x00, 0xe4, 0x0a, 0xc4, 0x6d, 0xe8, 0x2e, 0x4c, 0x9c, 0xa3, 0x14,
0x0f, 0xc7, 0xb2, 0x00, 0x87, 0x10, 0x30, 0x82, 0x04, 0x34, 0x30, 0x82,
0x03, 0x1c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xb9, 0x41,
0x24, 0xa0, 0x18, 0x2c, 0x92, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x84,
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
0x42, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0b,
0x49, 0x73, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x4d, 0x61, 0x6e, 0x31,
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x44, 0x6f,
0x75, 0x67, 0x6c, 0x61, 0x73, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
0x04, 0x0a, 0x0c, 0x0e, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61,
0x6c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x34, 0x30, 0x32, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x2b, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63,
0x61, 0x6c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x4d, 0x61, 0x73, 0x74,
0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x31, 0x32, 0x31, 0x31,
0x31, 0x32, 0x35, 0x31, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x34, 0x31,
0x31, 0x31, 0x31, 0x31, 0x32, 0x35, 0x31, 0x5a, 0x30, 0x81, 0x84, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42,
0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0b, 0x49,
0x73, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x4d, 0x61, 0x6e, 0x31, 0x10,
0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x44, 0x6f, 0x75,
0x67, 0x6c, 0x61, 0x73, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x0c, 0x0e, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c,
0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x34, 0x30, 0x32, 0x06, 0x03, 0x55,
0x04, 0x03, 0x0c, 0x2b, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61,
0x6c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65,
0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, 0x5b, 0x3a, 0x16,
0x74, 0xee, 0x21, 0x5d, 0xae, 0x61, 0xed, 0x9d, 0x56, 0xac, 0xbd, 0xde,
0xde, 0x72, 0xf3, 0xdd, 0x7e, 0x2d, 0x4c, 0x62, 0x0f, 0xac, 0xc0, 0x6d,
0x48, 0x08, 0x11, 0xcf, 0x8d, 0x8b, 0xfb, 0x61, 0x1f, 0x27, 0xcc, 0x11,
0x6e, 0xd9, 0x55, 0x3d, 0x39, 0x54, 0xeb, 0x40, 0x3b, 0xb1, 0xbb, 0xe2,
0x85, 0x34, 0x79, 0xca, 0xf7, 0x7b, 0xbf, 0xba, 0x7a, 0xc8, 0x10, 0x2d,
0x19, 0x7d, 0xad, 0x59, 0xcf, 0xa6, 0xd4, 0xe9, 0x4e, 0x0f, 0xda, 0xae,
0x52, 0xea, 0x4c, 0x9e, 0x90, 0xce, 0xc6, 0x99, 0x0d, 0x4e, 0x67, 0x65,
0x78, 0x5d, 0xf9, 0xd1, 0xd5, 0x38, 0x4a, 0x4a, 0x7a, 0x8f, 0x93, 0x9c,
0x7f, 0x1a, 0xa3, 0x85, 0xdb, 0xce, 0xfa, 0x8b, 0xf7, 0xc2, 0xa2, 0x21,
0x2d, 0x9b, 0x54, 0x41, 0x35, 0x10, 0x57, 0x13, 0x8d, 0x6c, 0xbc, 0x29,
0x06, 0x50, 0x4a, 0x7e, 0xea, 0x99, 0xa9, 0x68, 0xa7, 0x3b, 0xc7, 0x07,
0x1b, 0x32, 0x9e, 0xa0, 0x19, 0x87, 0x0e, 0x79, 0xbb, 0x68, 0x99, 0x2d,
0x7e, 0x93, 0x52, 0xe5, 0xf6, 0xeb, 0xc9, 0x9b, 0xf9, 0x2b, 0xed, 0xb8,
0x68, 0x49, 0xbc, 0xd9, 0x95, 0x50, 0x40, 0x5b, 0xc5, 0xb2, 0x71, 0xaa,
0xeb, 0x5c, 0x57, 0xde, 0x71, 0xf9, 0x40, 0x0a, 0xdd, 0x5b, 0xac, 0x1e,
0x84, 0x2d, 0x50, 0x1a, 0x52, 0xd6, 0xe1, 0xf3, 0x6b, 0x6e, 0x90, 0x64,
0x4f, 0x5b, 0xb4, 0xeb, 0x20, 0xe4, 0x61, 0x10, 0xda, 0x5a, 0xf0, 0xea,
0xe4, 0x42, 0xd7, 0x01, 0xc4, 0xfe, 0x21, 0x1f, 0xd9, 0xb9, 0xc0, 0x54,
0x95, 0x42, 0x81, 0x52, 0x72, 0x1f, 0x49, 0x64, 0x7a, 0xc8, 0x6c, 0x24,
0xf1, 0x08, 0x70, 0x0b, 0x4d, 0xa5, 0xa0, 0x32, 0xd1, 0xa0, 0x1c, 0x57,
0xa8, 0x4d, 0xe3, 0xaf, 0xa5, 0x8e, 0x05, 0x05, 0x3e, 0x10, 0x43, 0xa1,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa6, 0x30, 0x81, 0xa3, 0x30,
0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xad, 0x91,
0x99, 0x0b, 0xc2, 0x2a, 0xb1, 0xf5, 0x17, 0x04, 0x8c, 0x23, 0xb6, 0x65,
0x5a, 0x26, 0x8e, 0x34, 0x5a, 0x63, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xad, 0x91, 0x99, 0x0b, 0xc2,
0x2a, 0xb1, 0xf5, 0x17, 0x04, 0x8c, 0x23, 0xb6, 0x65, 0x5a, 0x26, 0x8e,
0x34, 0x5a, 0x63, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03,
0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x43, 0x06,
0x03, 0x55, 0x1d, 0x1f, 0x04, 0x3c, 0x30, 0x3a, 0x30, 0x38, 0xa0, 0x36,
0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
0x77, 0x77, 0x2e, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2d,
0x62, 0x6f, 0x6f, 0x74, 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2d,
0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01,
0x01, 0x00, 0x3f, 0x7d, 0xf6, 0x76, 0xa5, 0xb3, 0x83, 0xb4, 0x2b, 0x7a,
0xd0, 0x6d, 0x52, 0x1a, 0x03, 0x83, 0xc4, 0x12, 0xa7, 0x50, 0x9c, 0x47,
0x92, 0xcc, 0xc0, 0x94, 0x77, 0x82, 0xd2, 0xae, 0x57, 0xb3, 0x99, 0x04,
0xf5, 0x32, 0x3a, 0xc6, 0x55, 0x1d, 0x07, 0xdb, 0x12, 0xa9, 0x56, 0xfa,
0xd8, 0xd4, 0x76, 0x20, 0xeb, 0xe4, 0xc3, 0x51, 0xdb, 0x9a, 0x5c, 0x9c,
0x92, 0x3f, 0x18, 0x73, 0xda, 0x94, 0x6a, 0xa1, 0x99, 0x38, 0x8c, 0xa4,
0x88, 0x6d, 0xc1, 0xfc, 0x39, 0x71, 0xd0, 0x74, 0x76, 0x16, 0x03, 0x3e,
0x56, 0x23, 0x35, 0xd5, 0x55, 0x47, 0x5b, 0x1a, 0x1d, 0x41, 0xc2, 0xd3,
0x12, 0x4c, 0xdc, 0xff, 0xae, 0x0a, 0x92, 0x9c, 0x62, 0x0a, 0x17, 0x01,
0x9c, 0x73, 0xe0, 0x5e, 0xb1, 0xfd, 0xbc, 0xd6, 0xb5, 0x19, 0x11, 0x7a,
0x7e, 0xcd, 0x3e, 0x03, 0x7e, 0x66, 0xdb, 0x5b, 0xa8, 0xc9, 0x39, 0x48,
0x51, 0xff, 0x53, 0xe1, 0x9c, 0x31, 0x53, 0x91, 0x1b, 0x3b, 0x10, 0x75,
0x03, 0x17, 0xba, 0xe6, 0x81, 0x02, 0x80, 0x94, 0x70, 0x4c, 0x46, 0xb7,
0x94, 0xb0, 0x3d, 0x15, 0xcd, 0x1f, 0x8e, 0x02, 0xe0, 0x68, 0x02, 0x8f,
0xfb, 0xf9, 0x47, 0x1d, 0x7d, 0xa2, 0x01, 0xc6, 0x07, 0x51, 0xc4, 0x9a,
0xcc, 0xed, 0xdd, 0xcf, 0xa3, 0x5d, 0xed, 0x92, 0xbb, 0xbe, 0xd1, 0xfd,
0xe6, 0xec, 0x1f, 0x33, 0x51, 0x73, 0x04, 0xbe, 0x3c, 0x72, 0xb0, 0x7d,
0x08, 0xf8, 0x01, 0xff, 0x98, 0x7d, 0xcb, 0x9c, 0xe0, 0x69, 0x39, 0x77,
0x25, 0x47, 0x71, 0x88, 0xb1, 0x8d, 0x27, 0xa5, 0x2e, 0xa8, 0xf7, 0x3f,
0x5f, 0x80, 0x69, 0x97, 0x3e, 0xa9, 0xf4, 0x99, 0x14, 0xdb, 0xce, 0x03,
0x0e, 0x0b, 0x66, 0xc4, 0x1c, 0x6d, 0xbd, 0xb8, 0x27, 0x77, 0xc1, 0x42,
0x94, 0xbd, 0xfc, 0x6a, 0x0a, 0xbc, 0x26, 0x16, 0xc4, 0xc1, 0x4c, 0x50,
0x92, 0x40, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf5, 0x8f, 0xbd, 0xf7, 0x1b, 0xe8, 0xc3, 0x7c, 0xbb, 0xd6,
0x94, 0x4e, 0x47, 0x2c, 0x45, 0x0b, 0x10, 0x43, 0x81, 0x7b, 0x97, 0x29,
0x14, 0x48, 0x7c, 0x22, 0x10, 0x33, 0xf3, 0x07, 0x9e, 0x43, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x97, 0x01, 0x57, 0xde, 0x52, 0xcd, 0xae, 0x14, 0xcf,
0x17, 0xee, 0x36, 0x98, 0x81, 0xd6, 0x24, 0x5b, 0x3a, 0x6a, 0xb6, 0x35,
0x2e, 0xab, 0xae, 0xe5, 0x88, 0xa0, 0x58, 0x4b, 0x03, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf1, 0x6b, 0x5f, 0xc3, 0x61, 0x18, 0x3f, 0x58, 0x71, 0x20,
0xe6, 0x02, 0xc0, 0xd6, 0x57, 0x73, 0xaf, 0xdf, 0xe7, 0x86, 0x12, 0x41,
0x84, 0xfa, 0x70, 0x80, 0x52, 0x58, 0xd7, 0x6d, 0x59, 0x4c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x02, 0x1f, 0x15, 0xe3, 0xa6, 0x7b, 0x75, 0xac, 0xe8,
0x84, 0x99, 0x9b, 0xed, 0xff, 0xe3, 0x42, 0x13, 0x79, 0x2a, 0x61, 0x1e,
0x40, 0xe5, 0x62, 0xe8, 0x7e, 0x6b, 0x9a, 0x0c, 0xb2, 0x82, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xa5, 0xd1, 0x09, 0xb2, 0xaf, 0xa3, 0xfa, 0x90, 0x87, 0x8f,
0x70, 0x38, 0x2b, 0x23, 0x88, 0xfc, 0xd2, 0xfe, 0xae, 0xae, 0x8a, 0x51,
0xb8, 0x0a, 0xdd, 0x04, 0x8e, 0x9f, 0x87, 0x6b, 0x2a, 0x4e
};
#endif /* !TEST_DATA_EFIVARS_0_H_ */
// vim:fenc=utf-8:tw=75:noet

View File

@ -0,0 +1,106 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* test-data-efivars-1.h - test data
* Copyright Peter Jones <pjones@redhat.com>
*/
#ifndef TEST_DATA_EFIVARS_1_H_
#define TEST_DATA_EFIVARS_1_H_
static const unsigned char test_data_efivars_1_MokListRT[] = {
0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15,
0x5c, 0x2b, 0xf0, 0x72, 0x98, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7c, 0x03, 0x00, 0x00, 0x50, 0xab, 0x5d, 0x60, 0x46, 0xe0, 0x00, 0x43,
0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23, 0x30, 0x82, 0x03, 0x68,
0x30, 0x82, 0x02, 0x50, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x00,
0x99, 0x76, 0xf2, 0xf4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x20, 0x31, 0x1e, 0x30,
0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x46, 0x65, 0x64, 0x6f,
0x72, 0x61, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f,
0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,
0x32, 0x30, 0x37, 0x31, 0x36, 0x32, 0x35, 0x35, 0x34, 0x5a, 0x17, 0x0d,
0x32, 0x32, 0x31, 0x32, 0x30, 0x35, 0x31, 0x36, 0x32, 0x35, 0x35, 0x34,
0x5a, 0x30, 0x20, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x15, 0x46, 0x65, 0x64, 0x6f, 0x72, 0x61, 0x20, 0x53, 0x65, 0x63,
0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xf5, 0xf7, 0x52,
0x81, 0xa9, 0x5c, 0x3e, 0x2b, 0xf7, 0x1d, 0x55, 0xf4, 0x5a, 0x68, 0x84,
0x2d, 0xbc, 0x8b, 0x76, 0x96, 0x85, 0x0d, 0x27, 0xb8, 0x18, 0xa5, 0xcd,
0xc1, 0x83, 0xb2, 0x8c, 0x27, 0x5d, 0x23, 0x0a, 0xd1, 0x12, 0x0a, 0x75,
0x98, 0xa2, 0xe6, 0x5d, 0x01, 0x8a, 0xf4, 0xd9, 0x9f, 0xfc, 0x70, 0xbc,
0xc3, 0xc4, 0x17, 0x7b, 0x02, 0xb5, 0x13, 0xc4, 0x51, 0x92, 0xe0, 0xc0,
0x05, 0x74, 0xb9, 0x2e, 0x3d, 0x24, 0x78, 0xa0, 0x79, 0x73, 0x94, 0xc0,
0xc2, 0x2b, 0xb2, 0x82, 0xa7, 0xf4, 0xab, 0x67, 0x4a, 0x22, 0xf3, 0x64,
0xcd, 0xc3, 0xf9, 0x0c, 0x26, 0x01, 0xbf, 0x1b, 0xd5, 0x3d, 0x39, 0xbf,
0xc9, 0xfa, 0xfb, 0x5e, 0x52, 0xb9, 0xa4, 0x48, 0xfb, 0x13, 0xbf, 0x87,
0x29, 0x0a, 0x64, 0xef, 0x21, 0x7b, 0xbc, 0x1e, 0x16, 0x7b, 0x88, 0x4f,
0xf1, 0x40, 0x2b, 0xd9, 0x22, 0x15, 0x47, 0x4e, 0x84, 0xf6, 0x24, 0x1c,
0x4d, 0x53, 0x16, 0x5a, 0xb1, 0x29, 0xbb, 0x5e, 0x7d, 0x7f, 0xc0, 0xd4,
0xe2, 0xd5, 0x79, 0xaf, 0x59, 0x73, 0x02, 0xdc, 0xb7, 0x48, 0xbf, 0xae,
0x2b, 0x70, 0xc1, 0xfa, 0x74, 0x7f, 0x79, 0xf5, 0xee, 0x23, 0xd0, 0x03,
0x05, 0xb1, 0x79, 0x18, 0x4f, 0xfd, 0x4f, 0x2f, 0xe2, 0x63, 0x19, 0x4d,
0x77, 0xba, 0xc1, 0x2c, 0x8b, 0xb3, 0xd9, 0x05, 0x2e, 0xd9, 0xd8, 0xb6,
0x51, 0x13, 0xbf, 0xce, 0x36, 0x67, 0x97, 0xe4, 0xad, 0x58, 0x56, 0x07,
0xab, 0xd0, 0x8c, 0x66, 0x12, 0x49, 0xdc, 0x91, 0x68, 0xb4, 0xc8, 0xea,
0xdd, 0x9c, 0xc0, 0x81, 0xc6, 0x91, 0x5b, 0xdb, 0x12, 0x78, 0xdb, 0xff,
0xc1, 0xaf, 0x08, 0x16, 0xfc, 0x70, 0x13, 0x97, 0x5b, 0x57, 0xad, 0x6b,
0x44, 0x98, 0x7e, 0x1f, 0xec, 0xed, 0x46, 0x66, 0x95, 0x0f, 0x05, 0x55,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa8, 0x30, 0x81, 0xa5, 0x30,
0x4e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
0x42, 0x30, 0x40, 0x30, 0x3e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
0x07, 0x30, 0x02, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
0x2f, 0x66, 0x65, 0x64, 0x6f, 0x72, 0x61, 0x70, 0x72, 0x6f, 0x6a, 0x65,
0x63, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x69, 0x6b, 0x69, 0x2f,
0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2f, 0x53, 0x65, 0x63,
0x75, 0x72, 0x65, 0x42, 0x6f, 0x6f, 0x74, 0x30, 0x1f, 0x06, 0x03, 0x55,
0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xfd, 0xe3, 0x25, 0x99,
0xc2, 0xd6, 0x1d, 0xb1, 0xbf, 0x58, 0x07, 0x33, 0x5d, 0x7b, 0x20, 0xe4,
0xcd, 0x96, 0x3b, 0x42, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
0x03, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
0xfd, 0xe3, 0x25, 0x99, 0xc2, 0xd6, 0x1d, 0xb1, 0xbf, 0x58, 0x07, 0x33,
0x5d, 0x7b, 0x20, 0xe4, 0xcd, 0x96, 0x3b, 0x42, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
0x82, 0x01, 0x01, 0x00, 0x37, 0x77, 0xf0, 0x3a, 0x41, 0xa2, 0x1c, 0x9f,
0x71, 0x3b, 0xd6, 0x9b, 0x95, 0xb5, 0x15, 0xdf, 0x4a, 0xb6, 0xf4, 0xd1,
0x51, 0xba, 0x0d, 0x04, 0xda, 0x9c, 0xb2, 0x23, 0xf0, 0xf3, 0x34, 0x59,
0x8d, 0xb8, 0xd4, 0x9a, 0x75, 0x74, 0x65, 0x80, 0x17, 0x61, 0x3a, 0xc1,
0x96, 0x7f, 0xa7, 0xc1, 0x2b, 0xd3, 0x1a, 0xd6, 0x60, 0x3c, 0x71, 0x3a,
0xa4, 0xc4, 0xe3, 0x39, 0x03, 0x02, 0x15, 0x12, 0x08, 0x1f, 0x4e, 0xcd,
0x97, 0x50, 0xf8, 0xff, 0x50, 0xcc, 0xb6, 0x3e, 0x03, 0x7d, 0x7a, 0xe7,
0x82, 0x7a, 0xc2, 0x67, 0xbe, 0xc9, 0x0e, 0x11, 0x0f, 0x16, 0x2e, 0x1e,
0xa9, 0xf2, 0x6e, 0xfe, 0x04, 0xbd, 0xea, 0x9e, 0xf4, 0xa9, 0xb3, 0xd9,
0xd4, 0x61, 0x57, 0x08, 0x87, 0xc4, 0x98, 0xd8, 0xa2, 0x99, 0x64, 0xde,
0x15, 0x54, 0x8d, 0x57, 0x79, 0x14, 0x1f, 0xfa, 0x0d, 0x4d, 0x6b, 0xcd,
0x98, 0x35, 0xf5, 0x0c, 0x06, 0xbd, 0xf3, 0x31, 0xd6, 0xfe, 0x05, 0x1f,
0x60, 0x90, 0xb6, 0x1e, 0x10, 0xf7, 0x24, 0xe0, 0x3c, 0xf6, 0x33, 0x50,
0xcd, 0x44, 0xc2, 0x71, 0x18, 0x51, 0xbd, 0x18, 0x31, 0x81, 0x1e, 0x32,
0xe1, 0xe6, 0x9f, 0xf9, 0x9c, 0x02, 0x53, 0xb4, 0xe5, 0x6a, 0x41, 0xd6,
0x65, 0xb4, 0x2e, 0xf1, 0xcf, 0xb3, 0xb8, 0x82, 0xb0, 0xa3, 0x96, 0xe2,
0x24, 0xd8, 0x83, 0xae, 0x06, 0x5b, 0xb3, 0x24, 0x74, 0x4d, 0xd1, 0xa4,
0x0a, 0x1d, 0x0a, 0x32, 0x1b, 0x75, 0xa2, 0x96, 0xd1, 0x0e, 0x3e, 0xe1,
0x30, 0xc3, 0x18, 0xe8, 0xcb, 0x53, 0xc4, 0x0b, 0x00, 0xad, 0x7e, 0xad,
0xc8, 0x49, 0x41, 0xef, 0x97, 0x69, 0xbd, 0x13, 0x5f, 0xef, 0xef, 0x3c,
0xda, 0x60, 0x05, 0xd8, 0x92, 0xfc, 0xda, 0x6a, 0xea, 0x48, 0x3f, 0x0e,
0x3e, 0x73, 0x77, 0xfd, 0xa6, 0x89, 0xe9, 0x3f
};
static const unsigned char test_data_efivars_1_MokListXRT[] = {
0x26, 0x16, 0xc4, 0xc1, 0x4c, 0x50, 0x92, 0x40, 0xac, 0xa9, 0x41,
0xf9, 0x36, 0x93, 0x43, 0x28, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x50, 0xab, 0x5d, 0x60, 0x46,
0xe0, 0x00, 0x43, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char test_data_efivars_1_SbatLevelRT[] = {
0x73, 0x62, 0x61, 0x74, 0x2c, 0x31, 0x2c, 0x32, 0x30,
0x32, 0x31, 0x30, 0x33, 0x30, 0x32, 0x31, 0x38, 0x0a
};
#endif /* !TEST_DATA_EFIVARS_1_H_ */
// vim:fenc=utf-8:tw=75:noet

View File

@ -8,7 +8,14 @@
#ifndef TEST_H_ #ifndef TEST_H_
#define TEST_H_ #define TEST_H_
#define _GNU_SOURCE
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#if defined(__aarch64__) #if defined(__aarch64__)
#include <aarch64/efibind.h> #include <aarch64/efibind.h>
@ -36,17 +43,368 @@
#include <stdlib.h> #include <stdlib.h>
#define ZeroMem(buf, sz) memset(buf, 0, sz) #include <assert.h>
#define SetMem(buf, sz, value) memset(buf, value, sz)
#define CopyMem(dest, src, len) memcpy(dest, src, len) #include <efiui.h>
#define CompareMem(dest, src, len) memcmp(dest, src, len) #include <efilib.h>
#include <efivar/efivar.h>
#include <assert.h> #include <assert.h>
#define AllocateZeroPool(x) calloc(1, (x)) #include "list.h"
#define AllocatePool(x) malloc(x)
#define FreePool(x) free(x) INTN StrCmp(IN CONST CHAR16 *s1,
#define ReallocatePool(old, oldsz, newsz) realloc(old, newsz) IN CONST CHAR16 *s2);
INTN StrnCmp(IN CONST CHAR16 *s1,
IN CONST CHAR16 *s2,
IN UINTN len);
VOID StrCpy(IN CHAR16 *Dest,
IN CONST CHAR16 *Src);
VOID StrnCpy(IN CHAR16 *Dest,
IN CONST CHAR16 *Src,
IN UINTN Len);
CHAR16 *StrDuplicate(IN CONST CHAR16 *Src);
UINTN StrLen(IN CONST CHAR16 *s1);
UINTN StrSize(IN CONST CHAR16 *s1);
VOID StrCat(IN CHAR16 *Dest, IN CONST CHAR16 *Src);
CHAR16 *DevicePathToStr(EFI_DEVICE_PATH *DevPath);
extern EFI_SYSTEM_TABLE *ST;
extern EFI_BOOT_SERVICES *BS;
extern EFI_RUNTIME_SERVICES *RT;
#define GUID_FMT "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
#define GUID_ARGS(guid) \
((EFI_GUID)guid).Data1, ((EFI_GUID)guid).Data2, ((EFI_GUID)guid).Data3, \
((EFI_GUID)guid).Data4[1], ((EFI_GUID)guid).Data4[0], \
((EFI_GUID)guid).Data4[2], ((EFI_GUID)guid).Data4[3], \
((EFI_GUID)guid).Data4[4], ((EFI_GUID)guid).Data4[5], \
((EFI_GUID)guid).Data4[6], ((EFI_GUID)guid).Data4[7]
static inline INT64
guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1)
{
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s(): Comparing "GUID_FMT" to "GUID_FMT"\n",
__FILE__, __LINE__-1, __func__,
GUID_ARGS(*guid0), GUID_ARGS(*guid1));
#endif
if (guid0->Data1 != guid1->Data1) {
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
__FILE__, __LINE__-1, __func__,
(INT64)guid0->Data1, (INT64)guid1->Data1,
(INT64)guid0->Data1 - (INT64)guid1->Data1);
#endif
return (INT64)guid0->Data1 - (INT64)guid1->Data1;
}
if (guid0->Data2 != guid1->Data2) {
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
__FILE__, __LINE__-1, __func__,
(INT64)guid0->Data2, (INT64)guid1->Data2,
(INT64)guid0->Data2 - (INT64)guid1->Data2);
#endif
return (INT64)guid0->Data2 - (INT64)guid1->Data2;
}
if (guid0->Data3 != guid1->Data3) {
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
__FILE__, __LINE__-1, __func__,
(INT64)guid0->Data3, (INT64)guid1->Data3,
(INT64)guid0->Data3 - (INT64)guid1->Data3);
#endif
return (INT64)guid0->Data3 - (INT64)guid1->Data3;
}
/*
* This is out of order because that's also true in the string
* representation of it.
*/
if (guid0->Data4[1] != guid1->Data4[1]) {
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
__FILE__, __LINE__-1, __func__,
(INT64)guid0->Data4[1], (INT64)guid1->Data4[1],
(INT64)guid0->Data4[1] - (INT64)guid1->Data4[1]);
#endif
return (INT64)guid0->Data4[1] - (INT64)guid1->Data4[1];
}
if (guid0->Data4[0] != guid1->Data4[0]) {
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
__FILE__, __LINE__-1, __func__,
(INT64)guid0->Data4[0], (INT64)guid1->Data4[0],
(INT64)guid0->Data4[0] - (INT64)guid1->Data4[0]);
#endif
return (INT64)guid0->Data4[0] - (INT64)guid1->Data4[0];
}
for (UINTN i = 2; i < 8; i++) {
if (guid0->Data4[i] != guid1->Data4[i]) {
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n",
__FILE__, __LINE__-1, __func__,
(INT64)guid0->Data4[i], (INT64)guid1->Data4[i],
(INT64)guid0->Data4[i] - (INT64)guid1->Data4[i]);
#endif
return (INT64)guid0->Data4[i] - (INT64)guid1->Data4[i];
}
}
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s(): returning 0x0\n",
__FILE__, __LINE__-1, __func__);
#endif
return 0;
}
static inline int
guidcmp(const EFI_GUID * const guid0, const EFI_GUID * const guid1)
{
INT64 cmp;
int ret;
EFI_GUID empty;
const EFI_GUID * const guida = guid0 ? guid0 : &empty;
const EFI_GUID * const guidb = guid1 ? guid1 : &empty;
SetMem(&empty, sizeof(EFI_GUID), 0);
cmp = guidcmp_helper(guida, guidb);
ret = cmp < 0 ? -1 : (cmp > 0 ? 1 : 0);
#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
printf("%s:%d:%s():CompareGuid("GUID_FMT","GUID_FMT")->%lld (%d)\n",
__FILE__, __LINE__-1, __func__,
GUID_ARGS(*guida), GUID_ARGS(*guidb), cmp, ret);
#endif
return ret;
}
#define CompareGuid(a, b) guidcmp(a, b)
static inline char *
efi_strerror(EFI_STATUS status)
{
static char buf0[1024];
static char buf1[1024];
char *out;
static int n;
out = n++ % 2 ? buf0 : buf1;
if (n > 1)
n -= 2;
SetMem(out, 1024, 0);
switch (status) {
case EFI_SUCCESS:
strcpy(out, "EFI_SUCCESS");
break;
case EFI_LOAD_ERROR:
strcpy(out, "EFI_LOAD_ERROR");
break;
case EFI_INVALID_PARAMETER:
strcpy(out, "EFI_INVALID_PARAMETER");
break;
case EFI_UNSUPPORTED:
strcpy(out, "EFI_UNSUPPORTED");
break;
case EFI_BAD_BUFFER_SIZE:
strcpy(out, "EFI_BAD_BUFFER_SIZE");
break;
case EFI_BUFFER_TOO_SMALL:
strcpy(out, "EFI_BUFFER_TOO_SMALL");
break;
case EFI_NOT_READY:
strcpy(out, "EFI_NOT_READY");
break;
case EFI_DEVICE_ERROR:
strcpy(out, "EFI_DEVICE_ERROR");
break;
case EFI_WRITE_PROTECTED:
strcpy(out, "EFI_WRITE_PROTECTED");
break;
case EFI_OUT_OF_RESOURCES:
strcpy(out, "EFI_OUT_OF_RESOURCES");
break;
case EFI_VOLUME_CORRUPTED:
strcpy(out, "EFI_VOLUME_CORRUPTED");
break;
case EFI_VOLUME_FULL:
strcpy(out, "EFI_VOLUME_FULL");
break;
case EFI_NO_MEDIA:
strcpy(out, "EFI_NO_MEDIA");
break;
case EFI_MEDIA_CHANGED:
strcpy(out, "EFI_MEDIA_CHANGED");
break;
case EFI_NOT_FOUND:
strcpy(out, "EFI_NOT_FOUND");
break;
case EFI_ACCESS_DENIED:
strcpy(out, "EFI_ACCESS_DENIED");
break;
case EFI_NO_RESPONSE:
strcpy(out, "EFI_NO_RESPONSE");
break;
case EFI_NO_MAPPING:
strcpy(out, "EFI_NO_MAPPING");
break;
case EFI_TIMEOUT:
strcpy(out, "EFI_TIMEOUT");
break;
case EFI_NOT_STARTED:
strcpy(out, "EFI_NOT_STARTED");
break;
case EFI_ALREADY_STARTED:
strcpy(out, "EFI_ALREADY_STARTED");
break;
case EFI_ABORTED:
strcpy(out, "EFI_ABORTED");
break;
case EFI_ICMP_ERROR:
strcpy(out, "EFI_ICMP_ERROR");
break;
case EFI_TFTP_ERROR:
strcpy(out, "EFI_TFTP_ERROR");
break;
case EFI_PROTOCOL_ERROR:
strcpy(out, "EFI_PROTOCOL_ERROR");
break;
case EFI_INCOMPATIBLE_VERSION:
strcpy(out, "EFI_INCOMPATIBLE_VERSION");
break;
case EFI_SECURITY_VIOLATION:
strcpy(out, "EFI_SECURITY_VIOLATION");
break;
case EFI_CRC_ERROR:
strcpy(out, "EFI_CRC_ERROR");
break;
case EFI_END_OF_MEDIA:
strcpy(out, "EFI_END_OF_MEDIA");
break;
case EFI_END_OF_FILE:
strcpy(out, "EFI_END_OF_FILE");
break;
case EFI_INVALID_LANGUAGE:
strcpy(out, "EFI_INVALID_LANGUAGE");
break;
case EFI_COMPROMISED_DATA:
strcpy(out, "EFI_COMPROMISED_DATA");
break;
default:
sprintf(out, "0x%lx", status);
break;
}
return out;
}
static inline char *
Str2str(CHAR16 *in)
{
static char buf0[1024];
static char buf1[1024];
char *out;
static int n;
out = n++ % 2 ? buf0 : buf1;
if (n > 1)
n -= 2;
SetMem(out, 1024, 0);
for (UINTN i = 0; i < 1023 && in[i]; i++)
out[i] = in[i];
return out;
}
static inline char *
format_var_attrs(UINT32 attr)
{
static char buf0[1024];
static char buf1[1024];
static int n;
int pos = 0;
bool found = false;
char *buf, *bufp;
buf = n++ % 2 ? buf0 : buf1;
if (n > 1)
n -= 2;
SetMem(buf, sizeof(buf0), 0);
bufp = &buf[0];
for (UINT32 i = 0; i < 8; i++) {
switch((1ul << i) & attr) {
case EFI_VARIABLE_NON_VOLATILE:
if (found)
bufp = stpcpy(bufp, "|");
bufp = stpcpy(bufp, "NV");
attr &= ~EFI_VARIABLE_NON_VOLATILE;
found = true;
break;
case EFI_VARIABLE_BOOTSERVICE_ACCESS:
if (found)
bufp = stpcpy(bufp, "|");
bufp = stpcpy(bufp, "BS");
attr &= ~EFI_VARIABLE_BOOTSERVICE_ACCESS;
found = true;
break;
case EFI_VARIABLE_RUNTIME_ACCESS:
if (found)
bufp = stpcpy(bufp, "|");
bufp = stpcpy(bufp, "RT");
attr &= ~EFI_VARIABLE_RUNTIME_ACCESS;
found = true;
break;
case EFI_VARIABLE_HARDWARE_ERROR_RECORD:
if (found)
bufp = stpcpy(bufp, "|");
bufp = stpcpy(bufp, "HER");
attr &= ~EFI_VARIABLE_HARDWARE_ERROR_RECORD;
found = true;
break;
case EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS:
if (found)
bufp = stpcpy(bufp, "|");
bufp = stpcpy(bufp, "AUTH");
attr &= ~EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
found = true;
break;
case EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS:
if (found)
bufp = stpcpy(bufp, "|");
bufp = stpcpy(bufp, "TIMEAUTH");
attr &= ~EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
found = true;
break;
case EFI_VARIABLE_APPEND_WRITE:
if (found)
bufp = stpcpy(bufp, "|");
bufp = stpcpy(bufp, "APPEND");
attr &= ~EFI_VARIABLE_APPEND_WRITE;
found = true;
break;
case EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS:
if (found)
bufp = stpcpy(bufp, "|");
bufp = stpcpy(bufp, "ENHANCED_AUTH");
attr &= ~EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS;
found = true;
break;
default:
break;
}
}
if (attr) {
if (found)
bufp = stpcpy(bufp, "|");
snprintf(bufp, bufp - buf - 1, "0x%x", attr);
}
return &buf[0];
}
extern int debug; extern int debug;
#ifdef dprint #ifdef dprint
@ -54,6 +412,14 @@ extern int debug;
#define dprint(fmt, ...) {( if (debug) printf("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); }) #define dprint(fmt, ...) {( if (debug) printf("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); })
#endif #endif
void EFIAPI mock_efi_void();
EFI_STATUS EFIAPI mock_efi_success();
EFI_STATUS EFIAPI mock_efi_unsupported();
EFI_STATUS EFIAPI mock_efi_not_found();
void init_efi_system_table(void);
void reset_efi_system_table(void);
void print_traceback(int skip);
#define eassert(cond, fmt, ...) \ #define eassert(cond, fmt, ...) \
({ \ ({ \
if (!(cond)) { \ if (!(cond)) { \
@ -65,10 +431,10 @@ extern int debug;
#define assert_true_as_expr(a, status, fmt, ...) \ #define assert_true_as_expr(a, status, fmt, ...) \
({ \ ({ \
int rc_ = 0; \ __typeof__(status) rc_ = 0; \
if (!(a)) { \ if (!(a)) { \
printf("%s:%d:got %lld, expected nonzero " fmt, \ printf("%s:%d:got %lld, expected nonzero " fmt, \
__func__, __LINE__, (long long)(a), \ __func__, __LINE__, (long long)(uintptr_t)(a), \
##__VA_ARGS__); \ ##__VA_ARGS__); \
printf("%s:%d:Assertion `%s' failed.\n", __func__, \ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
__LINE__, __stringify(!(a))); \ __LINE__, __stringify(!(a))); \
@ -80,7 +446,7 @@ extern int debug;
#define assert_false_as_expr(a, status, fmt, ...) \ #define assert_false_as_expr(a, status, fmt, ...) \
({ \ ({ \
int rc_ = 0; \ __typeof__(status) rc_ = (__typeof__(status))0; \
if (a) { \ if (a) { \
printf("%s:%d:got %lld, expected zero " fmt, __func__, \ printf("%s:%d:got %lld, expected zero " fmt, __func__, \
__LINE__, (long long)(a), ##__VA_ARGS__); \ __LINE__, (long long)(a), ##__VA_ARGS__); \
@ -94,7 +460,7 @@ extern int debug;
#define assert_positive_as_expr(a, status, fmt, ...) \ #define assert_positive_as_expr(a, status, fmt, ...) \
({ \ ({ \
int rc_ = 0; \ __typeof__(status) rc_ = (__typeof__(status))0; \
if ((a) <= 0) { \ if ((a) <= 0) { \
printf("%s:%d:got %lld, expected > 0 " fmt, __func__, \ printf("%s:%d:got %lld, expected > 0 " fmt, __func__, \
__LINE__, (long long)(a), ##__VA_ARGS__); \ __LINE__, (long long)(a), ##__VA_ARGS__); \
@ -107,7 +473,7 @@ extern int debug;
#define assert_negative_as_expr(a, status, fmt, ...) \ #define assert_negative_as_expr(a, status, fmt, ...) \
({ \ ({ \
int rc_ = 0; \ __typeof__(status) rc_ = (__typeof__(status))0; \
if ((a) >= 0) { \ if ((a) >= 0) { \
printf("%s:%d:got %lld, expected < 0 " fmt, __func__, \ printf("%s:%d:got %lld, expected < 0 " fmt, __func__, \
__LINE__, (long long)(a), ##__VA_ARGS__); \ __LINE__, (long long)(a), ##__VA_ARGS__); \
@ -120,7 +486,7 @@ extern int debug;
#define assert_equal_as_expr(a, b, status, fmt, ...) \ #define assert_equal_as_expr(a, b, status, fmt, ...) \
({ \ ({ \
int rc_ = 0; \ __typeof__(status) rc_ = (__typeof__(status))0; \
if (!((a) == (b))) { \ if (!((a) == (b))) { \
printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \ printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \
##__VA_ARGS__); \ ##__VA_ARGS__); \
@ -131,9 +497,22 @@ extern int debug;
rc_; \ rc_; \
}) })
#define assert_not_equal_as_expr(a, b, status, fmt, ...) \
({ \
__typeof__(status) rc_ = (__typeof__(status))0; \
if (!((a) != (b))) { \
printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \
##__VA_ARGS__); \
printf("%s:%d:Assertion `%s' failed.\n", __func__, \
__LINE__, __stringify(a != b)); \
rc_ = status; \
} \
rc_; \
})
#define assert_as_expr(cond, status, fmt, ...) \ #define assert_as_expr(cond, status, fmt, ...) \
({ \ ({ \
int rc_ = 0; \ __typeof__(status) rc_ = (__typeof__(status))0; \
if (!(cond)) { \ if (!(cond)) { \
printf("%s:%d:" fmt, __func__, __LINE__, \ printf("%s:%d:" fmt, __func__, __LINE__, \
##__VA_ARGS__); \ ##__VA_ARGS__); \
@ -146,7 +525,8 @@ extern int debug;
#define assert_true_return(a, status, fmt, ...) \ #define assert_true_return(a, status, fmt, ...) \
({ \ ({ \
int rc_ = assert_true_as_expr(a, status, fmt, ##__VA_ARGS__); \ __typeof__(status) rc_ = \
assert_true_as_expr(a, status, fmt, ##__VA_ARGS__); \
if (rc_ != 0) \ if (rc_ != 0) \
return rc_; \ return rc_; \
}) })
@ -154,7 +534,8 @@ extern int debug;
#define assert_false_return(a, status, fmt, ...) \ #define assert_false_return(a, status, fmt, ...) \
({ \ ({ \
int rc_ = assert_false_as_expr(a, status, fmt, ##__VA_ARGS__); \ __typeof__(status) rc_ = \
assert_false_as_expr(a, status, fmt, ##__VA_ARGS__); \
if (rc_ != 0) \ if (rc_ != 0) \
return rc_; \ return rc_; \
}) })
@ -162,31 +543,40 @@ extern int debug;
#define assert_positive_return(a, status, fmt, ...) \ #define assert_positive_return(a, status, fmt, ...) \
({ \ ({ \
int rc_ = assert_positive_as_expr(a, status, fmt, \ __typeof__(status) rc_ = assert_positive_as_expr( \
##__VA_ARGS__); \ a, status, fmt, ##__VA_ARGS__); \
if (rc_ != 0) \ if (rc_ != 0) \
return rc_; \ return rc_; \
}) })
#define assert_negative_return(a, status, fmt, ...) \ #define assert_negative_return(a, status, fmt, ...) \
({ \ ({ \
int rc_ = assert_negative_as_expr(a, status, fmt, \ __typeof__(status) rc_ = assert_negative_as_expr( \
##__VA_ARGS__); \ a, status, fmt, ##__VA_ARGS__); \
if (rc_ != 0) \ if (rc_ != 0) \
return rc_; \ return rc_; \
}) })
#define assert_equal_return(a, b, status, fmt, ...) \ #define assert_equal_return(a, b, status, fmt, ...) \
({ \ ({ \
int rc_ = assert_equal_as_expr(a, b, status, fmt, \ __typeof__(status) rc_ = assert_equal_as_expr( \
##__VA_ARGS__); \ a, b, status, fmt, ##__VA_ARGS__); \
if (rc_ != 0) \
return rc_; \
})
#define assert_not_equal_return(a, b, status, fmt, ...) \
({ \
__typeof__(status) rc_ = assert_not_equal_as_expr( \
a, b, status, fmt, ##__VA_ARGS__); \
if (rc_ != 0) \ if (rc_ != 0) \
return rc_; \ return rc_; \
}) })
#define assert_return(cond, status, fmt, ...) \ #define assert_return(cond, status, fmt, ...) \
({ \ ({ \
int rc_ = assert_as_expr(cond, status, fmt, ##__VA_ARGS__); \ __typeof__(status) rc_ = \
assert_as_expr(cond, status, fmt, ##__VA_ARGS__); \
if (rc_ != 0) \ if (rc_ != 0) \
return rc_; \ return rc_; \
}) })
@ -213,6 +603,41 @@ extern int debug;
} \ } \
}) })
#define assert_not_equal_goto(a, b, label, fmt, ...) \
({ \
if (!((a) != (b))) { \
printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \
##__VA_ARGS__); \
printf("%s:%d:Assertion `%s' failed.\n", __func__, \
__LINE__, __stringify(a != b)); \
goto label; \
} \
})
#define assert_true_goto(a, label, fmt, ...) \
({ \
if (!(a)) { \
printf("%s:%d:" fmt, __func__, __LINE__, (a), \
##__VA_ARGS__); \
printf("%s:%d:Assertion `%s' failed.\n", __func__, \
__LINE__, __stringify(!(a))); \
goto label; \
} \
})
#define assert_nonzero_goto(a, ...) assert_true_goto(a, ##__VA_ARGS__)
#define assert_false_goto(a, label, fmt, ...) \
({ \
if (a) { \
printf("%s:%d:" fmt, __func__, __LINE__, (a), \
##__VA_ARGS__); \
printf("%s:%d:Assertion `%s' failed.\n", __func__, \
__LINE__, __stringify(a)); \
goto label; \
} \
})
#define assert_zero_goto(a, ...) assert_false_goto(a, ##__VA_ARGS__)
#define assert_negative_goto(a, label, fmt, ...) \ #define assert_negative_goto(a, label, fmt, ...) \
({ \ ({ \
int rc_ = assert_negative_as_expr(a, -1, fmt, ##__VA_ARGS__); \ int rc_ = assert_negative_as_expr(a, -1, fmt, ##__VA_ARGS__); \

View File

@ -5,21 +5,39 @@
.SUFFIXES: .SUFFIXES:
include Make.defaults
CC = gcc CC = gcc
VALGRIND ?= VALGRIND ?=
DEBUG_PRINTS ?= 0 DEBUG_PRINTS ?= 0
CFLAGS = -O2 -ggdb -std=gnu11 \ OPTIMIZATIONS=-O2 -ggdb
CFLAGS_LTO =
CFLAGS_GCOV =
CFLAGS = $(OPTIMIZATIONS) -std=gnu11 \
-isystem $(TOPDIR)/include/system \ -isystem $(TOPDIR)/include/system \
$(EFI_INCLUDES) \ $(EFI_INCLUDES) \
-Iinclude -iquote . \ -Iinclude -iquote . \
-fshort-wchar -flto -fno-builtin \ -isystem /usr/include \
-Wall \ -isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include) \
-Wextra \ $(ARCH_CFLAGS) \
$(CFLAGS_LTO) \
$(CFLAGS_GCOV) \
-fshort-wchar \
-fno-builtin \
-rdynamic \
-fno-inline \
-fno-eliminate-unused-debug-types \
-fno-eliminate-unused-debug-symbols \
-gpubnames \
-grecord-gcc-switches \
$(if $(findstring clang,$(CC)),-Wno-unknown-warning-option) \
$(DEFAULT_WARNFLAGS) \
-Wsign-compare \ -Wsign-compare \
-Wno-deprecated-declarations \ -Wno-deprecated-declarations \
$(if $(findstring gcc,$(CC)),-Wno-unused-but-set-variable) \
-Wno-unused-variable \
-Wno-pointer-sign \ -Wno-pointer-sign \
-Wno-unused \ $(DEFAULT_WERRFLAGS) \
-Werror \
-Werror=nonnull \ -Werror=nonnull \
$(shell $(CC) -Werror=nonnull-compare -E -x c /dev/null >/dev/null 2>&1 && echo -Werror=nonnull-compare) \ $(shell $(CC) -Werror=nonnull-compare -E -x c /dev/null >/dev/null 2>&1 && echo -Werror=nonnull-compare) \
$(ARCH_DEFINES) \ $(ARCH_DEFINES) \
@ -28,29 +46,79 @@ CFLAGS = -O2 -ggdb -std=gnu11 \
-DSHIM_UNIT_TEST \ -DSHIM_UNIT_TEST \
"-DDEFAULT_DEBUG_PRINT_STATE=$(DEBUG_PRINTS)" "-DDEFAULT_DEBUG_PRINT_STATE=$(DEBUG_PRINTS)"
$(wildcard test-*.c) :: %.c : test-random.h # On some systems (e.g. Arch Linux), limits.h is in the "include-fixed" instead
$(patsubst %.c,%,$(wildcard test-*.c)) :: | test-random.h # of the "include" directory
$(patsubst %.c,%.o,$(wildcard test-*.c)) : | test-random.h CFLAGS += -isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include-fixed)
export CFLAGS_LTO CFLAGS_GCOV
libefi-test.a :
$(MAKE) -C gnu-efi \
COMPILER="$(COMPILER)" \
CC="$(CC)" \
ARCH=$(ARCH_GNUEFI) \
TOPDIR=$(TOPDIR)/gnu-efi \
CFLAGS_LTO="$(CFLAGS_LTO)" \
CFLAGS_GCOV="$(CFLAGS_GCOV)" \
-f $(TOPDIR)/gnu-efi/Makefile \
clean lib
mv gnu-efi/$(ARCH)/lib/libefi.a $@
$(MAKE) -C gnu-efi \
COMPILER="$(COMPILER)" \
ARCH=$(ARCH_GNUEFI) \
TOPDIR=$(TOPDIR)/gnu-efi \
CFLAGS_LTO="$(CFLAGS_LTO)" \
CFLAGS_GCOV="$(CFLAGS_GCOV)" \
-f $(TOPDIR)/gnu-efi/Makefile \
clean
test-random.h: test-random.h:
dd if=/dev/urandom bs=512 count=17 of=random.bin dd if=/dev/urandom bs=512 count=17 of=random.bin
xxd -i random.bin test-random.h xxd -i random.bin test-random.h
test-sbat_FILES = csv.c $(wildcard test-*.c) :: %.c : test-random.h
$(patsubst %.c,%,$(wildcard test-*.c)) :: | test-random.h
$(patsubst %.c,%.o,$(wildcard test-*.c)) : | test-random.h
test-load-options_FILES = lib/guid.c
test-load-options : CFLAGS+=-DHAVE_SHIM_LOCK_GUID
test-mock-variables_FILES = mok.c globals.c tpm.c lib/guid.c lib/variables.c mock-variables.c
test-mock-variables: CFLAGS+=-DHAVE_SHIM_LOCK_GUID
test-mok-mirror_FILES = mok.c globals.c tpm.c lib/guid.c lib/variables.c mock-variables.c
test-mok-mirror: CFLAGS+=-DHAVE_START_IMAGE -DHAVE_SHIM_LOCK_GUID
test-sbat_FILES = csv.c lib/variables.c lib/guid.c
test-sbat :: CFLAGS+=-DHAVE_GET_VARIABLE -DHAVE_GET_VARIABLE_ATTR -DHAVE_SHIM_LOCK_GUID
test-str_FILES = lib/string.c test-str_FILES = lib/string.c
tests := $(patsubst %.c,%,$(wildcard test-*.c)) tests := $(patsubst %.c,%,$(wildcard test-*.c))
$(tests) :: test-% : | libefi-test.a
$(tests) :: test-% : test.c test-%.c $(test-%_FILES) $(tests) :: test-% : test.c test-%.c $(test-%_FILES)
$(CC) $(CFLAGS) -o $@ $^ $(wildcard $*.c) $(test-$*_FILES) $(CC) $(CFLAGS) -o $@ $(sort $^ $(wildcard $*.c) $(test-$*_FILES)) libefi-test.a -lefivar
$(VALGRIND) ./$@ $(VALGRIND) ./$@
test : $(tests) test : $(tests)
$(MAKE) -f include/test.mk test-clean
clean : test-lto : CFLAGS_LTO+=-flto
@rm -vf test-random.h random.bin test-lto : $(tests)
$(MAKE) -f include/test.mk test-clean
all : clean test test-coverage : CFLAGS_GCOV+=--coverage
test-coverage : $(tests)
test-clean :
@rm -vf test-random.h random.bin libefi-test.a
@rm -vf *.gcda *.gcno *.gcov vgcore.*
clean : test-clean
all : test-clean test
.PHONY: $(tests) all test clean .PHONY: $(tests) all test clean
.SECONDARY: random.bin .SECONDARY: random.bin

View File

@ -81,31 +81,4 @@ is_all_nuls(UINT8 *data, UINTN data_size)
return true; return true;
} }
static inline UINTN
__attribute__((__unused__))
count_ucs2_strings(UINT8 *data, UINTN data_size)
{
UINTN pos = 0;
UINTN last_nul_pos = 0;
UINTN num_nuls = 0;
UINTN i;
if (data_size % 2 != 0)
return 0;
for (i = pos; i < data_size; i++) {
if (i % 2 != 0) {
if (data[i] != 0)
return 0;
} else if (data[i] == 0) {
last_nul_pos = i;
num_nuls++;
}
pos = i;
}
if (num_nuls > 0 && last_nul_pos != pos - 1)
return 0;
return num_nuls;
}
#endif /* SHIM_UCS2_H */ #endif /* SHIM_UCS2_H */

View File

@ -34,8 +34,11 @@ console_get_keystroke(EFI_INPUT_KEY *key)
UINTN EventIndex; UINTN EventIndex;
EFI_STATUS efi_status; EFI_STATUS efi_status;
if (!ci)
return EFI_UNSUPPORTED;
do { do {
gBS->WaitForEvent(1, &ci->WaitForKey, &EventIndex); BS->WaitForEvent(1, &ci->WaitForKey, &EventIndex);
efi_status = ci->ReadKeyStroke(ci, key); efi_status = ci->ReadKeyStroke(ci, key);
} while (efi_status == EFI_NOT_READY); } while (efi_status == EFI_NOT_READY);
@ -109,6 +112,7 @@ console_print_at(UINTN col, UINTN row, const CHAR16 *fmt, ...)
if (!console_text_mode) if (!console_text_mode)
setup_console(1); setup_console(1);
if (co)
co->SetCursorPosition(co, col, row); co->SetCursorPosition(co, col, row);
ms_va_start(args, fmt); ms_va_start(args, fmt);
@ -136,6 +140,9 @@ console_print_box_at(CHAR16 *str_arr[], int highlight,
if (!console_text_mode) if (!console_text_mode)
setup_console(1); setup_console(1);
if (!co)
return;
co->QueryMode(co, co->Mode->Mode, &cols, &rows); co->QueryMode(co, co->Mode->Mode, &cols, &rows);
/* last row on screen is unusable without scrolling, so ignore it */ /* last row on screen is unusable without scrolling, so ignore it */
@ -241,6 +248,9 @@ console_print_box(CHAR16 *str_arr[], int highlight)
if (!console_text_mode) if (!console_text_mode)
setup_console(1); setup_console(1);
if (!co)
return;
CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode)); CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
co->EnableCursor(co, FALSE); co->EnableCursor(co, FALSE);
co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
@ -274,6 +284,9 @@ console_select(CHAR16 *title[], CHAR16* selectors[], unsigned int start)
if (!console_text_mode) if (!console_text_mode)
setup_console(1); setup_console(1);
if (!co)
return -1;
co->QueryMode(co, co->Mode->Mode, &cols, &rows); co->QueryMode(co, co->Mode->Mode, &cols, &rows);
for (i = 0; i < selector_lines; i++) { for (i = 0; i < selector_lines; i++) {
@ -413,6 +426,9 @@ console_save_and_set_mode(SIMPLE_TEXT_OUTPUT_MODE * SavedMode)
return; return;
} }
if (!co)
return;
CopyMem(SavedMode, co->Mode, sizeof(SIMPLE_TEXT_OUTPUT_MODE)); CopyMem(SavedMode, co->Mode, sizeof(SIMPLE_TEXT_OUTPUT_MODE));
co->EnableCursor(co, FALSE); co->EnableCursor(co, FALSE);
co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
@ -423,6 +439,9 @@ console_restore_mode(SIMPLE_TEXT_OUTPUT_MODE * SavedMode)
{ {
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut; SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
if (!co)
return;
co->EnableCursor(co, SavedMode->CursorVisible); co->EnableCursor(co, SavedMode->CursorVisible);
co->SetCursorPosition(co, SavedMode->CursorColumn, co->SetCursorPosition(co, SavedMode->CursorColumn,
SavedMode->CursorRow); SavedMode->CursorRow);
@ -441,6 +460,9 @@ console_countdown(CHAR16* title, const CHAR16* message, int timeout)
CHAR16 *titles[2]; CHAR16 *titles[2];
int wait = 10000000; int wait = 10000000;
if (!co || !ci)
return -1;
console_save_and_set_mode(&SavedMode); console_save_and_set_mode(&SavedMode);
titles[0] = title; titles[0] = title;
@ -495,7 +517,10 @@ console_mode_handle(VOID)
UINTN rows = 0, columns = 0; UINTN rows = 0, columns = 0;
EFI_STATUS efi_status = EFI_SUCCESS; EFI_STATUS efi_status = EFI_SUCCESS;
efi_status = gBS->LocateProtocol(&gop_guid, NULL, (void **)&gop); if (!co)
return;
efi_status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_error(L"Locate graphic output protocol fail", efi_status); console_error(L"Locate graphic output protocol fail", efi_status);
return; return;
@ -555,7 +580,7 @@ console_mode_handle(VOID)
efi_status = co->SetMode(co, mode_set); efi_status = co->SetMode(co, mode_set);
} }
co->ClearScreen(co); clear_screen();
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_error(L"Console set mode fail", efi_status); console_error(L"Console set mode fail", efi_status);
@ -649,13 +674,25 @@ console_reset(void)
if (!console_text_mode) if (!console_text_mode)
setup_console(1); setup_console(1);
if (!co)
return;
co->Reset(co, TRUE); co->Reset(co, TRUE);
/* set mode 0 - required to be 80x25 */ /* set mode 0 - required to be 80x25 */
co->SetMode(co, 0); co->SetMode(co, 0);
co->ClearScreen(co); co->ClearScreen(co);
} }
UINT32 verbose = 0; void
clear_screen(void)
{
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
if (!co)
return;
co->ClearScreen(co);
}
VOID VOID
setup_verbosity(VOID) setup_verbosity(VOID)
@ -679,7 +716,7 @@ setup_verbosity(VOID)
VOID VOID
msleep(unsigned long msecs) msleep(unsigned long msecs)
{ {
gBS->Stall(msecs); BS->Stall(msecs);
} }
/* This is used in various things to determine if we should print to the /* This is used in various things to determine if we should print to the

View File

@ -63,7 +63,7 @@ execute(EFI_HANDLE image, CHAR16 *name)
EFI_DEVICE_PATH *devpath; EFI_DEVICE_PATH *devpath;
CHAR16 *PathName; CHAR16 *PathName;
efi_status = gBS->HandleProtocol(image, &IMAGE_PROTOCOL, efi_status = BS->HandleProtocol(image, &IMAGE_PROTOCOL,
(void **) &li); (void **) &li);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return efi_status; return efi_status;
@ -72,12 +72,12 @@ execute(EFI_HANDLE image, CHAR16 *name)
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return efi_status; return efi_status;
efi_status = gBS->LoadImage(FALSE, image, devpath, NULL, 0, &h); efi_status = BS->LoadImage(FALSE, image, devpath, NULL, 0, &h);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
goto out; goto out;
efi_status = gBS->StartImage(h, NULL, NULL); efi_status = BS->StartImage(h, NULL, NULL);
gBS->UnloadImage(h); BS->UnloadImage(h);
out: out:
FreePool(PathName); FreePool(PathName);

View File

@ -123,7 +123,7 @@ security_policy_authentication (
* EFI_SECURITY_VIOLATION */ * EFI_SECURITY_VIOLATION */
fail_status = efi_status; fail_status = efi_status;
efi_status = gBS->LocateDevicePath(&SIMPLE_FS_PROTOCOL, &DevPath, &h); efi_status = BS->LocateDevicePath(&SIMPLE_FS_PROTOCOL, &DevPath, &h);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
goto out; goto out;

View File

@ -16,7 +16,7 @@ argsplit(EFI_HANDLE image, int *argc, CHAR16*** ARGV)
*argc = 0; *argc = 0;
efi_status = gBS->HandleProtocol(image, &LoadedImageProtocol, efi_status = BS->HandleProtocol(image, &LoadedImageProtocol,
(VOID **) &info); (VOID **) &info);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_print(L"Failed to get arguments\n"); console_print(L"Failed to get arguments\n");

View File

@ -11,7 +11,7 @@ simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UIN
EFI_FILE_IO_INTERFACE *drive; EFI_FILE_IO_INTERFACE *drive;
EFI_FILE *root; EFI_FILE *root;
efi_status = gBS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID, efi_status = BS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
(void **)&drive); (void **)&drive);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_print(L"Unable to find simple file protocol (%d)\n", console_print(L"Unable to find simple file protocol (%d)\n",
@ -40,7 +40,7 @@ simple_file_open(EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode)
EFI_DEVICE_PATH *loadpath = NULL; EFI_DEVICE_PATH *loadpath = NULL;
CHAR16 *PathName = NULL; CHAR16 *PathName = NULL;
efi_status = gBS->HandleProtocol(image, &IMAGE_PROTOCOL, efi_status = BS->HandleProtocol(image, &IMAGE_PROTOCOL,
(void **) &li); (void **) &li);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return simple_file_open_by_handle(image, name, file, mode); return simple_file_open_by_handle(image, name, file, mode);
@ -176,7 +176,7 @@ simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h)
CHAR16 **entries; CHAR16 **entries;
int val; int val;
efi_status = gBS->LocateHandleBuffer(ByProtocol, efi_status = BS->LocateHandleBuffer(ByProtocol,
&EFI_SIMPLE_FILE_SYSTEM_GUID, &EFI_SIMPLE_FILE_SYSTEM_GUID,
NULL, &count, &vol_handles); NULL, &count, &vol_handles);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
@ -196,7 +196,7 @@ simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h)
CHAR16 *name; CHAR16 *name;
EFI_FILE_IO_INTERFACE *drive; EFI_FILE_IO_INTERFACE *drive;
efi_status = gBS->HandleProtocol(vol_handles[i], efi_status = BS->HandleProtocol(vol_handles[i],
&EFI_SIMPLE_FILE_SYSTEM_GUID, &EFI_SIMPLE_FILE_SYSTEM_GUID,
(void **) &drive); (void **) &drive);
if (EFI_ERROR(efi_status) || !drive) if (EFI_ERROR(efi_status) || !drive)

View File

@ -12,6 +12,10 @@
*/ */
#include "shim.h" #include "shim.h"
extern EFI_SYSTEM_TABLE *ST;
extern EFI_BOOT_SERVICES *BS;
extern EFI_RUNTIME_SERVICES *RT;
EFI_STATUS EFI_STATUS
fill_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany, fill_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany,
const EFI_GUID *type, const UINT32 sig_size, const EFI_GUID *type, const UINT32 sig_size,
@ -45,7 +49,7 @@ fill_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany,
sl->SignatureListSize = needed; sl->SignatureListSize = needed;
sd = (EFI_SIGNATURE_DATA *)(out + sizeof(EFI_SIGNATURE_LIST)); sd = (EFI_SIGNATURE_DATA *)(out + sizeof(EFI_SIGNATURE_LIST));
CopyMem(sd, first_sig, data_len); CopyMem(sd, (void *)first_sig, data_len);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -64,9 +68,11 @@ fill_esl_with_one_signature(const uint8_t *data, const uint32_t data_len,
if (out) { if (out) {
sd = AllocateZeroPool(sig_size); sd = AllocateZeroPool(sig_size);
if (!sd)
return EFI_OUT_OF_RESOURCES;
if (owner) if (owner)
CopyMem(sd, owner, sizeof(EFI_GUID)); CopyMem(sd, (void *)owner, sizeof(EFI_GUID));
CopyMem(sd->SignatureData, data, data_len); CopyMem(sd->SignatureData, (void *)data, data_len);
} }
efi_status = fill_esl(sd, 1, type, sig_size, out, outlen); efi_status = fill_esl(sd, 1, type, sig_size, out, outlen);
@ -154,7 +160,7 @@ CreateTimeBasedPayload(IN OUT UINTN * DataSize, IN OUT UINT8 ** Data)
DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData); DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
ZeroMem(&Time, sizeof(EFI_TIME)); ZeroMem(&Time, sizeof(EFI_TIME));
efi_status = gRT->GetTime(&Time, NULL); efi_status = RT->GetTime(&Time, NULL);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
FreePool(NewData); FreePool(NewData);
return efi_status; return efi_status;
@ -225,7 +231,7 @@ SetSecureVariable(const CHAR16 * const var, UINT8 *Data, UINTN len,
return efi_status; return efi_status;
} }
efi_status = gRT->SetVariable((CHAR16 *)var, &owner, efi_status = RT->SetVariable((CHAR16 *)var, &owner,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS |
@ -241,7 +247,7 @@ GetOSIndications(void)
UINTN DataSize = sizeof(indications); UINTN DataSize = sizeof(indications);
EFI_STATUS efi_status; EFI_STATUS efi_status;
efi_status = gRT->GetVariable(L"OsIndicationsSupported", &GV_GUID, efi_status = RT->GetVariable(L"OsIndicationsSupported", &GV_GUID,
NULL, &DataSize, &indications); NULL, &DataSize, &indications);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return 0; return 0;
@ -255,7 +261,7 @@ SETOSIndicationsAndReboot(UINT64 indications)
UINTN DataSize = sizeof(indications); UINTN DataSize = sizeof(indications);
EFI_STATUS efi_status; EFI_STATUS efi_status;
efi_status = gRT->SetVariable(L"OsIndications", &GV_GUID, efi_status = RT->SetVariable(L"OsIndications", &GV_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
@ -263,7 +269,7 @@ SETOSIndicationsAndReboot(UINT64 indications)
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return efi_status; return efi_status;
gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL); RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
/* does not return */ /* does not return */
return EFI_SUCCESS; return EFI_SUCCESS;
@ -280,7 +286,7 @@ get_variable_attr(const CHAR16 * const var, UINT8 **data, UINTN *len,
*len = 0; *len = 0;
efi_status = gRT->GetVariable((CHAR16 *)var, &owner, NULL, len, NULL); efi_status = RT->GetVariable((CHAR16 *)var, &owner, NULL, len, NULL);
if (efi_status != EFI_BUFFER_TOO_SMALL) { if (efi_status != EFI_BUFFER_TOO_SMALL) {
if (!EFI_ERROR(efi_status)) /* this should never happen */ if (!EFI_ERROR(efi_status)) /* this should never happen */
return EFI_PROTOCOL_ERROR; return EFI_PROTOCOL_ERROR;
@ -298,7 +304,7 @@ get_variable_attr(const CHAR16 * const var, UINT8 **data, UINTN *len,
if (!*data) if (!*data)
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
efi_status = gRT->GetVariable((CHAR16 *)var, &owner, attributes, len, *data); efi_status = RT->GetVariable((CHAR16 *)var, &owner, attributes, len, *data);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
FreePool(*data); FreePool(*data);
*data = NULL; *data = NULL;
@ -341,7 +347,7 @@ EFI_STATUS
set_variable(CHAR16 *var, EFI_GUID owner, UINT32 attributes, set_variable(CHAR16 *var, EFI_GUID owner, UINT32 attributes,
UINTN datasize, void *data) UINTN datasize, void *data)
{ {
return gRT->SetVariable(var, &owner, attributes, datasize, data); return RT->SetVariable(var, &owner, attributes, datasize, data);
} }
EFI_STATUS EFI_STATUS
@ -394,7 +400,7 @@ variable_is_setupmode(int default_return)
UINTN DataSize = sizeof(SetupMode); UINTN DataSize = sizeof(SetupMode);
EFI_STATUS efi_status; EFI_STATUS efi_status;
efi_status = gRT->GetVariable(L"SetupMode", &GV_GUID, NULL, efi_status = RT->GetVariable(L"SetupMode", &GV_GUID, NULL,
&DataSize, &SetupMode); &DataSize, &SetupMode);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return default_return; return default_return;
@ -411,7 +417,7 @@ variable_is_secureboot(void)
EFI_STATUS efi_status; EFI_STATUS efi_status;
DataSize = sizeof(SecureBoot); DataSize = sizeof(SecureBoot);
efi_status = gRT->GetVariable(L"SecureBoot", &GV_GUID, NULL, efi_status = RT->GetVariable(L"SecureBoot", &GV_GUID, NULL,
&DataSize, &SecureBoot); &DataSize, &SecureBoot);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
return 0; return 0;
@ -445,7 +451,7 @@ variable_enroll_hash(const CHAR16 * const var, EFI_GUID owner,
efi_status = SetSecureVariable(var, sig, sizeof(sig), owner, efi_status = SetSecureVariable(var, sig, sizeof(sig), owner,
EFI_VARIABLE_APPEND_WRITE, 0); EFI_VARIABLE_APPEND_WRITE, 0);
else else
efi_status = gRT->SetVariable((CHAR16 *)var, &owner, efi_status = RT->SetVariable((CHAR16 *)var, &owner,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_APPEND_WRITE, EFI_VARIABLE_APPEND_WRITE,

456
load-options.c Normal file
View File

@ -0,0 +1,456 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* load-options.c - all the stuff we need to parse the load options
*/
#include "shim.h"
CHAR16 *second_stage;
void *load_options;
UINT32 load_options_size;
/*
* Generate the path of an executable given shim's path and the name
* of the executable
*/
EFI_STATUS
generate_path_from_image_path(EFI_LOADED_IMAGE *li,
CHAR16 *ImagePath,
CHAR16 **PathName)
{
EFI_DEVICE_PATH *devpath;
unsigned int i;
int j, last = -1;
unsigned int pathlen = 0;
EFI_STATUS efi_status = EFI_SUCCESS;
CHAR16 *bootpath;
/*
* Suuuuper lazy technique here, but check and see if this is a full
* path to something on the ESP. Backwards compatibility demands
* that we don't just use \\, because we (not particularly brightly)
* used to require that the relative file path started with that.
*
* If it is a full path, don't try to merge it with the directory
* from our Loaded Image handle.
*/
if (StrSize(ImagePath) > 5 && StrnCmp(ImagePath, L"\\EFI\\", 5) == 0) {
*PathName = StrDuplicate(ImagePath);
if (!*PathName) {
perror(L"Failed to allocate path buffer\n");
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
devpath = li->FilePath;
bootpath = DevicePathToStr(devpath);
pathlen = StrLen(bootpath);
/*
* DevicePathToStr() concatenates two nodes with '/'.
* Convert '/' to '\\'.
*/
for (i = 0; i < pathlen; i++) {
if (bootpath[i] == '/')
bootpath[i] = '\\';
}
for (i=pathlen; i>0; i--) {
if (bootpath[i] == '\\' && bootpath[i-1] == '\\')
bootpath[i] = '/';
else if (last == -1 && bootpath[i] == '\\')
last = i;
}
if (last == -1 && bootpath[0] == '\\')
last = 0;
bootpath[last+1] = '\0';
if (last > 0) {
for (i = 0, j = 0; bootpath[i] != '\0'; i++) {
if (bootpath[i] != '/') {
bootpath[j] = bootpath[i];
j++;
}
}
bootpath[j] = '\0';
}
for (i = 0, last = 0; i < StrLen(ImagePath); i++)
if (ImagePath[i] == '\\')
last = i + 1;
ImagePath = ImagePath + last;
*PathName = AllocatePool(StrSize(bootpath) + StrSize(ImagePath));
if (!*PathName) {
perror(L"Failed to allocate path buffer\n");
efi_status = EFI_OUT_OF_RESOURCES;
goto error;
}
*PathName[0] = '\0';
if (StrnCaseCmp(bootpath, ImagePath, StrLen(bootpath)))
StrCat(*PathName, bootpath);
StrCat(*PathName, ImagePath);
error:
FreePool(bootpath);
return efi_status;
}
/*
* Extract the OptionalData and OptionalData fields from an
* EFI_LOAD_OPTION.
*/
static inline EFI_STATUS
get_load_option_optional_data(VOID *data, UINT32 data_size,
VOID **od, UINT32 *ods)
{
/*
* If it's not at least Attributes + FilePathListLength +
* Description=L"" + 0x7fff0400 (EndEntrireDevicePath), it can't
* be valid.
*/
if (data_size < (sizeof(UINT32) + sizeof(UINT16) + 2 + 4))
return EFI_INVALID_PARAMETER;
UINT8 *start = (UINT8 *)data;
UINT8 *cur = start + sizeof(UINT32);
UINT16 fplistlen = *(UINT16 *)cur;
/*
* If there's not enough space for the file path list and the
* smallest possible description (L""), it's not valid.
*/
if (fplistlen > data_size - (sizeof(UINT32) + 2 + 4))
return EFI_INVALID_PARAMETER;
cur += sizeof(UINT16);
UINT32 limit = data_size - (cur - start) - fplistlen;
UINT32 i;
for (i = 0; i < limit ; i++) {
/* If the description isn't valid UCS2-LE, it's not valid. */
if (i % 2 != 0) {
if (cur[i] != 0)
return EFI_INVALID_PARAMETER;
} else if (cur[i] == 0) {
/* we've found the end */
i++;
if (i >= limit || cur[i] != 0)
return EFI_INVALID_PARAMETER;
break;
}
}
i++;
if (i > limit)
return EFI_INVALID_PARAMETER;
/*
* If i is limit, we know the rest of this is the FilePathList and
* there's no optional data. So just bail now.
*/
if (i == limit) {
*od = NULL;
*ods = 0;
return EFI_SUCCESS;
}
cur += i;
limit -= i;
limit += fplistlen;
i = 0;
while (limit - i >= 4) {
struct {
UINT8 type;
UINT8 subtype;
UINT16 len;
} dp = {
.type = cur[i],
.subtype = cur[i+1],
/*
* it's a little endian UINT16, but we're not
* guaranteed alignment is sane, so we can't just
* typecast it directly.
*/
.len = (cur[i+3] << 8) | cur[i+2],
};
/*
* We haven't found an EndEntire, so this has to be a valid
* EFI_DEVICE_PATH in order for the data to be valid. That
* means it has to fit, and it can't be smaller than 4 bytes.
*/
if (dp.len < 4 || dp.len > limit)
return EFI_INVALID_PARAMETER;
/*
* see if this is an EndEntire node...
*/
if (dp.type == 0x7f && dp.subtype == 0xff) {
/*
* if we've found the EndEntire node, it must be 4
* bytes
*/
if (dp.len != 4)
return EFI_INVALID_PARAMETER;
i += dp.len;
break;
}
/*
* It's just some random DP node; skip it.
*/
i += dp.len;
}
if (i != fplistlen)
return EFI_INVALID_PARAMETER;
/*
* if there's any space left, it's "optional data"
*/
*od = cur + i;
*ods = limit - i;
return EFI_SUCCESS;
}
static int
is_our_path(EFI_LOADED_IMAGE *li, CHAR16 *path)
{
CHAR16 *dppath = NULL;
CHAR16 *PathName = NULL;
EFI_STATUS efi_status;
int ret = 1;
dppath = DevicePathToStr(li->FilePath);
if (!dppath)
return 0;
efi_status = generate_path_from_image_path(li, path, &PathName);
if (EFI_ERROR(efi_status)) {
perror(L"Unable to generate path %s: %r\n", path,
efi_status);
goto done;
}
dprint(L"dppath: %s\n", dppath);
dprint(L"path: %s\n", path);
if (StrnCaseCmp(dppath, PathName, StrLen(dppath)))
ret = 0;
done:
FreePool(dppath);
FreePool(PathName);
return ret;
}
/*
* Split the supplied load options in to a NULL terminated
* string representing the path of the second stage loader,
* and return a pointer to the remaining load options data
* and its remaining size.
*
* This expects the supplied load options to begin with a
* string that is either NULL terminated or terminated with
* a space and some optional data. It will return NULL if
* the supplied load options contains no spaces or NULL
* terminators.
*/
static CHAR16 *
split_load_options(VOID *in, UINT32 in_size,
VOID **remaining,
UINT32 *remaining_size) {
UINTN i;
CHAR16 *arg0 = NULL;
CHAR16 *start = (CHAR16 *)in;
/* Skip spaces */
for (i = 0; i < in_size / sizeof(CHAR16); i++) {
if (*start != L' ')
break;
start++;
}
in_size -= ((VOID *)start - in);
/*
* Ensure that the first argument is NULL terminated by
* replacing L' ' with L'\0'.
*/
for (i = 0; i < in_size / sizeof(CHAR16); i++) {
if (start[i] == L' ' || start[i] == L'\0') {
start[i] = L'\0';
arg0 = (CHAR16 *)start;
break;
}
}
if (arg0) {
UINTN skip = i + 1;
*remaining_size = in_size - (skip * sizeof(CHAR16));
*remaining = *remaining_size > 0 ? start + skip : NULL;
}
return arg0;
}
/*
* Check the load options to specify the second stage loader
*/
EFI_STATUS
parse_load_options(EFI_LOADED_IMAGE *li)
{
EFI_STATUS efi_status;
VOID *remaining = NULL;
UINT32 remaining_size;
CHAR16 *loader_str = NULL;
dprint(L"full load options:\n");
dhexdumpat(li->LoadOptions, li->LoadOptionsSize, 0);
/*
* Sanity check since we make several assumptions about the length
* Some firmware feeds the following load option when booting from
* an USB device:
*
* 0x46 0x4a 0x00 |FJ.|
*
* The string is meaningless for shim and so just ignore it.
*/
if (li->LoadOptionsSize % 2 != 0)
return EFI_SUCCESS;
/* So, load options are a giant pain in the ass. If we're invoked
* from the EFI shell, we get something like this:
00000000 5c 00 45 00 36 00 49 00 5c 00 66 00 65 00 64 00 |\.E.F.I.\.f.e.d.|
00000010 6f 00 72 00 61 00 5c 00 73 00 68 00 69 00 6d 00 |o.r.a.\.s.h.i.m.|
00000020 78 00 36 00 34 00 2e 00 64 00 66 00 69 00 20 00 |x.6.4...e.f.i. .|
00000030 5c 00 45 00 46 00 49 00 5c 00 66 00 65 00 64 00 |\.E.F.I.\.f.e.d.|
00000040 6f 00 72 00 61 00 5c 00 66 00 77 00 75 00 70 00 |o.r.a.\.f.w.u.p.|
00000050 64 00 61 00 74 00 65 00 2e 00 65 00 66 00 20 00 |d.a.t.e.e.f.i. .|
00000060 00 00 66 00 73 00 30 00 3a 00 5c 00 00 00 |..f.s.0.:.\...|
*
* which is just some paths rammed together separated by a UCS-2 NUL.
* But if we're invoked from BDS, we get something more like:
*
00000000 01 00 00 00 62 00 4c 00 69 00 6e 00 75 00 78 00 |....b.L.i.n.u.x.|
00000010 20 00 46 00 69 00 72 00 6d 00 77 00 61 00 72 00 | .F.i.r.m.w.a.r.|
00000020 65 00 20 00 55 00 70 00 64 00 61 00 74 00 65 00 |e. .U.p.d.a.t.e.|
00000030 72 00 00 00 40 01 2a 00 01 00 00 00 00 08 00 00 |r.....*.........|
00000040 00 00 00 00 00 40 06 00 00 00 00 00 1a 9e 55 bf |.....@........U.|
00000050 04 57 f2 4f b4 4a ed 26 4a 40 6a 94 02 02 04 04 |.W.O.:.&J@j.....|
00000060 34 00 5c 00 45 00 46 00 49 00 5c 00 66 00 65 00 |4.\.E.F.I.f.e.d.|
00000070 64 00 6f 00 72 00 61 00 5c 00 73 00 68 00 69 00 |o.r.a.\.s.h.i.m.|
00000080 6d 00 78 00 36 00 34 00 2e 00 65 00 66 00 69 00 |x.6.4...e.f.i...|
00000090 00 00 7f ff 40 00 20 00 5c 00 66 00 77 00 75 00 |...... .\.f.w.u.|
000000a0 70 00 78 00 36 00 34 00 2e 00 65 00 66 00 69 00 |p.x.6.4...e.f.i.|
000000b0 00 00 |..|
*
* which is clearly an EFI_LOAD_OPTION filled in halfway reasonably.
* In short, the UEFI shell is still a useless piece of junk.
*
* But then on some versions of BDS, we get:
00000000 5c 00 66 00 77 00 75 00 70 00 78 00 36 00 34 00 |\.f.w.u.p.x.6.4.|
00000010 2e 00 65 00 66 00 69 00 00 00 |..e.f.i...|
0000001a
* which as you can see is one perfectly normal UCS2-EL string
* containing the load option from the Boot#### variable.
*
* We also sometimes find a guid or partial guid at the end, because
* BDS will add that, but we ignore that here.
*/
/*
* Maybe there just aren't any options...
*/
if (li->LoadOptionsSize == 0)
return EFI_SUCCESS;
/*
* In either case, we've got to have at least a UCS2 NUL...
*/
if (li->LoadOptionsSize < 2)
return EFI_BAD_BUFFER_SIZE;
/*
* Some awesome versions of BDS will add entries for Linux. On top
* of that, some versions of BDS will "tag" any Boot#### entries they
* create by putting a GUID at the very end of the optional data in
* the EFI_LOAD_OPTIONS, thus screwing things up for everybody who
* tries to actually *use* the optional data for anything. Why they
* did this instead of adding a flag to the spec to /say/ it's
* created by BDS, I do not know. For shame.
*
* Anyway, just nerf that out from the start. It's always just
* garbage at the end.
*/
if (li->LoadOptionsSize > 16) {
if (CompareGuid((EFI_GUID *)(li->LoadOptions
+ (li->LoadOptionsSize - 16)),
&BDS_GUID) == 0)
li->LoadOptionsSize -= 16;
}
/*
* Apparently sometimes we get L"\0\0"? Which isn't useful at all.
*/
if (is_all_nuls(li->LoadOptions, li->LoadOptionsSize))
return EFI_SUCCESS;
/*
* See if this is an EFI_LOAD_OPTION and extract the optional
* data if it is. This will return an error if it is not a valid
* EFI_LOAD_OPTION.
*/
efi_status = get_load_option_optional_data(li->LoadOptions,
li->LoadOptionsSize,
&li->LoadOptions,
&li->LoadOptionsSize);
if (EFI_ERROR(efi_status)) {
/*
* it's not an EFI_LOAD_OPTION, so it's probably just a string
* or list of strings.
*
* UEFI shell copies the whole line of the command into
* LoadOptions. We ignore the first string, i.e. the name of this
* program in this case.
*/
loader_str = split_load_options(li->LoadOptions,
li->LoadOptionsSize,
&remaining,
&remaining_size);
if (loader_str && is_our_path(li, loader_str)) {
li->LoadOptions = remaining;
li->LoadOptionsSize = remaining_size;
}
}
loader_str = split_load_options(li->LoadOptions, li->LoadOptionsSize,
&remaining, &remaining_size);
/*
* Set up the name of the alternative loader and the LoadOptions for
* the loader
*/
if (loader_str) {
second_stage = loader_str;
load_options = remaining;
load_options_size = remaining_size;
}
return EFI_SUCCESS;
}
// vim:fenc=utf-8:tw=75:noet

1400
mock-variables.c Normal file

File diff suppressed because it is too large Load Diff

154
mok.c
View File

@ -16,7 +16,7 @@ static BOOLEAN check_var(CHAR16 *varname)
UINT32 MokVar; UINT32 MokVar;
UINT32 attributes; UINT32 attributes;
efi_status = gRT->GetVariable(varname, &SHIM_LOCK_GUID, &attributes, efi_status = RT->GetVariable(varname, &SHIM_LOCK_GUID, &attributes,
&size, (void *)&MokVar); &size, (void *)&MokVar);
if (!EFI_ERROR(efi_status) || efi_status == EFI_BUFFER_TOO_SMALL) if (!EFI_ERROR(efi_status) || efi_status == EFI_BUFFER_TOO_SMALL)
return TRUE; return TRUE;
@ -27,7 +27,7 @@ static BOOLEAN check_var(CHAR16 *varname)
#define SetVariable(name, guid, attrs, varsz, var) \ #define SetVariable(name, guid, attrs, varsz, var) \
({ \ ({ \
EFI_STATUS efi_status_; \ EFI_STATUS efi_status_; \
efi_status_ = gRT->SetVariable(name, guid, attrs, varsz, var); \ efi_status_ = RT->SetVariable(name, guid, attrs, varsz, var); \
dprint_(L"%a:%d:%a() SetVariable(\"%s\", ... varsz=0x%llx) = %r\n", \ dprint_(L"%a:%d:%a() SetVariable(\"%s\", ... varsz=0x%llx) = %r\n", \
__FILE__, __LINE__ - 5, __func__, name, varsz, \ __FILE__, __LINE__ - 5, __func__, name, varsz, \
efi_status_); \ efi_status_); \
@ -46,7 +46,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
check_var(L"MokPW") || check_var(L"MokAuth") || check_var(L"MokPW") || check_var(L"MokAuth") ||
check_var(L"MokDel") || check_var(L"MokDB") || check_var(L"MokDel") || check_var(L"MokDB") ||
check_var(L"MokXNew") || check_var(L"MokXDel") || check_var(L"MokXNew") || check_var(L"MokXDel") ||
check_var(L"MokXAuth")) { check_var(L"MokXAuth") || check_var(L"MokListTrustedNew")) {
efi_status = start_image(image_handle, MOK_MANAGER); efi_status = start_image(image_handle, MOK_MANAGER);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
@ -58,85 +58,6 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
typedef enum {
VENDOR_ADDEND_DB,
VENDOR_ADDEND_X509,
VENDOR_ADDEND_NONE,
} vendor_addend_category_t;
struct mok_state_variable;
typedef vendor_addend_category_t (vendor_addend_categorizer_t)(struct mok_state_variable *);
/*
* MoK variables that need to have their storage validated.
*
* The order here is important, since this is where we measure for the
* tpm as well.
*/
struct mok_state_variable {
CHAR16 *name; /* UCS-2 BS|NV variable name */
char *name8; /* UTF-8 BS|NV variable name */
CHAR16 *rtname; /* UCS-2 RT variable name */
char *rtname8; /* UTF-8 RT variable name */
EFI_GUID *guid; /* variable GUID */
/*
* these are used during processing, they shouldn't be filled out
* in the static table below.
*/
UINT8 *data;
UINTN data_size;
/*
* addend are added to the input variable, as part of the runtime
* variable, so that they're visible to the kernel. These are
* where we put vendor_cert / vendor_db / vendor_dbx
*
* These are indirect pointers just to make initialization saner...
*/
vendor_addend_categorizer_t *categorize_addend; /* determines format */
/*
* we call categorize_addend() and it determines what kind of thing
* this is. That is, if this shim was built with VENDOR_CERT, for
* the DB entry it'll return VENDOR_ADDEND_X509; if you used
* VENDOR_DB instead, it'll return VENDOR_ADDEND_DB. If you used
* neither, it'll do VENDOR_ADDEND_NONE.
*
* The existing categorizers are for db and dbx; they differ
* because we don't currently support a CERT for dbx.
*/
UINT8 **addend;
UINT32 *addend_size;
/*
* build_cert is our build-time cert. Like addend, this is added
* to the input variable, as part of the runtime variable, so that
* they're visible to the kernel. This is the ephemeral cert used
* for signing MokManager.efi and fallback.efi.
*
* These are indirect pointers just to make initialization saner...
*/
UINT8 **build_cert;
UINT32 *build_cert_size;
UINT32 yes_attr; /* var attrs that must be set */
UINT32 no_attr; /* var attrs that must not be set */
UINT32 flags; /* flags on what and how to mirror */
/*
* MOK_MIRROR_KEYDB mirror this as a key database
* MOK_MIRROR_DELETE_FIRST delete any existing variable first
* MOK_VARIABLE_MEASURE extend PCR 7 and log the hash change
* MOK_VARIABLE_LOG measure into whatever .pcr says and log
*/
UINTN pcr; /* PCR to measure and hash to */
/*
* if this is a state value, a pointer to our internal state to be
* mirrored.
*/
UINT8 *state;
};
static vendor_addend_category_t static vendor_addend_category_t
categorize_authorized(struct mok_state_variable *v) categorize_authorized(struct mok_state_variable *v)
{ {
@ -164,7 +85,7 @@ categorize_deauthorized(struct mok_state_variable *v)
#define MOK_VARIABLE_MEASURE 0x04 #define MOK_VARIABLE_MEASURE 0x04
#define MOK_VARIABLE_LOG 0x08 #define MOK_VARIABLE_LOG 0x08
struct mok_state_variable mok_state_variables[] = { struct mok_state_variable mok_state_variable_data[] = {
{.name = L"MokList", {.name = L"MokList",
.name8 = "MokList", .name8 = "MokList",
.rtname = L"MokListRT", .rtname = L"MokListRT",
@ -245,8 +166,24 @@ struct mok_state_variable mok_state_variables[] = {
MOK_VARIABLE_MEASURE, MOK_VARIABLE_MEASURE,
.pcr = 7, .pcr = 7,
}, },
{.name = L"MokListTrusted",
.name8 = "MokListTrusted",
.rtname = L"MokListTrustedRT",
.rtname8 = "MokListTrustedRT",
.guid = &SHIM_LOCK_GUID,
.yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
.no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
.flags = MOK_MIRROR_DELETE_FIRST |
MOK_VARIABLE_MEASURE |
MOK_VARIABLE_LOG,
.pcr = 14,
.state = &trust_mok_list,
},
{ NULL, } { NULL, }
}; };
size_t n_mok_state_variables = sizeof(mok_state_variable_data) / sizeof(mok_state_variable_data[0]);
struct mok_state_variable *mok_state_variables = &mok_state_variable_data[0];
#define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE)) #define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE))
@ -261,6 +198,9 @@ static const uint8_t null_sha256[32] = { 0, };
typedef UINTN SIZE_T; typedef UINTN SIZE_T;
#define EFI_MAJOR_VERSION(tablep) ((UINT16)((((tablep)->Hdr.Revision) >> 16) & 0xfffful))
#define EFI_MINOR_VERSION(tablep) ((UINT16)(((tablep)->Hdr.Revision) & 0xfffful))
static EFI_STATUS static EFI_STATUS
get_max_var_sz(UINT32 attrs, SIZE_T *max_var_szp) get_max_var_sz(UINT32 attrs, SIZE_T *max_var_szp)
{ {
@ -270,12 +210,22 @@ get_max_var_sz(UINT32 attrs, SIZE_T *max_var_szp)
uint64_t max_var_sz = 0; uint64_t max_var_sz = 0;
*max_var_szp = 0; *max_var_szp = 0;
efi_status = gRT->QueryVariableInfo(attrs, &max_storage_sz, if (EFI_MAJOR_VERSION(RT) < 2) {
dprint(L"EFI %d.%d; no RT->QueryVariableInfo(). Using 1024!\n",
EFI_MAJOR_VERSION(RT), EFI_MINOR_VERSION(RT));
max_var_sz = remaining_sz = max_storage_sz = 1024;
efi_status = EFI_SUCCESS;
} else {
dprint(L"calling RT->QueryVariableInfo() at 0x%lx\n",
RT->QueryVariableInfo);
efi_status = RT->QueryVariableInfo(attrs, &max_storage_sz,
&remaining_sz, &max_var_sz); &remaining_sz, &max_var_sz);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Could not get variable storage info: %r\n", efi_status); perror(L"Could not get variable storage info: %r\n",
efi_status);
return efi_status; return efi_status;
} }
}
/* /*
* I just don't trust implementations to not be showing static data * I just don't trust implementations to not be showing static data
@ -351,13 +301,18 @@ mirror_mok_db(CHAR16 *name, CHAR8 *name8, EFI_GUID *guid, UINT32 attrs,
SIZE_T max_var_sz; SIZE_T max_var_sz;
efi_status = get_max_var_sz(attrs, &max_var_sz); efi_status = get_max_var_sz(attrs, &max_var_sz);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status) && efi_status != EFI_UNSUPPORTED) {
LogError(L"Could not get maximum variable size: %r", LogError(L"Could not get maximum variable size: %r",
efi_status); efi_status);
return efi_status; return efi_status;
} }
if (FullDataSize <= max_var_sz) { /* Some UEFI environment such as u-boot doesn't implement
* QueryVariableInfo() and we will only get EFI_UNSUPPORTED when
* querying the available space. In this case, we just mirror
* the variable directly. */
if (FullDataSize <= max_var_sz || efi_status == EFI_UNSUPPORTED) {
efi_status = EFI_SUCCESS;
if (only_first) if (only_first)
efi_status = SetVariable(name, guid, attrs, efi_status = SetVariable(name, guid, attrs,
FullDataSize, FullData); FullDataSize, FullData);
@ -850,7 +805,7 @@ maybe_mirror_one_mok_variable(struct mok_state_variable *v,
BOOLEAN present = FALSE; BOOLEAN present = FALSE;
if (v->rtname) { if (v->rtname) {
if (!only_first && (v->flags & MOK_MIRROR_DELETE_FIRST)) { if (only_first && (v->flags & MOK_MIRROR_DELETE_FIRST)) {
dprint(L"deleting \"%s\"\n", v->rtname); dprint(L"deleting \"%s\"\n", v->rtname);
efi_status = LibDeleteVariable(v->rtname, v->guid); efi_status = LibDeleteVariable(v->rtname, v->guid);
dprint(L"LibDeleteVariable(\"%s\",...) => %r\n", v->rtname, efi_status); dprint(L"LibDeleteVariable(\"%s\",...) => %r\n", v->rtname, efi_status);
@ -876,26 +831,18 @@ maybe_mirror_one_mok_variable(struct mok_state_variable *v,
return ret; return ret;
} }
struct mok_variable_config_entry {
CHAR8 name[256];
UINT64 data_size;
UINT8 data[];
};
EFI_STATUS import_one_mok_state(struct mok_state_variable *v, EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
BOOLEAN only_first) BOOLEAN only_first)
{ {
EFI_STATUS ret = EFI_SUCCESS; EFI_STATUS ret = EFI_SUCCESS;
EFI_STATUS efi_status; EFI_STATUS efi_status;
user_insecure_mode = 0;
ignore_db = 0;
UINT32 attrs = 0; UINT32 attrs = 0;
BOOLEAN delete = FALSE; BOOLEAN delete = FALSE;
dprint(L"importing mok state for \"%s\"\n", v->name); dprint(L"importing mok state for \"%s\"\n", v->name);
if (!v->data && !v->data_size) {
efi_status = get_variable_attr(v->name, efi_status = get_variable_attr(v->name,
&v->data, &v->data_size, &v->data, &v->data_size,
*v->guid, &attrs); *v->guid, &attrs);
@ -922,6 +869,7 @@ EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
delete = TRUE; delete = TRUE;
} }
} }
}
if (delete == TRUE) { if (delete == TRUE) {
perror(L"Deleting bad variable %s\n", v->name); perror(L"Deleting bad variable %s\n", v->name);
efi_status = LibDeleteVariable(v->name, v->guid); efi_status = LibDeleteVariable(v->name, v->guid);
@ -935,7 +883,9 @@ EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
} }
dprint(L"maybe mirroring \"%s\". original data:\n", v->name); dprint(L"maybe mirroring \"%s\". original data:\n", v->name);
if (v->data && v->data_size) {
dhexdumpat(v->data, v->data_size, 0); dhexdumpat(v->data, v->data_size, 0);
}
ret = maybe_mirror_one_mok_variable(v, ret, only_first); ret = maybe_mirror_one_mok_variable(v, ret, only_first);
dprint(L"returning %r\n", ret); dprint(L"returning %r\n", ret);
@ -963,6 +913,7 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
user_insecure_mode = 0; user_insecure_mode = 0;
ignore_db = 0; ignore_db = 0;
trust_mok_list = 0;
UINT64 config_sz = 0; UINT64 config_sz = 0;
UINT8 *config_table = NULL; UINT8 *config_table = NULL;
@ -1001,9 +952,8 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
config_sz += sizeof(config_template); config_sz += sizeof(config_template);
npages = ALIGN_VALUE(config_sz, PAGE_SIZE) >> EFI_PAGE_SHIFT; npages = ALIGN_VALUE(config_sz, PAGE_SIZE) >> EFI_PAGE_SHIFT;
config_table = NULL; config_table = NULL;
efi_status = gBS->AllocatePages(AllocateAnyPages, efi_status = BS->AllocatePages(
EfiRuntimeServicesData, AllocateAnyPages, EfiRuntimeServicesData, npages,
npages,
(EFI_PHYSICAL_ADDRESS *)&config_table); (EFI_PHYSICAL_ADDRESS *)&config_table);
if (EFI_ERROR(efi_status) || !config_table) { if (EFI_ERROR(efi_status) || !config_table) {
console_print(L"Allocating %lu pages for mok config table failed: %r\n", console_print(L"Allocating %lu pages for mok config table failed: %r\n",
@ -1024,16 +974,18 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
config_template.data_size = v->data_size; config_template.data_size = v->data_size;
if (v->data && v->data_size) {
CopyMem(p, &config_template, sizeof(config_template)); CopyMem(p, &config_template, sizeof(config_template));
p += sizeof(config_template); p += sizeof(config_template);
CopyMem(p, v->data, v->data_size); CopyMem(p, v->data, v->data_size);
p += v->data_size; p += v->data_size;
} }
}
if (p) { if (p) {
ZeroMem(&config_template, sizeof(config_template)); ZeroMem(&config_template, sizeof(config_template));
CopyMem(p, &config_template, sizeof(config_template)); CopyMem(p, &config_template, sizeof(config_template));
efi_status = gBS->InstallConfigurationTable(&MOK_VARIABLE_STORE, efi_status = BS->InstallConfigurationTable(&MOK_VARIABLE_STORE,
config_table); config_table);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_print(L"Couldn't install MoK configuration table\n"); console_print(L"Couldn't install MoK configuration table\n");

View File

@ -36,7 +36,7 @@ BOOLEAN findNetboot(EFI_HANDLE device)
{ {
EFI_STATUS efi_status; EFI_STATUS efi_status;
efi_status = gBS->HandleProtocol(device, &PxeBaseCodeProtocol, efi_status = BS->HandleProtocol(device, &PxeBaseCodeProtocol,
(VOID **) &pxe); (VOID **) &pxe);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
pxe = NULL; pxe = NULL;

33
pe.c
View File

@ -298,26 +298,22 @@ get_section_vma_by_name (char *name, size_t namesz,
*/ */
EFI_STATUS EFI_STATUS
generate_hash(char *data, unsigned int datasize_in, generate_hash(char *data, unsigned int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash, PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash,
UINT8 *sha1hash) UINT8 *sha1hash)
{ {
unsigned int sha256ctxsize, sha1ctxsize; unsigned int sha256ctxsize, sha1ctxsize;
unsigned int size = datasize_in;
void *sha256ctx = NULL, *sha1ctx = NULL; void *sha256ctx = NULL, *sha1ctx = NULL;
char *hashbase; char *hashbase;
unsigned int hashsize; unsigned int hashsize;
unsigned int SumOfBytesHashed, SumOfSectionBytes; unsigned int SumOfBytesHashed, SumOfSectionBytes;
unsigned int index, pos; unsigned int index, pos;
unsigned int datasize;
EFI_IMAGE_SECTION_HEADER *Section; EFI_IMAGE_SECTION_HEADER *Section;
EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL; EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL;
EFI_STATUS efi_status = EFI_SUCCESS; EFI_STATUS efi_status = EFI_SUCCESS;
EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data; EFI_IMAGE_DOS_HEADER *DosHdr = (void *)data;
unsigned int PEHdr_offset = 0; unsigned int PEHdr_offset = 0;
size = datasize = datasize_in;
if (datasize <= sizeof (*DosHdr) || if (datasize <= sizeof (*DosHdr) ||
DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
perror(L"Invalid signature\n"); perror(L"Invalid signature\n");
@ -346,7 +342,7 @@ generate_hash(char *data, unsigned int datasize_in,
hashbase = data; hashbase = data;
hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum - hashsize = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum -
hashbase; hashbase;
check_size(data, datasize_in, hashbase, hashsize); check_size(data, datasize, hashbase, hashsize);
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) { !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@ -359,7 +355,7 @@ generate_hash(char *data, unsigned int datasize_in,
hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum + hashbase = (char *)&context->PEHdr->Pe32.OptionalHeader.CheckSum +
sizeof (int); sizeof (int);
hashsize = (char *)context->SecDir - hashbase; hashsize = (char *)context->SecDir - hashbase;
check_size(data, datasize_in, hashbase, hashsize); check_size(data, datasize, hashbase, hashsize);
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) { !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@ -372,12 +368,12 @@ generate_hash(char *data, unsigned int datasize_in,
EFI_IMAGE_DATA_DIRECTORY *dd = context->SecDir + 1; EFI_IMAGE_DATA_DIRECTORY *dd = context->SecDir + 1;
hashbase = (char *)dd; hashbase = (char *)dd;
hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data); hashsize = context->SizeOfHeaders - (unsigned long)((char *)dd - data);
if (hashsize > datasize_in) { if (hashsize > datasize) {
perror(L"Data Directory size %d is invalid\n", hashsize); perror(L"Data Directory size %d is invalid\n", hashsize);
efi_status = EFI_INVALID_PARAMETER; efi_status = EFI_INVALID_PARAMETER;
goto done; goto done;
} }
check_size(data, datasize_in, hashbase, hashsize); check_size(data, datasize, hashbase, hashsize);
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) { !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@ -491,7 +487,8 @@ generate_hash(char *data, unsigned int datasize_in,
continue; continue;
} }
hashbase = ImageAddress(data, size, Section->PointerToRawData); hashbase = ImageAddress(data, datasize,
Section->PointerToRawData);
if (!hashbase) { if (!hashbase) {
perror(L"Malformed section header\n"); perror(L"Malformed section header\n");
efi_status = EFI_INVALID_PARAMETER; efi_status = EFI_INVALID_PARAMETER;
@ -506,7 +503,7 @@ generate_hash(char *data, unsigned int datasize_in,
goto done; goto done;
} }
hashsize = (unsigned int) Section->SizeOfRawData; hashsize = (unsigned int) Section->SizeOfRawData;
check_size(data, datasize_in, hashbase, hashsize); check_size(data, datasize, hashbase, hashsize);
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) { !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@ -532,7 +529,7 @@ generate_hash(char *data, unsigned int datasize_in,
efi_status = EFI_INVALID_PARAMETER; efi_status = EFI_INVALID_PARAMETER;
goto done; goto done;
} }
check_size(data, datasize_in, hashbase, hashsize); check_size(data, datasize, hashbase, hashsize);
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) { !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@ -552,7 +549,7 @@ generate_hash(char *data, unsigned int datasize_in,
hashbase = data + SumOfBytesHashed; hashbase = data + SumOfBytesHashed;
hashsize = datasize - SumOfBytesHashed; hashsize = datasize - SumOfBytesHashed;
check_size(data, datasize_in, hashbase, hashsize); check_size(data, datasize, hashbase, hashsize);
if (!(Sha256Update(sha256ctx, hashbase, hashsize)) || if (!(Sha256Update(sha256ctx, hashbase, hashsize)) ||
!(Sha1Update(sha1ctx, hashbase, hashsize))) { !(Sha1Update(sha1ctx, hashbase, hashsize))) {
@ -949,7 +946,7 @@ handle_image (void *data, unsigned int datasize,
PAGE_SIZE); PAGE_SIZE);
*alloc_pages = alloc_size / PAGE_SIZE; *alloc_pages = alloc_size / PAGE_SIZE;
efi_status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderCode, efi_status = BS->AllocatePages(AllocateAnyPages, EfiLoaderCode,
*alloc_pages, alloc_address); *alloc_pages, alloc_address);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Failed to allocate image buffer\n"); perror(L"Failed to allocate image buffer\n");
@ -963,7 +960,7 @@ handle_image (void *data, unsigned int datasize,
*entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint); *entry_point = ImageAddress(buffer, context.ImageSize, context.EntryPoint);
if (!*entry_point) { if (!*entry_point) {
perror(L"Entry point is invalid\n"); perror(L"Entry point is invalid\n");
gBS->FreePages(*alloc_address, *alloc_pages); BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
@ -1004,7 +1001,7 @@ handle_image (void *data, unsigned int datasize,
if (end < base) { if (end < base) {
perror(L"Section %d has negative size\n", i); perror(L"Section %d has negative size\n", i);
gBS->FreePages(*alloc_address, *alloc_pages); BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
@ -1144,17 +1141,15 @@ handle_image (void *data, unsigned int datasize,
li->ImageSize = context.ImageSize; li->ImageSize = context.ImageSize;
/* Pass the load options to the second stage loader */ /* Pass the load options to the second stage loader */
if ( load_options ) {
li->LoadOptions = load_options; li->LoadOptions = load_options;
li->LoadOptionsSize = load_options_size; li->LoadOptionsSize = load_options_size;
}
if (!found_entry_point) { if (!found_entry_point) {
perror(L"Entry point is not within sections\n"); perror(L"Entry point is not within sections\n");
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
if (found_entry_point > 1) { if (found_entry_point > 1) {
perror(L"%d sections contain entry point\n"); perror(L"%d sections contain entry point\n", found_entry_point);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }

501
post-process-pe.c Normal file
View File

@ -0,0 +1,501 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* post-process-pe.c - fix up timestamps and checksums in broken PE files
* Copyright Peter Jones <pjones@redhat.com>
*/
#define _GNU_SOURCE 1
#include <err.h>
#include <fcntl.h>
#include <getopt.h>
#include <inttypes.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
static int verbosity;
#define ERROR 0
#define WARNING 1
#define INFO 2
#define NOISE 3
#define MIN_VERBOSITY ERROR
#define MAX_VERBOSITY NOISE
#define debug(level, ...) \
({ \
if (verbosity >= (level)) { \
printf("%s():%d: ", __func__, __LINE__); \
printf(__VA_ARGS__); \
} \
0; \
})
typedef uint8_t UINT8;
typedef uint16_t UINT16;
typedef uint32_t UINT32;
typedef uint64_t UINT64;
typedef uint16_t CHAR16;
typedef unsigned long UINTN;
typedef struct {
UINT32 Data1;
UINT16 Data2;
UINT16 Data3;
UINT8 Data4[8];
} EFI_GUID;
#include "include/peimage.h"
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define GNUC_PREREQ(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
#define GNUC_PREREQ(maj, min) 0
#endif
#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
#define CLANG_PREREQ(maj, min) \
((__clang_major__ > (maj)) || \
(__clang_major__ == (maj) && __clang_minor__ >= (min)))
#else
#define CLANG_PREREQ(maj, min) 0
#endif
#if GNUC_PREREQ(5, 1) || CLANG_PREREQ(3, 8)
#define add(a0, a1, s) __builtin_add_overflow(a0, a1, s)
#define sub(s0, s1, d) __builtin_sub_overflow(s0, s1, d)
#define mul(f0, f1, p) __builtin_mul_overflow(f0, f1, p)
#else
#define add(a0, a1, s) \
({ \
(*s) = ((a0) + (a1)); \
0; \
})
#define sub(s0, s1, d) \
({ \
(*d) = ((s0) - (s1)); \
0; \
})
#define mul(f0, f1, p) \
({ \
(*p) = ((f0) * (f1)); \
0; \
})
#endif
#define div(d0, d1, q) \
({ \
unsigned int ret_ = ((d1) == 0); \
if (ret_ == 0) \
(*q) = ((d0) / (d1)); \
ret_; \
})
static int
image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
{
/* .Magic is the same offset in all cases */
if (PEHdr->Pe32Plus.OptionalHeader.Magic ==
EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)
return 1;
return 0;
}
static void
load_pe(const char *const file, void *const data, const size_t datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
{
EFI_IMAGE_DOS_HEADER *DOSHdr = data;
EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
size_t HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
size_t FileAlignment = 0;
size_t sz0 = 0, sz1 = 0;
uintptr_t loc = 0;
debug(NOISE, "datasize:%zu sizeof(PEHdr->Pe32):%zu\n", datasize,
sizeof(PEHdr->Pe32));
if (datasize < sizeof(PEHdr->Pe32))
errx(1, "%s: Invalid image size %zu (%zu < %zu)", file,
datasize, datasize, sizeof(PEHdr->Pe32));
debug(NOISE,
"DOSHdr->e_magic:0x%02hx EFI_IMAGE_DOS_SIGNATURE:0x%02hx\n",
DOSHdr->e_magic, EFI_IMAGE_DOS_SIGNATURE);
if (DOSHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE)
errx(1,
"%s: Invalid DOS header signature 0x%04hx (expected 0x%04hx)",
file, DOSHdr->e_magic, EFI_IMAGE_DOS_SIGNATURE);
debug(NOISE, "DOSHdr->e_lfanew:%u datasize:%zu\n", DOSHdr->e_lfanew,
datasize);
if (DOSHdr->e_lfanew >= datasize ||
add((uintptr_t)data, DOSHdr->e_lfanew, &loc))
errx(1, "%s: invalid pe header location", file);
ctx->PEHdr = PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)loc;
debug(NOISE, "PE signature:0x%04x EFI_IMAGE_NT_SIGNATURE:0x%04x\n",
PEHdr->Pe32.Signature, EFI_IMAGE_NT_SIGNATURE);
if (PEHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE)
errx(1, "%s: Unsupported image type", file);
if (image_is_64_bit(PEHdr)) {
debug(NOISE, "image is 64bit\n");
ctx->NumberOfRvaAndSizes =
PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
ctx->SizeOfHeaders =
PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
ctx->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
ctx->SectionAlignment =
PEHdr->Pe32Plus.OptionalHeader.SectionAlignment;
FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment;
OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
} else {
debug(NOISE, "image is 32bit\n");
ctx->NumberOfRvaAndSizes =
PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
ctx->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
ctx->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
ctx->SectionAlignment =
PEHdr->Pe32.OptionalHeader.SectionAlignment;
FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment;
OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
}
if (FileAlignment % 2 != 0)
errx(1, "%s: Invalid file alignment %ld", file, FileAlignment);
if (FileAlignment == 0)
FileAlignment = 0x200;
if (ctx->SectionAlignment == 0)
ctx->SectionAlignment = PAGE_SIZE;
if (ctx->SectionAlignment < FileAlignment)
ctx->SectionAlignment = FileAlignment;
ctx->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
debug(NOISE,
"Number of RVAs:%"PRIu64" EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES:%d\n",
ctx->NumberOfRvaAndSizes, EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES);
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < ctx->NumberOfRvaAndSizes)
errx(1, "%s: invalid number of RVAs (%lu entries, max is %d)",
file, ctx->NumberOfRvaAndSizes,
EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES);
if (mul(sizeof(EFI_IMAGE_DATA_DIRECTORY),
EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, &sz0) ||
sub(OptHeaderSize, sz0, &HeaderWithoutDataDir) ||
sub(PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
HeaderWithoutDataDir, &sz0) ||
mul(ctx->NumberOfRvaAndSizes, sizeof(EFI_IMAGE_DATA_DIRECTORY),
&sz1) ||
(sz0 != sz1)) {
if (mul(sizeof(EFI_IMAGE_DATA_DIRECTORY),
EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, &sz0))
debug(ERROR,
"sizeof(EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES overflows\n");
else
debug(ERROR,
"sizeof(EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES = %zu\n",
sz0);
if (sub(OptHeaderSize, sz0, &HeaderWithoutDataDir))
debug(ERROR,
"OptHeaderSize (%zu) - HeaderWithoutDataDir (%zu) overflows\n",
OptHeaderSize, HeaderWithoutDataDir);
else
debug(ERROR,
"OptHeaderSize (%zu) - HeaderWithoutDataDir (%zu) = %zu\n",
OptHeaderSize, sz0, HeaderWithoutDataDir);
if (sub(PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
HeaderWithoutDataDir, &sz0)) {
debug(ERROR,
"PEHdr->Pe32.FileHeader.SizeOfOptionalHeader (%d) - %zu overflows\n",
PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
HeaderWithoutDataDir);
} else {
debug(ERROR,
"PEHdr->Pe32.FileHeader.SizeOfOptionalHeader (%d)- %zu = %zu\n",
PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
HeaderWithoutDataDir, sz0);
}
if (mul(ctx->NumberOfRvaAndSizes,
sizeof(EFI_IMAGE_DATA_DIRECTORY), &sz1))
debug(ERROR,
"ctx->NumberOfRvaAndSizes (%zu) * sizeof(EFI_IMAGE_DATA_DIRECTORY) overflows\n",
ctx->NumberOfRvaAndSizes);
else
debug(ERROR,
"ctx->NumberOfRvaAndSizes (%zu) * sizeof(EFI_IMAGE_DATA_DIRECTORY) = %zu\n",
ctx->NumberOfRvaAndSizes, sz1);
debug(ERROR,
"space after image header:%zu data directory size:%zu\n",
sz0, sz1);
errx(1, "%s: image header overflows data directory", file);
}
if (add(DOSHdr->e_lfanew, sizeof(UINT32), &SectionHeaderOffset) ||
add(SectionHeaderOffset, sizeof(EFI_IMAGE_FILE_HEADER),
&SectionHeaderOffset) ||
add(SectionHeaderOffset,
PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
&SectionHeaderOffset)) {
debug(ERROR, "SectionHeaderOffset:%" PRIu32 " + %zu + %zu + %d",
DOSHdr->e_lfanew, sizeof(UINT32),
sizeof(EFI_IMAGE_FILE_HEADER),
PEHdr->Pe32.FileHeader.SizeOfOptionalHeader);
errx(1, "%s: SectionHeaderOffset would overflow", file);
}
if (sub(ctx->ImageSize, SectionHeaderOffset, &sz0) ||
div(sz0, EFI_IMAGE_SIZEOF_SECTION_HEADER, &sz0) ||
(sz0 <= ctx->NumberOfSections)) {
debug(ERROR, "(%" PRIu64 " - %zu) / %d > %d\n", ctx->ImageSize,
SectionHeaderOffset, EFI_IMAGE_SIZEOF_SECTION_HEADER,
ctx->NumberOfSections);
errx(1, "%s: image sections overflow image size", file);
}
if (sub(ctx->SizeOfHeaders, SectionHeaderOffset, &sz0) ||
div(sz0, EFI_IMAGE_SIZEOF_SECTION_HEADER, &sz0) ||
(sz0 < ctx->NumberOfSections)) {
debug(ERROR, "(%zu - %zu) / %d >= %d\n", ctx->SizeOfHeaders,
SectionHeaderOffset, EFI_IMAGE_SIZEOF_SECTION_HEADER,
ctx->NumberOfSections);
errx(1, "%s: image sections overflow section headers", file);
}
if (sub((uintptr_t)PEHdr, (uintptr_t)data, &sz0) ||
add(sz0, sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION), &sz0) ||
(sz0 > datasize)) {
errx(1, "%s: PE Image size %zu > %zu", file, sz0, datasize);
}
if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED)
errx(1, "%s: Unsupported image - Relocations have been stripped", file);
if (image_is_64_bit(PEHdr)) {
ctx->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
ctx->EntryPoint =
PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
ctx->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
ctx->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
} else {
ctx->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
ctx->EntryPoint =
PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
ctx->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
ctx->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
}
if (add((uintptr_t)PEHdr, PEHdr->Pe32.FileHeader.SizeOfOptionalHeader,
&loc) ||
add(loc, sizeof(UINT32), &loc) ||
add(loc, sizeof(EFI_IMAGE_FILE_HEADER), &loc))
errx(1, "%s: invalid location for first section", file);
ctx->FirstSection = (EFI_IMAGE_SECTION_HEADER *)loc;
if (ctx->ImageSize < ctx->SizeOfHeaders)
errx(1,
"%s: Image size %"PRIu64" is smaller than header size %lu",
file, ctx->ImageSize, ctx->SizeOfHeaders);
if (sub((uintptr_t)ctx->SecDir, (uintptr_t)data, &sz0) ||
sub(datasize, sizeof(EFI_IMAGE_DATA_DIRECTORY), &sz1) ||
sz0 > sz1)
errx(1,
"%s: security direcory offset %zu past data directory at %zu",
file, sz0, sz1);
if (ctx->SecDir->VirtualAddress > datasize ||
(ctx->SecDir->VirtualAddress == datasize &&
ctx->SecDir->Size > 0))
errx(1, "%s: Security directory extends past end", file);
}
static void
fix_timestamp(PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
{
uint32_t ts;
if (image_is_64_bit(ctx->PEHdr)) {
ts = ctx->PEHdr->Pe32Plus.FileHeader.TimeDateStamp;
} else {
ts = ctx->PEHdr->Pe32.FileHeader.TimeDateStamp;
}
if (ts != 0) {
debug(INFO, "Updating timestamp from 0x%08x to 0\n", ts);
if (image_is_64_bit(ctx->PEHdr)) {
ctx->PEHdr->Pe32Plus.FileHeader.TimeDateStamp = 0;
} else {
ctx->PEHdr->Pe32.FileHeader.TimeDateStamp = 0;
}
}
}
static void
fix_checksum(PE_COFF_LOADER_IMAGE_CONTEXT *ctx, void *map, size_t mapsize)
{
uint32_t old;
uint32_t checksum = 0;
uint16_t word;
uint8_t *data = map;
if (image_is_64_bit(ctx->PEHdr)) {
old = ctx->PEHdr->Pe32Plus.OptionalHeader.CheckSum;
ctx->PEHdr->Pe32Plus.OptionalHeader.CheckSum = 0;
} else {
old = ctx->PEHdr->Pe32.OptionalHeader.CheckSum;
ctx->PEHdr->Pe32.OptionalHeader.CheckSum = 0;
}
debug(NOISE, "old checksum was 0x%08x\n", old);
for (size_t i = 0; i < mapsize - 1; i += 2) {
word = (data[i + 1] << 8ul) | data[i];
checksum += word;
checksum = 0xffff & (checksum + (checksum >> 0x10));
}
debug(NOISE, "checksum = 0x%08x + 0x%08zx = 0x%08zx\n", checksum,
mapsize, checksum + mapsize);
checksum += mapsize;
if (checksum != old)
debug(INFO, "Updating checksum from 0x%08x to 0x%08x\n",
old, checksum);
if (image_is_64_bit(ctx->PEHdr)) {
ctx->PEHdr->Pe32Plus.OptionalHeader.CheckSum = checksum;
} else {
ctx->PEHdr->Pe32.OptionalHeader.CheckSum = checksum;
}
}
static void
handle_one(char *f)
{
int fd;
int rc;
struct stat statbuf;
size_t sz;
void *map;
int failed = 0;
PE_COFF_LOADER_IMAGE_CONTEXT ctx = { 0, 0 };
fd = open(f, O_RDWR | O_EXCL);
if (fd < 0)
err(1, "Could not open \"%s\"", f);
rc = fstat(fd, &statbuf);
if (rc < 0)
err(1, "Could not stat \"%s\"", f);
sz = statbuf.st_size;
map = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED)
err(1, "Could not map \"%s\"", f);
load_pe(f, map, sz, &ctx);
fix_timestamp(&ctx);
fix_checksum(&ctx, map, sz);
rc = msync(map, sz, MS_SYNC);
if (rc < 0) {
warn("msync(%p, %zu, MS_SYNC) failed", map, sz);
failed = 1;
}
munmap(map, sz);
if (rc < 0) {
warn("munmap(%p, %zu) failed", map, sz);
failed = 1;
}
rc = close(fd);
if (rc < 0) {
warn("close(%d) failed", fd);
failed = 1;
}
if (failed)
exit(1);
}
static void __attribute__((__noreturn__)) usage(int status)
{
FILE *out = status ? stderr : stdout;
fprintf(out,
"Usage: post-process-pe [OPTIONS] file0 [file1 [.. fileN]]\n");
fprintf(out, "Options:\n");
fprintf(out, " -q Be more quiet\n");
fprintf(out, " -v Be more verbose\n");
fprintf(out, " -h Print this help text and exit\n");
exit(status);
}
int main(int argc, char **argv)
{
int i;
struct option options[] = {
{.name = "help",
.val = '?',
},
{.name = "usage",
.val = '?',
},
{.name = "quiet",
.val = 'q',
},
{.name = "verbose",
.val = 'v',
},
{.name = ""}
};
int longindex = -1;
while ((i = getopt_long(argc, argv, "hqsv", options, &longindex)) != -1) {
switch (i) {
case 'h':
case '?':
usage(longindex == -1 ? 1 : 0);
break;
case 'q':
verbosity = MAX(verbosity - 1, MIN_VERBOSITY);
break;
case 'v':
verbosity = MIN(verbosity + 1, MAX_VERBOSITY);
break;
}
}
if (optind == argc)
usage(1);
for (i = optind; i < argc; i++)
handle_one(argv[i]);
return 0;
}
// vim:fenc=utf-8:tw=75:noet

View File

@ -33,7 +33,9 @@ get_active_systab(void)
static typeof(systab->BootServices->LoadImage) system_load_image; static typeof(systab->BootServices->LoadImage) system_load_image;
static typeof(systab->BootServices->StartImage) system_start_image; static typeof(systab->BootServices->StartImage) system_start_image;
static typeof(systab->BootServices->Exit) system_exit; static typeof(systab->BootServices->Exit) system_exit;
#if !defined(DISABLE_EBS_PROTECTION)
static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services; static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services;
#endif /* !defined(DISABLE_EBS_PROTECTION) */
static EFI_HANDLE last_loaded_image; static EFI_HANDLE last_loaded_image;
@ -45,8 +47,10 @@ unhook_system_services(void)
systab->BootServices->LoadImage = system_load_image; systab->BootServices->LoadImage = system_load_image;
systab->BootServices->StartImage = system_start_image; systab->BootServices->StartImage = system_start_image;
#if !defined(DISABLE_EBS_PROTECTION)
systab->BootServices->ExitBootServices = system_exit_boot_services; systab->BootServices->ExitBootServices = system_exit_boot_services;
gBS = systab->BootServices; #endif /* !defined(DISABLE_EBS_PROTECTION) */
BS = systab->BootServices;
} }
static EFI_STATUS EFIAPI static EFI_STATUS EFIAPI
@ -57,7 +61,7 @@ load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
EFI_STATUS efi_status; EFI_STATUS efi_status;
unhook_system_services(); unhook_system_services();
efi_status = gBS->LoadImage(BootPolicy, ParentImageHandle, DevicePath, efi_status = BS->LoadImage(BootPolicy, ParentImageHandle, DevicePath,
SourceBuffer, SourceSize, ImageHandle); SourceBuffer, SourceSize, ImageHandle);
hook_system_services(systab); hook_system_services(systab);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
@ -77,7 +81,7 @@ replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 *
loader_is_participating = 1; loader_is_participating = 1;
uninstall_shim_protocols(); uninstall_shim_protocols();
} }
efi_status = gBS->StartImage(image_handle, exit_data_size, exit_data); efi_status = BS->StartImage(image_handle, exit_data_size, exit_data);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
if (image_handle == last_loaded_image) { if (image_handle == last_loaded_image) {
EFI_STATUS efi_status2 = install_shim_protocols(); EFI_STATUS efi_status2 = install_shim_protocols();
@ -87,7 +91,7 @@ replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 *
efi_status2); efi_status2);
console_print(L"shim cannot continue, sorry.\n"); console_print(L"shim cannot continue, sorry.\n");
msleep(5000000); msleep(5000000);
gRT->ResetSystem(EfiResetShutdown, RT->ResetSystem(EfiResetShutdown,
EFI_SECURITY_VIOLATION, EFI_SECURITY_VIOLATION,
0, NULL); 0, NULL);
} }
@ -106,7 +110,7 @@ exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
verification_method == VERIFIED_BY_HASH) { verification_method == VERIFIED_BY_HASH) {
unhook_system_services(); unhook_system_services();
EFI_STATUS efi_status; EFI_STATUS efi_status;
efi_status = gBS->ExitBootServices(image_key, map_key); efi_status = BS->ExitBootServices(image_key, map_key);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
hook_system_services(systab); hook_system_services(systab);
return efi_status; return efi_status;
@ -115,7 +119,7 @@ exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
console_print(L"Bootloader has not verified loaded image.\n"); console_print(L"Bootloader has not verified loaded image.\n");
console_print(L"System is compromised. halting.\n"); console_print(L"System is compromised. halting.\n");
msleep(5000000); msleep(5000000);
gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, 0, NULL); RT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, 0, NULL);
return EFI_SECURITY_VIOLATION; return EFI_SECURITY_VIOLATION;
} }
#endif /* !defined(DISABLE_EBS_PROTECTION) */ #endif /* !defined(DISABLE_EBS_PROTECTION) */
@ -130,7 +134,7 @@ do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
restore_loaded_image(); restore_loaded_image();
efi_status = gBS->Exit(ImageHandle, ExitStatus, efi_status = BS->Exit(ImageHandle, ExitStatus,
ExitDataSize, ExitData); ExitDataSize, ExitData);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
EFI_STATUS efi_status2 = shim_init(); EFI_STATUS efi_status2 = shim_init();
@ -140,7 +144,7 @@ do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
efi_status2); efi_status2);
console_print(L"shim cannot continue, sorry.\n"); console_print(L"shim cannot continue, sorry.\n");
msleep(5000000); msleep(5000000);
gRT->ResetSystem(EfiResetShutdown, RT->ResetSystem(EfiResetShutdown,
EFI_SECURITY_VIOLATION, 0, NULL); EFI_SECURITY_VIOLATION, 0, NULL);
} }
} }
@ -151,7 +155,7 @@ void
hook_system_services(EFI_SYSTEM_TABLE *local_systab) hook_system_services(EFI_SYSTEM_TABLE *local_systab)
{ {
systab = local_systab; systab = local_systab;
gBS = systab->BootServices; BS = systab->BootServices;
/* We need to hook various calls to make this work... */ /* We need to hook various calls to make this work... */
@ -181,18 +185,15 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab)
void void
unhook_exit(void) unhook_exit(void)
{ {
#if !defined(DISABLE_EBS_PROTECTION)
systab->BootServices->Exit = system_exit; systab->BootServices->Exit = system_exit;
gBS = systab->BootServices; BS = systab->BootServices;
#endif /* defined(DISABLE_EBS_PROTECTION) */
return;
} }
void void
hook_exit(EFI_SYSTEM_TABLE *local_systab) hook_exit(EFI_SYSTEM_TABLE *local_systab)
{ {
systab = local_systab; systab = local_systab;
gBS = local_systab->BootServices; BS = local_systab->BootServices;
/* we need to hook Exit() so that we can allow users to quit the /* we need to hook Exit() so that we can allow users to quit the
* bootloader and still e.g. start a new one or run an internal * bootloader and still e.g. start a new one or run an internal

569
shim.c
View File

@ -40,10 +40,6 @@ static EFI_HANDLE global_image_handle;
static EFI_LOADED_IMAGE *shim_li; static EFI_LOADED_IMAGE *shim_li;
static EFI_LOADED_IMAGE shim_li_bak; static EFI_LOADED_IMAGE shim_li_bak;
static CHAR16 *second_stage;
void *load_options;
UINT32 load_options_size;
list_t sbat_var; list_t sbat_var;
/* /*
@ -56,28 +52,8 @@ extern struct {
UINT32 vendor_deauthorized_offset; UINT32 vendor_deauthorized_offset;
} cert_table; } cert_table;
UINT32 vendor_authorized_size = 0;
UINT8 *vendor_authorized = NULL;
UINT32 vendor_deauthorized_size = 0;
UINT8 *vendor_deauthorized = NULL;
#if defined(ENABLE_SHIM_CERT)
UINT32 build_cert_size;
UINT8 *build_cert;
#endif /* defined(ENABLE_SHIM_CERT) */
/*
* indicator of how an image has been verified
*/
verification_method_t verification_method;
int loader_is_participating;
#define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }} #define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }}
UINT8 user_insecure_mode;
UINT8 ignore_db;
typedef enum { typedef enum {
DATA_FOUND, DATA_FOUND,
DATA_NOT_FOUND, DATA_NOT_FOUND,
@ -453,8 +429,11 @@ BOOLEAN secure_mode (void)
return FALSE; return FALSE;
if (variable_is_secureboot() != 1) { if (variable_is_secureboot() != 1) {
if (verbose && !in_protocol && first) if (verbose && !in_protocol && first) {
console_notify(L"Secure boot not enabled"); CHAR16 *title = L"Secure boot not enabled";
CHAR16 *message = L"Press any key to continue";
console_countdown(title, message, 5);
}
first = 0; first = 0;
return FALSE; return FALSE;
} }
@ -466,8 +445,11 @@ BOOLEAN secure_mode (void)
* to consider it. * to consider it.
*/ */
if (variable_is_setupmode(0) == 1) { if (variable_is_setupmode(0) == 1) {
if (verbose && !in_protocol && first) if (verbose && !in_protocol && first) {
console_notify(L"Platform is in setup mode"); CHAR16 *title = L"Platform is in setup mode";
CHAR16 *message = L"Press any key to continue";
console_countdown(title, message, 5);
}
first = 0; first = 0;
return FALSE; return FALSE;
} }
@ -714,25 +696,12 @@ verify_buffer (char *data, int datasize,
} }
static int static int
should_use_fallback(EFI_HANDLE image_handle) is_removable_media_path(EFI_LOADED_IMAGE *li)
{ {
EFI_LOADED_IMAGE *li;
unsigned int pathlen = 0; unsigned int pathlen = 0;
CHAR16 *bootpath = NULL; CHAR16 *bootpath = NULL;
EFI_FILE_IO_INTERFACE *fio = NULL;
EFI_FILE *vh = NULL;
EFI_FILE *fh = NULL;
EFI_STATUS efi_status;
int ret = 0; int ret = 0;
efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
(void **)&li);
if (EFI_ERROR(efi_status)) {
perror(L"Could not get image for bootx64.efi: %r\n",
efi_status);
return 0;
}
bootpath = DevicePathToStr(li->FilePath); bootpath = DevicePathToStr(li->FilePath);
/* Check the beginning of the string and the end, to avoid /* Check the beginning of the string and the end, to avoid
@ -750,7 +719,37 @@ should_use_fallback(EFI_HANDLE image_handle)
if (pathlen < 5 || StrCaseCmp(bootpath + pathlen - 4, L".EFI")) if (pathlen < 5 || StrCaseCmp(bootpath + pathlen - 4, L".EFI"))
goto error; goto error;
efi_status = gBS->HandleProtocol(li->DeviceHandle, &FileSystemProtocol, ret = 1;
error:
if (bootpath)
FreePool(bootpath);
return ret;
}
static int
should_use_fallback(EFI_HANDLE image_handle)
{
EFI_LOADED_IMAGE *li;
EFI_FILE_IO_INTERFACE *fio = NULL;
EFI_FILE *vh = NULL;
EFI_FILE *fh = NULL;
EFI_STATUS efi_status;
int ret = 0;
efi_status = BS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
(void **)&li);
if (EFI_ERROR(efi_status)) {
perror(L"Could not get image for boot" EFI_ARCH L".efi: %r\n",
efi_status);
return 0;
}
if (!is_removable_media_path(li))
goto error;
efi_status = BS->HandleProtocol(li->DeviceHandle, &FileSystemProtocol,
(void **) &fio); (void **) &fio);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Could not get fio for li->DeviceHandle: %r\n", perror(L"Could not get fio for li->DeviceHandle: %r\n",
@ -782,105 +781,9 @@ error:
fh->Close(fh); fh->Close(fh);
if (vh) if (vh)
vh->Close(vh); vh->Close(vh);
if (bootpath)
FreePool(bootpath);
return ret; return ret;
} }
/*
* Generate the path of an executable given shim's path and the name
* of the executable
*/
static EFI_STATUS generate_path_from_image_path(EFI_LOADED_IMAGE *li,
CHAR16 *ImagePath,
CHAR16 **PathName)
{
EFI_DEVICE_PATH *devpath;
unsigned int i;
int j, last = -1;
unsigned int pathlen = 0;
EFI_STATUS efi_status = EFI_SUCCESS;
CHAR16 *bootpath;
/*
* Suuuuper lazy technique here, but check and see if this is a full
* path to something on the ESP. Backwards compatibility demands
* that we don't just use \\, because we (not particularly brightly)
* used to require that the relative file path started with that.
*
* If it is a full path, don't try to merge it with the directory
* from our Loaded Image handle.
*/
if (StrSize(ImagePath) > 5 && StrnCmp(ImagePath, L"\\EFI\\", 5) == 0) {
*PathName = StrDuplicate(ImagePath);
if (!*PathName) {
perror(L"Failed to allocate path buffer\n");
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
devpath = li->FilePath;
bootpath = DevicePathToStr(devpath);
pathlen = StrLen(bootpath);
/*
* DevicePathToStr() concatenates two nodes with '/'.
* Convert '/' to '\\'.
*/
for (i = 0; i < pathlen; i++) {
if (bootpath[i] == '/')
bootpath[i] = '\\';
}
for (i=pathlen; i>0; i--) {
if (bootpath[i] == '\\' && bootpath[i-1] == '\\')
bootpath[i] = '/';
else if (last == -1 && bootpath[i] == '\\')
last = i;
}
if (last == -1 && bootpath[0] == '\\')
last = 0;
bootpath[last+1] = '\0';
if (last > 0) {
for (i = 0, j = 0; bootpath[i] != '\0'; i++) {
if (bootpath[i] != '/') {
bootpath[j] = bootpath[i];
j++;
}
}
bootpath[j] = '\0';
}
for (i = 0, last = 0; i < StrLen(ImagePath); i++)
if (ImagePath[i] == '\\')
last = i + 1;
ImagePath = ImagePath + last;
*PathName = AllocatePool(StrSize(bootpath) + StrSize(ImagePath));
if (!*PathName) {
perror(L"Failed to allocate path buffer\n");
efi_status = EFI_OUT_OF_RESOURCES;
goto error;
}
*PathName[0] = '\0';
if (StrnCaseCmp(bootpath, ImagePath, StrLen(bootpath)))
StrCat(*PathName, bootpath);
StrCat(*PathName, ImagePath);
error:
FreePool(bootpath);
return efi_status;
}
/* /*
* Open the second stage bootloader and read it into a buffer * Open the second stage bootloader and read it into a buffer
*/ */
@ -900,7 +803,7 @@ static EFI_STATUS load_image (EFI_LOADED_IMAGE *li, void **data,
/* /*
* Open the device * Open the device
*/ */
efi_status = gBS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID, efi_status = BS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
(void **) &drive); (void **) &drive);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Failed to find fs: %r\n", efi_status); perror(L"Failed to find fs: %r\n", efi_status);
@ -1101,7 +1004,7 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
* We need to refer to the loaded image protocol on the running * We need to refer to the loaded image protocol on the running
* binary in order to find our path * binary in order to find our path
*/ */
efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID, efi_status = BS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
(void **)&shim_li); (void **)&shim_li);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Unable to init protocol\n"); perror(L"Unable to init protocol\n");
@ -1233,6 +1136,19 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
use_fb ? FALLBACK : second_stage); use_fb ? FALLBACK : second_stage);
} }
// If the filename is invalid, or the file does not exist,
// just fallback to the default loader.
if (!use_fb && (efi_status == EFI_INVALID_PARAMETER ||
efi_status == EFI_NOT_FOUND)) {
console_print(
L"start_image() returned %r, falling back to default loader\n",
efi_status);
msleep(2000000);
load_options = NULL;
load_options_size = 0;
efi_status = start_image(image_handle, DEFAULT_LOADER);
}
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_print(L"start_image() returned %r\n", efi_status); console_print(L"start_image() returned %r\n", efi_status);
msleep(2000000); msleep(2000000);
@ -1241,145 +1157,6 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
return efi_status; return efi_status;
} }
static inline EFI_STATUS
get_load_option_optional_data(UINT8 *data, UINTN data_size,
UINT8 **od, UINTN *ods)
{
/*
* If it's not at least Attributes + FilePathListLength +
* Description=L"" + 0x7fff0400 (EndEntrireDevicePath), it can't
* be valid.
*/
if (data_size < (sizeof(UINT32) + sizeof(UINT16) + 2 + 4))
return EFI_INVALID_PARAMETER;
UINT8 *cur = data + sizeof(UINT32);
UINT16 fplistlen = *(UINT16 *)cur;
/*
* If there's not enough space for the file path list and the
* smallest possible description (L""), it's not valid.
*/
if (fplistlen > data_size - (sizeof(UINT32) + 2 + 4))
return EFI_INVALID_PARAMETER;
cur += sizeof(UINT16);
UINTN limit = data_size - (cur - data) - fplistlen;
UINTN i;
for (i = 0; i < limit ; i++) {
/* If the description isn't valid UCS2-LE, it's not valid. */
if (i % 2 != 0) {
if (cur[i] != 0)
return EFI_INVALID_PARAMETER;
} else if (cur[i] == 0) {
/* we've found the end */
i++;
if (i >= limit || cur[i] != 0)
return EFI_INVALID_PARAMETER;
break;
}
}
i++;
if (i > limit)
return EFI_INVALID_PARAMETER;
/*
* If i is limit, we know the rest of this is the FilePathList and
* there's no optional data. So just bail now.
*/
if (i == limit) {
*od = NULL;
*ods = 0;
return EFI_SUCCESS;
}
cur += i;
limit -= i;
limit += fplistlen;
i = 0;
while (limit - i >= 4) {
struct {
UINT8 type;
UINT8 subtype;
UINT16 len;
} dp = {
.type = cur[i],
.subtype = cur[i+1],
/*
* it's a little endian UINT16, but we're not
* guaranteed alignment is sane, so we can't just
* typecast it directly.
*/
.len = (cur[i+3] << 8) | cur[i+2],
};
/*
* We haven't found an EndEntire, so this has to be a valid
* EFI_DEVICE_PATH in order for the data to be valid. That
* means it has to fit, and it can't be smaller than 4 bytes.
*/
if (dp.len < 4 || dp.len > limit)
return EFI_INVALID_PARAMETER;
/*
* see if this is an EndEntire node...
*/
if (dp.type == 0x7f && dp.subtype == 0xff) {
/*
* if we've found the EndEntire node, it must be 4
* bytes
*/
if (dp.len != 4)
return EFI_INVALID_PARAMETER;
i += dp.len;
break;
}
/*
* It's just some random DP node; skip it.
*/
i += dp.len;
}
if (i != fplistlen)
return EFI_INVALID_PARAMETER;
/*
* if there's any space left, it's "optional data"
*/
*od = cur + i;
*ods = limit - i;
return EFI_SUCCESS;
}
static int is_our_path(EFI_LOADED_IMAGE *li, CHAR16 *path)
{
CHAR16 *dppath = NULL;
CHAR16 *PathName = NULL;
EFI_STATUS efi_status;
int ret = 1;
dppath = DevicePathToStr(li->FilePath);
if (!dppath)
return 0;
efi_status = generate_path_from_image_path(li, path, &PathName);
if (EFI_ERROR(efi_status)) {
perror(L"Unable to generate path %s: %r\n", path,
efi_status);
goto done;
}
dprint(L"dppath: %s\n", dppath);
dprint(L"path: %s\n", path);
if (StrnCaseCmp(dppath, PathName, StrLen(dppath)))
ret = 0;
done:
FreePool(dppath);
FreePool(PathName);
return ret;
}
/* /*
* Check the load options to specify the second stage loader * Check the load options to specify the second stage loader
*/ */
@ -1387,218 +1164,33 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
{ {
EFI_STATUS efi_status; EFI_STATUS efi_status;
EFI_LOADED_IMAGE *li = NULL; EFI_LOADED_IMAGE *li = NULL;
CHAR16 *start = NULL;
UINTN remaining_size = 0;
CHAR16 *loader_str = NULL;
UINTN loader_len = 0;
unsigned int i;
UINTN second_stage_len;
second_stage_len = (StrLen(DEFAULT_LOADER) + 1) * sizeof(CHAR16); second_stage = DEFAULT_LOADER;
second_stage = AllocatePool(second_stage_len);
if (!second_stage) {
perror(L"Could not allocate %lu bytes\n", second_stage_len);
return EFI_OUT_OF_RESOURCES;
}
StrCpy(second_stage, DEFAULT_LOADER);
load_options = NULL; load_options = NULL;
load_options_size = 0; load_options_size = 0;
efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol, efi_status = BS->HandleProtocol(image_handle, &LoadedImageProtocol,
(void **) &li); (void **) &li);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror (L"Failed to get load options: %r\n", efi_status); perror (L"Failed to get load options: %r\n", efi_status);
return efi_status; return efi_status;
} }
/* Sanity check since we make several assumptions about the length */ #if defined(DISABLE_REMOVABLE_LOAD_OPTIONS)
if (li->LoadOptionsSize % 2 != 0)
return EFI_INVALID_PARAMETER;
/* So, load options are a giant pain in the ass. If we're invoked
* from the EFI shell, we get something like this:
00000000 5c 00 45 00 36 00 49 00 5c 00 66 00 65 00 64 00 |\.E.F.I.\.f.e.d.|
00000010 6f 00 72 00 61 00 5c 00 73 00 68 00 69 00 6d 00 |o.r.a.\.s.h.i.m.|
00000020 78 00 36 00 34 00 2e 00 64 00 66 00 69 00 20 00 |x.6.4...e.f.i. .|
00000030 5c 00 45 00 46 00 49 00 5c 00 66 00 65 00 64 00 |\.E.F.I.\.f.e.d.|
00000040 6f 00 72 00 61 00 5c 00 66 00 77 00 75 00 70 00 |o.r.a.\.f.w.u.p.|
00000050 64 00 61 00 74 00 65 00 2e 00 65 00 66 00 20 00 |d.a.t.e.e.f.i. .|
00000060 00 00 66 00 73 00 30 00 3a 00 5c 00 00 00 |..f.s.0.:.\...|
*
* which is just some paths rammed together separated by a UCS-2 NUL.
* But if we're invoked from BDS, we get something more like:
*
00000000 01 00 00 00 62 00 4c 00 69 00 6e 00 75 00 78 00 |....b.L.i.n.u.x.|
00000010 20 00 46 00 69 00 72 00 6d 00 77 00 61 00 72 00 | .F.i.r.m.w.a.r.|
00000020 65 00 20 00 55 00 70 00 64 00 61 00 74 00 65 00 |e. .U.p.d.a.t.e.|
00000030 72 00 00 00 40 01 2a 00 01 00 00 00 00 08 00 00 |r.....*.........|
00000040 00 00 00 00 00 40 06 00 00 00 00 00 1a 9e 55 bf |.....@........U.|
00000050 04 57 f2 4f b4 4a ed 26 4a 40 6a 94 02 02 04 04 |.W.O.:.&J@j.....|
00000060 34 00 5c 00 45 00 46 00 49 00 5c 00 66 00 65 00 |4.\.E.F.I.f.e.d.|
00000070 64 00 6f 00 72 00 61 00 5c 00 73 00 68 00 69 00 |o.r.a.\.s.h.i.m.|
00000080 6d 00 78 00 36 00 34 00 2e 00 65 00 66 00 69 00 |x.6.4...e.f.i...|
00000090 00 00 7f ff 40 00 20 00 5c 00 66 00 77 00 75 00 |...... .\.f.w.u.|
000000a0 70 00 78 00 36 00 34 00 2e 00 65 00 66 00 69 00 |p.x.6.4...e.f.i.|
000000b0 00 00 |..|
*
* which is clearly an EFI_LOAD_OPTION filled in halfway reasonably.
* In short, the UEFI shell is still a useless piece of junk.
*
* But then on some versions of BDS, we get:
00000000 5c 00 66 00 77 00 75 00 70 00 78 00 36 00 34 00 |\.f.w.u.p.x.6.4.|
00000010 2e 00 65 00 66 00 69 00 00 00 |..e.f.i...|
0000001a
* which as you can see is one perfectly normal UCS2-EL string
* containing the load option from the Boot#### variable.
*
* We also sometimes find a guid or partial guid at the end, because
* BDS will add that, but we ignore that here.
*/
/* /*
* Maybe there just aren't any options... * boot services build very strange load options, and we might misparse them,
*/ * causing boot failures on removable media.
if (li->LoadOptionsSize == 0)
return EFI_SUCCESS;
/*
* In either case, we've got to have at least a UCS2 NUL...
*/
if (li->LoadOptionsSize < 2)
return EFI_BAD_BUFFER_SIZE;
/*
* Some awesome versions of BDS will add entries for Linux. On top
* of that, some versions of BDS will "tag" any Boot#### entries they
* create by putting a GUID at the very end of the optional data in
* the EFI_LOAD_OPTIONS, thus screwing things up for everybody who
* tries to actually *use* the optional data for anything. Why they
* did this instead of adding a flag to the spec to /say/ it's
* created by BDS, I do not know. For shame.
*
* Anyway, just nerf that out from the start. It's always just
* garbage at the end.
*/
if (li->LoadOptionsSize > 16) {
if (CompareGuid((EFI_GUID *)(li->LoadOptions
+ (li->LoadOptionsSize - 16)),
&BDS_GUID) == 0)
li->LoadOptionsSize -= 16;
}
/*
* Apparently sometimes we get L"\0\0"? Which isn't useful at all.
*/
if (is_all_nuls(li->LoadOptions, li->LoadOptionsSize))
return EFI_SUCCESS;
/*
* Check and see if this is just a list of strings. If it's an
* EFI_LOAD_OPTION, it'll be 0, since we know EndEntire device path
* won't pass muster as UCS2-LE.
*
* If there are 3 strings, we're launched from the shell most likely,
* But we actually only care about the second one.
*/
UINTN strings = count_ucs2_strings(li->LoadOptions,
li->LoadOptionsSize);
/*
* In some cases we get strings == 1 because BDS is using L' ' as the
* delimeter:
* 0000:74 00 65 00 73 00 74 00 2E 00 65 00 66 00 69 00 t.e.s.t...e.f.i.
* 0016:20 00 6F 00 6E 00 65 00 20 00 74 00 77 00 6F 00 ..o.n.e...t.w.o.
* 0032:20 00 74 00 68 00 72 00 65 00 65 00 00 00 ..t.h.r.e.e...
*
* If so replace it with NULs since the code already handles that
* case.
*/
if (strings == 1) {
UINT16 *cur = start = li->LoadOptions;
/* replace L' ' with L'\0' if we find any */
for (i = 0; i < li->LoadOptionsSize / 2; i++) {
if (cur[i] == L' ')
cur[i] = L'\0';
}
/* redo the string count */
strings = count_ucs2_strings(li->LoadOptions,
li->LoadOptionsSize);
}
/*
* If it's not string data, try it as an EFI_LOAD_OPTION.
*/
if (strings == 0) {
/*
* We at least didn't find /enough/ strings. See if it works
* as an EFI_LOAD_OPTION.
*/
efi_status = get_load_option_optional_data(li->LoadOptions,
li->LoadOptionsSize,
(UINT8 **)&start,
&loader_len);
if (EFI_ERROR(efi_status))
return EFI_SUCCESS;
remaining_size = 0;
} else if (strings >= 2) {
/*
* UEFI shell copies the whole line of the command into
* LoadOptions. We ignore the string before the first L'\0',
* i.e. the name of this program.
*/
UINT16 *cur = li->LoadOptions;
for (i = 1; i < li->LoadOptionsSize / 2; i++) {
if (cur[i - 1] == L'\0') {
start = &cur[i];
remaining_size = li->LoadOptionsSize - (i * 2);
break;
}
}
remaining_size -= i * 2 + 2;
} else if (strings == 1 && is_our_path(li, start)) {
/*
* And then I found a version of BDS that gives us our own path
* in LoadOptions:
77162C58 5c 00 45 00 46 00 49 00 |\.E.F.I.|
77162C60 5c 00 42 00 4f 00 4f 00 54 00 5c 00 42 00 4f 00 |\.B.O.O.T.\.B.O.|
77162C70 4f 00 54 00 58 00 36 00 34 00 2e 00 45 00 46 00 |O.T.X.6.4...E.F.|
77162C80 49 00 00 00 |I...|
* which is just cruel... So yeah, just don't use it.
*/ */
if (is_removable_media_path(li)) {
dprint("Invoked from removable media path, ignoring boot options");
return EFI_SUCCESS; return EFI_SUCCESS;
} }
#endif
/* efi_status = parse_load_options(li);
* Set up the name of the alternative loader and the LoadOptions for if (EFI_ERROR(efi_status)) {
* the loader perror (L"Failed to get load options: %r\n", efi_status);
*/ return efi_status;
if (loader_len > 0) {
/* we might not always have a NULL at the end */
loader_str = AllocatePool(loader_len + 2);
if (!loader_str) {
perror(L"Failed to allocate loader string\n");
return EFI_OUT_OF_RESOURCES;
}
for (i = 0; i < loader_len / 2; i++)
loader_str[i] = start[i];
loader_str[loader_len/2] = L'\0';
second_stage = loader_str;
load_options = remaining_size ? start + (loader_len/2) : NULL;
load_options_size = remaining_size;
} }
return EFI_SUCCESS; return EFI_SUCCESS;
@ -1677,7 +1269,7 @@ install_shim_protocols(void)
/* /*
* Install the protocol * Install the protocol
*/ */
efi_status = gBS->InstallProtocolInterface(&shim_lock_handle, efi_status = BS->InstallProtocolInterface(&shim_lock_handle,
&SHIM_LOCK_GUID, &SHIM_LOCK_GUID,
EFI_NATIVE_INTERFACE, EFI_NATIVE_INTERFACE,
&shim_lock_interface); &shim_lock_interface);
@ -1706,7 +1298,7 @@ uninstall_shim_protocols(void)
/* /*
* If we're back here then clean everything up before exiting * If we're back here then clean everything up before exiting
*/ */
gBS->UninstallProtocolInterface(shim_lock_handle, &SHIM_LOCK_GUID, BS->UninstallProtocolInterface(shim_lock_handle, &SHIM_LOCK_GUID,
&shim_lock_interface); &shim_lock_interface);
if (!secure_mode()) if (!secure_mode())
@ -1777,12 +1369,6 @@ shim_fini(void)
unhook_exit(); unhook_exit();
/*
* Free the space allocated for the alternative 2nd stage loader
*/
if (load_options_size > 0 && second_stage)
FreePool(second_stage);
console_fini(); console_fini();
} }
@ -1837,7 +1423,7 @@ debug_hook(void)
if (x > 12000) if (x > 12000)
break; break;
#endif #endif
pause(); wait_for_debug();
} }
x = 1; x = 1;
} }
@ -1867,7 +1453,7 @@ devel_egress(devel_egress_action action UNUSED)
console_print(L"\ndoing %a\n", action); console_print(L"\ndoing %a\n", action);
if (action == COLD_RESET) if (action == COLD_RESET)
gRT->ResetSystem(EfiResetCold, EFI_SECURITY_VIOLATION, 0, NULL); RT->ResetSystem(EfiResetCold, EFI_SECURITY_VIOLATION, 0, NULL);
#endif #endif
} }
@ -1973,10 +1559,13 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
* boot-services-only state variables are what we think they are. * boot-services-only state variables are what we think they are.
*/ */
efi_status = import_mok_state(image_handle); efi_status = import_mok_state(image_handle);
if (!secure_mode() && efi_status == EFI_INVALID_PARAMETER) { if (!secure_mode() &&
(efi_status == EFI_INVALID_PARAMETER ||
efi_status == EFI_OUT_OF_RESOURCES)) {
/* /*
* Make copy failures fatal only if secure_mode is enabled, or * Make copy failures fatal only if secure_mode is enabled, or
* the error was anything else than EFI_INVALID_PARAMETER. * the error was anything else than EFI_INVALID_PARAMETER or
* EFI_OUT_OF_RESOURCES.
* There are non-secureboot firmware implementations that don't * There are non-secureboot firmware implementations that don't
* reserve enough EFI variable memory to fit the variable. * reserve enough EFI variable memory to fit the variable.
*/ */
@ -1991,7 +1580,7 @@ die:
devel_egress(COLD_RESET); devel_egress(COLD_RESET);
#else #else
msleep(5000000); msleep(5000000);
gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, RT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION,
0, NULL); 0, NULL);
#endif #endif
} }

7
shim.h
View File

@ -27,6 +27,10 @@
#error On x86_64 you must have a compiler new enough to support __attribute__((__ms_abi__)) #error On x86_64 you must have a compiler new enough to support __attribute__((__ms_abi__))
#endif #endif
#if CLANG_PREREQ(3, 4)
#pragma GCC diagnostic ignored "-Wpointer-bool-conversion"
#endif
#if !defined(GNU_EFI_USE_EXTERNAL_STDARG) #if !defined(GNU_EFI_USE_EXTERNAL_STDARG)
#define GNU_EFI_USE_EXTERNAL_STDARG #define GNU_EFI_USE_EXTERNAL_STDARG
#endif #endif
@ -167,6 +171,8 @@
#include "include/httpboot.h" #include "include/httpboot.h"
#include "include/ip4config2.h" #include "include/ip4config2.h"
#include "include/ip6config.h" #include "include/ip6config.h"
#include "include/load-options.h"
#include "include/mok.h"
#include "include/netboot.h" #include "include/netboot.h"
#include "include/passwordcrypt.h" #include "include/passwordcrypt.h"
#include "include/peimage.h" #include "include/peimage.h"
@ -249,6 +255,7 @@ extern UINT8 *build_cert;
extern UINT8 user_insecure_mode; extern UINT8 user_insecure_mode;
extern UINT8 ignore_db; extern UINT8 ignore_db;
extern UINT8 trust_mok_list;
extern UINT8 in_protocol; extern UINT8 in_protocol;
extern void *load_options; extern void *load_options;
extern UINT32 load_options_size; extern UINT32 load_options_size;

View File

@ -337,6 +337,68 @@ fail:
return -1; return -1;
} }
int
test_csv_3(void)
{
char csv[] =
"a,b,c,d,e,f,g,h\n"
"a,b,c\n"
"\n"
"\n"
"a,b,c,d,e,f,g,h\n"
"a,b,c\0x,y\0z\0";
struct test_entry test_entries[]= {
{ 7, { "a", "b", "c", "d", "e", "f", "g" } },
{ 3, { "a", "b", "c", NULL, NULL, NULL, NULL } },
{ 7, { "a", "b", "c", "d", "e", "f", "g" } },
{ 3, { "a", "b", "c", NULL, NULL, NULL, NULL } },
};
list_t entry_list;
size_t i;
char *current, *end;
list_t *pos = NULL;
EFI_STATUS efi_status;
INIT_LIST_HEAD(&entry_list);
assert_equal_return(list_size(&entry_list), 0, -1,
"got %d expected %d\n");
current = csv;
end = csv + sizeof(csv) - 1;
efi_status = parse_csv_data(current, end, 7, &entry_list);
assert_equal_return(efi_status, EFI_SUCCESS, -1, "got %x expected %x\n");
i = 0;
list_for_each(pos, &entry_list) {
struct csv_row *csv_row;
struct test_entry *test_entry = &test_entries[i++];
size_t j;
assert_goto(i > 0 && i <= 4, fail, "got %d expected 0 to 4\n", i);
csv_row = list_entry(pos, struct csv_row, list);
assert_equal_goto(csv_row->n_columns, test_entry->n_columns,
fail, "got %d expected %d\n");
for (j = 0; j < csv_row->n_columns; j++) {
assert_equal_goto(strcmp(csv_row->columns[j],
test_entry->columns[j]), 0,
fail, "got %d expected %d\n");
}
}
assert_equal_return(list_size(&entry_list), 4, -1,
"got %d expected %d\n");
free_csv_list(&entry_list);
assert_equal_return(list_size(&entry_list), 0, -1,
"got %d expected %d\n");
return 0;
fail:
free_csv_list(&entry_list);
return -1;
}
int int
test_simple_sbat_csv(void) test_simple_sbat_csv(void)
{ {
@ -456,6 +518,7 @@ main(void)
test(test_csv_0); test(test_csv_0);
test(test_csv_1); test(test_csv_1);
test(test_csv_2); test(test_csv_2);
test(test_csv_3);
test(test_simple_sbat_csv); test(test_simple_sbat_csv);
test(test_csv_simple_fuzz, random_bin, random_bin_len, false); test(test_csv_simple_fuzz, random_bin, random_bin_len, false);
for (i = 0; i < random_bin_len; i++) { for (i = 0; i < random_bin_len; i++) {

Some files were not shown because too many files have changed in this diff Show More