mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-07-27 08:57:14 +00:00
Updated version 12+1503074702.5202f80 from 'upstream/12+1503074702.5202f80'
with Debian dir 08243b332b
This commit is contained in:
commit
c224bb09d2
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
certdb
|
||||
shim_cert.h
|
||||
*.a
|
||||
*.CSV
|
||||
*.cer
|
||||
*.crl
|
||||
*.crt
|
||||
|
61
BUILDING
Normal file
61
BUILDING
Normal file
@ -0,0 +1,61 @@
|
||||
It's pretty straightforward:
|
||||
|
||||
cp $MY_DER_ENCODED_CERT pub.cer
|
||||
make VENDOR_CERT_FILE=pub.cer
|
||||
make EFIDIR=my_esp_dir_name install
|
||||
|
||||
There are a couple of ways to customize the build:
|
||||
|
||||
Install targets:
|
||||
- install
|
||||
installs shim as if to a hard drive, including installing MokManager and
|
||||
fallback appropriately.
|
||||
- install-as-data
|
||||
installs shim files to /usr/share/shim/$(EFI_ARCH)-$(VERSION)/
|
||||
|
||||
Variables you should set to customize the build:
|
||||
- EFIDIR
|
||||
This is the name of the ESP directory. The install targets won't work
|
||||
without it.
|
||||
- DESTDIR
|
||||
This will be prepended to any install targets, so you don't have to
|
||||
install to a live root directory.
|
||||
- DEFAULT_LOADER
|
||||
defaults to \\\\grub$(EFI_ARCH).efi , but you could set it to whatever.
|
||||
Be careful with the leading backslashes, they can be hard to get
|
||||
correct.
|
||||
|
||||
Variables you could set to customize the build:
|
||||
- ENABLE_SHIM_CERT
|
||||
if this variable is defined one the make command line, shim will
|
||||
generate keys during the build and sign MokManager and fallback with
|
||||
them, and the signed version will be what gets installed with the
|
||||
install targets
|
||||
- ENABLE_HTTPBOOT
|
||||
build support for http booting
|
||||
- ARCH
|
||||
This allows you to do a build for a different arch that we support. For
|
||||
instance, on x86_64 you could do "setarch linux32 make ARCH=ia32" to get
|
||||
the ia32 build instead. (DEFAULT_LOADER will be automatically adjusted
|
||||
in that case.)
|
||||
- TOPDIR
|
||||
You can use this along with make -f to build in a subdir. For instance,
|
||||
on an x86_64 machine you could do:
|
||||
|
||||
mkdir build-ia32 build-x64 inst
|
||||
cd build-ia32
|
||||
setarch linux32 make TOPDIR=.. ARCH=ia32 -f ../Makefile
|
||||
setarch linux32 make TOPDIR=.. ARCH=ia32 \
|
||||
DESTDIR=../inst EFIDIR=debian \
|
||||
-f ../Makefile install
|
||||
cd ../build-x64
|
||||
make TOPDIR=.. -f ../Makefile
|
||||
make TOPDIR=.. DESTDIR=../inst EFIDIR=debian \
|
||||
-f ../Makefile install
|
||||
|
||||
That would get you x86_64 and ia32 builds in the "inst" subdir.
|
||||
- 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 .
|
||||
|
||||
# vim:filetype=mail:tw=74
|
@ -8,7 +8,7 @@ CFLAGS = -ggdb -O0 -I$(TOPDIR) -iquote $(TOPDIR) -fno-stack-protector -fno-stri
|
||||
ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -mno-mmx -mno-sse -mno-red-zone -nostdinc -maccumulate-outgoing-args \
|
||||
-DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI -DNO_BUILTIN_VA_FUNCS \
|
||||
-DMDE_CPU_IA64
|
||||
-DMDE_CPU_X64
|
||||
endif
|
||||
ifeq ($(ARCH),ia32)
|
||||
CFLAGS += -mno-mmx -mno-sse -mno-red-zone -nostdinc -maccumulate-outgoing-args -m32 \
|
||||
|
@ -11,7 +11,7 @@ CFLAGS = -ggdb -O0 -I$(TOPDIR) -I$(TOPDIR)/.. -I$(TOPDIR)/../Include/ -I$(TOPDI
|
||||
ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -mno-mmx -mno-sse -mno-red-zone -maccumulate-outgoing-args \
|
||||
-DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI \
|
||||
-UNO_BUILTIN_VA_FUNCS -DMDE_CPU_IA64
|
||||
-UNO_BUILTIN_VA_FUNCS -DMDE_CPU_X64
|
||||
endif
|
||||
ifeq ($(ARCH),ia32)
|
||||
CFLAGS += -mno-mmx -mno-sse -mno-red-zone -maccumulate-outgoing-args \
|
||||
|
221
Makefile
221
Makefile
@ -1,7 +1,8 @@
|
||||
VERSION = 12
|
||||
RELEASE :=
|
||||
ifneq ($(RELEASE),"")
|
||||
RELEASE:="-$(RELEASE)"
|
||||
ifneq ($(origin RELEASE),undefined)
|
||||
DASHRELEASE ?= -$(RELEASE)
|
||||
else
|
||||
DASHRELEASE ?=
|
||||
endif
|
||||
|
||||
ifeq ($(MAKELEVEL),0)
|
||||
@ -10,15 +11,28 @@ endif
|
||||
override TOPDIR := $(abspath $(TOPDIR))
|
||||
VPATH = $(TOPDIR)
|
||||
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
LD = $(CROSS_COMPILE)ld
|
||||
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
OPENSSL ?= openssl
|
||||
HEXDUMP ?= hexdump
|
||||
INSTALL ?= install
|
||||
PK12UTIL ?= pk12util
|
||||
CERTUTIL ?= certutil
|
||||
PESIGN ?= pesign
|
||||
SBSIGN ?= sbsign
|
||||
prefix ?= /usr
|
||||
prefix := $(abspath $(prefix))
|
||||
datadir ?= $(prefix)/share/
|
||||
PKGNAME ?= shim
|
||||
ESPROOTDIR ?= boot/efi/
|
||||
EFIBOOTDIR ?= $(ESPROOTDIR)EFI/BOOT/
|
||||
TARGETDIR ?= $(ESPROOTDIR)EFI/$(EFIDIR)/
|
||||
DATATARGETDIR ?= $(datadir)/$(PKGNAME)/$(VERSION)$(DASHRELEASE)/$(ARCH_SUFFIX)/
|
||||
DEBUGINFO ?= $(prefix)/lib/debug/
|
||||
DEBUGSOURCE ?= $(prefix)/src/debug/
|
||||
OSLABEL ?= $(EFIDIR)
|
||||
DEFAULT_LOADER ?= \\\\grub$(ARCH_SUFFIX).efi
|
||||
|
||||
ARCH ?= $(shell $(CC) -dumpmachine | cut -f1 -d- | sed s,i[3456789]86,ia32,)
|
||||
OBJCOPY_GTE224 = $(shell expr `$(OBJCOPY) --version |grep ^"GNU objcopy" | sed 's/^.*\((.*)\|version\) //g' | cut -f1-2 -d.` \>= 2.24)
|
||||
@ -36,7 +50,6 @@ EFI_LIBS = -lefi -lgnuefi --start-group Cryptlib/libcryptlib.a Cryptlib/OpenSSL/
|
||||
EFI_CRT_OBJS = $(EFI_PATH)/crt0-efi-$(ARCH).o
|
||||
EFI_LDS = $(TOPDIR)/elf_$(ARCH)_efi.lds
|
||||
|
||||
DEFAULT_LOADER := \\\\grub.efi
|
||||
CFLAGS = -ggdb -O0 -fno-stack-protector -fno-strict-aliasing -fpic \
|
||||
-fshort-wchar -Wall -Wsign-compare -Werror -fno-builtin \
|
||||
-Werror=sign-compare -ffreestanding -std=gnu89 \
|
||||
@ -44,9 +57,6 @@ CFLAGS = -ggdb -O0 -fno-stack-protector -fno-strict-aliasing -fpic \
|
||||
"-DDEFAULT_LOADER=L\"$(DEFAULT_LOADER)\"" \
|
||||
"-DDEFAULT_LOADER_CHAR=\"$(DEFAULT_LOADER)\"" \
|
||||
$(EFI_INCLUDES)
|
||||
SHIMNAME = shim
|
||||
MMNAME = MokManager
|
||||
FBNAME = fallback
|
||||
|
||||
COMMITID ?= $(shell if [ -d .git ] ; then git log -1 --pretty=format:%H ; elif [ -f commit ]; then cat commit ; else echo commit id not available; fi)
|
||||
|
||||
@ -62,36 +72,55 @@ ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -mno-mmx -mno-sse -mno-red-zone -nostdinc \
|
||||
-maccumulate-outgoing-args \
|
||||
-DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI \
|
||||
-DNO_BUILTIN_VA_FUNCS \
|
||||
-DMDE_CPU_X64 "-DEFI_ARCH=L\"x64\"" -DPAGE_SIZE=4096 \
|
||||
"-DDEBUGDIR=L\"/usr/lib/debug/usr/share/shim/x64-$(VERSION)$(RELEASE)/\""
|
||||
MMNAME = mmx64
|
||||
FBNAME = fbx64
|
||||
SHIMNAME= shimx64
|
||||
EFI_PATH:=/usr/lib64/gnuefi
|
||||
LIB_PATH:=/usr/lib64
|
||||
|
||||
-DNO_BUILTIN_VA_FUNCS -DMDE_CPU_X64 -DPAGE_SIZE=4096
|
||||
LIBDIR ?= $(prefix)/lib64
|
||||
ARCH_SUFFIX ?= x64
|
||||
ARCH_SUFFIX_UPPER ?= X64
|
||||
endif
|
||||
ifeq ($(ARCH),ia32)
|
||||
CFLAGS += -mno-mmx -mno-sse -mno-red-zone -nostdinc \
|
||||
-maccumulate-outgoing-args -m32 \
|
||||
-DMDE_CPU_IA32 "-DEFI_ARCH=L\"ia32\"" -DPAGE_SIZE=4096 \
|
||||
"-DDEBUGDIR=L\"/usr/lib/debug/usr/share/shim/ia32-$(VERSION)$(RELEASE)/\""
|
||||
MMNAME = mmia32
|
||||
FBNAME = fbia32
|
||||
SHIMNAME= shimia32
|
||||
EFI_PATH:=/usr/lib/gnuefi
|
||||
LIB_PATH:=/usr/lib
|
||||
-DMDE_CPU_IA32 -DPAGE_SIZE=4096
|
||||
LIBDIR ?= $(prefix)/lib
|
||||
ARCH_SUFFIX ?= ia32
|
||||
ARCH_SUFFIX_UPPER ?= IA32
|
||||
endif
|
||||
ifeq ($(ARCH),aarch64)
|
||||
CFLAGS += -DMDE_CPU_AARCH64 "-DEFI_ARCH=L\"aa64\"" -DPAGE_SIZE=4096 \
|
||||
"-DDEBUGDIR=L\"/usr/lib/debug/usr/share/shim/aa64-$(VERSION)$(RELEASE)/\""
|
||||
MMNAME = mmaa64
|
||||
FBNAME = fbaa64
|
||||
SHIMNAME= shimaa64
|
||||
EFI_PATH:=/usr/lib64/gnuefi
|
||||
LIB_PATH:=/usr/lib64
|
||||
CFLAGS += -DMDE_CPU_AARCH64 -DPAGE_SIZE=4096 -mstrict-align
|
||||
LIBDIR ?= $(prefix)/lib64
|
||||
ARCH_SUFFIX ?= aa64
|
||||
ARCH_SUFFIX_UPPER ?= AA64
|
||||
FORMAT := -O binary
|
||||
SUBSYSTEM := 0xa
|
||||
LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
|
||||
endif
|
||||
ifeq ($(ARCH),arm)
|
||||
CFLAGS += -DMDE_CPU_ARM -DPAGE_SIZE=4096 -mstrict-align
|
||||
LIBDIR ?= $(prefix)/lib
|
||||
ARCH_SUFFIX ?= arm
|
||||
ARCH_SUFFIX_UPPER ?= ARM
|
||||
FORMAT := -O binary
|
||||
SUBSYSTEM := 0xa
|
||||
LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
|
||||
endif
|
||||
|
||||
FORMAT ?= --target efi-app-$(ARCH)
|
||||
EFI_PATH ?= $(LIBDIR)/gnuefi
|
||||
|
||||
MMSTEM ?= mm$(ARCH_SUFFIX)
|
||||
MMNAME = $(MMSTEM).efi
|
||||
MMSONAME = $(MMSTEM).so
|
||||
FBSTEM ?= fb$(ARCH_SUFFIX)
|
||||
FBNAME = $(FBSTEM).efi
|
||||
FBSONAME = $(FBSTEM).so
|
||||
SHIMSTEM ?= shim$(ARCH_SUFFIX)
|
||||
SHIMNAME = $(SHIMSTEM).efi
|
||||
SHIMSONAME = $(SHIMSTEM).so
|
||||
SHIMHASHNAME = $(SHIMSTEM).hash
|
||||
BOOTEFINAME ?= BOOT$(ARCH_SUFFIX_UPPER).EFI
|
||||
BOOTCSVNAME ?= BOOT$(ARCH_SUFFIX_UPPER).CSV
|
||||
|
||||
CFLAGS += "-DEFI_ARCH=L\"$(ARCH_SUFFIX)\"" "-DDEBUGDIR=L\"/usr/lib/debug/usr/share/shim/$(ARCH_SUFFIX)-$(VERSION)$(DASHRELEASE)/\""
|
||||
|
||||
ifneq ($(origin VENDOR_CERT_FILE), undefined)
|
||||
CFLAGS += -DVENDOR_CERT_FILE=\"$(VENDOR_CERT_FILE)\"
|
||||
@ -100,15 +129,25 @@ ifneq ($(origin VENDOR_DBX_FILE), undefined)
|
||||
CFLAGS += -DVENDOR_DBX_FILE=\"$(VENDOR_DBX_FILE)\"
|
||||
endif
|
||||
|
||||
LDFLAGS = --hash-style=sysv -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIB_PATH) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS) --build-id=sha1
|
||||
LDFLAGS = --hash-style=sysv -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIBDIR) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS) --build-id=sha1
|
||||
|
||||
TARGET = $(SHIMNAME).efi $(MMNAME).efi.signed $(FBNAME).efi.signed
|
||||
TARGETS = $(SHIMNAME)
|
||||
TARGETS += $(SHIMNAME).debug $(MMNAME).debug $(FBNAME).debug
|
||||
ifneq ($(origin ENABLE_SHIM_HASH),undefined)
|
||||
TARGETS += $(SHIMHASHNAME)
|
||||
endif
|
||||
ifneq ($(origin ENABLE_SHIM_CERT),undefined)
|
||||
TARGETS += $(MMNAME).signed $(FBNAME).signed
|
||||
CFLAGS += -DENABLE_SHIM_CERT
|
||||
else
|
||||
TARGETS += $(MMNAME) $(FBNAME)
|
||||
endif
|
||||
OBJS = shim.o netboot.o cert.o replacements.o tpm.o version.o
|
||||
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
|
||||
ORIG_SOURCES = shim.c shim.h netboot.c include/PeImage.h include/wincert.h include/console.h replacements.c replacements.h tpm.c tpm.h version.h
|
||||
MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o
|
||||
ORIG_MOK_SOURCES = MokManager.c shim.h include/console.h PasswordCrypt.c PasswordCrypt.h crypt_blowfish.c crypt_blowfish.h
|
||||
FALLBACK_OBJS = fallback.o
|
||||
FALLBACK_OBJS = fallback.o tpm.o
|
||||
ORIG_FALLBACK_SRCS = fallback.c
|
||||
|
||||
ifneq ($(origin ENABLE_HTTPBOOT), undefined)
|
||||
@ -120,7 +159,7 @@ SOURCES = $(foreach source,$(ORIG_SOURCES),$(TOPDIR)/$(source)) version.c
|
||||
MOK_SOURCES = $(foreach source,$(ORIG_MOK_SOURCES),$(TOPDIR)/$(source))
|
||||
FALLBACK_SRCS = $(foreach source,$(ORIG_FALLBACK_SRCS),$(TOPDIR)/$(source))
|
||||
|
||||
all: $(TARGET)
|
||||
all: $(TARGETS)
|
||||
|
||||
shim.crt:
|
||||
$(TOPDIR)/make-certs shim shim@xn--u4h.net all codesign 1.3.6.1.4.1.311.10.3.1 </dev/null
|
||||
@ -144,23 +183,30 @@ certdb/secmod.db: shim.crt
|
||||
$(PK12UTIL) -d certdb/ -i shim.p12 -W "" -K ""
|
||||
$(CERTUTIL) -d certdb/ -A -i shim.crt -n shim -t u
|
||||
|
||||
shim.o: $(SOURCES) shim_cert.h
|
||||
shim.o: $(wildcard $(TOPDIR)/*.h *.h)
|
||||
shim.o: $(SOURCES)
|
||||
ifneq ($(origin ENABLE_SHIM_CERT),undefined)
|
||||
shim.o: shim_cert.h
|
||||
endif
|
||||
shim.o: $(wildcard $(TOPDIR)/*.h)
|
||||
|
||||
cert.o : $(TOPDIR)/cert.S
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(SHIMNAME).so: $(OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
||||
$(SHIMNAME) : $(SHIMSONAME)
|
||||
$(MMNAME) : $(MMSONAME)
|
||||
$(FBNAME) : $(FBSONAME)
|
||||
|
||||
$(SHIMSONAME): $(OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
||||
$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
|
||||
|
||||
fallback.o: $(FALLBACK_SRCS)
|
||||
|
||||
$(FBNAME).so: $(FALLBACK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
||||
$(FBSONAME): $(FALLBACK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
||||
$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
|
||||
|
||||
MokManager.o: $(MOK_SOURCES)
|
||||
|
||||
$(MMNAME).so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
||||
$(MMSONAME): $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
||||
$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS) lib/lib.a
|
||||
|
||||
Cryptlib/libcryptlib.a:
|
||||
@ -175,19 +221,77 @@ lib/lib.a:
|
||||
if [ ! -d lib ]; then mkdir lib ; fi
|
||||
$(MAKE) VPATH=$(TOPDIR)/lib TOPDIR=$(TOPDIR) CFLAGS="$(CFLAGS)" -C lib -f $(TOPDIR)/lib/Makefile
|
||||
|
||||
ifeq ($(ARCH),aarch64)
|
||||
FORMAT := -O binary
|
||||
SUBSYSTEM := 0xa
|
||||
LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
|
||||
buildid : $(TOPDIR)/buildid.c
|
||||
$(CC) -Og -g3 -Wall -Werror -Wextra -o $@ $< -lelf
|
||||
|
||||
$(BOOTCSVNAME) :
|
||||
@echo Making $@
|
||||
@( printf "\xff\xfe" ; echo "$(SHIMNAME),$(OSLABEL),,This is the boot entry for $(OSLABEL)" | sed -z 's/./&\x00/g' ) > $@
|
||||
|
||||
install-check :
|
||||
ifeq ($(origin LIBDIR),undefined)
|
||||
$(error Architecture $(ARCH) is not a supported build target.)
|
||||
endif
|
||||
ifeq ($(origin EFIDIR),undefined)
|
||||
$(error EFIDIR must be set to your reserved EFI System Partition subdirectory name)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
FORMAT := -O binary
|
||||
SUBSYSTEM := 0xa
|
||||
LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
|
||||
install-deps : $(TARGETS)
|
||||
install-deps : $(SHIMNAME).debug $(MMNAME).debug $(FBNAME).debug buildid
|
||||
install-deps : $(BOOTCSVNAME)
|
||||
|
||||
install-debugsource : install-deps
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/$(DEBUGSOURCE)/$(PKGNAME)-$(VERSION)$(DASHRELEASE)
|
||||
find $(TOPDIR) -type f -a '(' -iname '*.c' -o -iname '*.h' -o -iname '*.S' ')' | while read file ; do \
|
||||
outfile=$$(echo $${file} | sed -e "s,^$(TOPDIR),,") ; \
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/$(DEBUGSOURCE)/$(PKGNAME)-$(VERSION)$(DASHRELEASE)/$$(dirname $${outfile}) ; \
|
||||
$(INSTALL) -m 0644 $${file} $(DESTDIR)/$(DEBUGSOURCE)/$(PKGNAME)-$(VERSION)$(DASHRELEASE)/$${outfile} ; \
|
||||
done
|
||||
|
||||
install-debuginfo : install-deps
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/$(DEBUGINFO)$(TARGETDIR)/
|
||||
@./buildid $(wildcard *.efi.debug) | while read file buildid ; do \
|
||||
first=$$(echo $${buildid} | cut -b -2) ; \
|
||||
rest=$$(echo $${buildid} | cut -b 3-) ; \
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/$(DEBUGINFO).build-id/$${first}/ ;\
|
||||
$(INSTALL) -m 0644 $${file} $(DESTDIR)/$(DEBUGINFO)$(TARGETDIR) ; \
|
||||
ln -s ../../../../..$(DEBUGINFO)$(TARGETDIR)$${file} $(DESTDIR)/$(DEBUGINFO).build-id/$${first}/$${rest}.debug ;\
|
||||
ln -s ../../../.build-id/$${first}/$${rest} $(DESTDIR)/$(DEBUGINFO).build-id/$${first}/$${rest} ;\
|
||||
done
|
||||
|
||||
install : | install-check
|
||||
install : install-deps install-debuginfo install-debugsource
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/
|
||||
$(INSTALL) -d -m 0700 $(DESTDIR)/$(ESPROOTDIR)
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/$(EFIBOOTDIR)
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/$(TARGETDIR)
|
||||
$(INSTALL) -m 0644 $(SHIMNAME) $(DESTDIR)/$(EFIBOOTDIR)/$(BOOTEFINAME)
|
||||
$(INSTALL) -m 0644 $(SHIMNAME) $(DESTDIR)/$(TARGETDIR)/
|
||||
$(INSTALL) -m 0644 $(BOOTCSVNAME) $(DESTDIR)/$(TARGETDIR)/
|
||||
ifneq ($(origin ENABLE_SHIM_CERT),undefined)
|
||||
$(INSTALL) -m 0644 $(FBNAME).signed $(DESTDIR)/$(EFIBOOTDIR)/$(FBNAME)
|
||||
$(INSTALL) -m 0644 $(MMNAME).signed $(DESTDIR)/$(EFIBOOTDIR)/$(MMNAME)
|
||||
$(INSTALL) -m 0644 $(MMNAME).signed $(DESTDIR)/$(TARGETDIR)/$(MMNAME)
|
||||
else
|
||||
$(INSTALL) -m 0644 $(FBNAME) $(DESTDIR)/$(EFIBOOTDIR)/
|
||||
$(INSTALL) -m 0644 $(MMNAME) $(DESTDIR)/$(EFIBOOTDIR)/
|
||||
$(INSTALL) -m 0644 $(MMNAME) $(DESTDIR)/$(TARGETDIR)/
|
||||
endif
|
||||
|
||||
FORMAT ?= --target efi-app-$(ARCH)
|
||||
install-as-data : install-deps
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)/$(DATATARGETDIR)
|
||||
$(INSTALL) -m 0644 $(SHIMNAME) $(DESTDIR)/$(DATATARGETDIR)/
|
||||
ifneq ($(origin ENABLE_SHIM_HASH),undefined)
|
||||
$(INSTALL) -m 0644 $(SHIMHASHNAME) $(DESTDIR)/$(DATATARGETDIR)/
|
||||
endif
|
||||
ifneq ($(origin ENABLE_SHIM_CERT),undefined)
|
||||
$(INSTALL) -m 0644 $(MMNAME).signed $(DESTDIR)/$(DATATARGETDIR)/$(MMNAME)
|
||||
$(INSTALL) -m 0644 $(FBNAME).signed $(DESTDIR)/$(DATATARGETDIR)/$(FBNAME)
|
||||
else
|
||||
$(INSTALL) -m 0644 $(MMNAME) $(DESTDIR)/$(DATATARGETDIR)/$(MMNAME)
|
||||
$(INSTALL) -m 0644 $(FBNAME) $(DESTDIR)/$(DATATARGETDIR)/$(FBNAME)
|
||||
endif
|
||||
|
||||
%.efi: %.so
|
||||
ifneq ($(OBJCOPY_GTE224),1)
|
||||
@ -198,16 +302,31 @@ endif
|
||||
-j .rela* -j .reloc -j .eh_frame \
|
||||
-j .vendor_cert \
|
||||
$(FORMAT) $^ $@
|
||||
|
||||
ifneq ($(origin ENABLE_SHIM_HASH),undefined)
|
||||
%.hash : %.efi
|
||||
$(PESIGN) -i $< -P -h > $@
|
||||
endif
|
||||
|
||||
%.efi.debug : %.so
|
||||
ifneq ($(OBJCOPY_GTE224),1)
|
||||
$(error objcopy >= 2.24 is required)
|
||||
endif
|
||||
$(OBJCOPY) -j .text -j .sdata -j .data \
|
||||
-j .dynamic -j .dynsym -j .rel* \
|
||||
-j .rela* -j .reloc -j .eh_frame \
|
||||
-j .debug_info -j .debug_abbrev -j .debug_aranges \
|
||||
-j .debug_line -j .debug_str -j .debug_ranges \
|
||||
-j .note.gnu.build-id \
|
||||
$(FORMAT) $^ $@.debug
|
||||
$^ $@
|
||||
|
||||
ifneq ($(origin ENABLE_SBSIGN),undefined)
|
||||
%.efi.signed: %.efi shim.key shim.crt
|
||||
$(SBSIGN) --key shim.key --cert shim.crt --output $@ $<
|
||||
else
|
||||
%.efi.signed: %.efi certdb/secmod.db
|
||||
$(PESIGN) -n certdb -i $< -c "shim" -s -o $@ -f
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(MAKE) -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile clean
|
||||
@ -243,4 +362,6 @@ archive: tag
|
||||
@rm -rf /tmp/shim-$(VERSION)
|
||||
@echo "The archive is in shim-$(VERSION).tar.bz2"
|
||||
|
||||
.PHONY : install-deps
|
||||
|
||||
export ARCH CC LD OBJCOPY EFI_INCLUDE
|
||||
|
@ -60,6 +60,11 @@ as described in the UEFI specification. BS,NV
|
||||
|
||||
MokListRT: A copy of MokList made available to the kernel at runtime. RT
|
||||
|
||||
MokListX: A list of blacklisted keys and hashes. An EFI_SIGNATURE_LIST
|
||||
as described in the UEFI specification. BS,NV
|
||||
|
||||
MokListXRT: A copy of MokListX made available to the kernel at runtime. RT
|
||||
|
||||
MokSBState: An 8-bit unsigned integer. If 1, shim will switch to
|
||||
insecure mode. BS,NV
|
||||
|
||||
|
7
README
7
README
@ -12,5 +12,12 @@ in the shim.h header file and provides a single entry point. On 64-bit systems
|
||||
this entry point expects to be called with SysV ABI rather than MSABI, and
|
||||
so calls to it should not be wrapped.
|
||||
|
||||
On systems with a TPM chip enabled and supported by the system firmware,
|
||||
shim will extend various PCRs with the digests of the targets it is
|
||||
loading. A full list is in the file README.tpm .
|
||||
|
||||
To use shim, simply place a DER-encoded public certificate in a file such as
|
||||
pub.cer and build with "make VENDOR_CERT_FILE=pub.cer".
|
||||
|
||||
There are a couple of build options, and a couple of ways to customize the
|
||||
build, described in BUILDING.
|
||||
|
22
README.tpm
Normal file
22
README.tpm
Normal file
@ -0,0 +1,22 @@
|
||||
The following PCRs are extended by shim:
|
||||
|
||||
PCR4:
|
||||
- the Authenticode hash of the binary being loaded will be extended into
|
||||
PCR4 before SB verification.
|
||||
|
||||
PCR7:
|
||||
- Any certificate in one of our certificate databases that matches a binary
|
||||
we try to load will be extended into PCR7. That includes:
|
||||
- DBX - the system blacklist, logged as "dbx"
|
||||
- MokListX - the Mok blacklist, logged as "MokListX"
|
||||
- vendor_dbx - shim's built-in vendor blacklist, logged as "dbx"
|
||||
- DB - the system whitelist, logged as "db"
|
||||
- MokList the Mok whitelist, logged as "MokList"
|
||||
- vendor_cert - shim's built-in vendor whitelist, logged as "Shim"
|
||||
- shim_cert - shim's build-time generated whitelist, logged as "Shim"
|
||||
- MokSBState will be extended into PCR7 if it is set, logged as
|
||||
"MokSBState".
|
||||
|
||||
PCR14:
|
||||
- MokList, MokListX, and MokSBState will be extended into PCR14 if they are
|
||||
set.
|
31
TODO
31
TODO
@ -1,23 +1,14 @@
|
||||
Versioned protocol:
|
||||
- Versioned protocol:
|
||||
- Make shim and the bootloaders using it express how enlightened they
|
||||
are to one another, so we can stop earlier without tricks like
|
||||
the one above
|
||||
MokListRT signing:
|
||||
- For kexec and hybernate to work right, MokListRT probably needs to
|
||||
be an authenticated variable. It's probable this needs to be done
|
||||
in the kernel boot stub instead, just because it'll need an
|
||||
ephemeral key to be generated, and that means we need some entropy
|
||||
to build up.
|
||||
New security protocol:
|
||||
- TBD
|
||||
kexec MoK Management:
|
||||
Modsign enforcement mgmt MoK:
|
||||
- This is part of the plan for SecureBoot patches. Basically these
|
||||
features need to be disableable/enableable in MokManager.
|
||||
Variable for debug:
|
||||
- basically we need to be able to set a UEFI variable and get debug
|
||||
output. Right now some code uses SHIM_VERBOSE but that needs a fair
|
||||
amount of work to actually be useful.
|
||||
Hashing of option roms:
|
||||
are to one another, so we can stop earlier without tricks like the one
|
||||
above
|
||||
- Make a LoadImage/CheckImage/StartImage based protocol
|
||||
- Hashing of option roms:
|
||||
- hash option roms and add them to MokListRT
|
||||
- probably belongs in MokManager
|
||||
- Ability to specify second stage as a device path
|
||||
- including vendor path that means "parent of this image's path"
|
||||
- including vendor path that means "this image"
|
||||
- including path that's like Fv() to embed images.
|
||||
|
||||
# vim:filetype=mail:tw=74
|
||||
|
192
buildid.c
Normal file
192
buildid.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Walk a list of input files, printing the name and buildid of any file
|
||||
* that has one.
|
||||
*
|
||||
* This program is licensed under the GNU Public License version 2.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
|
||||
static Elf_Scn *get_scn_named(Elf * elf, char *goal, GElf_Shdr * shdrp_out)
|
||||
{
|
||||
int rc;
|
||||
size_t shstrndx = -1;
|
||||
int scn_no = 0;
|
||||
Elf_Scn *scn = NULL;
|
||||
GElf_Shdr shdr_data, *shdrp;
|
||||
|
||||
shdrp = shdrp_out ? shdrp_out : &shdr_data;
|
||||
|
||||
rc = elf_getshdrstrndx(elf, &shstrndx);
|
||||
if (rc < 0)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
GElf_Shdr *shdr;
|
||||
char *name;
|
||||
|
||||
scn = elf_getscn(elf, ++scn_no);
|
||||
if (!scn)
|
||||
break;
|
||||
|
||||
shdr = gelf_getshdr(scn, shdrp);
|
||||
if (!shdr)
|
||||
/*
|
||||
* the binary is malformed, but hey, maybe the next
|
||||
* one is fine, why not...
|
||||
*/
|
||||
continue;
|
||||
|
||||
name = elf_strptr(elf, shstrndx, shdr->sh_name);
|
||||
if (name && !strcmp(name, goal))
|
||||
return scn;
|
||||
} while (scn != NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *get_buildid(Elf * elf, size_t * sz)
|
||||
{
|
||||
Elf_Scn *scn;
|
||||
size_t notesz;
|
||||
size_t offset = 0;
|
||||
Elf_Data *data;
|
||||
GElf_Shdr shdr;
|
||||
|
||||
scn = get_scn_named(elf, ".note.gnu.build-id", &shdr);
|
||||
if (!scn)
|
||||
return NULL;
|
||||
|
||||
data = elf_getdata(scn, NULL);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
size_t nameoff;
|
||||
size_t descoff;
|
||||
GElf_Nhdr nhdr;
|
||||
char *name;
|
||||
|
||||
notesz = gelf_getnote(data, offset, &nhdr, &nameoff, &descoff);
|
||||
if (!notesz)
|
||||
break;
|
||||
offset += notesz;
|
||||
|
||||
if (nhdr.n_type != NT_GNU_BUILD_ID)
|
||||
continue;
|
||||
|
||||
name = data->d_buf + nameoff;
|
||||
if (!name || strcmp(name, ELF_NOTE_GNU))
|
||||
continue;
|
||||
|
||||
*sz = nhdr.n_descsz;
|
||||
return data->d_buf + descoff;
|
||||
} while (notesz);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void data2hex(uint8_t * data, size_t ds, char *str)
|
||||
{
|
||||
const char hex[] = "0123456789abcdef";
|
||||
int s;
|
||||
unsigned int d;
|
||||
for (d = 0, s = 0; d < ds; d += 1, s += 2) {
|
||||
str[s + 0] = hex[(data[d] >> 4) & 0x0f];
|
||||
str[s + 1] = hex[(data[d] >> 0) & 0x0f];
|
||||
}
|
||||
str[s] = '\0';
|
||||
}
|
||||
|
||||
static void handle_one(char *f)
|
||||
{
|
||||
int fd;
|
||||
Elf *elf;
|
||||
char *b = NULL;
|
||||
size_t sz;
|
||||
uint8_t *data;
|
||||
|
||||
if (!strcmp(f, "-")) {
|
||||
fd = STDIN_FILENO;
|
||||
|
||||
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
|
||||
errx(1, "Couldn't read ELF data from \"%s\"", f);
|
||||
} else {
|
||||
if ((fd = open(f, O_RDONLY)) < 0)
|
||||
err(1, "Couldn't open \"%s\"", f);
|
||||
|
||||
if ((elf = elf_begin(fd, ELF_C_READ_MMAP, NULL)) == NULL)
|
||||
errx(1, "Couldn't read ELF data from \"%s\"", f);
|
||||
}
|
||||
|
||||
data = get_buildid(elf, &sz);
|
||||
if (data) {
|
||||
b = alloca(sz * 2 + 1);
|
||||
data2hex(data, sz, b);
|
||||
if (b) {
|
||||
write(1, f, strlen(f));
|
||||
write(1, " ", 1);
|
||||
write(1, b, strlen(b));
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
}
|
||||
elf_end(elf);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__ ((__noreturn__))
|
||||
usage(int status)
|
||||
{
|
||||
FILE *out = status ? stderr : stdout;
|
||||
|
||||
fprintf(out, "Usage: buildid [ flags | file0 [file1 [.. fileN]]]\n");
|
||||
fprintf(out, "Flags:\n");
|
||||
fprintf(out, " -h Print this help text and exit\n");
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
struct option options[] = {
|
||||
{.name = "help",
|
||||
.val = '?',
|
||||
},
|
||||
{.name = "usage",
|
||||
.val = '?',
|
||||
},
|
||||
{.name = ""}
|
||||
};
|
||||
int longindex = -1;
|
||||
|
||||
while ((i = getopt_long(argc, argv, "h", options, &longindex)) != -1) {
|
||||
switch (i) {
|
||||
case 'h':
|
||||
case '?':
|
||||
usage(longindex == -1 ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
elf_version(EV_CURRENT);
|
||||
|
||||
if (optind == argc)
|
||||
usage(1);
|
||||
|
||||
for (i = optind; i < argc; i++)
|
||||
handle_one(argv[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// vim:fenc=utf-8:tw=75
|
2
commit
2
commit
@ -1 +1 @@
|
||||
478f9bb2ea91b361ab52dac6604fdfb47e1e963c
|
||||
5202f80c32bdcab0469785e953bf9fa8dd4eaaa1
|
123
fallback.c
123
fallback.c
@ -12,6 +12,7 @@
|
||||
|
||||
#include "ucs2.h"
|
||||
#include "variables.h"
|
||||
#include "tpm.h"
|
||||
|
||||
EFI_LOADED_IMAGE *this_image = NULL;
|
||||
|
||||
@ -286,6 +287,105 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
/*
|
||||
* AMI BIOS (e.g, Intel NUC5i3MYHE) may automatically hide and patch BootXXXX
|
||||
* variables with ami_masked_device_path_guid. We can get the valid device path
|
||||
* if just skipping it and its next end path.
|
||||
*/
|
||||
|
||||
static EFI_GUID ami_masked_device_path_guid = {
|
||||
0x99e275e7, 0x75a0, 0x4b37,
|
||||
{ 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb }
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
calc_masked_boot_option_size(unsigned int size)
|
||||
{
|
||||
return size + sizeof(EFI_DEVICE_PATH) +
|
||||
sizeof(ami_masked_device_path_guid) + sizeof(EFI_DEVICE_PATH);
|
||||
}
|
||||
|
||||
static int
|
||||
check_masked_boot_option(CHAR8 *candidate, unsigned int candidate_size,
|
||||
CHAR8 *data, unsigned int data_size)
|
||||
{
|
||||
/*
|
||||
* The patched BootXXXX variables contain a hardware device path and
|
||||
* an end path, preceding the real device path.
|
||||
*/
|
||||
if (calc_masked_boot_option_size(data_size) != candidate_size)
|
||||
return 1;
|
||||
|
||||
CHAR8 *cursor = candidate;
|
||||
|
||||
/* Check whether the BootXXXX is patched */
|
||||
cursor += sizeof(UINT32) + sizeof(UINT16);
|
||||
cursor += StrSize((CHAR16 *)cursor);
|
||||
|
||||
unsigned int min_valid_size = cursor - candidate + sizeof(EFI_DEVICE_PATH);
|
||||
|
||||
if (candidate_size <= min_valid_size)
|
||||
return 1;
|
||||
|
||||
EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)cursor;
|
||||
unsigned int node_size = DevicePathNodeLength(dp) - sizeof(EFI_DEVICE_PATH);
|
||||
|
||||
min_valid_size += node_size;
|
||||
if (candidate_size <= min_valid_size ||
|
||||
DevicePathType(dp) != HARDWARE_DEVICE_PATH ||
|
||||
DevicePathSubType(dp) != HW_VENDOR_DP ||
|
||||
node_size != sizeof(ami_masked_device_path_guid) ||
|
||||
CompareGuid((EFI_GUID *)(cursor + sizeof(EFI_DEVICE_PATH)),
|
||||
&ami_masked_device_path_guid))
|
||||
return 1;
|
||||
|
||||
/* Check whether the patched guid is followed by an end path */
|
||||
min_valid_size += sizeof(EFI_DEVICE_PATH);
|
||||
if (candidate_size <= min_valid_size)
|
||||
return 1;
|
||||
|
||||
dp = NextDevicePathNode(dp);
|
||||
if (!IsDevicePathEnd(dp))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* OK. We may really get a masked BootXXXX variable. The next
|
||||
* step is to test whether it is hidden.
|
||||
*/
|
||||
UINT32 attrs = *(UINT32 *)candidate;
|
||||
#ifndef LOAD_OPTION_HIDDEN
|
||||
# define LOAD_OPTION_HIDDEN 0x00000008
|
||||
#endif
|
||||
if (!(attrs & LOAD_OPTION_HIDDEN))
|
||||
return 1;
|
||||
|
||||
attrs &= ~LOAD_OPTION_HIDDEN;
|
||||
|
||||
/* Compare the field Attributes */
|
||||
if (attrs != *(UINT32 *)data)
|
||||
return 1;
|
||||
|
||||
/* Compare the field FilePathListLength */
|
||||
data += sizeof(UINT32);
|
||||
candidate += sizeof(UINT32);
|
||||
if (calc_masked_boot_option_size(*(UINT16 *)data) !=
|
||||
*(UINT16 *)candidate)
|
||||
return 1;
|
||||
|
||||
/* Compare the field Description */
|
||||
data += sizeof(UINT16);
|
||||
candidate += sizeof(UINT16);
|
||||
if (CompareMem(candidate, data, cursor - candidate))
|
||||
return 1;
|
||||
|
||||
/* Compare the filed FilePathList */
|
||||
cursor = (CHAR8 *)NextDevicePathNode(dp);
|
||||
data += sizeof(UINT16);
|
||||
data += StrSize((CHAR16 *)data);
|
||||
|
||||
return CompareMem(cursor, data, candidate_size - min_valid_size);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
|
||||
CHAR16 *filename, CHAR16 *label, CHAR16 *arguments,
|
||||
@ -315,7 +415,8 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
|
||||
EFI_GUID global = EFI_GLOBAL_VARIABLE;
|
||||
EFI_STATUS rc;
|
||||
|
||||
CHAR8 *candidate = AllocateZeroPool(size);
|
||||
UINTN max_candidate_size = calc_masked_boot_option_size(size);
|
||||
CHAR8 *candidate = AllocateZeroPool(max_candidate_size);
|
||||
if (!candidate) {
|
||||
FreePool(data);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
@ -327,17 +428,21 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
|
||||
varname[6] = hexmap[(bootorder[i] & 0x00f0) >> 4];
|
||||
varname[7] = hexmap[(bootorder[i] & 0x000f) >> 0];
|
||||
|
||||
UINTN candidate_size = size;
|
||||
UINTN candidate_size = max_candidate_size;
|
||||
rc = uefi_call_wrapper(RT->GetVariable, 5, varname, &global,
|
||||
NULL, &candidate_size, candidate);
|
||||
if (EFI_ERROR(rc))
|
||||
continue;
|
||||
|
||||
if (candidate_size != size)
|
||||
if (candidate_size != size) {
|
||||
if (check_masked_boot_option(candidate, candidate_size,
|
||||
data, size))
|
||||
continue;
|
||||
} else if (CompareMem(candidate, data, size))
|
||||
continue;
|
||||
|
||||
if (CompareMem(candidate, data, size))
|
||||
continue;
|
||||
VerbosePrint(L"Found boot entry \"%s\" with label \"%s\" "
|
||||
L"for file \"%s\"\n", varname, label, filename);
|
||||
|
||||
/* at this point, we have duplicate data. */
|
||||
if (!first_new_option) {
|
||||
@ -481,7 +586,7 @@ add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *argum
|
||||
err:
|
||||
if (full_device_path)
|
||||
FreePool(full_device_path);
|
||||
if (dp)
|
||||
if (dp && dp != full_device_path)
|
||||
FreePool(dp);
|
||||
if (fullpath)
|
||||
FreePool(fullpath);
|
||||
@ -904,7 +1009,13 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = fallback_should_prefer_reset();
|
||||
if (EFI_ERROR(rc)) {
|
||||
VerbosePrint(L"tpm not present, starting the first image\n");
|
||||
try_start_first_option(image);
|
||||
} else {
|
||||
VerbosePrint(L"tpm present, resetting system\n");
|
||||
}
|
||||
|
||||
Print(L"Reset System\n");
|
||||
|
||||
|
120
shim.c
120
shim.c
@ -40,7 +40,6 @@
|
||||
#include "shim.h"
|
||||
#include "netboot.h"
|
||||
#include "httpboot.h"
|
||||
#include "shim_cert.h"
|
||||
#include "replacements.h"
|
||||
#include "tpm.h"
|
||||
#include "ucs2.h"
|
||||
@ -52,6 +51,10 @@
|
||||
#include "console.h"
|
||||
#include "version.h"
|
||||
|
||||
#ifdef ENABLE_SHIM_CERT
|
||||
#include "shim_cert.h"
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
@ -428,7 +431,8 @@ static BOOLEAN verify_eku(UINT8 *Cert, UINTN CertSize)
|
||||
static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
|
||||
UINTN dbsize,
|
||||
WIN_CERTIFICATE_EFI_PKCS *data,
|
||||
UINT8 *hash)
|
||||
UINT8 *hash, CHAR16 *dbname,
|
||||
EFI_GUID guid)
|
||||
{
|
||||
EFI_SIGNATURE_DATA *Cert;
|
||||
UINTN CertSize;
|
||||
@ -446,9 +450,11 @@ static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
|
||||
Cert->SignatureData,
|
||||
CertSize,
|
||||
hash, SHA256_DIGEST_SIZE);
|
||||
if (IsFound)
|
||||
if (IsFound) {
|
||||
tpm_measure_variable(dbname, guid, CertSize, Cert->SignatureData);
|
||||
return DATA_FOUND;
|
||||
}
|
||||
}
|
||||
} else if (verbose) {
|
||||
console_notify(L"Not a DER encoding x.509 Certificate");
|
||||
}
|
||||
@ -477,7 +483,7 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
|
||||
|
||||
CertList = (EFI_SIGNATURE_LIST *)db;
|
||||
|
||||
rc = check_db_cert_in_ram(CertList, dbsize, data, hash);
|
||||
rc = check_db_cert_in_ram(CertList, dbsize, data, hash, dbname, guid);
|
||||
|
||||
FreePool(db);
|
||||
|
||||
@ -489,7 +495,8 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
|
||||
*/
|
||||
static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
|
||||
UINTN dbsize, UINT8 *data,
|
||||
int SignatureSize, EFI_GUID CertType)
|
||||
int SignatureSize, EFI_GUID CertType,
|
||||
CHAR16 *dbname, EFI_GUID guid)
|
||||
{
|
||||
EFI_SIGNATURE_DATA *Cert;
|
||||
UINTN CertCount, Index;
|
||||
@ -505,6 +512,7 @@ static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
|
||||
// Find the signature in database.
|
||||
//
|
||||
IsFound = TRUE;
|
||||
tpm_measure_variable(dbname, guid, SignatureSize, data);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -545,7 +553,8 @@ static CHECK_STATUS check_db_hash(CHAR16 *dbname, EFI_GUID guid, UINT8 *data,
|
||||
CertList = (EFI_SIGNATURE_LIST *)db;
|
||||
|
||||
CHECK_STATUS rc = check_db_hash_in_ram(CertList, dbsize, data,
|
||||
SignatureSize, CertType);
|
||||
SignatureSize, CertType,
|
||||
dbname, guid);
|
||||
FreePool(db);
|
||||
return rc;
|
||||
|
||||
@ -563,15 +572,18 @@ static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
|
||||
EFI_SIGNATURE_LIST *dbx = (EFI_SIGNATURE_LIST *)vendor_dbx;
|
||||
|
||||
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha256hash,
|
||||
SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) ==
|
||||
SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID,
|
||||
L"dbx", secure_var) ==
|
||||
DATA_FOUND)
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha1hash,
|
||||
SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID) ==
|
||||
SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID,
|
||||
L"dbx", secure_var) ==
|
||||
DATA_FOUND)
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
if (cert && check_db_cert_in_ram(dbx, vendor_dbx_size, cert,
|
||||
sha256hash) == DATA_FOUND)
|
||||
sha256hash, L"dbx",
|
||||
secure_var) == DATA_FOUND)
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
|
||||
if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
|
||||
@ -953,13 +965,13 @@ static EFI_STATUS verify_mok (void) {
|
||||
* Check that the signature is valid and matches the binary
|
||||
*/
|
||||
static EFI_STATUS verify_buffer (char *data, int datasize,
|
||||
PE_COFF_LOADER_IMAGE_CONTEXT *context)
|
||||
PE_COFF_LOADER_IMAGE_CONTEXT *context,
|
||||
UINT8 *sha256hash, UINT8 *sha1hash)
|
||||
{
|
||||
UINT8 sha256hash[SHA256_DIGEST_SIZE];
|
||||
UINT8 sha1hash[SHA1_DIGEST_SIZE];
|
||||
EFI_STATUS status = EFI_SECURITY_VIOLATION;
|
||||
WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
|
||||
unsigned int size = datasize;
|
||||
EFI_GUID shim_var = SHIM_LOCK_GUID;
|
||||
|
||||
if (context->SecDir->Size != 0) {
|
||||
if (context->SecDir->Size >= size) {
|
||||
@ -1017,6 +1029,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
|
||||
return status;
|
||||
|
||||
if (cert) {
|
||||
#if defined(ENABLE_SHIM_CERT)
|
||||
/*
|
||||
* Check against the shim build key
|
||||
*/
|
||||
@ -1026,9 +1039,11 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
|
||||
shim_cert, sizeof(shim_cert), sha256hash,
|
||||
SHA256_DIGEST_SIZE)) {
|
||||
update_verification_method(VERIFIED_BY_CERT);
|
||||
tpm_measure_variable(L"Shim", shim_var, sizeof(shim_cert), shim_cert);
|
||||
status = EFI_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
#endif /* defined(ENABLE_SHIM_CERT) */
|
||||
|
||||
/*
|
||||
* And finally, check against shim's built-in key
|
||||
@ -1039,6 +1054,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
|
||||
vendor_cert, vendor_cert_size,
|
||||
sha256hash, SHA256_DIGEST_SIZE)) {
|
||||
update_verification_method(VERIFIED_BY_CERT);
|
||||
tpm_measure_variable(L"Shim", shim_var, vendor_cert_size, vendor_cert);
|
||||
status = EFI_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
@ -1194,6 +1210,8 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
|
||||
unsigned int alignment, alloc_size;
|
||||
EFI_PHYSICAL_ADDRESS alloc_address;
|
||||
int found_entry_point = 0;
|
||||
UINT8 sha1hash[SHA1_DIGEST_SIZE];
|
||||
UINT8 sha256hash[SHA256_DIGEST_SIZE];
|
||||
|
||||
/*
|
||||
* The binary header contains relevant context and section pointers
|
||||
@ -1207,8 +1225,17 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
|
||||
/*
|
||||
* We only need to verify the binary if we're in secure mode
|
||||
*/
|
||||
efi_status = generate_hash(data, datasize, &context, sha256hash,
|
||||
sha1hash);
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return efi_status;
|
||||
|
||||
/* Measure the binary into the TPM */
|
||||
tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize, sha1hash, 4);
|
||||
|
||||
if (secure_mode ()) {
|
||||
efi_status = verify_buffer(data, datasize, &context);
|
||||
efi_status = verify_buffer(data, datasize, &context,
|
||||
sha256hash, sha1hash);
|
||||
|
||||
if (EFI_ERROR(efi_status)) {
|
||||
console_error(L"Verification failed", efi_status);
|
||||
@ -1699,6 +1726,8 @@ EFI_STATUS shim_verify (void *buffer, UINT32 size)
|
||||
{
|
||||
EFI_STATUS status = EFI_SUCCESS;
|
||||
PE_COFF_LOADER_IMAGE_CONTEXT context;
|
||||
UINT8 sha1hash[SHA1_DIGEST_SIZE];
|
||||
UINT8 sha256hash[SHA256_DIGEST_SIZE];
|
||||
|
||||
loader_is_participating = 1;
|
||||
in_protocol = 1;
|
||||
@ -1710,7 +1739,11 @@ EFI_STATUS shim_verify (void *buffer, UINT32 size)
|
||||
if (status != EFI_SUCCESS)
|
||||
goto done;
|
||||
|
||||
status = verify_buffer(buffer, size, &context);
|
||||
status = generate_hash(buffer, size, &context, sha256hash, sha1hash);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto done;
|
||||
|
||||
status = verify_buffer(buffer, size, &context, sha256hash, sha1hash);
|
||||
done:
|
||||
in_protocol = 0;
|
||||
return status;
|
||||
@ -1814,10 +1847,6 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
|
||||
}
|
||||
}
|
||||
|
||||
/* Measure the binary into the TPM */
|
||||
tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize,
|
||||
9, (CHAR8 *)"Second stage bootloader");
|
||||
|
||||
/*
|
||||
* We need to modify the loaded image protocol entry before running
|
||||
* the new binary, so back it up
|
||||
@ -1888,38 +1917,65 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
|
||||
}
|
||||
|
||||
/*
|
||||
* Measure some of the MOK variables into the TPM
|
||||
* Measure some of the MOK variables into the TPM. We measure the entirety
|
||||
* of MokList into PCR 14, and also measure the raw MokSBState there. PCR 7
|
||||
* will be extended with MokSBState in the Microsoft format, and we'll
|
||||
* measure any matching hashes or certificates later on in order to behave
|
||||
* consistently with the PCR 7 spec.
|
||||
*/
|
||||
EFI_STATUS measure_mok()
|
||||
{
|
||||
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
||||
EFI_STATUS efi_status;
|
||||
EFI_STATUS efi_status, ret = EFI_SUCCESS;
|
||||
UINT8 *Data = NULL;
|
||||
UINTN DataSize = 0;
|
||||
|
||||
efi_status = get_variable(L"MokList", &Data, &DataSize, shim_lock_guid);
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return efi_status;
|
||||
|
||||
if (!EFI_ERROR(efi_status)) {
|
||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
|
||||
DataSize, 14, (CHAR8 *)"MokList");
|
||||
|
||||
FreePool(Data);
|
||||
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return efi_status;
|
||||
if (EFI_ERROR(efi_status))
|
||||
ret = efi_status;
|
||||
|
||||
} else {
|
||||
ret = efi_status;
|
||||
}
|
||||
|
||||
efi_status = get_variable(L"MokListX", &Data, &DataSize, shim_lock_guid);
|
||||
if (!EFI_ERROR(efi_status)) {
|
||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
|
||||
DataSize, 14, (CHAR8 *)"MokListX");
|
||||
FreePool(Data);
|
||||
|
||||
if (EFI_ERROR(efi_status) && !EFI_ERROR(ret))
|
||||
ret = efi_status;
|
||||
|
||||
} else if (!EFI_ERROR(ret)) {
|
||||
ret = efi_status;
|
||||
}
|
||||
|
||||
efi_status = get_variable(L"MokSBState", &Data, &DataSize,
|
||||
shim_lock_guid);
|
||||
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return efi_status;
|
||||
|
||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
|
||||
DataSize, 14, (CHAR8 *)"MokSBState");
|
||||
if (!EFI_ERROR(efi_status)) {
|
||||
efi_status = tpm_measure_variable(L"MokSBState",
|
||||
shim_lock_guid,
|
||||
DataSize, Data);
|
||||
if (!EFI_ERROR(efi_status)) {
|
||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)
|
||||
(UINTN)Data, DataSize, 14,
|
||||
(CHAR8 *)"MokSBState");
|
||||
}
|
||||
|
||||
FreePool(Data);
|
||||
|
||||
if (EFI_ERROR(efi_status) && !EFI_ERROR(ret))
|
||||
ret = efi_status;
|
||||
} else if (!EFI_ERROR(ret)) {
|
||||
ret = efi_status;
|
||||
}
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
|
256
tpm.c
256
tpm.c
@ -1,6 +1,7 @@
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tpm.h"
|
||||
|
||||
@ -14,6 +15,16 @@ extern UINT8 in_protocol;
|
||||
})
|
||||
|
||||
|
||||
typedef struct {
|
||||
CHAR16 *VariableName;
|
||||
EFI_GUID *VendorGuid;
|
||||
VOID *Data;
|
||||
UINTN Size;
|
||||
} VARIABLE_RECORD;
|
||||
|
||||
UINTN measuredcount = 0;
|
||||
VARIABLE_RECORD *measureddata = NULL;
|
||||
|
||||
EFI_GUID tpm_guid = EFI_TPM_GUID;
|
||||
EFI_GUID tpm2_guid = EFI_TPM2_GUID;
|
||||
|
||||
@ -108,28 +119,61 @@ static EFI_STATUS trigger_tcg2_final_events_table(efi_tpm2_protocol_t *tpm2,
|
||||
&start, &end, &truncated);
|
||||
}
|
||||
|
||||
EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
|
||||
const CHAR8 *description)
|
||||
static EFI_STATUS tpm_locate_protocol(efi_tpm_protocol_t **tpm,
|
||||
efi_tpm2_protocol_t **tpm2,
|
||||
BOOLEAN *old_caps_p,
|
||||
EFI_TCG2_BOOT_SERVICE_CAPABILITY *capsp)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
|
||||
*tpm = NULL;
|
||||
*tpm2 = NULL;
|
||||
status = LibLocateProtocol(&tpm2_guid, (VOID **)tpm2);
|
||||
/* TPM 2.0 */
|
||||
if (status == EFI_SUCCESS) {
|
||||
BOOLEAN old_caps;
|
||||
EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
|
||||
|
||||
status = tpm2_get_caps(*tpm2, &caps, &old_caps);
|
||||
if (EFI_ERROR(status))
|
||||
return status;
|
||||
|
||||
if (tpm2_present(&caps, old_caps)) {
|
||||
if (old_caps_p)
|
||||
*old_caps_p = old_caps;
|
||||
if (capsp)
|
||||
memcpy(capsp, &caps, sizeof(caps));
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
status = LibLocateProtocol(&tpm_guid, (VOID **)tpm);
|
||||
if (EFI_ERROR(status))
|
||||
return status;
|
||||
|
||||
if (tpm_present(*tpm))
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
|
||||
UINT8 pcr, const CHAR8 *log, UINTN logsize,
|
||||
UINT32 type, CHAR8 *hash)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
efi_tpm_protocol_t *tpm;
|
||||
efi_tpm2_protocol_t *tpm2;
|
||||
|
||||
status = LibLocateProtocol(&tpm2_guid, (VOID **)&tpm2);
|
||||
/* TPM 2.0 */
|
||||
if (status == EFI_SUCCESS) {
|
||||
BOOLEAN old_caps;
|
||||
EFI_TCG2_EVENT *event;
|
||||
EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
|
||||
|
||||
status = tpm_locate_protocol(&tpm, &tpm2, &old_caps, &caps);
|
||||
if (EFI_ERROR(status)) {
|
||||
return status;
|
||||
} else if (tpm2) {
|
||||
EFI_TCG2_EVENT *event;
|
||||
EFI_TCG2_EVENT_LOG_BITMAP supported_logs;
|
||||
|
||||
status = tpm2_get_caps(tpm2, &caps, &old_caps);
|
||||
if (status != EFI_SUCCESS)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
if (!tpm2_present(&caps, old_caps))
|
||||
return EFI_SUCCESS;
|
||||
|
||||
supported_logs = tpm2_get_supported_logs(tpm2, &caps, old_caps);
|
||||
|
||||
status = trigger_tcg2_final_events_table(tpm2, supported_logs);
|
||||
@ -138,7 +182,7 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
|
||||
return status;
|
||||
}
|
||||
|
||||
event = AllocatePool(sizeof(*event) + strlen(description) + 1);
|
||||
event = AllocatePool(sizeof(*event) + logsize);
|
||||
if (!event) {
|
||||
perror(L"Unable to allocate event structure\n");
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
@ -147,14 +191,24 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
|
||||
event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
|
||||
event->Header.HeaderVersion = 1;
|
||||
event->Header.PCRIndex = pcr;
|
||||
event->Header.EventType = EV_IPL;
|
||||
event->Size = sizeof(*event) - sizeof(event->Event) + strlen(description) + 1;
|
||||
memcpy(event->Event, description, strlen(description) + 1);
|
||||
status = uefi_call_wrapper(tpm2->hash_log_extend_event, 5, tpm2,
|
||||
0, buf, (UINT64) size, event);
|
||||
event->Header.EventType = type;
|
||||
event->Size = sizeof(*event) - sizeof(event->Event) + logsize + 1;
|
||||
CopyMem(event->Event, (VOID *)log, logsize);
|
||||
if (hash) {
|
||||
/* TPM 2 systems will generate the appropriate hash
|
||||
themselves if we pass PE_COFF_IMAGE
|
||||
*/
|
||||
status = uefi_call_wrapper(tpm2->hash_log_extend_event,
|
||||
5, tpm2, PE_COFF_IMAGE, buf,
|
||||
(UINT64) size, event);
|
||||
} else {
|
||||
status = uefi_call_wrapper(tpm2->hash_log_extend_event,
|
||||
5, tpm2, 0, buf,
|
||||
(UINT64) size, event);
|
||||
}
|
||||
FreePool(event);
|
||||
return status;
|
||||
} else {
|
||||
} else if (tpm) {
|
||||
TCG_PCR_EVENT *event;
|
||||
UINT32 eventnum = 0;
|
||||
EFI_PHYSICAL_ADDRESS lastevent;
|
||||
@ -167,7 +221,7 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
|
||||
if (!tpm_present(tpm))
|
||||
return EFI_SUCCESS;
|
||||
|
||||
event = AllocatePool(sizeof(*event) + strlen(description) + 1);
|
||||
event = AllocatePool(sizeof(*event) + logsize);
|
||||
|
||||
if (!event) {
|
||||
perror(L"Unable to allocate event structure\n");
|
||||
@ -175,14 +229,164 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
|
||||
}
|
||||
|
||||
event->PCRIndex = pcr;
|
||||
event->EventType = EV_IPL;
|
||||
event->EventSize = strlen(description) + 1;
|
||||
status = uefi_call_wrapper(tpm->log_extend_event, 7, tpm, buf,
|
||||
(UINT64)size, TPM_ALG_SHA, event,
|
||||
event->EventType = type;
|
||||
event->EventSize = logsize;
|
||||
CopyMem(event->Event, (VOID *)log, logsize);
|
||||
if (hash) {
|
||||
/* TPM 1.2 devices require us to pass the Authenticode
|
||||
hash rather than allowing the firmware to attempt
|
||||
to calculate it */
|
||||
CopyMem(event->digest, hash, sizeof(event->digest));
|
||||
status = uefi_call_wrapper(tpm->log_extend_event, 7,
|
||||
tpm, 0, 0, TPM_ALG_SHA,
|
||||
event, &eventnum,
|
||||
&lastevent);
|
||||
} else {
|
||||
status = uefi_call_wrapper(tpm->log_extend_event, 7,
|
||||
tpm, buf, (UINT64)size,
|
||||
TPM_ALG_SHA, event,
|
||||
&eventnum, &lastevent);
|
||||
}
|
||||
FreePool(event);
|
||||
return status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
|
||||
const CHAR8 *description)
|
||||
{
|
||||
return tpm_log_event_raw(buf, size, pcr, description,
|
||||
strlen(description) + 1, 0xd, NULL);
|
||||
}
|
||||
|
||||
EFI_STATUS tpm_log_pe(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 *sha1hash,
|
||||
UINT8 pcr)
|
||||
{
|
||||
EFI_IMAGE_LOAD_EVENT ImageLoad;
|
||||
|
||||
// All of this is informational and forces us to do more parsing before
|
||||
// we can generate it, so let's just leave it out for now
|
||||
ImageLoad.ImageLocationInMemory = 0;
|
||||
ImageLoad.ImageLengthInMemory = 0;
|
||||
ImageLoad.ImageLinkTimeAddress = 0;
|
||||
ImageLoad.LengthOfDevicePath = 0;
|
||||
|
||||
return tpm_log_event_raw(buf, size, pcr, (CHAR8 *)&ImageLoad,
|
||||
sizeof(ImageLoad),
|
||||
EV_EFI_BOOT_SERVICES_APPLICATION, sha1hash);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID VariableName;
|
||||
UINT64 UnicodeNameLength;
|
||||
UINT64 VariableDataLength;
|
||||
CHAR16 UnicodeName[1];
|
||||
INT8 VariableData[1];
|
||||
} EFI_VARIABLE_DATA_TREE;
|
||||
|
||||
static BOOLEAN tpm_data_measured(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
|
||||
{
|
||||
UINTN i;
|
||||
|
||||
for (i=0; i<measuredcount; i++) {
|
||||
if ((StrCmp (VarName, measureddata[i].VariableName) == 0) &&
|
||||
(CompareGuid (&VendorGuid, measureddata[i].VendorGuid)) &&
|
||||
(VarSize == measureddata[i].Size) &&
|
||||
(CompareMem (VarData, measureddata[i].Data, VarSize) == 0)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static EFI_STATUS tpm_record_data_measurement(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
|
||||
{
|
||||
if (measureddata == NULL) {
|
||||
measureddata = AllocatePool(sizeof(*measureddata));
|
||||
} else {
|
||||
measureddata = ReallocatePool(measureddata, measuredcount * sizeof(*measureddata),
|
||||
(measuredcount + 1) * sizeof(*measureddata));
|
||||
}
|
||||
|
||||
if (measureddata == NULL)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
measureddata[measuredcount].VariableName = AllocatePool(StrSize(VarName));
|
||||
measureddata[measuredcount].VendorGuid = AllocatePool(sizeof(EFI_GUID));
|
||||
measureddata[measuredcount].Data = AllocatePool(VarSize);
|
||||
|
||||
if (measureddata[measuredcount].VariableName == NULL ||
|
||||
measureddata[measuredcount].VendorGuid == NULL ||
|
||||
measureddata[measuredcount].Data == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
StrCpy(measureddata[measuredcount].VariableName, VarName);
|
||||
CopyMem(measureddata[measuredcount].VendorGuid, &VendorGuid, sizeof(EFI_GUID));
|
||||
CopyMem(measureddata[measuredcount].Data, VarData, VarSize);
|
||||
measureddata[measuredcount].Size = VarSize;
|
||||
measuredcount++;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS tpm_measure_variable(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN VarNameLength;
|
||||
EFI_VARIABLE_DATA_TREE *VarLog;
|
||||
UINT32 VarLogSize;
|
||||
|
||||
/* Don't measure something that we've already measured */
|
||||
if (tpm_data_measured(VarName, VendorGuid, VarSize, VarData))
|
||||
return EFI_SUCCESS;
|
||||
|
||||
VarNameLength = StrLen (VarName);
|
||||
VarLogSize = (UINT32)(sizeof (*VarLog) +
|
||||
VarNameLength * sizeof (*VarName) +
|
||||
VarSize -
|
||||
sizeof (VarLog->UnicodeName) -
|
||||
sizeof (VarLog->VariableData));
|
||||
|
||||
VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
|
||||
if (VarLog == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
CopyMem (&VarLog->VariableName, &VendorGuid,
|
||||
sizeof(VarLog->VariableName));
|
||||
VarLog->UnicodeNameLength = VarNameLength;
|
||||
VarLog->VariableDataLength = VarSize;
|
||||
CopyMem (VarLog->UnicodeName, VarName,
|
||||
VarNameLength * sizeof (*VarName));
|
||||
CopyMem ((CHAR16 *)VarLog->UnicodeName + VarNameLength, VarData,
|
||||
VarSize);
|
||||
|
||||
Status = tpm_log_event_raw((EFI_PHYSICAL_ADDRESS)(intptr_t)VarLog,
|
||||
VarLogSize, 7, (CHAR8 *)VarLog, VarLogSize,
|
||||
EV_EFI_VARIABLE_AUTHORITY, NULL);
|
||||
|
||||
FreePool(VarLog);
|
||||
|
||||
if (Status != EFI_SUCCESS)
|
||||
return Status;
|
||||
|
||||
return tpm_record_data_measurement(VarName, VendorGuid, VarSize,
|
||||
VarData);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
fallback_should_prefer_reset(void)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
efi_tpm_protocol_t *tpm;
|
||||
efi_tpm2_protocol_t *tpm2;
|
||||
|
||||
status = tpm_locate_protocol(&tpm, &tpm2, NULL, NULL);
|
||||
if (EFI_ERROR(status))
|
||||
return EFI_NOT_FOUND;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
32
tpm.h
32
tpm.h
@ -1,3 +1,5 @@
|
||||
#include <efilib.h>
|
||||
|
||||
#define EFI_TPM_GUID {0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd }};
|
||||
#define EFI_TPM2_GUID {0x607f766c, 0x7455, 0x42be, {0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }};
|
||||
|
||||
@ -6,6 +8,12 @@
|
||||
|
||||
EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
|
||||
const CHAR8 *description);
|
||||
EFI_STATUS fallback_should_prefer_reset(void);
|
||||
|
||||
EFI_STATUS tpm_log_pe(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 *sha1hash,
|
||||
UINT8 pcr);
|
||||
|
||||
EFI_STATUS tpm_measure_variable(CHAR16 *dbname, EFI_GUID guid, UINTN size, void *data);
|
||||
|
||||
typedef struct {
|
||||
uint8_t Major;
|
||||
@ -31,6 +39,14 @@ typedef struct _TCG_PCR_EVENT {
|
||||
uint8_t Event[1];
|
||||
} TCG_PCR_EVENT;
|
||||
|
||||
typedef struct _EFI_IMAGE_LOAD_EVENT {
|
||||
EFI_PHYSICAL_ADDRESS ImageLocationInMemory;
|
||||
UINTN ImageLengthInMemory;
|
||||
UINTN ImageLinkTimeAddress;
|
||||
UINTN LengthOfDevicePath;
|
||||
EFI_DEVICE_PATH DevicePath[1];
|
||||
} EFI_IMAGE_LOAD_EVENT;
|
||||
|
||||
struct efi_tpm_protocol
|
||||
{
|
||||
EFI_STATUS (EFIAPI *status_check) (struct efi_tpm_protocol *this,
|
||||
@ -154,3 +170,19 @@ struct efi_tpm2_protocol
|
||||
};
|
||||
|
||||
typedef struct efi_tpm2_protocol efi_tpm2_protocol_t;
|
||||
|
||||
typedef UINT32 TCG_EVENTTYPE;
|
||||
|
||||
#define EV_EFI_EVENT_BASE ((TCG_EVENTTYPE) 0x80000000)
|
||||
#define EV_EFI_VARIABLE_DRIVER_CONFIG (EV_EFI_EVENT_BASE + 1)
|
||||
#define EV_EFI_VARIABLE_BOOT (EV_EFI_EVENT_BASE + 2)
|
||||
#define EV_EFI_BOOT_SERVICES_APPLICATION (EV_EFI_EVENT_BASE + 3)
|
||||
#define EV_EFI_BOOT_SERVICES_DRIVER (EV_EFI_EVENT_BASE + 4)
|
||||
#define EV_EFI_RUNTIME_SERVICES_DRIVER (EV_EFI_EVENT_BASE + 5)
|
||||
#define EV_EFI_GPT_EVENT (EV_EFI_EVENT_BASE + 6)
|
||||
#define EV_EFI_ACTION (EV_EFI_EVENT_BASE + 7)
|
||||
#define EV_EFI_PLATFORM_FIRMWARE_BLOB (EV_EFI_EVENT_BASE + 8)
|
||||
#define EV_EFI_HANDOFF_TABLES (EV_EFI_EVENT_BASE + 9)
|
||||
#define EV_EFI_VARIABLE_AUTHORITY (EV_EFI_EVENT_BASE + 0xE0)
|
||||
|
||||
#define PE_COFF_IMAGE 0x0000000000000010
|
||||
|
Loading…
Reference in New Issue
Block a user