Release shimversion 15.8-1~deb12u1

-----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEzrtSMB1hfpEDkP4WWHl5VzRCaE4FAmY2t7IRHHN0ZXZlQGVp
 bnZhbC5jb20ACgkQWHl5VzRCaE6LrQ//ZVPsTgt+cha/BTK71nKSY9CjkeLdxlJO
 wbBPvcDUZmNjI6snpjYfMNDsB9B3uOcxQ/8GvQUmUvp/EWu17qzFLpF4C+MFd7cY
 xJVF29tUxCM2Ug00wmskV8RI6pVmbSmI6YKknNMPuBBbaN58/tE6WESaSNKerHYH
 B/26C7+1rB92gK2RqqQqQIavpsDZL+nTHfFlAbp4cewCgR7otuIx1i8dW/4Ewrh9
 vMECv0664teGdf7nebShKgwutLtVSdvk2L+YMMd1l+FbcU6fhduLENZz/dc3WGLf
 4QqYRkHC8JMK7eDSAXzUc2ghIUmJT8xPrU/7I4I2Zsc+86XNOZGmiu6cTnocW/QT
 3+T9o2uNWDK+p2P0uP5Fp/Z9gfIzXzkMs7UALc5CTC1PHhUg6I1f+tcVfkef7Afx
 4dZwA/sF/sgg2931AJqCz1eQC+btEAmMRvcXAtsxK1OBdoSZMZ37nA6E+wdlyako
 PJEXe9842WHuynG4JaRCndoMfoNswxC40DEqzn6n+kXvlZeRggR039BGfEKORdtK
 fuMbHBuvpHOxo51GjyFHbGVh/8GhCxub4YWOgidPUBzheQMTVTuWmWujLAVGpAs9
 oZ+4v2n3yrfDPMvT9HtTHXG66Gisz25l24hL4enJPuBf7ti2bPCBuTAor1WcqWto
 hEeOYwszGJw=
 =Krhw
 -----END PGP SIGNATURE-----

Merge tag 'debian/15.8-1_deb12u1' into proxmox/bookworm

Release shimversion 15.8-1~deb12u1
This commit is contained in:
Fabian Grünbichler 2024-05-07 09:00:42 +02:00
commit 437ba3a444
112 changed files with 3324 additions and 1035 deletions

View File

@ -135,10 +135,6 @@ jobs:
efiarch: x64 efiarch: x64
makearch: x86_64 makearch: x86_64
distro: centos8 distro: centos8
- arch: amd64
efiarch: x64
makearch: x86_64
distro: centos7
- arch: amd64 - arch: amd64
efiarch: ia32 efiarch: ia32
makearch: ia32 makearch: ia32
@ -155,10 +151,6 @@ jobs:
efiarch: ia32 efiarch: ia32
makearch: ia32 makearch: ia32
distro: centos8 distro: centos8
- arch: amd64
efiarch: ia32
makearch: ia32
distro: centos7
steps: steps:
- name: Checkout - name: Checkout

5
.gitignore vendored
View File

@ -33,7 +33,12 @@ Make.local
/.cache/ /.cache/
/certdb/ /certdb/
/compile_commands.json /compile_commands.json
/compile_commands.events.json
/cov-int/ /cov-int/
/crash-*
/fuzz-*
!/fuzz-*.c
/leak-*
/post-process-pe /post-process-pe
/random.bin /random.bin
/sbat.*.csv /sbat.*.csv

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.6 branch = shim-15.8

View File

@ -78,6 +78,9 @@ Variables you could set to customize the build:
- OSLABEL - OSLABEL
This is the label that will be put in BOOT$(EFI_ARCH).CSV for your OS. This is the label that will be put in BOOT$(EFI_ARCH).CSV for your OS.
By default this is the same value as EFIDIR . By default this is the same value as EFIDIR .
- POST_PROCESS_PE_FLAGS
This allows you to add flags to the invocation of "post-process-pe", for
example to disable the NX compatibility flag.
Vendor SBAT data: Vendor SBAT data:
It will sometimes be requested by reviewers that a build includes extra It will sometimes be requested by reviewers that a build includes extra

View File

@ -11,7 +11,8 @@ INCLUDES = -I$(CRYPTDIR) -I$(CRYPTDIR)/Include \
-isystem $(TOPDIR)/include/system \ -isystem $(TOPDIR)/include/system \
-isystem $(shell $(CC) -print-file-name=include) -isystem $(shell $(CC) -print-file-name=include)
WARNFLAGS += -Wno-unused-parameter WARNFLAGS += -Wno-unused-parameter \
-Wno-unused-but-set-variable
CFLAGS = $(FEATUREFLAGS) \ CFLAGS = $(FEATUREFLAGS) \
$(OPTIMIZATIONS) \ $(OPTIMIZATIONS) \

View File

@ -23,7 +23,7 @@ FEATUREFLAGS += -nostdinc
WARNFLAGS += -Wno-empty-body \ WARNFLAGS += -Wno-empty-body \
-Wno-implicit-fallthrough \ -Wno-implicit-fallthrough \
$(if $(findstring gcc,$(CC)),-Wno-old-style-declaration) \ $(if $(findstring gcc,$(CC)),-Wno-old-style-declaration) \
$(if $(findstring gcc,$(CC)),-Wno-unused-but-set-variable) \ -Wno-unused-but-set-variable \
-Wno-unused-parameter -Wno-unused-parameter
CFLAGS = $(FEATUREFLAGS) \ CFLAGS = $(FEATUREFLAGS) \

View File

@ -15,6 +15,20 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <OpenSslSupport.h> #include <OpenSslSupport.h>
//
// Extra header to record the memory buffer size from malloc routine.
//
#define CRYPTMEM_HEAD_SIGNATURE EFI_SIGNATURE_32('c','m','h','d')
typedef struct {
UINT32 Signature;
UINT32 Reserved;
UINTN Size;
} CRYPTMEM_HEAD;
#define CRYPTMEM_OVERHEAD sizeof(CRYPTMEM_HEAD)
#define MIN(a, b) ({(a) < (b) ? (a) : (b);})
// //
// -- Memory-Allocation Routines -- // -- Memory-Allocation Routines --
// //
@ -22,27 +36,84 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
/* Allocates memory blocks */ /* Allocates memory blocks */
void *malloc (size_t size) void *malloc (size_t size)
{ {
return AllocatePool ((UINTN) size); CRYPTMEM_HEAD *PoolHdr;
UINTN NewSize;
VOID *Data;
//
// Adjust the size by the buffer header overhead
//
NewSize = (UINTN)(size) + CRYPTMEM_OVERHEAD;
Data = AllocatePool (NewSize);
if (Data != NULL) {
PoolHdr = (CRYPTMEM_HEAD *)Data;
//
// Record the memory brief information
//
PoolHdr->Signature = CRYPTMEM_HEAD_SIGNATURE;
PoolHdr->Size = size;
return (VOID *)(PoolHdr + 1);
} else {
//
// The buffer allocation failed.
//
return NULL;
}
} }
/* Reallocate memory blocks */ /* Reallocate memory blocks */
void *realloc (void *ptr, size_t size) void *realloc (void *ptr, size_t size)
{ {
CRYPTMEM_HEAD *OldPoolHdr;
CRYPTMEM_HEAD *NewPoolHdr;
UINTN OldSize;
UINTN NewSize;
VOID *Data;
NewSize = (UINTN)size + CRYPTMEM_OVERHEAD;
Data = AllocatePool (NewSize);
if (Data != NULL) {
NewPoolHdr = (CRYPTMEM_HEAD *)Data;
NewPoolHdr->Signature = CRYPTMEM_HEAD_SIGNATURE;
NewPoolHdr->Size = size;
if (ptr != NULL) {
// //
// BUG: hardcode OldSize == size! We have no any knowledge about // Retrieve the original size from the buffer header.
// memory size of original pointer ptr.
// //
return ReallocatePool (ptr, (UINTN) size, (UINTN) size); OldPoolHdr = (CRYPTMEM_HEAD *)ptr - 1;
ASSERT (OldPoolHdr->Signature == CRYPTMEM_HEAD_SIGNATURE);
OldSize = OldPoolHdr->Size;
//
// Duplicate the buffer content.
//
CopyMem ((VOID *)(NewPoolHdr + 1), ptr, MIN (OldSize, size));
FreePool ((VOID *)OldPoolHdr);
}
return (VOID *)(NewPoolHdr + 1);
} else {
//
// The buffer allocation failed.
//
return NULL;
}
} }
/* De-allocates or frees a memory block */ /* De-allocates or frees a memory block */
void free (void *ptr) void free (void *ptr)
{ {
CRYPTMEM_HEAD *PoolHdr;
// //
// In Standard C, free() handles a null pointer argument transparently. This // In Standard C, free() handles a null pointer argument transparently. This
// is not true of FreePool() below, so protect it. // is not true of FreePool() below, so protect it.
// //
if (ptr != NULL) { if (ptr != NULL) {
FreePool (ptr); PoolHdr = (CRYPTMEM_HEAD *)ptr - 1;
ASSERT (PoolHdr->Signature == CRYPTMEM_HEAD_SIGNATURE);
FreePool (PoolHdr);
} }
} }

View File

@ -139,6 +139,8 @@ CFLAGS = $(FEATUREFLAGS) \
$(INCLUDES) \ $(INCLUDES) \
$(DEFINES) $(DEFINES)
POST_PROCESS_PE_FLAGS =
ifneq ($(origin OVERRIDE_SECURITY_POLICY), undefined) ifneq ($(origin OVERRIDE_SECURITY_POLICY), undefined)
DEFINES += -DOVERRIDE_SECURITY_POLICY DEFINES += -DOVERRIDE_SECURITY_POLICY
endif endif
@ -186,6 +188,9 @@ endif
ifneq ($(origin VENDOR_DBX_FILE), undefined) ifneq ($(origin VENDOR_DBX_FILE), undefined)
DEFINES += -DVENDOR_DBX_FILE=\"$(VENDOR_DBX_FILE)\" DEFINES += -DVENDOR_DBX_FILE=\"$(VENDOR_DBX_FILE)\"
endif endif
ifneq ($(origin SBAT_AUTOMATIC_DATE), undefined)
DEFINES += -DSBAT_AUTOMATIC_DATE=$(SBAT_AUTOMATIC_DATE)
endif
LDFLAGS = --hash-style=sysv -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(LOCAL_EFI_PATH) -L$(LIBDIR) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS) --build-id=sha1 $(ARCH_LDFLAGS) --no-undefined LDFLAGS = --hash-style=sysv -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(LOCAL_EFI_PATH) -L$(LIBDIR) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS) --build-id=sha1 $(ARCH_LDFLAGS) --no-undefined

View File

@ -36,6 +36,6 @@ $(strip $(foreach x,$(DEFAULT_$(1)),
endef endef
%.o : %.S %.o : %.S
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $< $(IGNORE_COMPILER_ERRORS)
# vim:filetype=make # vim:filetype=make

View File

@ -1,7 +1,7 @@
default : all default : all
NAME = shim NAME = shim
VERSION = 15.7 VERSION = 15.8
ifneq ($(origin RELEASE),undefined) ifneq ($(origin RELEASE),undefined)
DASHRELEASE ?= -$(RELEASE) DASHRELEASE ?= -$(RELEASE)
else else
@ -38,9 +38,9 @@ CFLAGS += -DENABLE_SHIM_CERT
else else
TARGETS += $(MMNAME) $(FBNAME) TARGETS += $(MMNAME) $(FBNAME)
endif endif
OBJS = shim.o globals.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o sbat.o sbat_data.o sbat_var.o pe.o httpboot.o csv.o load-options.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 sbat_var.o pe.o pe-relocate.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 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) cert.S sbat_var.S ORIG_SOURCES = shim.c globals.c mok.c netboot.c replacements.c tpm.c errlog.c sbat.c pe.c pe-relocate.c httpboot.c shim.h version.h $(wildcard include/*.h) cert.S sbat_var.S
MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o errlog.o sbat_data.o globals.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 globals.o FALLBACK_OBJS = fallback.o tpm.o errlog.o sbat_data.o globals.o
@ -76,6 +76,13 @@ ifneq ($(origin EFI_PATH),undefined)
$(error EFI_PATH is no longer supported, you must build using the supplied copy of gnu-efi) $(error EFI_PATH is no longer supported, you must build using the supplied copy of gnu-efi)
endif endif
compile_commands.json : Makefile Make.rules Make.defaults
make clean
bear -- make COMPILER=clang test all
sed -i \
-e 's/"-maccumulate-outgoing-args",//g' \
$@
update : update :
git submodule update --init --recursive git submodule update --init --recursive
@ -156,19 +163,19 @@ gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a:
ARCH=$(ARCH_GNUEFI) \ ARCH=$(ARCH_GNUEFI) \
TOPDIR=$(TOPDIR)/gnu-efi \ TOPDIR=$(TOPDIR)/gnu-efi \
-f $(TOPDIR)/gnu-efi/Makefile \ -f $(TOPDIR)/gnu-efi/Makefile \
lib gnuefi inc lib gnuefi inc $(IGNORE_COMPILER_ERRORS)
Cryptlib/libcryptlib.a: Cryptlib/libcryptlib.a:
for i in Hash Hmac Cipher Rand Pk Pem SysCall; do mkdir -p Cryptlib/$$i; done for i in Hash Hmac Cipher Rand Pk Pem SysCall; do mkdir -p Cryptlib/$$i; done
$(MAKE) TOPDIR=$(TOPDIR) VPATH=$(TOPDIR)/Cryptlib -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile $(MAKE) TOPDIR=$(TOPDIR) VPATH=$(TOPDIR)/Cryptlib -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile $(IGNORE_COMPILER_ERRORS)
Cryptlib/OpenSSL/libopenssl.a: Cryptlib/OpenSSL/libopenssl.a:
for i in x509v3 x509 txt_db stack sha rsa rc4 rand pkcs7 pkcs12 pem ocsp objects modes md5 lhash kdf hmac evp err dso dh conf comp cmac buffer bn bio async/arch asn1 aes; do mkdir -p Cryptlib/OpenSSL/crypto/$$i; done for i in x509v3 x509 txt_db stack sha rsa rc4 rand pkcs7 pkcs12 pem ocsp objects modes md5 lhash kdf hmac evp err dso dh conf comp cmac buffer bn bio async/arch asn1 aes; do mkdir -p Cryptlib/OpenSSL/crypto/$$i; done
$(MAKE) TOPDIR=$(TOPDIR) VPATH=$(TOPDIR)/Cryptlib/OpenSSL -C Cryptlib/OpenSSL -f $(TOPDIR)/Cryptlib/OpenSSL/Makefile $(MAKE) TOPDIR=$(TOPDIR) VPATH=$(TOPDIR)/Cryptlib/OpenSSL -C Cryptlib/OpenSSL -f $(TOPDIR)/Cryptlib/OpenSSL/Makefile $(IGNORE_COMPILER_ERRORS)
lib/lib.a: | $(TOPDIR)/lib/Makefile $(wildcard $(TOPDIR)/include/*.[ch]) 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 $(IGNORE_COMPILER_ERRORS)
post-process-pe : $(TOPDIR)/post-process-pe.c post-process-pe : $(TOPDIR)/post-process-pe.c
$(HOSTCC) -std=gnu11 -Og -g3 -Wall -Wextra -Wno-missing-field-initializers -Werror -o $@ $< $(HOSTCC) -std=gnu11 -Og -g3 -Wall -Wextra -Wno-missing-field-initializers -Werror -o $@ $<
@ -255,7 +262,7 @@ endif
-j .rela* -j .dyn -j .reloc -j .eh_frame \ -j .rela* -j .dyn -j .reloc -j .eh_frame \
-j .vendor_cert -j .sbat -j .sbatlevel \ -j .vendor_cert -j .sbat -j .sbatlevel \
$(FORMAT) $< $@ $(FORMAT) $< $@
./post-process-pe -vv $@ ./post-process-pe -vv $(POST_PROCESS_PE_FLAGS) $@
ifneq ($(origin ENABLE_SHIM_HASH),undefined) ifneq ($(origin ENABLE_SHIM_HASH),undefined)
%.hash : %.efi %.hash : %.efi
@ -286,6 +293,15 @@ else
$(PESIGN) -n certdb -i $< -c "shim" -s -o $@ -f $(PESIGN) -n certdb -i $< -c "shim" -s -o $@ -f
endif endif
fuzz fuzz-clean fuzz-coverage fuzz-lto :
@make -f $(TOPDIR)/include/fuzz.mk \
COMPILER="$(COMPILER)" \
CROSS_COMPILE="$(CROSS_COMPILE)" \
CLANG_WARNINGS="$(CLANG_WARNINGS)" \
ARCH_DEFINES="$(ARCH_DEFINES)" \
EFI_INCLUDES="$(EFI_INCLUDES)" \
fuzz-clean $@
test test-clean test-coverage test-lto : test test-clean test-coverage test-lto :
@make -f $(TOPDIR)/include/test.mk \ @make -f $(TOPDIR)/include/test.mk \
COMPILER="$(COMPILER)" \ COMPILER="$(COMPILER)" \
@ -295,14 +311,21 @@ test test-clean test-coverage test-lto :
EFI_INCLUDES="$(EFI_INCLUDES)" \ EFI_INCLUDES="$(EFI_INCLUDES)" \
test-clean $@ test-clean $@
$(patsubst %.c,%,$(wildcard fuzz-*.c)) :
@make -f $(TOPDIR)/include/fuzz.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" $@
$(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)" $@
.PHONY : $(patsubst %.c,%,$(wildcard test-*.c)) test clean-fuzz-objs:
@make -f $(TOPDIR)/include/fuzz.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" clean
clean-test-objs: clean-test-objs:
@make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" clean @make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" clean
.PHONY : $(patsubst %.c,%,$(wildcard fuzz-*.c)) fuzz
.PHONY : $(patsubst %.c,%,$(wildcard test-*.c)) test
clean-gnu-efi: clean-gnu-efi:
@if [ -d gnu-efi ] ; then \ @if [ -d gnu-efi ] ; then \
$(MAKE) -C gnu-efi \ $(MAKE) -C gnu-efi \
@ -322,7 +345,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 post-process-pe @rm -vf *.debug *.so *.efi *.efi.* *.tar.* version.c buildid post-process-pe compile_commands.json
@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
@ -336,7 +359,7 @@ clean-cryptlib-objs:
$(MAKE) -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile clean ; \ $(MAKE) -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile clean ; \
fi fi
clean: clean-shim-objs clean-test-objs clean-gnu-efi clean-openssl-objs clean-cryptlib-objs clean-lib-objs clean: clean-shim-objs clean-fuzz-objs clean-test-objs clean-gnu-efi clean-openssl-objs clean-cryptlib-objs clean-lib-objs
GITTAG = $(VERSION) GITTAG = $(VERSION)

View File

@ -53,6 +53,11 @@ The hash will be regenerated by MokManager after the user is requested
to enter their password to confirm enrolment of the keys. If the hash to enter their password to confirm enrolment of the keys. If the hash
matches MokAuth, the user will be prompted to enrol the keys. BS,RT,NV matches MokAuth, the user will be prompted to enrol the keys. BS,RT,NV
ShimRetainProtocol: UINT8, read by Shim before uninstalling protocol.
If set to non-zero, Shim will keep the protocol in place. It can be
used by second stages to ensure the protocol is still available for
later stages, and can thus be used to verify additional PE files. BS,RT.
State variables: State variables:
MokList: A list of authorized keys and hashes. An EFI_SIGNATURE_LIST MokList: A list of authorized keys and hashes. An EFI_SIGNATURE_LIST

View File

@ -25,3 +25,8 @@ There are a couple of build options, and a couple of ways to customize the
build, described in [BUILDING](BUILDING). build, described in [BUILDING](BUILDING).
See the [test plan](testplan.txt), and file a ticket if anything fails! See the [test plan](testplan.txt), and file a ticket if anything fails!
In the event that the developers need to be contacted related to a security
incident or vulnerability, please mail [secalert@redhat.com].
[secalert@redhat.com]: mailto:secalert@redhat.com

View File

@ -6,13 +6,13 @@ SBAT: Current proposal
the `.sbat` section has the following fields: the `.sbat` section has the following fields:
| field | meaning | | field | meaning |
|---|---| |----------------------|----------------------------------------------------------------------------------|
| component_name | the name we're comparing | component_name | the name we're comparing |
| component_generation | the generation number for the comparison | component_generation | the generation number for the comparison |
| vendor_name | human readable vendor name | vendor_name | human readable vendor name |
| vendor_package_name | human readable package name | vendor_package_name | human readable package name |
| vendor_version | human readable package version (maybe machine parseable too, not specified here) | vendor_version | human readable package version (maybe machine parseable too, not specified here) |
| vendor_url | url to look stuff up, contact, whatever. | vendor_url | url to look stuff up, contact, whatever. |
`SBAT` EFI variable `SBAT` EFI variable
----------------- -----------------

20
SBAT.md
View File

@ -255,7 +255,7 @@ 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 | 2 | 3 | 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 |
@ -307,7 +307,7 @@ most up to date UEFI metadata.
Even prior to or without moving to one-shim, it is desirable to get every Even prior to or without moving to one-shim, it is desirable to get every
vendor onto as few shims as possible. Ideally a vendor would have a single shim vendor onto as few shims as possible. Ideally a vendor would have a single shim
signed with their certificate embedded and then use that certificate to sign signed with their certificate embedded and then use that certificate to sign
additional <Vendor>_key.EFI key files that then contain all the keys that the additional `<Vendor>_key.EFI` key files that then contain all the keys that the
individual components for their products are signed with. This file name needs individual components for their products are signed with. This file name needs
to be registered at the time of shim review and should not be changed without to be registered at the time of shim review and should not be changed without
going back to a shim review. A vendor should be able to store as many going back to a shim review. A vendor should be able to store as many
@ -355,13 +355,13 @@ them.
Adding a .sbat section containing the SBAT metadata structure to PE images. Adding a .sbat section containing the SBAT metadata structure to PE images.
| field | meaning | | field | meaning |
|---|---| |----------------------|----------------------------------------------------------------------------------|
| component_name | the name we're comparing | component_name | the name we're comparing |
| component_generation | the generation number for the comparison | component_generation | the generation number for the comparison |
| vendor_name | human readable vendor name | vendor_name | human readable vendor name |
| vendor_package_name | human readable package name | vendor_package_name | human readable package name |
| vendor_version | human readable package version (maybe machine parseable too, not specified here) | vendor_version | human readable package version (maybe machine parseable too, not specified here) |
| 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 ASCII encoded strings. specifically ASCII encoded strings.
@ -448,7 +448,7 @@ fixed. The following show the evolution over a sample set of events:
## Starting point ## Starting point
Before CVEs are encountered, an undesirable moudule was built into the a fedora Before CVEs are encountered, an undesirable module was built into Fedora's
grub, so it's product-specific generation number has been bumped: grub, so it's product-specific generation number has been bumped:
``` ```

108
SbatLevel_Variable.txt Normal file
View File

@ -0,0 +1,108 @@
In order to apply SBAT based revocations on systems that will never
run shim, code running in boot services context needs to set the
following variable:
Name: SbatLevel
Attributes: (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)
Namespace Guid: 605dab50-e046-4300-abb6-3dd810dd8b23
Variable content:
Initialized, no revocations:
sbat,1,2021030218
To Revoke GRUB2 binaries impacted by
* CVE-2021-3695
* CVE-2021-3696
* CVE-2021-3697
* CVE-2022-28733
* CVE-2022-28734
* CVE-2022-28735
* CVE-2022-28736
sbat,1,2022052400
grub,2
and shim binaries impacted by
* CVE-2022-28737
sbat,1,2022052400
shim,2
grub,2
Shim delivered both versions of these revocations with
the same 2022052400 date stamp, once as an opt-in latest
revocation with shim,2 and then as an automatic revocation without
shim,2
To revoke GRUB2 grub binaries impacted by
* CVE-2022-2601
* CVE-2022-3775
sbat,1,2022111500
shim,2
grub,3
To revoke Debian's grub.3 which missed
the patches:
sbat,1,2023012900
shim,2
grub,3
grub.debian,4
An additonal bug was fixed in shim that was not considered exploitable,
can be revoked by setting:
sbat,1,2023012950
shim,3
grub,3
grub.debian,4
shim did not deliver this payload at the time
To Revoke GRUB2 binaries impacted by:
* CVE-2023-4692
* CVE-2023-4693
These CVEs are in the ntfs module and vendors that do and do not
ship this module as part of their signed binary are split.
sbat,1,2023091900
shim,2
grub,4
Since not everyone has shipped updated GRUB packages, shim did not
deliver this revocation at the time.
To Revoke shim binaries impacted by:
* CVE-2023-40547
* CVE-2023-40546
* CVE-2023-40548
* CVE-2023-40549
* CVE-2023-40550
* CVE-2023-40551
sbat,1,2024010900
shim,4
grub,3
grub.debian,4
Since http boot shim CVE is considerably more serious than then GRUB
ntfs CVEs shim is delivering the shim revocation without the updated
GRUB revocation as a latest payload.
To revoke both the impacted shim and impacted GRUB binaries:
sbat,1,2024<date TBD>
shim,4
grub,4

1
cert.S
View File

@ -52,3 +52,4 @@ vendor_deauthorized:
#endif #endif
.Lvendor_deauthorized_end: .Lvendor_deauthorized_end:
.Lcert_table_end: .Lcert_table_end:
.section .note.GNU-stack,"a"

1
commit
View File

@ -1 +0,0 @@
11491619f4336fef41c3519877ba242161763580

View File

@ -1,2 +1,2 @@
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
shim,3,UEFI shim,shim,1,https://github.com/rhboot/shim shim,4,UEFI shim,shim,1,https://github.com/rhboot/shim

1 sbat 1 SBAT Version sbat 1 https://github.com/rhboot/shim/blob/main/SBAT.md
2 shim 3 4 UEFI shim shim 1 https://github.com/rhboot/shim

31
debian/changelog vendored
View File

@ -1,3 +1,34 @@
shim (15.8-1~deb12u1) bookworm; urgency=medium
[ Steve McIntyre ]
* Cope with changes in pesign packaging.
* New upstream release fixing more bugs
* Remove all our previous patches, no longer needed:
+ Make-sbat_var.S-parse-right-with-buggy-gcc-binutils.patch (now
upstream)
+ Enable-NX.patch (we don't want NX just yet until the whole boot
stack is NX-capable)
+ block-grub-sbat3-debian.patch (not needed now upstream grub SBAT
is 4)
* Cherry-pick 2 new patches from upstream for grub revocations:
+ 0001-sbat-Add-grub.peimage-2-to-latest-CVE-2024-2312.patch
+ 0002-sbat-Also-bump-latest-for-grub-4-and-to-todays-date.patch
* Log if the build is nx-compatible or not
* Force shim to use the latest revocations by default to block some
older grub / peimage issues. This is:
"shim,4\ngrub,4\ngrub.peimage,2\n"
* Install a copy of the Debian CA certificate into /usr/share/shim.
Closes: #1069054
* Clean up better after build. Closes: #1046268
[ Bastien Roucariès ]
* Port autopkgtest from ubuntu
* Import MR-12: "shim-unsigned:amd64 cannot be installed alongside
shim-unsigned:i386", thanks to adrian15 adrian15 (Closes: #936009).
* Fix debian/watch and check signature
-- Steve McIntyre <93sam@debian.org> Sat, 04 May 2024 21:28:21 +0100
shim (15.7-1+pmx1) bookworm; urgency=medium shim (15.7-1+pmx1) bookworm; urgency=medium
* Bump version for Proxmox build. * Bump version for Proxmox build.

32
debian/check_nx vendored Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh
#
# Helper script - check if a binary is tagged as NX-compatible or not.
set -e
for FILE in "$@"; do
if [ ! -f "${FILE}" ]; then
echo "${FILE} does not exist. ABORT."
exit 1
fi
echo "Checking NX bit on ${FILE}:"
DLL_CHARACTERISTICS=$(objdump -x "${FILE}" | awk '/DllCharacteristics/ {print $2}')
echo " DllCharacteristics $DLL_CHARACTERISTICS"
case $DLL_CHARACTERISTICS in
00000000)
echo " NOT tagged as NX-compatible"
;;
00000100)
echo " tagged as NX-compatible"
;;
*)
echo " UNRECOGNISED value, ABORT";
exit 1
;;
esac
done

2
debian/control vendored
View File

@ -11,6 +11,7 @@ Build-Depends: debhelper-compat (= 12),
gcc-12, gcc-12,
dos2unix, dos2unix,
pesign (>= 0.112-5), pesign (>= 0.112-5),
efivar,
xxd, xxd,
libefivar-dev libefivar-dev
Vcs-Browser: https://git.proxmox.com/?p=efi-boot-shim.git Vcs-Browser: https://git.proxmox.com/?p=efi-boot-shim.git
@ -21,6 +22,7 @@ Architecture: amd64 arm64 i386
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}
Conflicts: shim (<< 15+1533136590.3beb971-3~), Conflicts: shim (<< 15+1533136590.3beb971-3~),
Replaces: shim (<< 15+1533136590.3beb971-3~), Replaces: shim (<< 15+1533136590.3beb971-3~),
Multi-Arch: same
Description: boot loader to chain-load signed boot loaders under Secure Boot Description: boot loader to chain-load signed boot loaders under Secure Boot
This package provides a minimalist boot loader which allows verifying This package provides a minimalist boot loader which allows verifying
signatures of other UEFI binaries against either the Secure Boot DB/DBX or signatures of other UEFI binaries against either the Secure Boot DB/DBX or

View File

@ -16,12 +16,39 @@ ARCH=$1
IN=$2 IN=$2
OUT=$3 OUT=$3
DEBIAN_UUID="fa31923d-6047-40bf-81d0-e63edefcf194"
# This needs to be fixed to make builds reproducible, of course. If
# you're deriving from Debian, please generate your own.
UUID="$DEBIAN_UUID"
rm -f $OUT rm -f $OUT
for HASH in $(grep -E "[[:xdigit:]]{32} $ARCH" < $IN | \ if [ -x /usr/bin/efisiglist ] ; then
# Older versions of the pesign package included the efisiglist
# utility. If we have that, use it.
for HASH in $(grep -E "[[:xdigit:]]{32} $ARCH" < $IN | \
awk '{print $1}' | sort | uniq); do awk '{print $1}' | sort | uniq); do
echo " Adding $HASH to dbx list" echo " Adding $HASH to dbx list"
efisiglist -o $OUT -a -h $HASH efisiglist -o $OUT -a -h $HASH
done done
else
# It appears we don't have efisiglist, so use efisecdb
# instead. It's a little more awkward to drive.
INTMP="" # First pass
for HASH in $(grep -E "[[:xdigit:]]{32} $ARCH" < $IN | \
awk '{print $1}' | sort | uniq); do
echo " Adding $HASH to dbx list"
efisecdb -g "$UUID" -a -t sha256 -h $HASH $INTMP -o $OUT
# Subsequent passes need to read the previous output as input
# each time, and won't overwrite the output.
mv -f $OUT $OUT.in
INTMP="-i $OUT.in"
done
if [ -f $OUT.in ]; then
mv -f $OUT.in $OUT
fi
fi
# If we have an empty hashes file, create an empty DBX file # If we have an empty hashes file, create an empty DBX file
touch $OUT touch $OUT

View File

@ -0,0 +1,42 @@
From 63edf92f8ae11b884bc7d24aecb8229cbc4ae014 Mon Sep 17 00:00:00 2001
From: Julian Andres Klode <julian.klode@canonical.com>
Date: Fri, 5 Apr 2024 21:57:07 +0200
Subject: [PATCH 1/2] sbat: Add grub.peimage,2 to latest (CVE-2024-2312)
Add the previous latest level to the switch for automatic.
Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
---
include/sbat_var_defs.h | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/include/sbat_var_defs.h b/include/sbat_var_defs.h
index f8cba029..04d708f2 100644
--- a/include/sbat_var_defs.h
+++ b/include/sbat_var_defs.h
@@ -47,6 +47,8 @@
#define SBAT_VAR_AUTOMATIC_REVOCATIONS "shim,2\ngrub,3\n"
#elif SBAT_AUTOMATIC_DATE == 2023012900
#define SBAT_VAR_AUTOMATIC_REVOCATIONS "shim,2\ngrub,3\ngrub.debian,4\n"
+#elif SBAT_AUTOMATIC_DATE == 2024010900
+#define SBAT_VAR_AUTOMATIC_REVOCATIONS "shim,4\ngrub,3\ngrub.debian,4\n"
#else
#error "Unknown SBAT_AUTOMATIC_DATE"
#endif /* SBAT_AUTOMATIC_DATE == */
@@ -56,10 +58,10 @@
SBAT_VAR_AUTOMATIC_REVOCATIONS
/*
- * Revocations for January 2024 shim CVEs
+ * Revocations for January 2024 shim CVEs + Debian/Ubuntu (peimage) CVE-2024-2312
*/
-#define SBAT_VAR_LATEST_DATE "2024010900"
-#define SBAT_VAR_LATEST_REVOCATIONS "shim,4\ngrub,3\ngrub.debian,4\n"
+#define SBAT_VAR_LATEST_DATE "2024040500"
+#define SBAT_VAR_LATEST_REVOCATIONS "shim,4\ngrub,3\ngrub.debian,4\ngrub.peimage,2\n"
#define SBAT_VAR_LATEST \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \
SBAT_VAR_LATEST_REVOCATIONS
--
2.39.2

View File

@ -0,0 +1,47 @@
From 3e1394e8e6fd0071a69196230f991612a960c154 Mon Sep 17 00:00:00 2001
From: Julian Andres Klode <julian.klode@canonical.com>
Date: Tue, 9 Apr 2024 18:55:12 +0200
Subject: [PATCH 2/2] sbat: Also bump latest for grub,4 (and to todays date)
Back in January we decided to bump the SBAT level for the shim
CVE without bumping the grub level for the previous NTFS issues
- CVE-2023-4692 CVE-2023-4693 - as not every vendor was signing
the ntfs module.
Catch up on this revocation to ensure it doesn't get lost. Doing
so also allows us to remove the grub.debian,4 revocation as this
happened before grub,4 and hence is obsolete.
Also bump the date of the sbat variable to today's. Don't copy
the April 5 one to a previous selection, as it wasn't shipped
to anyone.
Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
---
include/sbat_var_defs.h | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/include/sbat_var_defs.h b/include/sbat_var_defs.h
index 04d708f2..5c7115b9 100644
--- a/include/sbat_var_defs.h
+++ b/include/sbat_var_defs.h
@@ -58,10 +58,13 @@
SBAT_VAR_AUTOMATIC_REVOCATIONS
/*
- * Revocations for January 2024 shim CVEs + Debian/Ubuntu (peimage) CVE-2024-2312
+ * Revocations for:
+ * - January 2024 shim CVEs
+ * - October 2023 grub CVEs
+ * - Debian/Ubuntu (peimage) CVE-2024-2312
*/
-#define SBAT_VAR_LATEST_DATE "2024040500"
-#define SBAT_VAR_LATEST_REVOCATIONS "shim,4\ngrub,3\ngrub.debian,4\ngrub.peimage,2\n"
+#define SBAT_VAR_LATEST_DATE "2024040900"
+#define SBAT_VAR_LATEST_REVOCATIONS "shim,4\ngrub,4\ngrub.peimage,2\n"
#define SBAT_VAR_LATEST \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \
SBAT_VAR_LATEST_REVOCATIONS
--
2.39.2

View File

@ -1,79 +0,0 @@
commit 7c7642530fab73facaf3eac233cfbce29e10b0ef
Author: Peter Jones <pjones@redhat.com>
Date: Thu Nov 17 12:31:31 2022 -0500
Enable the NX compatibility flag by default.
Currently by default, when we build shim we do not set the PE
NX-compatibility DLL Characteristic flag. This signifies to the
firmware that shim (including the components it loads) is not prepared
for several related firmware changes:
- non-executable stack
- non-executable pages from AllocatePages()/AllocatePool()/etc.
- non-writable 0 page (not strictly related but some firmware will be
transitioning at the same time)
- the need to use the UEFI 2.10 Memory Attribute Protocol to set page
permissions.
This patch changes that default to be enabled by default. Distributors
of shim will need to ensure that either their builds disable this bit
(using "post-process-pe -N"), or that the bootloaders and kernels you
support loading are all compliant with this change. A new make
variable, POST_PROCESS_PE_FLAGS, has been added to simplify doing so.
Signed-off-by: Peter Jones <pjones@redhat.com>
diff --git a/BUILDING b/BUILDING
index 3b2e85d3..17cd98d3 100644
--- a/BUILDING
+++ b/BUILDING
@@ -78,6 +78,9 @@ Variables you could set to customize the build:
- OSLABEL
This is the label that will be put in BOOT$(EFI_ARCH).CSV for your OS.
By default this is the same value as EFIDIR .
+- POST_PROCESS_PE_FLAGS
+ This allows you to add flags to the invocation of "post-process-pe", for
+ example to disable the NX compatibility flag.
Vendor SBAT data:
It will sometimes be requested by reviewers that a build includes extra
diff --git a/Make.defaults b/Make.defaults
index c46164a3..9af89f4e 100644
--- a/Make.defaults
+++ b/Make.defaults
@@ -139,6 +139,8 @@ CFLAGS = $(FEATUREFLAGS) \
$(INCLUDES) \
$(DEFINES)
+POST_PROCESS_PE_FLAGS =
+
ifneq ($(origin OVERRIDE_SECURITY_POLICY), undefined)
DEFINES += -DOVERRIDE_SECURITY_POLICY
endif
diff --git a/Makefile b/Makefile
index a9202f46..f0f53f8f 100644
--- a/Makefile
+++ b/Makefile
@@ -255,7 +255,7 @@ endif
-j .rela* -j .dyn -j .reloc -j .eh_frame \
-j .vendor_cert -j .sbat -j .sbatlevel \
$(FORMAT) $< $@
- ./post-process-pe -vv $@
+ ./post-process-pe -vv $(POST_PROCESS_PE_FLAGS) $@
ifneq ($(origin ENABLE_SHIM_HASH),undefined)
%.hash : %.efi
diff --git a/post-process-pe.c b/post-process-pe.c
index de8f4a38..f39fdddf 100644
--- a/post-process-pe.c
+++ b/post-process-pe.c
@@ -42,7 +42,7 @@ static int verbosity;
0; \
})
-static bool set_nx_compat = false;
+static bool set_nx_compat = true;
typedef uint8_t UINT8;
typedef uint16_t UINT16;

View File

@ -1,104 +0,0 @@
From 657b2483ca6e9fcf2ad8ac7ee577ff546d24c3aa Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 5 Dec 2022 17:57:36 -0500
Subject: [PATCH] Make sbat_var.S parse right with buggy gcc/binutils
In https://github.com/rhboot/shim/issues/533 , iokomin noticed that
gas in binutils before 2.36 appears to be incorrectly concatenating
string literals in '.asciz' directives, including an extra NUL character
in between the strings, and this will cause us to incorrectly parse the
.sbatlevel section in shim binaries.
This patch adds test cases that will cause the build to fail if this has
happened, as well as changing sbat_var.S to to use '.ascii' and '.byte'
to construct the data, rather than using '.asciz'.
Signed-off-by: Peter Jones <pjones@redhat.com>
---
include/test.mk | 2 +-
sbat_var.S | 6 ++++--
test-sbat.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/include/test.mk b/include/test.mk
index c0e24095..c37b8446 100644
--- a/include/test.mk
+++ b/include/test.mk
@@ -92,7 +92,7 @@ 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 sbat_var.S
+test-sbat_FILES = csv.c lib/variables.c lib/guid.c sbat_var.S mock-variables.c
test-sbat :: CFLAGS+=-DHAVE_GET_VARIABLE -DHAVE_GET_VARIABLE_ATTR -DHAVE_SHIM_LOCK_GUID
test-str_FILES = lib/string.c
diff --git a/sbat_var.S b/sbat_var.S
index a115077a..2a813a40 100644
--- a/sbat_var.S
+++ b/sbat_var.S
@@ -14,7 +14,9 @@ sbat_var_payload_header:
.Lsbat_var_payload_header_end:
.balign 1, 0
.Lsbat_var_previous:
- .asciz SBAT_VAR_PREVIOUS
+ .ascii SBAT_VAR_PREVIOUS
+ .byte 0
.balign 1, 0
.Lsbat_var_latest:
- .asciz SBAT_VAR_LATEST
+ .ascii SBAT_VAR_LATEST
+ .byte 0
diff --git a/test-sbat.c b/test-sbat.c
index 72bebe7a..65bc6a84 100644
--- a/test-sbat.c
+++ b/test-sbat.c
@@ -1107,6 +1107,36 @@ test_preserve_sbat_uefi_variable_bad_short(void)
return 0;
}
+static int
+test_sbat_var_asciz(void)
+{
+ EFI_STATUS status;
+ char buf[1024] = "";
+ UINT32 attrs = 0;
+ UINTN size = sizeof(buf);
+ char expected[] = SBAT_VAR_PREVIOUS;
+
+ status = set_sbat_uefi_variable();
+ if (status != EFI_SUCCESS)
+ return -1;
+
+ status = RT->GetVariable(SBAT_VAR_NAME, &SHIM_LOCK_GUID, &attrs, &size, buf);
+ if (status != EFI_SUCCESS)
+ return -1;
+
+ /*
+ * this should be enough to get past "sbat,", which handles the
+ * first error.
+ */
+ if (size < (strlen(SBAT_VAR_SIG) + 2) || size != strlen(expected))
+ return -1;
+
+ if (strncmp(expected, buf, size) != 0)
+ return -1;
+
+ return 0;
+}
+
int
main(void)
{
@@ -1155,6 +1185,8 @@ main(void)
test(test_preserve_sbat_uefi_variable_version_older);
test(test_preserve_sbat_uefi_variable_version_olderlonger);
+ test(test_sbat_var_asciz);
+
return 0;
}
--
2.30.2

View File

@ -1,2 +1,2 @@
Make-sbat_var.S-parse-right-with-buggy-gcc-binutils.patch 0001-sbat-Add-grub.peimage-2-to-latest-CVE-2024-2312.patch
Enable-NX.patch 0002-sbat-Also-bump-latest-for-grub-4-and-to-todays-date.patch

16
debian/rules vendored
View File

@ -48,6 +48,11 @@ COMMON_OPTIONS += \
CC=$(DEB_HOST_GNU_TYPE)-gcc-12 \ CC=$(DEB_HOST_GNU_TYPE)-gcc-12 \
$(NULL) $(NULL)
# Force shim to use the latest revocations by default to block some
# older grub / peimage issues. This is:
# "shim,4\ngrub,4\ngrub.peimage,2\n"
COMMON_OPTIONS += SBAT_AUTOMATIC_DATE=2024010900
$(DBX_LIST): $(DBX_HASHES) $(DBX_LIST): $(DBX_HASHES)
./debian/generate_dbx_list $(EFI_ARCH) $< $@ ./debian/generate_dbx_list $(EFI_ARCH) $< $@
@ -65,7 +70,9 @@ $(SBAT_DATA): $(SBAT_IN)
override_dh_auto_clean: override_dh_auto_clean:
dh_auto_clean -- MAKELEVEL=0 dh_auto_clean -- MAKELEVEL=0
rm -f $(DBX_LIST) $(SBAT_DATA) sbat.*.csv BOOT*.CSV test-csv test-sbat test-str rm -f $(DBX_LIST) $(SBAT_DATA) sbat.*.csv BOOT*.CSV
rm -f test-csv test-sbat test-str test-load-options
rm -f test-mock-variables test-mok-mirror test-pe-relocate test-pe-util
override_dh_auto_build: $(DBX_LIST) $(SBAT_DATA) override_dh_auto_build: $(DBX_LIST) $(SBAT_DATA)
dh_auto_build -- INSTALL=install $(COMMON_OPTIONS) dh_auto_build -- INSTALL=install $(COMMON_OPTIONS)
@ -81,7 +88,14 @@ override_dh_auto_install:
# And remove the extra removable-media copy of shim too, it's # And remove the extra removable-media copy of shim too, it's
# not needed for our build and causes debhelper to complain # not needed for our build and causes debhelper to complain
rm -f debian/tmp/boot/efi/EFI/BOOT/BOOT*.EFI rm -f debian/tmp/boot/efi/EFI/BOOT/BOOT*.EFI
install -m 644 $(cert) debian/shim-unsigned/usr/share/shim
# Generate the template packages that we'll use for SB signing later
./debian/signing-template.generate ./debian/signing-template.generate
# Log some useful things about the build here
./debian/check_nx shim*.efi
sha256sum *.efi sha256sum *.efi
generate-gnu-efi: generate-gnu-efi:

3
debian/salsa-ci.yml vendored Normal file
View File

@ -0,0 +1,3 @@
---
include:
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml

1
debian/shim-unsigned.dirs vendored Normal file
View File

@ -0,0 +1 @@
/usr/share/shim

54
debian/tests/01_sanity_tests.py vendored Executable file
View File

@ -0,0 +1,54 @@
#
# UEFI Shim sanity checks for tests
#
# Copyright (C) 2019 Canonical, Ltd.
# Author: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import subprocess
import sys
import unittest
from uefi_tests_base import UEFITestsBase
class SanityTests(UEFITestsBase):
'''
Sanity checks for uefi tests
'''
def testArchitectureSuffixes(self):
"""Ensure sanity of our concept of architecture suffixes for UEFI"""
machine = subprocess.check_output(['uname', '-m']).rstrip().decode('utf-8')
if machine == 'x86_64':
self.assertEqual('x64', self.arch_suffix)
self.assertEqual('x86_64-efi', self.grub_arch)
self.assertEqual('qemu-system-x86_64', self.qemu_arch)
elif machine == 'aarch64':
self.assertEqual('aa64', self.arch_suffix)
self.assertEqual('arm64-efi', self.grub_arch)
self.assertEqual('qemu-system-aarch64', self.qemu_arch)
def testQemuAvailable(self):
"""Ensure QEMU is available for this architecture"""
try:
out = subprocess.run([self.qemu_arch, '-version'], stdout=None)
out.check_returncode()
except:
raise UEFINotAvailable(feature="qemu", arch=self.arch_machine,
details="%s failed to run" % self.qemu_arch)
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))

91
debian/tests/05_signature_tests.py vendored Executable file
View File

@ -0,0 +1,91 @@
#
# UEFI signature validation
#
# Copyright (C) 2019 Canonical, Ltd.
# Author: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import subprocess
import sys
import unittest
import tempfile
from pathlib import Path
from uefi_tests_base import UEFITestsBase
class TestSignatures(UEFITestsBase):
"""
Validate UEFI signatures for common problems
"""
@classmethod
def setUpClass(klass):
UEFITestsBase.setUpClass()
def testInstalledGrubIsSigned(self):
"""Check that the GRUB copy we installed is correctly signed"""
installed_grub_file = Path(self.signed_grub_path)
self.assertTrue(installed_grub_file.exists())
signed_out = subprocess.run(['sbverify', '--list', self.signed_grub_path],
stdout=subprocess.PIPE)
self.assertIn(b'image signature issuers:', signed_out.stdout)
def testGrubSignatureValid(self):
return
"""Ensure the installed GRUB binary from packaging is signed with the expected key"""
self.assertSignatureOK(self.ca, self.signed_grub_path)
def testInstalledShimIsSigned(self):
"""Check that the installed shim is signed"""
installed_shim_file = Path(self.signed_shim_path)
self.assertTrue(installed_shim_file.exists())
signed_out = subprocess.run(['sbverify', '--list', self.signed_shim_path],
stdout=subprocess.PIPE)
self.assertIn(b'image signature issuers:', signed_out.stdout)
def testHaveSignedShimOnESP(self):
"""Verify that packaging has provided a signed shim"""
return
signed_shim_file = Path(self.installed_shim)
self.assertTrue(signed_shim_file.exists())
def testSignaturesExist(self):
"""Validate that a binary has non-zero signatures"""
unsigned_out = subprocess.run(['sbverify', '--list', self.unsigned_shim_path],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
self.assertIn(b'No signature table present', unsigned_out.stderr)
signed_out = subprocess.run(['sbverify', '--list', self.signed_shim_path],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
self.assertIn(b'image signature issuers:', signed_out.stdout)
def testSignatureIsReplayable(self):
"""Attest that signature is retrievable from a binary and can be replayed"""
with tempfile.TemporaryDirectory() as tmpdirname:
subprocess.call(['sbattach',
'--detach', os.path.join(tmpdirname, 'sig.pkcs7'),
self.signed_shim_path])
pkcs7_certs = subprocess.run(['openssl', 'pkcs7',
'-inform', 'der',
'-in', os.path.join(tmpdirname, 'sig.pkcs7'),
'-print_certs'],
stdout=subprocess.PIPE)
with open(os.path.join(tmpdirname, 'out.crt'), 'ab+') as certstore:
certstore.write(pkcs7_certs.stdout)
self.assertSignatureOK(os.path.join(tmpdirname, 'out.crt'), self.signed_shim_path)
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))

51
debian/tests/10_uefi_boot_tests.py vendored Executable file
View File

@ -0,0 +1,51 @@
#
# UEFI boot testing
#
# Copyright (C) 2019 Canonical, Ltd.
# Author: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import subprocess
import sys
import unittest
from uefi_tests_base import UEFITestsBase, UEFINotAvailable, UEFIVirtualMachine
class UEFIBootTests(UEFITestsBase):
"""
Validate UEFI signatures for common problems
"""
@classmethod
def setUpClass(klass):
UEFITestsBase.setUpClass()
klass.base_image = UEFIVirtualMachine(arch=klass.image_arch)
#klass.base_image.prepare()
def testCanary(self):
"""Validate that a control/canary (unchanged) image boots fine"""
canary = UEFIVirtualMachine(self.base_image)
canary.run()
self.assertBoots(canary)
def testNewShim(self):
"""Validate that a new SHIM binary on the image will boot"""
new_shim = UEFIVirtualMachine(self.base_image)
new_shim.update(src='/usr/lib/shim/shimx64.efi.signed', dst='/boot/efi/EFI/debian/shimx64.efi')
new_shim.update(src='/usr/lib/shim/shimx64.efi.signed', dst='/boot/efi/EFI/BOOT/BOOTX64.efi')
new_shim.run()
self.assertBoots(new_shim)
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))

47
debian/tests/control vendored Normal file
View File

@ -0,0 +1,47 @@
Test-Command: python3 debian/tests/01_sanity_tests.py
Depends: @,
qemu-system-arm [arm64],
qemu-system-x86 [amd64],
lsb-release,
python3,
wget,
openssl,
Restrictions: allow-stderr, needs-root, isolation-machine
Features: test-name=sanity
Test-Command: python3 debian/tests/05_signature_tests.py
Depends: @,
sbsigntool,
grub-efi-arm64-signed [arm64],
grub-efi-amd64-signed [amd64],
shim-signed [amd64],
shim-signed [arm64],
lsb-release,
python3,
wget,
openssl,
Restrictions: allow-stderr, needs-root, isolation-machine
Features: test-name=signatures
Test-Command: python3 debian/tests/10_uefi_boot_tests.py
Depends: @,
autopkgtest,
genisoimage,
qemu-utils,
sbsigntool,
qemu-system-arm [arm64],
qemu-system-x86 [amd64],
ovmf [amd64],
qemu-efi-aarch64 [arm64],
grub-efi-arm64-signed [arm64],
grub-efi-amd64-signed [amd64],
shim-signed [amd64],
shim-signed [arm64],
lsb-release,
python3,
wget,
openssl,
ca-certificates,
distro-info,
Restrictions: allow-stderr, needs-root, isolation-machine
Features: test-name=boot-test

261
debian/tests/uefi_tests_base.py vendored Normal file
View File

@ -0,0 +1,261 @@
#
# UEFI validation/integration tests
#
# Copyright (C) 2019 Canonical, Ltd.
# Author: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import shutil
import stat
import math
import subprocess
import tempfile
from time import sleep
import unittest
class UEFINotAvailable(Exception):
"""Exception class for unavailable UEFI features"""
def __init__(self, feature=None, arch=None, details=None):
self.message = "UEFI is not available"
if arch and feature:
self.message = "%s is not available on %s" % (feature, arch)
elif feature:
self.message = "%s is not available" % feature
if details:
self.message = self.message + ": %s" % details
def __str__(self):
return repr(self.message)
class UEFITestsBase(unittest.TestCase):
'''
Common functionality for shim test cases
'''
@classmethod
def setUpClass(klass):
klass.arch_machine = os.uname().machine
klass.arch_suffix = ''
klass.grub_arch = ''
klass.qemu_arch = ''
if klass.arch_machine == 'x86_64':
klass.image_arch = 'amd64'
klass.arch_suffix = 'x64'
klass.grub_arch = 'x86_64-efi'
klass.qemu_arch = 'qemu-system-x86_64'
elif klass.arch_machine == 'aarch64':
klass.image_arch = 'arm64'
klass.arch_suffix = 'aa64'
klass.grub_arch = 'arm64-efi'
klass.qemu_arch = 'qemu-system-aarch64'
else:
raise UEFINotAvailable(feature='any UEFI Shim features', arch=klass.arch_machine)
# Base paths for the ESP.
klass.uefi_base_dir = os.path.join('/', 'boot', 'efi', 'EFI')
klass.uefi_boot_dir = os.path.join(klass.uefi_base_dir, 'BOOT')
klass.uefi_install_dir = os.path.join(klass.uefi_base_dir, 'debian')
# CAs for signature validation (not yet)
# klass.ca = os.path.join('/usr/share/grub', 'debian-uefi-ca.crt')
# Shim paths
klass.shim_pkg_dir = os.path.join('/', 'usr', 'lib', 'shim')
klass.unsigned_shim_path = os.path.join(klass.shim_pkg_dir, 'shim%s.efi' % klass.arch_suffix)
klass.signed_shim_path = os.path.join(klass.shim_pkg_dir, 'shim%s.efi.signed' % klass.arch_suffix)
klass.installed_shim = os.path.join(klass.uefi_install_dir, 'shim%s.efi' % klass.arch_suffix)
klass.removable_shim = os.path.join(klass.uefi_boot_dir, 'boot%s.efi' % klass.arch_suffix)
# GRUB paths
klass.grub_pkg_dir = os.path.join('/', 'usr', 'lib', 'grub', "%s-signed" % klass.grub_arch)
klass.signed_grub_path = os.path.join(klass.grub_pkg_dir, 'grub%s.efi.signed' % klass.arch_suffix)
klass.installed_grub = os.path.join(klass.uefi_install_dir, 'grub%s.efi' % klass.arch_suffix)
# OMVF paths
if klass.arch_machine == 'x86_64':
klass.uefi_code_path = '/usr/share/OVMF/OVMF_CODE_4M.ms.fd'
klass.uefi_vars_path = '/usr/share/OVMF/OVMF_VARS_4M.ms.fd'
klass.uefi_qemu_extra = [ '-machine', 'q35,smm=on' ]
elif klass.arch_machine == 'aarch64':
klass.uefi_code_path = '/usr/share/AAVMF/AAVMF_CODE.fd'
klass.uefi_vars_path = '/usr/share/AAVMF/AAVMF_VARS.fd'
klass.uefi_qemu_extra = []
subprocess.run(['modprobe', 'nbd'])
@classmethod
def tearDownClass(klass):
pass
def tearDown(self):
pass
def setUp(self):
pass
#
# Internal implementation details
#
@classmethod
def poll_text(klass, logpath, string, timeout=50):
'''Poll log file for a given string with a timeout.
Timeout is given in deciseconds.
'''
log = ''
while timeout > 0:
if os.path.exists(logpath):
break
timeout -= 1
sleep(0.1)
assert timeout > 0, 'Timed out waiting for file %s to appear' % logpath
with open(logpath) as f:
while timeout > 0:
line = f.readline()
if line:
log += line
if string in line:
break
continue
timeout -= 1
sleep(0.1)
assert timeout > 0, 'Timed out waiting for "%s":\n------------\n%s\n-------\n' % (string, log)
def assertSignatureOK(self, expected_signature, binary):
result = subprocess.check_call(['sbverify', '--cert', expected_signature, binary])
self.assertEquals(0, result)
def assertBoots(self, vm=None):
'''Assert that the VM is booted and ready for use'''
self.assertTrue(vm.ready())
DEFAULT_METADATA = 'instance-id: nocloud\nlocal-hostname: autopkgtest\n'
DEFAULT_USERDATA = """#cloud-config
locale: en_US.UTF-8
password: debian
chpasswd: { expire: False }
ssh_pwauth: True
manage_etc_hosts: True
runcmd:
- (while [ ! -e /var/lib/cloud/instance/boot-finished ]; do sleep 1; done;
touch /TESTOK;
shutdown -P now) &
"""
#
# VM management tools
#
class UEFIVirtualMachine(UEFITestsBase):
def __init__(self, base=None, arch=None):
self.autopkgtest_dir = tempfile.TemporaryDirectory()
os.makedirs(os.path.join(self.autopkgtest_dir.name, 'img'))
self.arch = arch
release = subprocess.run(['lsb_release','-c','-s'], capture_output=True, check=True)
self.release = release.stdout.strip().decode('utf-8')
release_number = subprocess.run(['lsb_release','-r','-s'], capture_output=True, check=True).stdout.strip().decode('utf-8')
self.release_number = None
try:
self.release_number = int(math.floor(float(release_number)))
except:
if(self.release == 'sid'):
self.release_number = 'sid'
else:
alias = subprocess.run(['distro-info','--alias', self.release], capture_output=True, check=True).stdout.strip().decode('utf-8')
number_distro = subprocess.run(['distro-info','-r', '--%s' % (alias)], capture_output=True, check=True).stdout.strip().decode('utf-8')
self.release_number = int(math.floor(float(number_distro)))
self.path = tempfile.mkstemp(dir=self.autopkgtest_dir.name)[1]
if not base:
subprocess.run(['wget',
'https://cloud.debian.org/images/cloud/%s/daily/latest/debian-%s-genericcloud-%s-daily.qcow2'
% (self.release, self.release_number, self.arch),
'-O', '%s/base.img' % self.autopkgtest_dir.name], check = True)
else:
self.arch = base.arch
shutil.copy(base.path, os.path.join(self.autopkgtest_dir.name, 'base.img'))
shutil.copy(os.path.join(self.autopkgtest_dir.name, 'base.img'), self.path)
shutil.copy("%s" % self.uefi_vars_path, "%s.VARS.fd" % self.path)
def _mount(self):
subprocess.run(['qemu-nbd', '--connect=/dev/nbd0', self.path])
# nbd doesn't show instantly...
sleep(1)
subprocess.run(['mount', '/dev/nbd0p1', os.path.join(self.autopkgtest_dir.name, 'img')])
subprocess.run(['mount', '/dev/nbd0p15', os.path.join(self.autopkgtest_dir.name, 'img', 'boot/efi')])
def _unmount(self):
subprocess.run(['umount', '/dev/nbd0p15'])
subprocess.run(['umount', '/dev/nbd0p1'])
subprocess.run(['qemu-nbd', '--disconnect', '/dev/nbd0'])
def prepare(self):
with open(os.path.join(self.autopkgtest_dir.name, 'meta-data'), 'w') as f:
f.write(DEFAULT_METADATA)
with open(os.path.join(self.autopkgtest_dir.name, 'user-data'), 'w') as f:
f.write(DEFAULT_USERDATA)
with open(os.path.join(self.autopkgtest_dir.name, 'network-config'), 'w') as f:
f.write('')
subprocess.run(['genisoimage', '-output', 'cloud-init.seed',
'-volid', 'cidata', '-joliet', '-rock',
'-quiet', 'user-data', 'meta-data', 'network-config'],
cwd=self.autopkgtest_dir.name)
def list(self, path='/etc/'):
self._mount()
subprocess.run(['ls', '-l', os.path.join(self.autopkgtest_dir.name, 'img', path)])
self._unmount()
def update(self, src=None, dst=None):
self._mount()
try:
os.makedirs(os.path.join(self.autopkgtest_dir.name, 'img', os.path.dirname(dst)))
except FileExistsError:
pass
shutil.copy(src, os.path.join(self.autopkgtest_dir.name, 'img', dst))
self._unmount()
def run(self):
self.prepare()
# start qemu-system-$arch, output log to serial and capture to variable
subprocess.run([self.qemu_arch] + self.uefi_qemu_extra + [
'-m', '1024', '-nographic',
'-serial', 'mon:stdio',
'-netdev', 'user,id=network0',
'-device', 'virtio-net-pci,netdev=network0,mac=52:54:00:12:34:56',
'-drive', 'file=%s,if=pflash,format=raw,unit=0,readonly=on' % self.uefi_code_path,
'-drive', 'file=%s.VARS.fd,if=pflash,format=raw,unit=1' % self.path,
'-drive', 'file=%s,if=none,id=harddrive0,format=qcow2' % self.path,
'-device', 'virtio-blk-pci,drive=harddrive0,bootindex=0',
'-drive', 'file=%s/cloud-init.seed,if=virtio,readonly=on' % self.autopkgtest_dir.name])
def ready(self):
"""Returns true if the VM is booted and ready at userland"""
# check captured serial for our marker
self._mount()
result = os.path.exists(os.path.join(self.autopkgtest_dir.name, 'img', 'TESTOK'))
self._unmount()
return result

465
debian/upstream/signing-key.asc vendored Normal file
View File

@ -0,0 +1,465 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: Hostname:
Version: Hockeypuck 2.1.1-10-gec3b0e7
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
/aD7gLo=
=+tM6
-----END PGP PUBLIC KEY BLOCK-----

6
debian/watch vendored
View File

@ -1,5 +1,5 @@
# Compulsory line, this is a version 4 file # Compulsory line, this is a version 4 file
version=4 version=4
opts="repack,compression=xz,pgpmode=auto,searchmode=plain" \
opts="repack,compression=xz,filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/shim-$1\.tar\.gz/" \ https://api.github.com/repos/rhboot/shim/releases?per_page=100 \
https://github.com/rhboot/shim/releases .*/v?(\d\S*)\.tar\.gz https://github.com/rhboot/shim/releases/download/[^/]+/@PACKAGE@-@ANY_VERSION@@ARCHIVE_EXT@

View File

@ -32,6 +32,9 @@ VLogError(const char *file, int line, const char *func, const CHAR16 *fmt,
ms_va_list args2; ms_va_list args2;
CHAR16 **newerrs; CHAR16 **newerrs;
if (file == NULL || func == NULL || fmt == NULL)
return EFI_INVALID_PARAMETER;
newerrs = ReallocatePool(errs, (nerrs + 1) * sizeof(*errs), newerrs = ReallocatePool(errs, (nerrs + 1) * sizeof(*errs),
(nerrs + 3) * sizeof(*errs)); (nerrs + 3) * sizeof(*errs));
if (!newerrs) if (!newerrs)

View File

@ -1006,14 +1006,14 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
EFI_HANDLE image_handle; EFI_HANDLE image_handle;
if (get_fallback_verbose()) { if (get_fallback_verbose()) {
int fallback_verbose_wait = 500000; /* default to 0.5s */ unsigned long fallback_verbose_wait = 500000; /* default to 0.5s */
#ifdef FALLBACK_VERBOSE_WAIT #ifdef FALLBACK_VERBOSE_WAIT
fallback_verbose_wait = FALLBACK_VERBOSE_WAIT; fallback_verbose_wait = FALLBACK_VERBOSE_WAIT;
#endif #endif
console_print(L"Verbose enabled, sleeping for %d mseconds... " console_print(L"Verbose enabled, sleeping for %d mseconds... "
L"Press the Pause key now to hold for longer.\n", L"Press the Pause key now to hold for longer.\n",
fallback_verbose_wait); fallback_verbose_wait);
msleep(fallback_verbose_wait); usleep(fallback_verbose_wait);
} }
if (!first_new_option) { if (!first_new_option) {
@ -1036,7 +1036,7 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
} }
console_print(L"\n"); console_print(L"\n");
msleep(500000000); usleep(500000000);
return efi_status; return efi_status;
} }
@ -1051,7 +1051,7 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
efi_status = BS->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); usleep(500000000);
} }
return efi_status; return efi_status;
} }
@ -1211,14 +1211,14 @@ reset:
console_print(L"Reset System\n"); console_print(L"Reset System\n");
if (get_fallback_verbose()) { if (get_fallback_verbose()) {
int fallback_verbose_wait = 500000; /* default to 0.5s */ unsigned long fallback_verbose_wait = 500000; /* default to 0.5s */
#ifdef FALLBACK_VERBOSE_WAIT #ifdef FALLBACK_VERBOSE_WAIT
fallback_verbose_wait = FALLBACK_VERBOSE_WAIT; fallback_verbose_wait = FALLBACK_VERBOSE_WAIT;
#endif #endif
console_print(L"Verbose enabled, sleeping for %d mseconds... " console_print(L"Verbose enabled, sleeping for %d mseconds... "
L"Press the Pause key now to hold for longer.\n", L"Press the Pause key now to hold for longer.\n",
fallback_verbose_wait); fallback_verbose_wait);
msleep(fallback_verbose_wait); usleep(fallback_verbose_wait);
} }
RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);

71
fuzz-csv.c Normal file
View File

@ -0,0 +1,71 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* test-csv.c - test our csv parser
*/
#ifndef SHIM_UNIT_TEST
#define SHIM_UNIT_TEST
#endif
#include "shim.h"
#include <stdio.h>
int
test_csv_simple_fuzz(char *random_bin, size_t random_bin_len)
{
list_t entry_list;
size_t i;
char *current, *end;
list_t *pos = NULL;
EFI_STATUS efi_status;
INIT_LIST_HEAD(&entry_list);
current = &random_bin[0];
current = current + 1 - 1;
end = current + random_bin_len - 1;
*end = '\0';
efi_status = parse_csv_data(current, end, 7, &entry_list);
if (efi_status != EFI_SUCCESS)
return 0;
if (list_size(&entry_list) <= 1)
goto fail;
i = 0;
list_for_each(pos, &entry_list) {
struct csv_row *csv_row;
csv_row = list_entry(pos, struct csv_row, list);
i++;
}
free_csv_list(&entry_list);
return 0;
fail:
free_csv_list(&entry_list);
return -1;
}
int
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
int rc;
uint8_t *data_copy;
if (size < 1)
return 0;
data_copy = malloc(size);
if (!data_copy)
return -1;
memcpy(data_copy, data, size);
rc = test_csv_simple_fuzz((char *)data_copy, size);
free(data_copy);
return rc; // Values other than 0 and -1 are reserved for future use.
}
// vim:fenc=utf-8:tw=75:noet

38
fuzz-pe-relocate.c Normal file
View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* fuzz-pe-relocate.c - fuzz our PE relocation code.
* Copyright Peter Jones <pjones@redhat.com>
*/
#ifndef SHIM_UNIT_TEST
#define SHIM_UNIT_TEST
#endif
#include "shim.h"
UINT8 mok_policy = 0;
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
uint8_t *data_copy;
EFI_STATUS status = 0;
size_t n = 0;
PE_COFF_LOADER_IMAGE_CONTEXT context = { 0, };
if (size < 1)
return 0;
data_copy = malloc(size+1);
if (!data_copy)
return -1;
memcpy(data_copy, data, size);
data_copy[size] = 0;
status = read_header(data_copy, size, &context);
free(data_copy);
return 0;
}
// vim:fenc=utf-8:tw=75:noet

46
fuzz-sbat.c Normal file
View File

@ -0,0 +1,46 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* fuzz-sbat-section.c - fuzz our .sbat parsing code
* Copyright Peter Jones <pjones@redhat.com>
*/
#ifndef SHIM_UNIT_TEST
#define SHIM_UNIT_TEST
#endif
#include "shim.h"
#include <stdio.h>
list_t sbat_var;
BOOLEAN
secure_mode() {
return 1;
}
int
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
uint8_t *data_copy;
EFI_STATUS status = 0;
size_t n = 0;
struct sbat_section_entry **entries = NULL;
if (size < 1)
return 0;
data_copy = malloc(size+1);
if (!data_copy)
return -1;
memcpy(data_copy, data, size);
data_copy[size] = 0;
status = parse_sbat_section(data_copy, size, &n, &entries);
cleanup_sbat_section_entries(n, entries);
free(data_copy);
return 0;
}
// vim:fenc=utf-8:tw=75:noet

View File

@ -205,7 +205,7 @@ endif
ASFLAGS += $(ARCH3264) ASFLAGS += $(ARCH3264)
LDFLAGS += -nostdlib --warn-common --no-undefined --fatal-warnings \ LDFLAGS += -nostdlib --warn-common --no-undefined --fatal-warnings \
--build-id=sha1 --build-id=sha1 --no-warn-rwx-segments
ifneq ($(ARCH),arm) ifneq ($(ARCH),arm)
export LIBGCC=$(shell $(CC) $(CFLAGS) $(ARCH3264) -print-libgcc-file-name) export LIBGCC=$(shell $(CC) $(CFLAGS) $(ARCH3264) -print-libgcc-file-name)

View File

@ -41,3 +41,4 @@ _start:
hello: .byte 'h',0,'e',0,'l',0,'l',0,'o',0,'\n',0,'\r',0,0,0 hello: .byte 'h',0,'e',0,'l',0,'l',0,'o',0,'\n',0,'\r',0,0,0
#endif #endif
.section .note.GNU-stack,"a"

View File

@ -51,3 +51,4 @@ _start:
.4byte .dummy1-.dummy0 // Page RVA .4byte .dummy1-.dummy0 // Page RVA
.4byte 10 // Block Size (2*4+2) .4byte 10 // Block Size (2*4+2)
.2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
.section .note.GNU-stack,"a"

View File

@ -191,3 +191,4 @@ _start:
.L_DYNAMIC: .L_DYNAMIC:
.word _DYNAMIC - . .word _DYNAMIC - .
.section .note.GNU-stack,"a"

View File

@ -75,3 +75,4 @@ _start:
.4byte .dummy1-.dummy0 // Page RVA .4byte .dummy1-.dummy0 // Page RVA
.4byte 10 // Block Size (2*4+2) .4byte 10 // Block Size (2*4+2)
.2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
.section .note.GNU-stack,"a"

View File

@ -85,3 +85,4 @@ _start_plabel:
data4 12 // Block Size (2*4+2*2) data4 12 // Block Size (2*4+2*2)
data2 (IMAGE_REL_BASED_DIR64<<12) + 0 // reloc for plabel's entry point data2 (IMAGE_REL_BASED_DIR64<<12) + 0 // reloc for plabel's entry point
data2 (IMAGE_REL_BASED_DIR64<<12) + 8 // reloc for plabel's global pointer data2 (IMAGE_REL_BASED_DIR64<<12) + 8 // reloc for plabel's global pointer
.section .note.GNU-stack,"a"

View File

@ -186,3 +186,4 @@ _pc:
.end _start .end _start
.set pop .set pop
.section .note.GNU-stack,"a"

View File

@ -72,3 +72,4 @@ _start:
.4byte .dummy1-.dummy0 // Page RVA .4byte .dummy1-.dummy0 // Page RVA
.4byte 10 // Block Size (2*4+2) .4byte 10 // Block Size (2*4+2)
.2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
.section .note.GNU-stack,"a"

View File

@ -225,3 +225,4 @@ apply_FPTR64:
fptr_mem_base: fptr_mem_base:
.space MAX_FUNCTION_DESCRIPTORS*16 .space MAX_FUNCTION_DESCRIPTORS*16
fptr_mem_limit: fptr_mem_limit:
.section .note.GNU-stack,"a"

View File

@ -28,6 +28,6 @@ typedef struct {
UINT64 D13; UINT64 D13;
UINT64 D14; UINT64 D14;
UINT64 D15; UINT64 D15;
} ALIGN(JMPBUF_ALIGN) jmp_buf[1]; } __attribute__((__aligned__(JMPBUF_ALIGN))) jmp_buf[1];
#endif /* GNU_EFI_AARCH64_SETJMP_H */ #endif /* GNU_EFI_AARCH64_SETJMP_H */

View File

@ -16,6 +16,6 @@ typedef struct {
UINT32 R12; UINT32 R12;
UINT32 R13; UINT32 R13;
UINT32 R14; UINT32 R14;
} ALIGN(JMPBUF_ALIGN) jmp_buf[1]; } __attribute__((__aligned__(JMPBUF_ALIGN))) jmp_buf[1];
#endif /* GNU_EFI_ARM_SETJMP_H */ #endif /* GNU_EFI_ARM_SETJMP_H */

View File

@ -10,6 +10,6 @@ typedef struct {
UINT32 Ebp; UINT32 Ebp;
UINT32 Esp; UINT32 Esp;
UINT32 Eip; UINT32 Eip;
} ALIGN(JMPBUF_ALIGN) jmp_buf[1]; } __attribute__((__aligned__(JMPBUF_ALIGN))) jmp_buf[1];
#endif /* GNU_EFI_IA32_SETJMP_H */ #endif /* GNU_EFI_IA32_SETJMP_H */

View File

@ -42,6 +42,6 @@ typedef struct {
UINT64 Predicates; UINT64 Predicates;
UINT64 LoopCount; UINT64 LoopCount;
UINT64 FPSR; UINT64 FPSR;
} ALIGN(JMPBUF_ALIGN) jmp_buf[1]; } __attribute__((__aligned__(JMPBUF_ALIGN))) jmp_buf[1];
#endif /* GNU_EFI_IA64_SETJMP_H */ #endif /* GNU_EFI_IA64_SETJMP_H */

View File

@ -29,6 +29,6 @@ typedef struct {
UINT64 F30; UINT64 F30;
UINT64 F31; UINT64 F31;
#endif #endif
} ALIGN(JMPBUF_ALIGN) jmp_buf[1]; } __attribute__((__aligned__(JMPBUF_ALIGN))) jmp_buf[1];
#endif /* GNU_EFI_MIPS64EL_SETJMP_H */ #endif /* GNU_EFI_MIPS64EL_SETJMP_H */

View File

@ -17,6 +17,6 @@ typedef struct {
UINT64 Rip; UINT64 Rip;
UINT64 MxCsr; UINT64 MxCsr;
UINT8 XmmBuffer[160]; // XMM6 - XMM15 UINT8 XmmBuffer[160]; // XMM6 - XMM15
} ALIGN(JMPBUF_ALIGN) jmp_buf[1]; } __attribute__((__aligned__(JMPBUF_ALIGN))) jmp_buf[1];
#endif /* GNU_EFI_X86_64_SETJMP_H */ #endif /* GNU_EFI_X86_64_SETJMP_H */

View File

@ -1,91 +0,0 @@
#
# Copyright (C) 1999-2001 Hewlett-Packard Co.
# Contributed by David Mosberger <davidm@hpl.hp.com>
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of Hewlett-Packard Co. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/../Make.defaults
TOPDIR = $(SRCDIR)/..
CDIR = $(TOPDIR)/..
FILES = boxdraw smbios console crc data debug dpath \
error event guid hand hw init lock \
misc print sread str cmdline \
runtime/rtlock runtime/efirtlib runtime/rtstr runtime/vm runtime/rtdata \
$(ARCH)/initplat $(ARCH)/math
ifeq ($(ARCH),ia64)
FILES += $(ARCH)/salpal $(ARCH)/palproc
endif
ifeq ($(ARCH),x86_64)
FILES += $(ARCH)/callwrap $(ARCH)/efi_stub
endif
ifeq ($(ARCH),arm)
FILES += $(ARCH)/lib1funcs $(ARCH)/div64
endif
OBJS = $(FILES:%=%.o)
SUBDIRS = ia32 x86_64 ia64 aarch64 arm runtime
LIBDIRINSTALL = $(INSTALLROOT)$(LIBDIR)
all: libsubdirs libefi.a
.PHONY: libsubdirs
libsubdirs:
for sdir in $(SUBDIRS); do mkdir -p $$sdir; done
libefi.a: $(patsubst %,libefi.a(%),$(OBJS))
clean:
rm -f libefi.a *~ $(OBJS) */*.o
$(LIBDIRINSTALL):
mkdir -p $@
$(LIBDIRINSTALL)/libefi.a: libefi.a | $(LIBDIRINSTALL)
$(INSTALL) -m 644 $< $(dir $@)
install: $(LIBDIRINSTALL)/libefi.a
include $(SRCDIR)/../Make.rules
.PHONY: libsubdirs

View File

@ -1 +1,2 @@
/* This stub is a stub to make the build happy */ /* This stub is a stub to make the build happy */
.section .note.GNU-stack,"a"

View File

@ -58,3 +58,4 @@ longjmp:
mov w0, #1 mov w0, #1
csel w0, w1, w0, ne csel w0, w1, w0, ne
br x30 br x30
.section .note.GNU-stack,"a"

View File

@ -153,3 +153,4 @@ label1:
@ What to do about division by zero? For now, just return. @ What to do about division by zero? For now, just return.
ASM_PFX(__aeabi_idiv0): ASM_PFX(__aeabi_idiv0):
bx r14 bx r14
.section .note.GNU-stack,"a"

View File

@ -1 +1,2 @@
/* This stub is a stub to make the build happy */ /* This stub is a stub to make the build happy */
.section .note.GNU-stack,"a"

View File

@ -59,3 +59,4 @@ L_Exit:
.section .note.GNU-stack,"a"

View File

@ -39,3 +39,4 @@ ASM_PFX(__aeabi_llsl):
lsl r1,r0,r3 lsl r1,r0,r3
mov r0,#0 mov r0,#0
bx lr bx lr
.section .note.GNU-stack,"a"

View File

@ -39,3 +39,4 @@ ASM_PFX(__aeabi_llsr):
lsr r0,r1,r3 lsr r0,r1,r3
mov r1,#0 mov r1,#0
bx lr bx lr
.section .note.GNU-stack,"a"

View File

@ -31,3 +31,4 @@ ASM_PFX(__aeabi_lmul):
mla r1, r2, r1, ip mla r1, r2, r1, ip
mla r1, r3, lr, r1 mla r1, r3, lr, r1
ldmia sp!, {pc} ldmia sp!, {pc}
.section .note.GNU-stack,"a"

View File

@ -23,3 +23,4 @@ setjmp:
.type longjmp, %function .type longjmp, %function
longjmp: longjmp:
ldmia r0, {r3-r12,r14} ldmia r0, {r3-r12,r14}
.section .note.GNU-stack,"a"

View File

@ -265,3 +265,4 @@ ASM_PFX(__aeabi_ldiv0):
bx r14 bx r14
.section .note.GNU-stack,"a"

View File

@ -1 +1,2 @@
/* This stub is a stub to make the build happy */ /* This stub is a stub to make the build happy */
.section .note.GNU-stack,"a"

View File

@ -43,3 +43,4 @@ longjmp:
movl (%edx), %ebx movl (%edx), %ebx
movl 4(%edx), %esi movl 4(%edx), %esi
movl 8(%edx), %edi movl 8(%edx), %edi
.section .note.GNU-stack,"a"

View File

@ -159,3 +159,4 @@ StackedComeBackFromPALCall:
PROCEDURE_EXIT(MakeStackedPALCall) PROCEDURE_EXIT(MakeStackedPALCall)
.section .note.GNU-stack,"a"

View File

@ -197,3 +197,4 @@ _skip_flushrs:
invala invala
mov ar.rsc = r16 mov ar.rsc = r16
br.ret.sptk b0 br.ret.sptk b0
.section .note.GNU-stack,"a"

View File

@ -1 +1,2 @@
/* This stub is a stub to make the build happy */ /* This stub is a stub to make the build happy */
.section .note.GNU-stack,"a"

View File

@ -90,3 +90,4 @@ longjmp:
li $v0, 1 li $v0, 1
movn $v0, $a1, $a1 movn $v0, $a1, $a1
jr $ra jr $ra
.section .note.GNU-stack,"a"

View File

@ -187,3 +187,4 @@ ENTRY(efi_call10)
ret ret
#endif #endif
.section .note.GNU-stack,"a"

View File

@ -46,3 +46,4 @@ longjmp:
cmp %rax,%rdx cmp %rax,%rdx
cmove %rcx,%rax cmove %rcx,%rax
jmp *0x38(%rdi) jmp *0x38(%rdi)
.section .note.GNU-stack,"a"

View File

@ -578,7 +578,13 @@ receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINT64 *buf_size)
} }
if (*buf_size == 0) { if (*buf_size == 0) {
perror(L"Failed to get Content-Lenght\n"); perror(L"Failed to get Content-Length\n");
goto error;
}
if (*buf_size < rx_message.BodyLength) {
efi_status = EFI_BAD_BUFFER_SIZE;
perror(L"Invalid Content-Length\n");
goto error; goto error;
} }
@ -713,18 +719,20 @@ error:
} }
EFI_STATUS EFI_STATUS
httpboot_fetch_buffer (EFI_HANDLE image, VOID **buffer, UINT64 *buf_size) httpboot_fetch_buffer (EFI_HANDLE image, VOID **buffer, UINT64 *buf_size,
CHAR8 *name)
{ {
EFI_STATUS efi_status; EFI_STATUS efi_status;
EFI_HANDLE nic; EFI_HANDLE nic;
CHAR8 next_loader[sizeof DEFAULT_LOADER_CHAR]; CHAR8 *next_loader;
CHAR8 *next_uri = NULL; CHAR8 *next_uri = NULL;
CHAR8 *hostname = NULL; CHAR8 *hostname = NULL;
if (!uri) if (!uri)
return EFI_NOT_READY; return EFI_NOT_READY;
translate_slashes(next_loader, DEFAULT_LOADER_CHAR); next_loader = (CHAR8 *)AllocatePool((strlen(name) + 1) * sizeof (CHAR8));
translate_slashes(next_loader, name);
/* Create the URI for the next loader based on the original URI */ /* Create the URI for the next loader based on the original URI */
efi_status = generate_next_uri(uri, next_loader, &next_uri); efi_status = generate_next_uri(uri, next_loader, &next_uri);

View File

@ -40,11 +40,11 @@ static inline void wait_for_debug(void)
{ {
uint64_t a, b; uint64_t a, b;
int x; int x;
extern void msleep(unsigned long msecs); extern void usleep(unsigned long usecs);
a = read_counter(); a = read_counter();
for (x = 0; x < 1000; x++) { for (x = 0; x < 1000; x++) {
msleep(1000); usleep(1000);
b = read_counter(); b = read_counter();
if (a != b) if (a != b)
break; break;

View File

@ -198,5 +198,55 @@
#error shim has no cache_invalidate() implementation for this compiler #error shim has no cache_invalidate() implementation for this compiler
#endif /* __GNUC__ */ #endif /* __GNUC__ */
#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 checked_add(addend0, addend1, sum) \
__builtin_add_overflow(addend0, addend1, sum)
#define checked_sub(minuend, subtrahend, difference) \
__builtin_sub_overflow(minuend, subtrahend, difference)
#define checked_mul(factor0, factor1, product) \
__builtin_mul_overflow(factor0, factor1, product)
#else
#define checked_add(a0, a1, s) \
({ \
(*s) = ((a0) + (a1)); \
0; \
})
#define checked_sub(s0, s1, d) \
({ \
(*d) = ((s0) - (s1)); \
0; \
})
#define checked_mul(f0, f1, p) \
({ \
(*p) = ((f0) * (f1)); \
0; \
})
#endif
#define checked_div(dividend, divisor, quotient) \
({ \
bool _ret = True; \
if ((divisor) != 0) { \
_ret = False; \
(quotient) = (dividend) / (divisor); \
} \
_ret; \
})
#endif /* !COMPILER_H_ */ #endif /* !COMPILER_H_ */
// vim:fenc=utf-8:tw=75:et // vim:fenc=utf-8:tw=75:et

View File

@ -106,8 +106,8 @@ extern UINT32 verbose;
dprint_(L"%a:%d:%a() " fmt, __FILE__, __LINE__ - 1, __func__, \ dprint_(L"%a:%d:%a() " fmt, __FILE__, __LINE__ - 1, __func__, \
##__VA_ARGS__) ##__VA_ARGS__)
#else #else
#define dprint_(...) #define dprint_(...) ({ ; })
#define dprint(fmt, ...) #define dprint(fmt, ...) ({ ; })
#endif #endif
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,
@ -122,7 +122,9 @@ extern EFI_STATUS EFIAPI vdprint_(const CHAR16 *fmt, const char *file, int line,
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__)
extern VOID msleep(unsigned long msecs); #ifndef SHIM_UNIT_TEST
extern VOID usleep(unsigned long usecs);
#endif
/* 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
* console */ * console */

View File

@ -21,6 +21,7 @@ fanalyzer-build-all : COMPILER=gcc
fanalyzer-build-all : CCACHE_DISABLE=1 fanalyzer-build-all : CCACHE_DISABLE=1
fanalyzer-build-all : FEATUREFLAGS+=-fanalyzer fanalyzer-build-all : FEATUREFLAGS+=-fanalyzer
fanalyzer-build-all : WERRFLAGS=-Werror=analyzer-null-dereference fanalyzer-build-all : WERRFLAGS=-Werror=analyzer-null-dereference
fanalyzer-build-all : IGNORE_COMPILER_ERRORS=" || :"
fanalyzer-build-all : all fanalyzer-build-all : all
fanalyzer-no-openssl : | fanalyzer-test fanalyzer-no-openssl : | fanalyzer-test

97
include/fuzz.mk Normal file
View File

@ -0,0 +1,97 @@
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
# fuzz.mk - makefile to fuzz local test programs
#
.SUFFIXES:
include Make.defaults
CC = clang
VALGRIND ?=
DEBUG_PRINTS ?= 0
OPTIMIZATIONS ?= -Og -ggdb
FUZZ_ARGS ?=
CFLAGS = $(OPTIMIZATIONS) -std=gnu11 \
-isystem $(TOPDIR)/include/system \
$(EFI_INCLUDES) \
-Iinclude -iquote . \
-isystem /usr/include \
-isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include) \
$(ARCH_CFLAGS) \
-fsanitize=fuzzer,address \
-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 \
-Wno-deprecated-declarations \
$(if $(findstring gcc,$(CC)),-Wno-unused-but-set-variable) \
-Wno-unused-but-set-variable \
-Wno-unused-variable \
-Wno-pointer-sign \
$(DEFAULT_WERRFLAGS) \
-Werror=nonnull \
$(shell $(CC) -Werror=nonnull-compare -E -x c /dev/null >/dev/null 2>&1 && echo -Werror=nonnull-compare) \
$(ARCH_DEFINES) \
-DEFI_FUNCTION_WRAPPER \
-DGNU_EFI_USE_MS_ABI -DPAGE_SIZE=4096 \
-DSHIM_UNIT_TEST \
-DSHIM_ENABLE_LIBFUZZER \
"-DDEFAULT_DEBUG_PRINT_STATE=$(DEBUG_PRINTS)"
# On some systems (e.g. Arch Linux), limits.h is in the "include-fixed" instead
# of the "include" directory
CFLAGS += -isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include-fixed)
# And on Debian also check the multi-arch include path
CFLAGS += -isystem /usr/include/$(shell $(CC) $(ARCH_CFLAGS) -print-multiarch)
libefi-test.a :
$(MAKE) -C gnu-efi \
COMPILER="$(COMPILER)" \
CC="$(CC)" \
ARCH=$(ARCH_GNUEFI) \
TOPDIR=$(TOPDIR)/gnu-efi \
-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 \
-f $(TOPDIR)/gnu-efi/Makefile \
clean
fuzz-sbat_FILES = csv.c lib/variables.c lib/guid.c sbat_var.S mock-variables.c
fuzz-sbat :: CFLAGS+=-DHAVE_GET_VARIABLE -DHAVE_GET_VARIABLE_ATTR -DHAVE_SHIM_LOCK_GUID
fuzzers := $(patsubst %.c,%,$(wildcard fuzz-*.c))
$(fuzzers) :: fuzz-% : | libefi-test.a
$(fuzzers) :: fuzz-% : test.c fuzz-%.c $(fuzz-%_FILES)
$(CC) $(CFLAGS) -o $@ $(sort $^ $(wildcard $*.c) $(fuzz-$*_FILES)) libefi-test.a -lefivar
$(VALGRIND) ./$@ -max_len=4096 -jobs=24 $(FUZZ_ARGS)
fuzz : $(fuzzers)
$(MAKE) -f include/fuzz.mk fuzz-clean
fuzz-clean :
@rm -vf random.bin libefi-test.a
@rm -vf vgcore.* fuzz*.log
clean : fuzz-clean
all : fuzz-clean fuzz
.PHONY: $(fuzzers) all fuzz clean
.SECONDARY: random.bin
# vim:ft=make

View File

@ -37,5 +37,6 @@ extern EFI_GUID SECURITY2_PROTOCOL_GUID;
extern EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; extern EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
extern EFI_GUID SHIM_LOCK_GUID; extern EFI_GUID SHIM_LOCK_GUID;
extern EFI_GUID MOK_VARIABLE_STORE; extern EFI_GUID MOK_VARIABLE_STORE;
extern EFI_GUID SECUREBOOT_EFI_NAMESPACE_GUID;
#endif /* SHIM_GUID_H */ #endif /* SHIM_GUID_H */

View File

@ -12,6 +12,6 @@
extern BOOLEAN find_httpboot(EFI_HANDLE device); extern BOOLEAN find_httpboot(EFI_HANDLE device);
extern EFI_STATUS httpboot_fetch_buffer(EFI_HANDLE image, VOID **buffer, extern EFI_STATUS httpboot_fetch_buffer(EFI_HANDLE image, VOID **buffer,
UINT64 *buf_size); UINT64 *buf_size, CHAR8 *name);
#endif /* SHIM_HTTPBOOT_H */ #endif /* SHIM_HTTPBOOT_H */

View File

@ -5,7 +5,7 @@
extern BOOLEAN findNetboot(EFI_HANDLE image_handle); extern BOOLEAN findNetboot(EFI_HANDLE image_handle);
extern EFI_STATUS parseNetbootinfo(EFI_HANDLE image_handle); extern EFI_STATUS parseNetbootinfo(EFI_HANDLE image_handle, CHAR8 *name);
extern EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle, VOID **buffer, UINT64 *bufsiz); extern EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle, VOID **buffer, UINT64 *bufsiz);

View File

@ -21,6 +21,20 @@ EFI_STATUS verify_image(void *data, unsigned int datasize,
EFI_STATUS EFI_STATUS
verify_sbat_section(char *SBATBase, size_t SBATSize); verify_sbat_section(char *SBATBase, size_t SBATSize);
EFI_STATUS
get_section_vma (UINTN section_num,
char *buffer, size_t bufsz UNUSED,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
char **basep, size_t *sizep,
EFI_IMAGE_SECTION_HEADER **sectionp);
EFI_STATUS
get_section_vma_by_name (char *name, size_t namesz,
char *buffer, size_t bufsz,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
char **basep, size_t *sizep,
EFI_IMAGE_SECTION_HEADER **sectionp);
EFI_STATUS EFI_STATUS
handle_image (void *data, unsigned int datasize, handle_image (void *data, unsigned int datasize,
EFI_LOADED_IMAGE *li, EFI_LOADED_IMAGE *li,

View File

@ -29,6 +29,9 @@
#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1))) #define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
#define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment)))) #define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment))))
// Check if `val` is evenly aligned to the page size.
#define IS_PAGE_ALIGNED(val) (!((val) & EFI_PAGE_MASK))
// //
// PE32+ Subsystem type for EFI images // PE32+ Subsystem type for EFI images
// //

View File

@ -30,10 +30,15 @@
#define SBAT_POLICY L"SbatPolicy" #define SBAT_POLICY L"SbatPolicy"
#define SBAT_POLICY8 "SbatPolicy" #define SBAT_POLICY8 "SbatPolicy"
#define SSP_POLICY L"SSPPolicy"
#define SSP_POLICY8 "SSPPolicy"
#define SBAT_POLICY_LATEST 1 #define POLICY_LATEST 1
#define SBAT_POLICY_PREVIOUS 2 #define POLICY_AUTOMATIC 2
#define SBAT_POLICY_RESET 3 #define POLICY_RESET 3
#define POLICY_NOTREAD 255
#define REVOCATIONFILE L"revocations.efi"
extern UINTN _sbat, _esbat; extern UINTN _sbat, _esbat;
@ -50,9 +55,10 @@ extern list_t sbat_var;
#define SBAT_VAR_COLUMNS ((sizeof (struct sbat_var_entry) - sizeof(list_t)) / sizeof(CHAR8 *)) #define SBAT_VAR_COLUMNS ((sizeof (struct sbat_var_entry) - sizeof(list_t)) / sizeof(CHAR8 *))
#define SBAT_VAR_REQUIRED_COLUMNS (SBAT_VAR_COLUMNS - 1) #define SBAT_VAR_REQUIRED_COLUMNS (SBAT_VAR_COLUMNS - 1)
EFI_STATUS parse_sbat_var(list_t *entries); EFI_STATUS parse_sbat_var(list_t *entries, char *sbat_var_candidate);
void cleanup_sbat_var(list_t *entries); void cleanup_sbat_var(list_t *entries);
EFI_STATUS set_sbat_uefi_variable(void); EFI_STATUS set_sbat_uefi_variable_internal(void);
EFI_STATUS set_sbat_uefi_variable(char *, char *);
bool preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, bool preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize,
UINT32 attributes, char *sbar_var); UINT32 attributes, char *sbar_var);

View File

@ -3,6 +3,9 @@
#ifndef SBAT_VAR_DEFS_H_ #ifndef SBAT_VAR_DEFS_H_
#define SBAT_VAR_DEFS_H_ #define SBAT_VAR_DEFS_H_
#define QUOTEVAL(s) QUOTE(s)
#define QUOTE(s) #s
/* /*
* This is the entry for the sbat data format * This is the entry for the sbat data format
*/ */
@ -13,11 +16,9 @@
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_ORIGINAL_DATE "\n" SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_ORIGINAL_DATE "\n"
#if defined(ENABLE_SHIM_DEVEL) #if defined(ENABLE_SHIM_DEVEL)
#define SBAT_VAR_PREVIOUS_DATE "2022020101" #define SBAT_VAR_AUTOMATIC_DATE "2021030218"
#define SBAT_VAR_PREVIOUS_REVOCATIONS "component,2\n" #define SBAT_VAR_AUTOMATIC \
#define SBAT_VAR_PREVIOUS \ SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_AUTOMATIC_DATE "\n"
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_PREVIOUS_DATE "\n" \
SBAT_VAR_PREVIOUS_REVOCATIONS
#define SBAT_VAR_LATEST_DATE "2022050100" #define SBAT_VAR_LATEST_DATE "2022050100"
#define SBAT_VAR_LATEST_REVOCATIONS "component,2\nothercomponent,2\n" #define SBAT_VAR_LATEST_REVOCATIONS "component,2\nothercomponent,2\n"
@ -25,21 +26,42 @@
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \ SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \
SBAT_VAR_LATEST_REVOCATIONS SBAT_VAR_LATEST_REVOCATIONS
#else /* !ENABLE_SHIM_DEVEL */ #else /* !ENABLE_SHIM_DEVEL */
/*
* As of 2022-11-16, most folks (including Ubuntu, SUSE, openSUSE) don't have
* a "shim,2" yet, so adding that here would end up unbootable.
*/
#define SBAT_VAR_PREVIOUS_DATE "2022052400"
#define SBAT_VAR_PREVIOUS_REVOCATIONS "grub,2\n"
#define SBAT_VAR_PREVIOUS \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_PREVIOUS_DATE "\n" \
SBAT_VAR_PREVIOUS_REVOCATIONS
#define SBAT_VAR_LATEST_DATE "2022111500" /*
#define SBAT_VAR_LATEST_REVOCATIONS "shim,2\ngrub,3\n" * Some distros may want to apply revocations from 2022052400
* or 2022111500 automatically. They can be selected by setting
* SBAT_AUTOMATIC_DATE=<datestamp> at build time. Otherwise the
* default is to apply the second to most recent revocations
* automatically. Distros that need to manage automatic updates
* externally from shim can choose the epoch 2021030218 emtpy
* revocations.
*/
#ifndef SBAT_AUTOMATIC_DATE
#define SBAT_AUTOMATIC_DATE 2023012900
#endif /* SBAT_AUTOMATIC_DATE */
#if SBAT_AUTOMATIC_DATE == 2021030218
#define SBAT_VAR_AUTOMATIC_REVOCATIONS
#elif SBAT_AUTOMATIC_DATE == 2022052400
#define SBAT_VAR_AUTOMATIC_REVOCATIONS "grub,2\n"
#elif SBAT_AUTOMATIC_DATE == 2022111500
#define SBAT_VAR_AUTOMATIC_REVOCATIONS "shim,2\ngrub,3\n"
#elif SBAT_AUTOMATIC_DATE == 2023012900
#define SBAT_VAR_AUTOMATIC_REVOCATIONS "shim,2\ngrub,3\ngrub.debian,4\n"
#else
#error "Unknown SBAT_AUTOMATIC_DATE"
#endif /* SBAT_AUTOMATIC_DATE == */
#define SBAT_VAR_AUTOMATIC_DATE QUOTEVAL(SBAT_AUTOMATIC_DATE)
#define SBAT_VAR_AUTOMATIC \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_AUTOMATIC_DATE "\n" \
SBAT_VAR_AUTOMATIC_REVOCATIONS
/*
* Revocations for January 2024 shim CVEs
*/
#define SBAT_VAR_LATEST_DATE "2024010900"
#define SBAT_VAR_LATEST_REVOCATIONS "shim,4\ngrub,3\ngrub.debian,4\n"
#define SBAT_VAR_LATEST \ #define SBAT_VAR_LATEST \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \ SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \
SBAT_VAR_LATEST_REVOCATIONS SBAT_VAR_LATEST_REVOCATIONS
#endif /* ENABLE_SHIM_DEVEL */ #endif /* ENABLE_SHIM_DEVEL */
#endif /* !SBAT_VAR_DEFS_H_ */ #endif /* !SBAT_VAR_DEFS_H_ */

View File

@ -22,6 +22,7 @@ scan-build-unchecked-openssl : Cryptlib/OpenSSL/libopenssl.a
scan-build-all : CCACHE_DISABLE=1 scan-build-all : CCACHE_DISABLE=1
scan-build-all : COMPILER=clang scan-build-all : COMPILER=clang
scan-build-all : IGNORE_COMPILER_ERRORS=" || :"
scan-build-all : | scan-test scan-build-all : | scan-test
scan-build-all : scan-build-all :
+scan-build -o scan-results make $(MAKEARGS) $(DASHJ) CCACHE_DISABLE=1 all +scan-build -o scan-results make $(MAKEARGS) $(DASHJ) CCACHE_DISABLE=1 all

14
include/ssp.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SSP_H_
#define SSP_H_
#define SSPVER_VAR_NAME L"SkuSiPolicyVersion"
#define SSPSIG_VAR_NAME L"SkuSiPolicyUpdateSigners"
#define SSP_VAR_ATTRS UEFI_VAR_NV_BS
#define SSPVER_SIZE 8
#define SSPSIG_SIZE 131
EFI_STATUS set_ssp_uefi_variable_internal(void);
EFI_STATUS set_ssp_uefi_variable(uint8_t*, uint8_t*, uint8_t*, uint8_t*);
#endif /* !SSP_H_ */

19
include/ssp_var_defs.h Normal file
View File

@ -0,0 +1,19 @@
/*
* variable definitions to enable bootmgr self revocation
*/
#ifndef SSP_VAR_DEFS_H_
#define SSP_VAR_DEFS_H_
uint8_t SkuSiPolicyVersion[] = { 0x2,0x0,0x0,0x0,0x0,0x0,0x2,0x0 };
uint8_t SkuSiPolicyUpdateSigners[] = {
0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
0x0b,0x00,0x00,0x00,0xd0,0x91,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
0x00,0x00,0x00,0x00,0x54,0xa6,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
0x00,0x00,0x00,0x00,0x5c,0xa6,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
0x00,0x00,0x00,0x00,0x64,0xa6,0x78,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,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x03,0x06,0x00,
0x00,0x00,0x00 };
#endif /* !SSP_VAR_DEFS_H_ */

View File

@ -92,9 +92,12 @@ 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_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-mok-mirror: CFLAGS+=-DHAVE_START_IMAGE -DHAVE_SHIM_LOCK_GUID
test-sbat_FILES = csv.c lib/variables.c lib/guid.c sbat_var.S test-sbat_FILES = csv.c lib/variables.c lib/guid.c sbat_var.S mock-variables.c
test-sbat :: CFLAGS+=-DHAVE_GET_VARIABLE -DHAVE_GET_VARIABLE_ATTR -DHAVE_SHIM_LOCK_GUID test-sbat :: CFLAGS+=-DHAVE_GET_VARIABLE -DHAVE_GET_VARIABLE_ATTR -DHAVE_SHIM_LOCK_GUID
test-pe-relocate_FILES = globals.c
test-pe-relocate :: CFLAGS+=-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))

View File

@ -743,11 +743,13 @@ setup_verbosity(VOID)
setup_console(-1); setup_console(-1);
} }
#ifndef SHIM_UNIT_TEST
VOID VOID
msleep(unsigned long msecs) usleep(unsigned long usecs)
{ {
BS->Stall(msecs); BS->Stall(usecs);
} }
#endif
/* 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
* console */ * console */

View File

@ -36,3 +36,4 @@ EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x
EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID = { 0xf4560cf6, 0x40ec, 0x4b4a, {0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89} }; EFI_GUID EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID = { 0xf4560cf6, 0x40ec, 0x4b4a, {0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89} };
EFI_GUID SHIM_LOCK_GUID = {0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } }; EFI_GUID SHIM_LOCK_GUID = {0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } };
EFI_GUID MOK_VARIABLE_STORE = {0xc451ed2b, 0x9694, 0x45d3, {0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89} }; EFI_GUID MOK_VARIABLE_STORE = {0xc451ed2b, 0x9694, 0x45d3, {0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89} };
EFI_GUID SECUREBOOT_EFI_NAMESPACE_GUID = {0x77fa9abd, 0x0359, 0x4d32, {0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b} };

View File

@ -54,7 +54,7 @@ gcm_gmult_4bit(u64 Xi[2], u128 Htable[16])
} }
void void
msleep(int n) usleep(int n)
{ {
__coverity_sleep__(); __coverity_sleep__();
} }

14
mok.c
View File

@ -291,7 +291,7 @@ mirror_one_esl(CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
&var, &varsz); &var, &varsz);
if (EFI_ERROR(efi_status) || !var || !varsz) { if (EFI_ERROR(efi_status) || !var || !varsz) {
LogError(L"Couldn't allocate %lu bytes for mok variable \"%s\": %r\n", LogError(L"Couldn't allocate %lu bytes for mok variable \"%s\": %r\n",
varsz, var, efi_status); varsz, name, efi_status);
return efi_status; return efi_status;
} }
@ -302,7 +302,7 @@ mirror_one_esl(CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
FreePool(var); FreePool(var);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
LogError(L"Couldn't create mok variable \"%s\": %r\n", LogError(L"Couldn't create mok variable \"%s\": %r\n",
varsz, var, efi_status); name, efi_status);
return efi_status; return efi_status;
} }
@ -423,12 +423,20 @@ mirror_mok_db(CHAR16 *name, CHAR8 *name8, EFI_GUID *guid, UINT32 attrs,
} }
/* The name counts towards the size of the variable */ /* The name counts towards the size of the variable */
max_var_sz -= (StrLen(namen) + 1) * 2; SIZE_T namen_sz = (StrLen(namen) + 1) * 2;
if (max_var_sz > namen_sz)
max_var_sz -= namen_sz;
else
max_var_sz = 0;
dprint(L"max_var_sz - name: %lx\n", max_var_sz); dprint(L"max_var_sz - name: %lx\n", max_var_sz);
SIZE_T howmany; SIZE_T howmany;
if (max_var_sz > sizeof(*esl))
howmany = MIN((max_var_sz - sizeof(*esl)) / esl->SignatureSize, howmany = MIN((max_var_sz - sizeof(*esl)) / esl->SignatureSize,
(esl_end_pos - pos) / esl->SignatureSize); (esl_end_pos - pos) / esl->SignatureSize);
else
howmany = 0;
if (howmany == 0) { if (howmany == 0) {
/* No signatures from this ESL can be mirrored in to a /* No signatures from this ESL can be mirrored in to a
* single variable, so skip it. * single variable, so skip it.

View File

@ -160,25 +160,30 @@ static CHAR8 *str2ip6(CHAR8 *str)
return (CHAR8 *)ip; return (CHAR8 *)ip;
} }
static BOOLEAN extract_tftp_info(CHAR8 *url) static BOOLEAN extract_tftp_info(CHAR8 *url, CHAR8 *name)
{ {
CHAR8 *start, *end; CHAR8 *start, *end;
CHAR8 ip6str[40]; CHAR8 ip6str[40];
CHAR8 ip6inv[16]; CHAR8 ip6inv[16];
CHAR8 template[sizeof DEFAULT_LOADER_CHAR]; int template_len = 0;
CHAR8 *template;
translate_slashes(template, DEFAULT_LOADER_CHAR); while (name[template_len++] != '\0');
template = (CHAR8 *)AllocatePool((template_len + 1) * sizeof (CHAR8));
translate_slashes(template, name);
// to check against str2ip6() errors // to check against str2ip6() errors
memset(ip6inv, 0, sizeof(ip6inv)); memset(ip6inv, 0, sizeof(ip6inv));
if (strncmp((const char *)url, (const char *)"tftp://", 7)) { if (strncmp((const char *)url, (const char *)"tftp://", 7)) {
console_print(L"URLS MUST START WITH tftp://\n"); console_print(L"URLS MUST START WITH tftp://\n");
FreePool(template);
return FALSE; return FALSE;
} }
start = url + 7; start = url + 7;
if (*start != '[') { if (*start != '[') {
console_print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n"); console_print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
FreePool(template);
return FALSE; return FALSE;
} }
@ -188,22 +193,28 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
end++; end++;
if (end - start >= (int)sizeof(ip6str)) { if (end - start >= (int)sizeof(ip6str)) {
console_print(L"TFTP URL includes malformed IPv6 address\n"); console_print(L"TFTP URL includes malformed IPv6 address\n");
FreePool(template);
return FALSE; return FALSE;
} }
} }
if (*end == '\0') { if (*end == '\0') {
console_print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n"); console_print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
FreePool(template);
return FALSE; return FALSE;
} }
memset(ip6str, 0, sizeof(ip6str)); memset(ip6str, 0, sizeof(ip6str));
memcpy(ip6str, start, end - start); memcpy(ip6str, start, end - start);
end++; end++;
memcpy(&tftp_addr.v6, str2ip6(ip6str), 16); memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
if (memcmp(&tftp_addr.v6, ip6inv, sizeof(ip6inv)) == 0) if (memcmp(&tftp_addr.v6, ip6inv, sizeof(ip6inv)) == 0) {
FreePool(template);
return FALSE; return FALSE;
}
full_path = AllocateZeroPool(strlen(end)+strlen(template)+1); full_path = AllocateZeroPool(strlen(end)+strlen(template)+1);
if (!full_path) if (!full_path) {
FreePool(template);
return FALSE; return FALSE;
}
memcpy(full_path, end, strlen(end)); memcpy(full_path, end, strlen(end));
end = (CHAR8 *)strrchr((char *)full_path, '/'); end = (CHAR8 *)strrchr((char *)full_path, '/');
if (!end) if (!end)
@ -211,10 +222,11 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
memcpy(end, template, strlen(template)); memcpy(end, template, strlen(template));
end[strlen(template)] = '\0'; end[strlen(template)] = '\0';
FreePool(template);
return TRUE; return TRUE;
} }
static EFI_STATUS parseDhcp6() static EFI_STATUS parseDhcp6(CHAR8 *name)
{ {
EFI_PXE_BASE_CODE_DHCPV6_PACKET *packet = (EFI_PXE_BASE_CODE_DHCPV6_PACKET *)&pxe->Mode->DhcpAck.Raw; EFI_PXE_BASE_CODE_DHCPV6_PACKET *packet = (EFI_PXE_BASE_CODE_DHCPV6_PACKET *)&pxe->Mode->DhcpAck.Raw;
CHAR8 *bootfile_url; CHAR8 *bootfile_url;
@ -222,7 +234,7 @@ static EFI_STATUS parseDhcp6()
bootfile_url = get_v6_bootfile_url(packet); bootfile_url = get_v6_bootfile_url(packet);
if (!bootfile_url) if (!bootfile_url)
return EFI_NOT_FOUND; return EFI_NOT_FOUND;
if (extract_tftp_info(bootfile_url) == FALSE) { if (extract_tftp_info(bootfile_url, name) == FALSE) {
FreePool(bootfile_url); FreePool(bootfile_url);
return EFI_NOT_FOUND; return EFI_NOT_FOUND;
} }
@ -230,14 +242,16 @@ static EFI_STATUS parseDhcp6()
return EFI_SUCCESS; return EFI_SUCCESS;
} }
static EFI_STATUS parseDhcp4() static EFI_STATUS parseDhcp4(CHAR8 *name)
{ {
CHAR8 template[sizeof DEFAULT_LOADER_CHAR]; CHAR8 *template;
INTN template_len; INTN template_len = 0;
UINTN template_ofs = 0; UINTN template_ofs = 0;
EFI_PXE_BASE_CODE_DHCPV4_PACKET* pkt_v4 = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)&pxe->Mode->DhcpAck.Dhcpv4; EFI_PXE_BASE_CODE_DHCPV4_PACKET* pkt_v4 = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)&pxe->Mode->DhcpAck.Dhcpv4;
translate_slashes(template, DEFAULT_LOADER_CHAR); while (name[template_len++] != '\0');
template = (CHAR8 *)AllocatePool((template_len + 1) * sizeof (CHAR8));
translate_slashes(template, name);
template_len = strlen(template) + 1; template_len = strlen(template) + 1;
if(pxe->Mode->ProxyOfferReceived) { if(pxe->Mode->ProxyOfferReceived) {
@ -263,30 +277,42 @@ static EFI_STATUS parseDhcp4()
UINT8 *dir = pkt_v4->BootpBootFile; UINT8 *dir = pkt_v4->BootpBootFile;
for (i = dir_len; i >= 0; i--) { for (i = dir_len; i >= 0; i--) {
if (dir[i] == '/') if ((dir[i] == '/') || (dir[i] == '\\'))
break; break;
} }
dir_len = (i >= 0) ? i + 1 : 0; dir_len = (i >= 0) ? i + 1 : 0;
full_path = AllocateZeroPool(dir_len + template_len); full_path = AllocateZeroPool(dir_len + template_len);
if (!full_path) if (!full_path) {
FreePool(template);
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
}
if (dir_len > 0) { if (dir_len > 0) {
strncpy(full_path, (CHAR8 *)dir, dir_len); strncpy(full_path, (CHAR8 *)dir, dir_len);
if (full_path[dir_len-1] == '/' && template[0] == '/') if (full_path[dir_len-1] == '/' && template[0] == '/')
full_path[dir_len-1] = '\0'; full_path[dir_len-1] = '\0';
/*
* If the path from DHCP is using backslash instead of slash,
* accept that and use it in the template in the same position
* as well.
*/
if (full_path[dir_len-1] == '\\' && template[0] == '/') {
full_path[dir_len-1] = '\0';
template[0] = '\\';
}
} }
if (dir_len == 0 && dir[0] != '/' && template[0] == '/') if (dir_len == 0 && dir[0] != '/' && template[0] == '/')
template_ofs++; template_ofs++;
strcat(full_path, template + template_ofs); strcat(full_path, template + template_ofs);
memcpy(&tftp_addr.v4, pkt_v4->BootpSiAddr, 4); memcpy(&tftp_addr.v4, pkt_v4->BootpSiAddr, 4);
FreePool(template);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
EFI_STATUS parseNetbootinfo(EFI_HANDLE image_handle UNUSED) EFI_STATUS parseNetbootinfo(EFI_HANDLE image_handle UNUSED, CHAR8 *netbootname)
{ {
EFI_STATUS efi_status; EFI_STATUS efi_status;
@ -301,9 +327,9 @@ EFI_STATUS parseNetbootinfo(EFI_HANDLE image_handle UNUSED)
* if its ipv4 or ipv6 * if its ipv4 or ipv6
*/ */
if (pxe->Mode->UsingIpv6){ if (pxe->Mode->UsingIpv6){
efi_status = parseDhcp6(); efi_status = parseDhcp6(netbootname);
} else } else
efi_status = parseDhcp4(); efi_status = parseDhcp4(netbootname);
return efi_status; return efi_status;
} }
@ -315,7 +341,7 @@ EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle UNUSED, VOID **buffer, UINT
BOOLEAN nobuffer = FALSE; BOOLEAN nobuffer = FALSE;
UINTN blksz = 512; UINTN blksz = 512;
console_print(L"Fetching Netboot Image\n"); console_print(L"Fetching Netboot Image %a\n", full_path);
if (*buffer == NULL) { if (*buffer == NULL) {
*buffer = AllocatePool(4096 * 1024); *buffer = AllocatePool(4096 * 1024);
if (!*buffer) if (!*buffer)

554
pe-relocate.c Normal file
View File

@ -0,0 +1,554 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* pe-relocate.c - our PE relocation/loading (but not verification) code
* Copyright Peter Jones <pjones@redhat.com>
*/
#include "shim.h"
/*
* Perform basic bounds checking of the intra-image pointers
*/
void *
ImageAddress (void *image, uint64_t size, uint64_t address)
{
uintptr_t img_addr;
/* ensure our local pointer isn't bigger than our size */
if (address >= size)
return NULL;
/* Insure our math won't overflow */
img_addr = (uintptr_t)image;
if (checked_add(img_addr, address, &img_addr))
return NULL;
/* return the absolute pointer */
return (void *)img_addr;
}
/*
* Perform the actual relocation
*/
EFI_STATUS
relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
EFI_IMAGE_SECTION_HEADER *Section,
void *orig, void *data)
{
EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
UINT64 Adjust;
UINT16 *Reloc, *RelocEnd;
char *Fixup, *FixupBase;
UINT16 *Fixup16;
UINT32 *Fixup32;
UINT64 *Fixup64;
int size = context->ImageSize;
void *ImageEnd = (char *)orig + size;
int n = 0;
/* Alright, so here's how this works:
*
* context->RelocDir gives us two things:
* - the VA the table of base relocation blocks are (maybe) to be
* mapped at (RelocDir->VirtualAddress)
* - the virtual size (RelocDir->Size)
*
* The .reloc section (Section here) gives us some other things:
* - the name! kind of. (Section->Name)
* - the virtual size (Section->VirtualSize), which should be the same
* as RelocDir->Size
* - the virtual address (Section->VirtualAddress)
* - the file section size (Section->SizeOfRawData), which is
* a multiple of OptHdr->FileAlignment. Only useful for image
* validation, not really useful for iteration bounds.
* - the file address (Section->PointerToRawData)
* - a bunch of stuff we don't use that's 0 in our binaries usually
* - Flags (Section->Characteristics)
*
* and then the thing that's actually at the file address is an array
* of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind
* them. The SizeOfBlock field of this structure includes the
* structure itself, and adding it to that structure's address will
* yield the next entry in the array.
*/
RelocBase = ImageAddress(orig, size, Section->PointerToRawData);
/* RelocBaseEnd here is the address of the first entry /past/ the
* table. */
RelocBaseEnd = ImageAddress(orig, size, Section->PointerToRawData +
context->RelocDir->Size - 1);
if (!RelocBase && !RelocBaseEnd)
return EFI_SUCCESS;
if (!RelocBase || !RelocBaseEnd) {
perror(L"Reloc table overflows binary\n");
return EFI_UNSUPPORTED;
}
Adjust = (UINTN)data - context->ImageAddress;
if (Adjust == 0)
return EFI_SUCCESS;
while (RelocBase < RelocBaseEnd) {
Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
if (RelocBase->SizeOfBlock == 0) {
perror(L"Reloc %d block size 0 is invalid\n", n);
return EFI_UNSUPPORTED;
} else if (RelocBase->SizeOfBlock > context->RelocDir->Size) {
perror(L"Reloc %d block size %d greater than reloc dir"
"size %d, which is invalid\n", n,
RelocBase->SizeOfBlock,
context->RelocDir->Size);
return EFI_UNSUPPORTED;
}
RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
if ((void *)RelocEnd < orig || (void *)RelocEnd > ImageEnd) {
perror(L"Reloc %d entry overflows binary\n", n);
return EFI_UNSUPPORTED;
}
FixupBase = ImageAddress(data, size, RelocBase->VirtualAddress);
if (!FixupBase) {
perror(L"Reloc %d Invalid fixupbase\n", n);
return EFI_UNSUPPORTED;
}
while (Reloc < RelocEnd) {
Fixup = FixupBase + (*Reloc & 0xFFF);
switch ((*Reloc) >> 12) {
case EFI_IMAGE_REL_BASED_ABSOLUTE:
break;
case EFI_IMAGE_REL_BASED_HIGH:
Fixup16 = (UINT16 *) Fixup;
*Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
break;
case EFI_IMAGE_REL_BASED_LOW:
Fixup16 = (UINT16 *) Fixup;
*Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
break;
case EFI_IMAGE_REL_BASED_HIGHLOW:
Fixup32 = (UINT32 *) Fixup;
*Fixup32 = *Fixup32 + (UINT32) Adjust;
break;
case EFI_IMAGE_REL_BASED_DIR64:
Fixup64 = (UINT64 *) Fixup;
*Fixup64 = *Fixup64 + (UINT64) Adjust;
break;
default:
perror(L"Reloc %d Unknown relocation\n", n);
return EFI_UNSUPPORTED;
}
Reloc += 1;
}
RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
n++;
}
return EFI_SUCCESS;
}
EFI_STATUS
get_section_vma (UINTN section_num,
char *buffer, size_t bufsz UNUSED,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
char **basep, size_t *sizep,
EFI_IMAGE_SECTION_HEADER **sectionp)
{
EFI_IMAGE_SECTION_HEADER *sections = context->FirstSection;
EFI_IMAGE_SECTION_HEADER *section;
char *base = NULL, *end = NULL;
if (section_num >= context->NumberOfSections)
return EFI_NOT_FOUND;
if (context->FirstSection == NULL) {
perror(L"Invalid section %d requested\n", section_num);
return EFI_UNSUPPORTED;
}
section = &sections[section_num];
base = ImageAddress (buffer, context->ImageSize, section->VirtualAddress);
end = ImageAddress (buffer, context->ImageSize,
section->VirtualAddress + section->Misc.VirtualSize - 1);
if (!(section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE)) {
if (!base) {
perror(L"Section %d has invalid base address\n", section_num);
return EFI_UNSUPPORTED;
}
if (!end) {
perror(L"Section %d has zero size\n", section_num);
return EFI_UNSUPPORTED;
}
}
if (!(section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) &&
(section->VirtualAddress < context->SizeOfHeaders ||
section->PointerToRawData < context->SizeOfHeaders)) {
perror(L"Section %d is inside image headers\n", section_num);
return EFI_UNSUPPORTED;
}
if (end < base) {
perror(L"Section %d has negative size\n", section_num);
return EFI_UNSUPPORTED;
}
*basep = base;
*sizep = end - base;
*sectionp = section;
return EFI_SUCCESS;
}
EFI_STATUS
get_section_vma_by_name (char *name, size_t namesz,
char *buffer, size_t bufsz,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
char **basep, size_t *sizep,
EFI_IMAGE_SECTION_HEADER **sectionp)
{
UINTN i;
char namebuf[9];
if (!name || namesz == 0 || !buffer || bufsz < namesz || !context
|| !basep || !sizep || !sectionp)
return EFI_INVALID_PARAMETER;
/*
* This code currently is only used for ".reloc\0\0" and
* ".sbat\0\0\0", and it doesn't know how to look up longer section
* names.
*/
if (namesz > 8)
return EFI_UNSUPPORTED;
SetMem(namebuf, sizeof(namebuf), 0);
CopyMem(namebuf, name, MIN(namesz, 8));
/*
* Copy the executable's sections to their desired offsets
*/
for (i = 0; i < context->NumberOfSections; i++) {
EFI_STATUS status;
EFI_IMAGE_SECTION_HEADER *section = NULL;
char *base = NULL;
size_t size = 0;
status = get_section_vma(i, buffer, bufsz, context, &base, &size, &section);
if (!EFI_ERROR(status)) {
if (CompareMem(section->Name, namebuf, 8) == 0) {
*basep = base;
*sizep = size;
*sectionp = section;
return EFI_SUCCESS;
}
continue;
}
switch(status) {
case EFI_NOT_FOUND:
break;
}
}
return EFI_NOT_FOUND;
}
/* here's a chart:
* i686 x86_64 aarch64
* 64-on-64: nyet yes yes
* 64-on-32: nyet yes nyet
* 32-on-32: yes yes no
*/
static int
allow_64_bit(void)
{
#if defined(__x86_64__) || defined(__aarch64__)
return 1;
#elif defined(__i386__) || defined(__i686__)
/* Right now blindly assuming the kernel will correctly detect this
* and /halt the system/ if you're not really on a 64-bit cpu */
if (in_protocol)
return 1;
return 0;
#else /* assuming everything else is 32-bit... */
return 0;
#endif
}
static int
allow_32_bit(void)
{
#if defined(__x86_64__)
#if defined(ALLOW_32BIT_KERNEL_ON_X64)
if (in_protocol)
return 1;
return 0;
#else
return 0;
#endif
#elif defined(__i386__) || defined(__i686__)
return 1;
#elif defined(__aarch64__)
return 0;
#else /* assuming everything else is 32-bit... */
return 1;
#endif
}
static int
image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
{
/* .Magic is the same offset in all cases */
if (PEHdr->Pe32.OptionalHeader.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)
return 1;
return 0;
}
static const UINT16 machine_type =
#if defined(__x86_64__)
IMAGE_FILE_MACHINE_X64;
#elif defined(__aarch64__)
IMAGE_FILE_MACHINE_ARM64;
#elif defined(__arm__)
IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
IMAGE_FILE_MACHINE_I386;
#elif defined(__ia64__)
IMAGE_FILE_MACHINE_IA64;
#else
#error this architecture is not supported by shim
#endif
static int
image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
{
/* If the machine type doesn't match the binary, bail, unless
* we're in an allowed 64-on-32 scenario */
if (PEHdr->Pe32.FileHeader.Machine != machine_type) {
if (!(machine_type == IMAGE_FILE_MACHINE_I386 &&
PEHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64 &&
allow_64_bit())) {
return 0;
}
}
/* If it's not a header type we recognize at all, bail */
switch (PEHdr->Pe32Plus.OptionalHeader.Magic) {
case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
break;
default:
return 0;
}
/* and now just check for general 64-vs-32 compatibility */
if (image_is_64_bit(PEHdr)) {
if (allow_64_bit())
return 1;
} else {
if (allow_32_bit())
return 1;
}
return 0;
}
/*
* Read the binary header and grab appropriate information from it
*/
EFI_STATUS
read_header(void *data, unsigned int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context)
{
EFI_IMAGE_DOS_HEADER *DosHdr = data;
EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
unsigned long FileAlignment = 0;
UINT16 DllFlags;
size_t dos_sz = 0;
size_t tmpsz0, tmpsz1;
if (datasize < sizeof (*DosHdr)) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
if (DosHdr->e_lfanew < sizeof (*DosHdr) ||
DosHdr->e_lfanew > datasize - 4) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
dos_sz = DosHdr->e_lfanew;
PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
}
if (datasize - dos_sz < sizeof (PEHdr->Pe32)) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (image_is_64_bit(PEHdr) &&
(datasize - dos_sz < sizeof (PEHdr->Pe32Plus))) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (!image_is_loadable(PEHdr)) {
perror(L"Platform does not support this image\n");
return EFI_UNSUPPORTED;
}
if (image_is_64_bit(PEHdr)) {
context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
context->SectionAlignment = PEHdr->Pe32Plus.OptionalHeader.SectionAlignment;
FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment;
OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
} else {
context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
context->SectionAlignment = PEHdr->Pe32.OptionalHeader.SectionAlignment;
FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment;
OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
}
if (FileAlignment % 2 != 0) {
perror(L"File Alignment is invalid (%d)\n", FileAlignment);
return EFI_UNSUPPORTED;
}
if (FileAlignment == 0)
FileAlignment = 0x200;
if (context->SectionAlignment == 0)
context->SectionAlignment = PAGE_SIZE;
if (context->SectionAlignment < FileAlignment)
context->SectionAlignment = FileAlignment;
context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->NumberOfRvaAndSizes) {
perror(L"Image header too large\n");
return EFI_UNSUPPORTED;
}
if (checked_mul(sizeof(EFI_IMAGE_DATA_DIRECTORY), EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, &tmpsz0) ||
checked_sub(OptHeaderSize, tmpsz0, &HeaderWithoutDataDir) ||
checked_sub((size_t)PEHdr->Pe32.FileHeader.SizeOfOptionalHeader, HeaderWithoutDataDir, &tmpsz0) ||
checked_mul((size_t)context->NumberOfRvaAndSizes, sizeof (EFI_IMAGE_DATA_DIRECTORY), &tmpsz1) ||
(tmpsz0 != tmpsz1)) {
perror(L"Image header overflows data directory\n");
return EFI_UNSUPPORTED;
}
if (checked_add((size_t)DosHdr->e_lfanew, sizeof(UINT32), &tmpsz0) ||
checked_add(tmpsz0, sizeof(EFI_IMAGE_FILE_HEADER), &tmpsz0) ||
checked_add(tmpsz0, PEHdr->Pe32.FileHeader.SizeOfOptionalHeader, &SectionHeaderOffset)) {
perror(L"Image sections overflow image size\n");
return EFI_UNSUPPORTED;
}
if (checked_sub((size_t)context->ImageSize, SectionHeaderOffset, &tmpsz0) ||
(tmpsz0 / EFI_IMAGE_SIZEOF_SECTION_HEADER <= context->NumberOfSections)) {
perror(L"Image sections overflow image size\n");
return EFI_UNSUPPORTED;
}
if (checked_sub((size_t)context->SizeOfHeaders, SectionHeaderOffset, &tmpsz0) ||
(tmpsz0 / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)context->NumberOfSections)) {
perror(L"Image sections overflow section headers\n");
return EFI_UNSUPPORTED;
}
if (checked_mul((size_t)context->NumberOfSections, sizeof(EFI_IMAGE_SECTION_HEADER), &tmpsz0) ||
checked_add(tmpsz0, SectionHeaderOffset, &tmpsz0) ||
(tmpsz0 > datasize)) {
perror(L"Image sections overflow section headers\n");
return EFI_UNSUPPORTED;
}
if (checked_sub((size_t)(uintptr_t)PEHdr, (size_t)(uintptr_t)data, &tmpsz0) ||
checked_add(tmpsz0, sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION), &tmpsz0) ||
(tmpsz0 > datasize)) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) {
perror(L"Unsupported image type\n");
return EFI_UNSUPPORTED;
}
if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {
perror(L"Unsupported image - Relocations have been stripped\n");
return EFI_UNSUPPORTED;
}
context->PEHdr = PEHdr;
if (image_is_64_bit(PEHdr)) {
context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
DllFlags = PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics;
} else {
context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
DllFlags = PEHdr->Pe32.OptionalHeader.DllCharacteristics;
}
if ((mok_policy & MOK_POLICY_REQUIRE_NX) &&
!(DllFlags & EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT)) {
perror(L"Policy requires NX, but image does not support NX\n");
return EFI_UNSUPPORTED;
}
if (checked_add((size_t)(uintptr_t)PEHdr, PEHdr->Pe32.FileHeader.SizeOfOptionalHeader, &tmpsz0) ||
checked_add(tmpsz0, sizeof(UINT32), &tmpsz0) ||
checked_add(tmpsz0, sizeof(EFI_IMAGE_FILE_HEADER), &tmpsz0)) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)(uintptr_t)tmpsz0;
if ((uint64_t)(uintptr_t)(context->FirstSection)
> (uint64_t)(uintptr_t)data + datasize) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (context->ImageSize < context->SizeOfHeaders) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (checked_sub((size_t)(uintptr_t)context->SecDir, (size_t)(uintptr_t)data, &tmpsz0) ||
(tmpsz0 > datasize - sizeof(EFI_IMAGE_DATA_DIRECTORY))) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (context->SecDir->VirtualAddress > datasize ||
(context->SecDir->VirtualAddress == datasize &&
context->SecDir->Size > 0)) {
perror(L"Malformed security header\n");
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
// vim:fenc=utf-8:tw=75:noet

544
pe.c
View File

@ -21,152 +21,6 @@
#include <Library/BaseCryptLib.h> #include <Library/BaseCryptLib.h>
/*
* Perform basic bounds checking of the intra-image pointers
*/
void *
ImageAddress (void *image, uint64_t size, uint64_t address)
{
/* ensure our local pointer isn't bigger than our size */
if (address > size)
return NULL;
/* Insure our math won't overflow */
if (UINT64_MAX - address < (uint64_t)(intptr_t)image)
return NULL;
/* return the absolute pointer */
return image + address;
}
/*
* Perform the actual relocation
*/
EFI_STATUS
relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
EFI_IMAGE_SECTION_HEADER *Section,
void *orig, void *data)
{
EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
UINT64 Adjust;
UINT16 *Reloc, *RelocEnd;
char *Fixup, *FixupBase;
UINT16 *Fixup16;
UINT32 *Fixup32;
UINT64 *Fixup64;
int size = context->ImageSize;
void *ImageEnd = (char *)orig + size;
int n = 0;
/* Alright, so here's how this works:
*
* context->RelocDir gives us two things:
* - the VA the table of base relocation blocks are (maybe) to be
* mapped at (RelocDir->VirtualAddress)
* - the virtual size (RelocDir->Size)
*
* The .reloc section (Section here) gives us some other things:
* - the name! kind of. (Section->Name)
* - the virtual size (Section->VirtualSize), which should be the same
* as RelocDir->Size
* - the virtual address (Section->VirtualAddress)
* - the file section size (Section->SizeOfRawData), which is
* a multiple of OptHdr->FileAlignment. Only useful for image
* validation, not really useful for iteration bounds.
* - the file address (Section->PointerToRawData)
* - a bunch of stuff we don't use that's 0 in our binaries usually
* - Flags (Section->Characteristics)
*
* and then the thing that's actually at the file address is an array
* of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind
* them. The SizeOfBlock field of this structure includes the
* structure itself, and adding it to that structure's address will
* yield the next entry in the array.
*/
RelocBase = ImageAddress(orig, size, Section->PointerToRawData);
/* RelocBaseEnd here is the address of the first entry /past/ the
* table. */
RelocBaseEnd = ImageAddress(orig, size, Section->PointerToRawData +
Section->Misc.VirtualSize);
if (!RelocBase && !RelocBaseEnd)
return EFI_SUCCESS;
if (!RelocBase || !RelocBaseEnd) {
perror(L"Reloc table overflows binary\n");
return EFI_UNSUPPORTED;
}
Adjust = (UINTN)data - context->ImageAddress;
if (Adjust == 0)
return EFI_SUCCESS;
while (RelocBase < RelocBaseEnd) {
Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
if (RelocBase->SizeOfBlock == 0) {
perror(L"Reloc %d block size 0 is invalid\n", n);
return EFI_UNSUPPORTED;
} else if (RelocBase->SizeOfBlock > context->RelocDir->Size) {
perror(L"Reloc %d block size %d greater than reloc dir"
"size %d, which is invalid\n", n,
RelocBase->SizeOfBlock,
context->RelocDir->Size);
return EFI_UNSUPPORTED;
}
RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
if ((void *)RelocEnd < orig || (void *)RelocEnd > ImageEnd) {
perror(L"Reloc %d entry overflows binary\n", n);
return EFI_UNSUPPORTED;
}
FixupBase = ImageAddress(data, size, RelocBase->VirtualAddress);
if (!FixupBase) {
perror(L"Reloc %d Invalid fixupbase\n", n);
return EFI_UNSUPPORTED;
}
while (Reloc < RelocEnd) {
Fixup = FixupBase + (*Reloc & 0xFFF);
switch ((*Reloc) >> 12) {
case EFI_IMAGE_REL_BASED_ABSOLUTE:
break;
case EFI_IMAGE_REL_BASED_HIGH:
Fixup16 = (UINT16 *) Fixup;
*Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
break;
case EFI_IMAGE_REL_BASED_LOW:
Fixup16 = (UINT16 *) Fixup;
*Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
break;
case EFI_IMAGE_REL_BASED_HIGHLOW:
Fixup32 = (UINT32 *) Fixup;
*Fixup32 = *Fixup32 + (UINT32) Adjust;
break;
case EFI_IMAGE_REL_BASED_DIR64:
Fixup64 = (UINT64 *) Fixup;
*Fixup64 = *Fixup64 + (UINT64) Adjust;
break;
default:
perror(L"Reloc %d Unknown relocation\n", n);
return EFI_UNSUPPORTED;
}
Reloc += 1;
}
RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
n++;
}
return EFI_SUCCESS;
}
#define check_size_line(data, datasize_in, hashbase, hashsize, l) ({ \ #define check_size_line(data, datasize_in, hashbase, hashsize, l) ({ \
if ((unsigned long)hashbase > \ if ((unsigned long)hashbase > \
(unsigned long)data + datasize_in) { \ (unsigned long)data + datasize_in) { \
@ -185,113 +39,6 @@ relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
}) })
#define check_size(d, ds, h, hs) check_size_line(d, ds, h, hs, __LINE__) #define check_size(d, ds, h, hs) check_size_line(d, ds, h, hs, __LINE__)
EFI_STATUS
get_section_vma (UINTN section_num,
char *buffer, size_t bufsz UNUSED,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
char **basep, size_t *sizep,
EFI_IMAGE_SECTION_HEADER **sectionp)
{
EFI_IMAGE_SECTION_HEADER *sections = context->FirstSection;
EFI_IMAGE_SECTION_HEADER *section;
char *base = NULL, *end = NULL;
if (section_num >= context->NumberOfSections)
return EFI_NOT_FOUND;
if (context->FirstSection == NULL) {
perror(L"Invalid section %d requested\n", section_num);
return EFI_UNSUPPORTED;
}
section = &sections[section_num];
base = ImageAddress (buffer, context->ImageSize, section->VirtualAddress);
end = ImageAddress (buffer, context->ImageSize,
section->VirtualAddress + section->Misc.VirtualSize - 1);
if (!(section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE)) {
if (!base) {
perror(L"Section %d has invalid base address\n", section_num);
return EFI_UNSUPPORTED;
}
if (!end) {
perror(L"Section %d has zero size\n", section_num);
return EFI_UNSUPPORTED;
}
}
if (!(section->Characteristics & EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA) &&
(section->VirtualAddress < context->SizeOfHeaders ||
section->PointerToRawData < context->SizeOfHeaders)) {
perror(L"Section %d is inside image headers\n", section_num);
return EFI_UNSUPPORTED;
}
if (end < base) {
perror(L"Section %d has negative size\n", section_num);
return EFI_UNSUPPORTED;
}
*basep = base;
*sizep = end - base;
*sectionp = section;
return EFI_SUCCESS;
}
EFI_STATUS
get_section_vma_by_name (char *name, size_t namesz,
char *buffer, size_t bufsz,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
char **basep, size_t *sizep,
EFI_IMAGE_SECTION_HEADER **sectionp)
{
UINTN i;
char namebuf[9];
if (!name || namesz == 0 || !buffer || bufsz < namesz || !context
|| !basep || !sizep || !sectionp)
return EFI_INVALID_PARAMETER;
/*
* This code currently is only used for ".reloc\0\0" and
* ".sbat\0\0\0", and it doesn't know how to look up longer section
* names.
*/
if (namesz > 8)
return EFI_UNSUPPORTED;
SetMem(namebuf, sizeof(namebuf), 0);
CopyMem(namebuf, name, MIN(namesz, 8));
/*
* Copy the executable's sections to their desired offsets
*/
for (i = 0; i < context->NumberOfSections; i++) {
EFI_STATUS status;
EFI_IMAGE_SECTION_HEADER *section = NULL;
char *base = NULL;
size_t size = 0;
status = get_section_vma(i, buffer, bufsz, context, &base, &size, &section);
if (!EFI_ERROR(status)) {
if (CompareMem(section->Name, namebuf, 8) == 0) {
*basep = base;
*sizep = size;
*sectionp = section;
return EFI_SUCCESS;
}
continue;
}
switch(status) {
case EFI_NOT_FOUND:
break;
}
}
return EFI_NOT_FOUND;
}
/* /*
* Calculate the SHA1 and SHA256 hashes of a binary * Calculate the SHA1 and SHA256 hashes of a binary
@ -585,249 +332,6 @@ done:
return efi_status; return efi_status;
} }
/* here's a chart:
* i686 x86_64 aarch64
* 64-on-64: nyet yes yes
* 64-on-32: nyet yes nyet
* 32-on-32: yes yes no
*/
static int
allow_64_bit(void)
{
#if defined(__x86_64__) || defined(__aarch64__)
return 1;
#elif defined(__i386__) || defined(__i686__)
/* Right now blindly assuming the kernel will correctly detect this
* and /halt the system/ if you're not really on a 64-bit cpu */
if (in_protocol)
return 1;
return 0;
#else /* assuming everything else is 32-bit... */
return 0;
#endif
}
static int
allow_32_bit(void)
{
#if defined(__x86_64__)
#if defined(ALLOW_32BIT_KERNEL_ON_X64)
if (in_protocol)
return 1;
return 0;
#else
return 0;
#endif
#elif defined(__i386__) || defined(__i686__)
return 1;
#elif defined(__aarch64__)
return 0;
#else /* assuming everything else is 32-bit... */
return 1;
#endif
}
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 const UINT16 machine_type =
#if defined(__x86_64__)
IMAGE_FILE_MACHINE_X64;
#elif defined(__aarch64__)
IMAGE_FILE_MACHINE_ARM64;
#elif defined(__arm__)
IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
IMAGE_FILE_MACHINE_I386;
#elif defined(__ia64__)
IMAGE_FILE_MACHINE_IA64;
#else
#error this architecture is not supported by shim
#endif
static int
image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
{
/* If the machine type doesn't match the binary, bail, unless
* we're in an allowed 64-on-32 scenario */
if (PEHdr->Pe32.FileHeader.Machine != machine_type) {
if (!(machine_type == IMAGE_FILE_MACHINE_I386 &&
PEHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64 &&
allow_64_bit())) {
return 0;
}
}
/* If it's not a header type we recognize at all, bail */
switch (PEHdr->Pe32Plus.OptionalHeader.Magic) {
case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
break;
default:
return 0;
}
/* and now just check for general 64-vs-32 compatibility */
if (image_is_64_bit(PEHdr)) {
if (allow_64_bit())
return 1;
} else {
if (allow_32_bit())
return 1;
}
return 0;
}
/*
* Read the binary header and grab appropriate information from it
*/
EFI_STATUS
read_header(void *data, unsigned int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context)
{
EFI_IMAGE_DOS_HEADER *DosHdr = data;
EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
unsigned long FileAlignment = 0;
UINT16 DllFlags;
if (datasize < sizeof (PEHdr->Pe32)) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
if (!image_is_loadable(PEHdr)) {
perror(L"Platform does not support this image\n");
return EFI_UNSUPPORTED;
}
if (image_is_64_bit(PEHdr)) {
context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders;
context->ImageSize = PEHdr->Pe32Plus.OptionalHeader.SizeOfImage;
context->SectionAlignment = PEHdr->Pe32Plus.OptionalHeader.SectionAlignment;
FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment;
OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
} else {
context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes;
context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders;
context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage;
context->SectionAlignment = PEHdr->Pe32.OptionalHeader.SectionAlignment;
FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment;
OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
}
if (FileAlignment % 2 != 0) {
perror(L"File Alignment is invalid (%d)\n", FileAlignment);
return EFI_UNSUPPORTED;
}
if (FileAlignment == 0)
FileAlignment = 0x200;
if (context->SectionAlignment == 0)
context->SectionAlignment = PAGE_SIZE;
if (context->SectionAlignment < FileAlignment)
context->SectionAlignment = FileAlignment;
context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections;
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->NumberOfRvaAndSizes) {
perror(L"Image header too small\n");
return EFI_UNSUPPORTED;
}
HeaderWithoutDataDir = OptHeaderSize
- sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
if (((UINT32)PEHdr->Pe32.FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
context->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
perror(L"Image header overflows data directory\n");
return EFI_UNSUPPORTED;
}
SectionHeaderOffset = DosHdr->e_lfanew
+ sizeof (UINT32)
+ sizeof (EFI_IMAGE_FILE_HEADER)
+ PEHdr->Pe32.FileHeader.SizeOfOptionalHeader;
if (((UINT32)context->ImageSize - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= context->NumberOfSections) {
perror(L"Image sections overflow image size\n");
return EFI_UNSUPPORTED;
}
if ((context->SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32)context->NumberOfSections) {
perror(L"Image sections overflow section headers\n");
return EFI_UNSUPPORTED;
}
if ((((UINT8 *)PEHdr - (UINT8 *)data) + sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION)) > datasize) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (PEHdr->Te.Signature != EFI_IMAGE_NT_SIGNATURE) {
perror(L"Unsupported image type\n");
return EFI_UNSUPPORTED;
}
if (PEHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) {
perror(L"Unsupported image - Relocations have been stripped\n");
return EFI_UNSUPPORTED;
}
context->PEHdr = PEHdr;
if (image_is_64_bit(PEHdr)) {
context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase;
context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
DllFlags = PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics;
} else {
context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
DllFlags = PEHdr->Pe32.OptionalHeader.DllCharacteristics;
}
if ((mok_policy & MOK_POLICY_REQUIRE_NX) &&
!(DllFlags & EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT)) {
perror(L"Policy requires NX, but image does not support NX\n");
return EFI_UNSUPPORTED;
}
context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
if (context->ImageSize < context->SizeOfHeaders) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if ((unsigned long)((UINT8 *)context->SecDir - (UINT8 *)data) >
(datasize - sizeof(EFI_IMAGE_DATA_DIRECTORY))) {
perror(L"Invalid image\n");
return EFI_UNSUPPORTED;
}
if (context->SecDir->VirtualAddress > datasize ||
(context->SecDir->VirtualAddress == datasize &&
context->SecDir->Size > 0)) {
perror(L"Malformed security header\n");
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
EFI_STATUS EFI_STATUS
verify_sbat_section(char *SBATBase, size_t SBATSize) verify_sbat_section(char *SBATBase, size_t SBATSize)
{ {
@ -851,7 +355,11 @@ verify_sbat_section(char *SBATBase, size_t SBATSize)
return in_protocol ? EFI_SUCCESS : EFI_SECURITY_VIOLATION; return in_protocol ? EFI_SUCCESS : EFI_SECURITY_VIOLATION;
} }
sbat_size = SBATSize + 1; if (checked_add(SBATSize, 1, &sbat_size)) {
dprint(L"SBATSize + 1 would overflow\n");
return EFI_SECURITY_VIOLATION;
}
sbat_data = AllocatePool(sbat_size); sbat_data = AllocatePool(sbat_size);
if (!sbat_data) { if (!sbat_data) {
console_print(L"Failed to allocate .sbat section buffer\n"); console_print(L"Failed to allocate .sbat section buffer\n");
@ -937,7 +445,7 @@ get_mem_attrs (uintptr_t addr, size_t size, uint64_t *attrs)
if (EFI_ERROR(efi_status) || !proto) if (EFI_ERROR(efi_status) || !proto)
return efi_status; return efi_status;
if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) { if (!IS_PAGE_ALIGNED(physaddr) || !IS_PAGE_ALIGNED(size) || size == 0 || attrs == NULL) {
dprint(L"%a called on 0x%llx-0x%llx and attrs 0x%llx\n", dprint(L"%a called on 0x%llx-0x%llx and attrs 0x%llx\n",
__func__, (unsigned long long)physaddr, __func__, (unsigned long long)physaddr,
(unsigned long long)(physaddr+size-1), (unsigned long long)(physaddr+size-1),
@ -971,7 +479,7 @@ update_mem_attrs(uintptr_t addr, uint64_t size,
(unsigned long long)addr, (unsigned long long)size, (unsigned long long)addr, (unsigned long long)size,
&before, efi_status); &before, efi_status);
if (physaddr & 0xfff || size & 0xfff || size == 0) { if (!IS_PAGE_ALIGNED(physaddr) || !IS_PAGE_ALIGNED(size) || size == 0) {
dprint(L"%a called on 0x%llx-0x%llx (size 0x%llx) +%a%a%a -%a%a%a\n", dprint(L"%a called on 0x%llx-0x%llx (size 0x%llx) +%a%a%a -%a%a%a\n",
__func__, (unsigned long long)physaddr, __func__, (unsigned long long)physaddr,
(unsigned long long)(physaddr + size - 1), (unsigned long long)(physaddr + size - 1),
@ -990,10 +498,20 @@ update_mem_attrs(uintptr_t addr, uint64_t size,
uefi_clear_attrs = shim_mem_attrs_to_uefi_mem_attrs (clear_attrs); uefi_clear_attrs = shim_mem_attrs_to_uefi_mem_attrs (clear_attrs);
dprint("translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs); dprint("translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs);
efi_status = EFI_SUCCESS; efi_status = EFI_SUCCESS;
if (uefi_set_attrs) if (uefi_set_attrs) {
efi_status = proto->SetMemoryAttributes(proto, physaddr, size, uefi_set_attrs); efi_status = proto->SetMemoryAttributes(proto, physaddr, size, uefi_set_attrs);
if (!EFI_ERROR(efi_status) && uefi_clear_attrs) if (EFI_ERROR(efi_status)) {
dprint(L"Failed to set memory attrs:0x%0x physaddr:0x%llx size:0x%0lx status:%r\n",
uefi_set_attrs, physaddr, size, efi_status);
}
}
if (!EFI_ERROR(efi_status) && uefi_clear_attrs) {
efi_status = proto->ClearMemoryAttributes(proto, physaddr, size, uefi_clear_attrs); efi_status = proto->ClearMemoryAttributes(proto, physaddr, size, uefi_clear_attrs);
if (EFI_ERROR(efi_status)) {
dprint(L"Failed to clear memory attrs:0x%0x physaddr:0x%llx size:0x%0lx status:%r\n",
uefi_clear_attrs, physaddr, size, efi_status);
}
}
ret = efi_status; ret = efi_status;
efi_status = get_mem_attrs (addr, size, &after); efi_status = get_mem_attrs (addr, size, &after);
@ -1243,6 +761,7 @@ handle_image (void *data, unsigned int datasize,
(Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) && (Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) &&
(mok_policy & MOK_POLICY_REQUIRE_NX)) { (mok_policy & MOK_POLICY_REQUIRE_NX)) {
perror(L"Section %d is writable and executable\n", i); perror(L"Section %d is writable and executable\n", i);
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
@ -1268,6 +787,7 @@ handle_image (void *data, unsigned int datasize,
if (CompareMem(Section->Name, ".reloc\0\0", 8) == 0) { if (CompareMem(Section->Name, ".reloc\0\0", 8) == 0) {
if (RelocSection) { if (RelocSection) {
perror(L"Image has multiple relocation sections\n"); perror(L"Image has multiple relocation sections\n");
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
/* If it has nonzero sizes, and our bounds check /* If it has nonzero sizes, and our bounds check
@ -1277,8 +797,12 @@ handle_image (void *data, unsigned int datasize,
Section->Misc.VirtualSize && Section->Misc.VirtualSize &&
base && end && base && end &&
RelocBase == base && RelocBase == base &&
RelocBaseEnd == end) { RelocBaseEnd <= end) {
RelocSection = Section; RelocSection = Section;
} else {
perror(L"Relocation section is invalid \n");
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED;
} }
} }
@ -1288,10 +812,12 @@ handle_image (void *data, unsigned int datasize,
if (!base) { if (!base) {
perror(L"Section %d has invalid base address\n", i); perror(L"Section %d has invalid base address\n", i);
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
if (!end) { if (!end) {
perror(L"Section %d has zero size\n", i); perror(L"Section %d has zero size\n", i);
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
@ -1299,6 +825,7 @@ handle_image (void *data, unsigned int datasize,
(Section->VirtualAddress < context.SizeOfHeaders || (Section->VirtualAddress < context.SizeOfHeaders ||
Section->PointerToRawData < context.SizeOfHeaders)) { Section->PointerToRawData < context.SizeOfHeaders)) {
perror(L"Section %d is inside image headers\n", i); perror(L"Section %d is inside image headers\n", i);
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
@ -1307,6 +834,7 @@ handle_image (void *data, unsigned int datasize,
} else { } else {
if (Section->PointerToRawData < context.SizeOfHeaders) { if (Section->PointerToRawData < context.SizeOfHeaders) {
perror(L"Section %d is inside image headers\n", i); perror(L"Section %d is inside image headers\n", i);
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
@ -1324,7 +852,7 @@ handle_image (void *data, unsigned int datasize,
if (context.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { if (context.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
perror(L"Image has no relocation entry\n"); perror(L"Image has no relocation entry\n");
FreePool(buffer); BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
@ -1337,7 +865,7 @@ handle_image (void *data, unsigned int datasize,
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Relocation failed: %r\n", efi_status); perror(L"Relocation failed: %r\n", efi_status);
FreePool(buffer); BS->FreePages(*alloc_address, *alloc_pages);
return efi_status; return efi_status;
} }
} }
@ -1372,7 +900,11 @@ handle_image (void *data, unsigned int datasize,
+ Section->Misc.VirtualSize - 1); + Section->Misc.VirtualSize - 1);
addr = (uintptr_t)base; addr = (uintptr_t)base;
length = (uintptr_t)end - (uintptr_t)base + 1; // Align the length up to PAGE_SIZE. This is required because
// platforms generally set memory attributes at page
// granularity, but the section length (unlike the section
// address) is not required to be aligned.
length = ALIGN_VALUE((uintptr_t)end - (uintptr_t)base + 1, PAGE_SIZE);
if (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) { if (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) {
set_attrs |= MEM_ATTR_W; set_attrs |= MEM_ATTR_W;
@ -1399,10 +931,12 @@ handle_image (void *data, unsigned int datasize,
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");
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
if (found_entry_point > 1) { if (found_entry_point > 1) {
perror(L"%d sections contain entry point\n", found_entry_point); perror(L"%d sections contain entry point\n", found_entry_point);
BS->FreePages(*alloc_address, *alloc_pages);
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }

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