New upstream version 15.6

This commit is contained in:
Steve McIntyre 2022-06-23 00:16:56 +01:00
parent 8529e0f7f7
commit e6ace38abd
41 changed files with 1370 additions and 444 deletions

View File

@ -15,28 +15,24 @@ jobs:
name: ${{ matrix.distro }} ${{ matrix.efiarch }} cross-build name: ${{ matrix.distro }} ${{ matrix.efiarch }} cross-build
strategy: strategy:
fail-fast: false
matrix: matrix:
include: include:
- arch: amd64 - arch: amd64
efiarch: aa64 efiarch: aa64
gccarch: aarch64 gccarch: aarch64
makearch: aarch64 makearch: aarch64
distro: f35 distro: f36
- arch: amd64 - arch: amd64
efiarch: aa64 efiarch: aa64
gccarch: aarch64 gccarch: aarch64
makearch: aarch64 makearch: aarch64
distro: f34 distro: f35
- arch: amd64 - arch: amd64
efiarch: aa64 efiarch: arm
gccarch: aarch64 gccarch: arm
makearch: aarch64 makearch: arm
distro: f33 distro: f36
- arch: amd64
efiarch: aa64
gccarch: aarch64
makearch: aarch64
distro: f32
- arch: amd64 - arch: amd64
efiarch: arm efiarch: arm
gccarch: arm gccarch: arm
@ -48,15 +44,10 @@ jobs:
makearch: arm makearch: arm
distro: f34 distro: f34
- arch: amd64 - arch: amd64
efiarch: arm efiarch: x64
gccarch: arm gccarch: x86_64
makearch: arm makearch: x86_64
distro: f33 distro: f36
- arch: amd64
efiarch: arm
gccarch: arm
makearch: arm
distro: f32
- arch: amd64 - arch: amd64
efiarch: x64 efiarch: x64
gccarch: x86_64 gccarch: x86_64
@ -68,15 +59,10 @@ jobs:
makearch: x86_64 makearch: x86_64
distro: f34 distro: f34
- arch: amd64 - arch: amd64
efiarch: x64 efiarch: ia32
gccarch: x86_64 gccarch: x86_64
makearch: x86_64 makearch: ia32
distro: f33 distro: f36
- arch: amd64
efiarch: x64
gccarch: x86_64
makearch: x86_64
distro: f32
- arch: amd64 - arch: amd64
efiarch: ia32 efiarch: ia32
gccarch: x86_64 gccarch: x86_64
@ -87,16 +73,6 @@ jobs:
gccarch: x86_64 gccarch: x86_64
makearch: ia32 makearch: ia32
distro: f34 distro: f34
- arch: amd64
efiarch: ia32
gccarch: x86_64
makearch: ia32
distro: f33
- arch: amd64
efiarch: ia32
gccarch: x86_64
makearch: ia32
distro: f32
steps: steps:
- name: Checkout - name: Checkout
@ -139,6 +115,10 @@ jobs:
strategy: strategy:
matrix: matrix:
include: include:
- arch: amd64
efiarch: x64
makearch: x86_64
distro: f36
- arch: amd64 - arch: amd64
efiarch: x64 efiarch: x64
makearch: x86_64 makearch: x86_64
@ -150,11 +130,7 @@ jobs:
- arch: amd64 - arch: amd64
efiarch: x64 efiarch: x64
makearch: x86_64 makearch: x86_64
distro: f33 distro: centos9
- arch: amd64
efiarch: x64
makearch: x86_64
distro: f32
- arch: amd64 - arch: amd64
efiarch: x64 efiarch: x64
makearch: x86_64 makearch: x86_64
@ -163,6 +139,10 @@ jobs:
efiarch: x64 efiarch: x64
makearch: x86_64 makearch: x86_64
distro: centos7 distro: centos7
- arch: amd64
efiarch: ia32
makearch: ia32
distro: f36
- arch: amd64 - arch: amd64
efiarch: ia32 efiarch: ia32
makearch: ia32 makearch: ia32
@ -171,14 +151,6 @@ jobs:
efiarch: ia32 efiarch: ia32
makearch: ia32 makearch: ia32
distro: f34 distro: f34
- arch: amd64
efiarch: ia32
makearch: ia32
distro: f33
- arch: amd64
efiarch: ia32
makearch: ia32
distro: f32
- arch: amd64 - arch: amd64
efiarch: ia32 efiarch: ia32
makearch: ia32 makearch: ia32

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.5 branch = shim-15.6

View File

@ -35,7 +35,8 @@ Variables you could set to customize the build:
If this is set, we look for SHIM_DEVEL_DEBUG instead of SHIM_DEBUG in If this is set, we look for SHIM_DEVEL_DEBUG instead of SHIM_DEBUG in
our debugger delay hook, thus meaning you can have it pause for a our debugger delay hook, thus meaning you can have it pause for a
debugger only on the development branch and not the OS you need to boot debugger only on the development branch and not the OS you need to boot
to scp in a new development build. to scp in a new development build. Likewise, we look for
SHIM_DEVEL_VERBOSE rather than SHIM_VERBOSE.
- DISABLE_EBS_PROTECTION - DISABLE_EBS_PROTECTION
On systems where a second stage bootloader is not used, and the Linux On systems where a second stage bootloader is not used, and the Linux
Kernel is embedded in the same EFI image as shim and booted directly Kernel is embedded in the same EFI image as shim and booted directly

134
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,134 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
rharwood AT redhat DOT com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@ -84,9 +84,7 @@ ifeq ($(ARCH),aarch64)
ARCH_GNUEFI ?= aarch64 ARCH_GNUEFI ?= aarch64
ARCH_SUFFIX ?= aa64 ARCH_SUFFIX ?= aa64
ARCH_SUFFIX_UPPER ?= AA64 ARCH_SUFFIX_UPPER ?= AA64
FORMAT := -O binary ARCH_LDFLAGS ?=
SUBSYSTEM := 0xa
ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
ARCH_CFLAGS ?= ARCH_CFLAGS ?=
endif endif
ifeq ($(ARCH),arm) ifeq ($(ARCH),arm)

View File

@ -35,4 +35,7 @@ $(strip $(foreach x,$(DEFAULT_$(1)),
$(eval override $(1)+=$(x))))) $(eval override $(1)+=$(x)))))
endef endef
%.o : %.S
$(CC) $(CFLAGS) -c -o $@ $<
# vim:filetype=make # vim:filetype=make

View File

@ -1,7 +1,7 @@
default : all default : all
NAME = shim NAME = shim
VERSION = 15.5 VERSION = 15.6
ifneq ($(origin RELEASE),undefined) ifneq ($(origin RELEASE),undefined)
DASHRELEASE ?= -$(RELEASE) DASHRELEASE ?= -$(RELEASE)
else else
@ -40,7 +40,7 @@ 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 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 pe.o httpboot.o csv.o load-options.o
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
ORIG_SOURCES = shim.c 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) 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
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
@ -108,9 +108,6 @@ shim.o: shim_cert.h
endif endif
shim.o: $(wildcard $(TOPDIR)/*.h) shim.o: $(wildcard $(TOPDIR)/*.h)
cert.o : $(TOPDIR)/cert.S
$(CC) $(CFLAGS) -c -o $@ $<
sbat.%.csv : data/sbat.%.csv sbat.%.csv : data/sbat.%.csv
$(DOS2UNIX) $(D2UFLAGS) $< $@ $(DOS2UNIX) $(D2UFLAGS) $< $@
tail -c1 $@ | read -r _ || echo >> $@ # ensure a trailing newline tail -c1 $@ | read -r _ || echo >> $@ # ensure a trailing newline
@ -154,6 +151,7 @@ gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a:
mkdir -p gnu-efi/lib gnu-efi/gnuefi mkdir -p gnu-efi/lib gnu-efi/gnuefi
$(MAKE) -C gnu-efi \ $(MAKE) -C gnu-efi \
COMPILER="$(COMPILER)" \ COMPILER="$(COMPILER)" \
CCC_CC="$(COMPILER)" \
CC="$(CC)" \ CC="$(CC)" \
ARCH=$(ARCH_GNUEFI) \ ARCH=$(ARCH_GNUEFI) \
TOPDIR=$(TOPDIR)/gnu-efi \ TOPDIR=$(TOPDIR)/gnu-efi \

View File

@ -1776,17 +1776,7 @@ static EFI_STATUS mok_tml_prompt(void *MokTML, UINTN MokTMLSize)
LibDeleteVariable(L"MokListTrustedNew", &SHIM_LOCK_GUID); LibDeleteVariable(L"MokListTrustedNew", &SHIM_LOCK_GUID);
return EFI_ABORTED; return EFI_ABORTED;
} }
if (var->MokTMLState == 0) { if (var->MokTMLState == 0) {
efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS,
1, &dbval);
if (EFI_ERROR(efi_status)) {
console_notify(L"Failed to set MokListTrusted state");
return efi_status;
}
} else {
efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID, efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS, EFI_VARIABLE_BOOTSERVICE_ACCESS,
@ -1795,8 +1785,16 @@ static EFI_STATUS mok_tml_prompt(void *MokTML, UINTN MokTMLSize)
console_notify(L"Failed to delete MokListTrusted state"); console_notify(L"Failed to delete MokListTrusted state");
return efi_status; return efi_status;
} }
} else {
efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS,
1, &dbval);
if (EFI_ERROR(efi_status)) {
console_notify(L"Failed to set MokListTrusted state");
return efi_status;
}
} }
return EFI_SUCCESS; return EFI_SUCCESS;
} }

2
commit
View File

@ -1 +1 @@
f2c598bb2218da966872ba3e0c6e7e830dca6ef0 505cdb678b319fcf9a7fdee77c0f091b4147cbe5

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

View File

@ -3,109 +3,94 @@ OUTPUT_ARCH(aarch64)
ENTRY(_start) ENTRY(_start)
SECTIONS SECTIONS
{ {
.text 0x0 : { . = 0;
_text = .; ImageBase = .;
*(.text.head) .hash : { *(.hash) } /* this MUST come first! */
*(.text) . = ALIGN(4096);
*(.text.*) .eh_frame :
*(.gnu.linkonce.t.*) {
_evtext = .; *(.eh_frame)
. = ALIGN(4096); }
. = ALIGN(4096);
.text :
{
_text = .;
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
_etext = .;
}
. = ALIGN(4096);
.reloc :
{
*(.reloc)
}
. = ALIGN(4096);
.note.gnu.build-id : {
*(.note.gnu.build-id)
}
. = ALIGN(4096);
.data.ident : {
*(.data.ident)
} }
_etext = .;
_text_size = . - _text;
_text_vsize = _evtext - _text;
. = ALIGN(4096); . = ALIGN(4096);
.data : .data :
{ {
_data = .; _data = .;
*(.sdata) *(.rodata*)
*(.data)
*(.data1)
*(.data.*)
*(.got.plt) *(.got.plt)
*(.got) *(.got)
*(.data*)
*(.dynamic) *(.sdata)
/* the EFI loader doesn't seem to like a .bss section, so we stick /* the EFI loader doesn't seem to like a .bss section, so we stick
it all into .data: */ it all into .data: */
. = ALIGN(16);
_bss = .;
*(.sbss) *(.sbss)
*(.scommon) *(.scommon)
*(.dynbss) *(.dynbss)
*(.bss) *(.bss)
*(COMMON) *(COMMON)
_evdata = .; *(.rel.local)
. = ALIGN(4096); }
_bss_end = .;
. = ALIGN(4096);
.vendor_cert :
{
*(.vendor_cert)
}
. = ALIGN(4096);
.dynamic : { *(.dynamic) }
. = ALIGN(4096);
.rela :
{
*(.rela.data*)
*(.rela.got*)
*(.rela.stab*)
} }
_edata = .; _edata = .;
_data_vsize = _evdata - _data;
_data_size = . - _data; _data_size = . - _data;
/*
* Note that _sbat must be the beginning of the data, and _esbat must be the
* end and must be before any section padding. The sbat self-check uses
* _esbat to find the bounds of the data, and if the padding is included, the
* CSV parser (correctly) rejects the data as having NUL values in one of the
* required columns.
*/
. = ALIGN(4096); . = ALIGN(4096);
.sbat : .sbat :
{ {
_sbat = .; _sbat = .;
*(.sbat) *(.sbat)
*(.sbat.*) *(.sbat.*)
_esbat = .;
. = ALIGN(4096);
_epsbat = .;
} }
_sbat_size = _epsbat - _sbat; _esbat = .;
_sbat_vsize = _esbat - _sbat; _sbat_size = . - _sbat;
. = ALIGN(4096); . = ALIGN(4096);
.rodata : .dynsym : { *(.dynsym) }
{
_rodata = .;
*(.rodata*)
*(.srodata)
. = ALIGN(16);
*(.note.gnu.build-id)
. = ALIGN(4096);
*(.vendor_cert)
*(.data.ident)
. = ALIGN(4096);
}
. = ALIGN(4096); . = ALIGN(4096);
.rela : .dynstr : { *(.dynstr) }
{
*(.rela.dyn)
*(.rela.plt)
*(.rela.got)
*(.rela.data)
*(.rela.data*)
}
. = ALIGN(4096); . = ALIGN(4096);
.dyn : .ignored.reloc :
{ {
*(.dynsym) *(.rela.reloc)
*(.dynstr)
_evrodata = .;
. = ALIGN(4096);
}
_erodata = .;
_rodata_size = . - _rodata;
_rodata_vsize = _evrodata - _rodata;
_alldata_size = . - _data;
/DISCARD/ :
{
*(.rel.reloc)
*(.eh_frame) *(.eh_frame)
*(.note.GNU-stack) *(.note.GNU-stack)
} }
.comment 0 : { *(.comment) } .comment 0 : { *(.comment) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
} }

View File

@ -24,7 +24,7 @@ get_fallback_verbose(void)
if (state != -1) if (state != -1)
return state; return state;
efi_status = get_variable(L"FALLBACK_VERBOSE", efi_status = get_variable(FALLBACK_VERBOSE_VAR_NAME,
&data, &dataSize, SHIM_LOCK_GUID); &data, &dataSize, SHIM_LOCK_GUID);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
state = 0; state = 0;
@ -1130,7 +1130,7 @@ debug_hook(void)
register volatile int x = 0; register volatile int x = 0;
extern char _etext, _edata; extern char _etext, _edata;
efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize, efi_status = get_variable(DEBUG_VAR_NAME, &data, &dataSize,
SHIM_LOCK_GUID); SHIM_LOCK_GUID);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
return; return;

View File

@ -12,6 +12,9 @@ UINT8 *vendor_authorized = NULL;
UINT32 vendor_deauthorized_size = 0; UINT32 vendor_deauthorized_size = 0;
UINT8 *vendor_deauthorized = NULL; UINT8 *vendor_deauthorized = NULL;
UINT32 user_cert_size;
UINT8 *user_cert;
#if defined(ENABLE_SHIM_CERT) #if defined(ENABLE_SHIM_CERT)
UINT32 build_cert_size; UINT32 build_cert_size;
UINT8 *build_cert; UINT8 *build_cert;
@ -26,6 +29,7 @@ int loader_is_participating;
UINT8 user_insecure_mode; UINT8 user_insecure_mode;
UINT8 ignore_db; UINT8 ignore_db;
UINT8 trust_mok_list; UINT8 trust_mok_list;
UINT8 mok_policy = 0;
UINT32 verbose = 0; UINT32 verbose = 0;

View File

@ -153,13 +153,11 @@ endif
# Set HAVE_EFI_OBJCOPY if objcopy understands --target efi-[app|bsdrv|rtdrv], # Set HAVE_EFI_OBJCOPY if objcopy understands --target efi-[app|bsdrv|rtdrv],
# otherwise we need to compose the PE/COFF header using the assembler # otherwise we need to compose the PE/COFF header using the assembler
# #
ifneq ($(ARCH),aarch64)
ifneq ($(ARCH),arm) ifneq ($(ARCH),arm)
ifneq ($(ARCH),mips64el) ifneq ($(ARCH),mips64el)
export HAVE_EFI_OBJCOPY=y export HAVE_EFI_OBJCOPY=y
endif endif
endif endif
endif
ifeq ($(ARCH),arm) ifeq ($(ARCH),arm)
CFLAGS += -marm CFLAGS += -marm

View File

@ -16,136 +16,11 @@
* either version 2 of the License, or (at your option) any later version. * either version 2 of the License, or (at your option) any later version.
*/ */
.section .text.head
/*
* Magic "MZ" signature for PE/COFF
*/
.globl ImageBase
ImageBase:
.ascii "MZ"
.skip 58 // 'MZ' + pad + offset == 64
.long pe_header - ImageBase // Offset to the PE header.
pe_header:
.ascii "PE"
.short 0
coff_header:
.short 0xaa64 // AArch64
.short 4 // nr_sections
.long 0 // TimeDateStamp
.long 0 // PointerToSymbolTable
.long 1 // NumberOfSymbols
.short section_table - optional_header // SizeOfOptionalHeader
.short 0x206 // Characteristics.
// IMAGE_FILE_DEBUG_STRIPPED |
// IMAGE_FILE_EXECUTABLE_IMAGE |
// IMAGE_FILE_LINE_NUMS_STRIPPED
optional_header:
.short 0x20b // PE32+ format
.byte 0x02 // MajorLinkerVersion
.byte 0x14 // MinorLinkerVersion
.long _text_size // SizeOfCode
.long _alldata_size // SizeOfInitializedData
.long 0 // SizeOfUninitializedData
.long _start - ImageBase // AddressOfEntryPoint
.long _start - ImageBase // BaseOfCode
extra_header_fields:
.quad 0 // ImageBase
.long 0x1000 // SectionAlignment
.long 0x200 // FileAlignment
.short 0 // MajorOperatingSystemVersion
.short 0 // MinorOperatingSystemVersion
.short 0 // MajorImageVersion
.short 0 // MinorImageVersion
.short 0 // MajorSubsystemVersion
.short 0 // MinorSubsystemVersion
.long 0 // Win32VersionValue
.long _erodata - ImageBase // SizeOfImage
// Everything before the kernel image is considered part of the header
.long _start - ImageBase // SizeOfHeaders
.long 0 // CheckSum
.short EFI_SUBSYSTEM // Subsystem
.short 0 // DllCharacteristics
.quad 0 // SizeOfStackReserve
.quad 0 // SizeOfStackCommit
.quad 0 // SizeOfHeapReserve
.quad 0 // SizeOfHeapCommit
.long 0 // LoaderFlags
.long 0x6 // NumberOfRvaAndSizes
.quad 0 // ExportTable
.quad 0 // ImportTable
.quad 0 // ResourceTable
.quad 0 // ExceptionTable
.quad 0 // CertificationTable
.quad 0 // BaseRelocationTable
// Section table
section_table:
.ascii ".text\0\0\0"
.long _evtext - _start // VirtualSize
.long _start - ImageBase // VirtualAddress
.long _etext - _start // SizeOfRawData
.long _start - ImageBase // PointerToRawData
.long 0 // PointerToRelocations (0 for executables)
.long 0 // PointerToLineNumbers (0 for executables)
.short 0 // NumberOfRelocations (0 for executables)
.short 0 // NumberOfLineNumbers (0 for executables)
/*
* EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_CNT_CODE
*/
.long 0x60000020 // Characteristics (section flags)
.ascii ".data\0\0\0"
.long _data_vsize // VirtualSize
.long _data - ImageBase // VirtualAddress
.long _data_size // SizeOfRawData
.long _data - ImageBase // PointerToRawData
.long 0 // PointerToRelocations (0 for executables)
.long 0 // PointerToLineNumbers (0 for executables)
.short 0 // NumberOfRelocations (0 for executables)
.short 0 // NumberOfLineNumbers (0 for executables)
/*
* EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
*/
.long 0xc0000040 // Characteristics (section flags)
.ascii ".sbat\0\0\0"
.long _sbat_vsize // VirtualSize
.long _sbat - ImageBase // VirtualAddress
.long _sbat_size // SizeOfRawData
.long _sbat - ImageBase // PointerToRawData
.long 0 // PointerToRelocations (0 for executables)
.long 0 // PointerToLineNumbers (0 for executables)
.short 0 // NumberOfRelocations (0 for executables)
.short 0 // NumberOfLineNumbers (0 for executables)
/*
* EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_ALIGN_8BYTES | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
*/
.long 0x40400040 // Characteristics (section flags)
.ascii ".rodata\0"
.long _rodata_vsize // VirtualSize
.long _rodata - ImageBase // VirtualAddress
.long _rodata_size // SizeOfRawData
.long _rodata - ImageBase // PointerToRawData
.long 0 // PointerToRelocations (0 for executables)
.long 0 // PointerToLineNumbers (0 for executables)
.short 0 // NumberOfRelocations (0 for executables)
.short 0 // NumberOfLineNumbers (0 for executables)
/*
* EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_ALIGN_8BYTES | EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
*/
.long 0x40400040 // Characteristics (section flags)
.text
.align 12 .align 12
.globl _start
_start: _start:
stp x29, x30, [sp, #-32]! stp x29, x30, [sp, #-32]!
mov x29, sp mov x29, sp
@ -164,3 +39,15 @@ _start:
0: ldp x29, x30, [sp], #32 0: ldp x29, x30, [sp], #32
ret ret
// hand-craft a dummy .reloc section so EFI knows it's a relocatable executable:
.data
.dummy0:
.dummy1:
.4byte 0
#define IMAGE_REL_ABSOLUTE 0
.section .reloc, "a"
.4byte .dummy1-.dummy0 // Page RVA
.4byte 10 // Block Size (2*4+2)
.2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy

View File

@ -68,10 +68,10 @@ _start:
.data .data
.dummy0: .dummy0:
.dummy1: .dummy1:
.long 0 .4byte 0
#define IMAGE_REL_ABSOLUTE 0 #define IMAGE_REL_ABSOLUTE 0
.section .reloc, "a" .section .reloc, "a"
.long .dummy1-.dummy0 // Page RVA .4byte .dummy1-.dummy0 // Page RVA
.long 10 // Block Size (2*4+2) .4byte 10 // Block Size (2*4+2)
.word (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy

View File

@ -59,18 +59,16 @@ _start:
call efi_main call efi_main
addq $8, %rsp addq $8, %rsp
.exit:
ret ret
// hand-craft a dummy .reloc section so EFI knows it's a relocatable executable: // hand-craft a dummy .reloc section so EFI knows it's a relocatable executable:
.data .data
.dummy0: .dummy0:
.dummy1: .dummy1:
.long 0 .4byte 0
#define IMAGE_REL_ABSOLUTE 0 #define IMAGE_REL_ABSOLUTE 0
.section .reloc, "a" .section .reloc, "a"
.long .dummy1-.dummy0 // Page RVA .4byte .dummy1-.dummy0 // Page RVA
.long 10 // Block Size (2*4+2) .4byte 10 // Block Size (2*4+2)
.word (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy

View File

@ -170,11 +170,12 @@ typedef enum {
#define EFI_MEMORY_WT 0x0000000000000004 #define EFI_MEMORY_WT 0x0000000000000004
#define EFI_MEMORY_WB 0x0000000000000008 #define EFI_MEMORY_WB 0x0000000000000008
#define EFI_MEMORY_UCE 0x0000000000000010 #define EFI_MEMORY_UCE 0x0000000000000010
#define EFI_MEMORY_WP 0x0000000000001000
// physical memory protection on range // physical memory protection on range
#define EFI_MEMORY_WP 0x0000000000001000
#define EFI_MEMORY_RP 0x0000000000002000 #define EFI_MEMORY_RP 0x0000000000002000
#define EFI_MEMORY_XP 0x0000000000004000 #define EFI_MEMORY_XP 0x0000000000004000
#define EFI_MEMORY_RO 0x0000000000020000
// range requires a runtime mapping // range requires a runtime mapping
#define EFI_MEMORY_RUNTIME 0x8000000000000000 #define EFI_MEMORY_RUNTIME 0x8000000000000000

View File

@ -1422,4 +1422,39 @@ typedef struct _EFI_EBC_PROTOCOL {
EFI_EBC_GET_VERSION GetVersion; EFI_EBC_GET_VERSION GetVersion;
} EFI_EBC_PROTOCOL; } EFI_EBC_PROTOCOL;
INTERFACE_DECL(_EFI_MEMORY_ATTRIBUTE_PROTOCOL);
typedef
EFI_STATUS
(EFIAPI *EFI_GET_MEMORY_ATTRIBUTES)(
IN struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
OUT UINT64 *Attributes
);
typedef
EFI_STATUS
(EFIAPI *EFI_SET_MEMORY_ATTRIBUTES)(
IN struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN UINT64 Attributes
);
typedef
EFI_STATUS
(EFIAPI *EFI_CLEAR_MEMORY_ATTRIBUTES)(
IN struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN UINT64 Attributes
);
typedef struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL {
EFI_GET_MEMORY_ATTRIBUTES GetMemoryAttributes;
EFI_SET_MEMORY_ATTRIBUTES SetMemoryAttributes;
EFI_CLEAR_MEMORY_ATTRIBUTES ClearMemoryAttributes;
} EFI_MEMORY_ATTRIBUTE_PROTOCOL;
#endif #endif

View File

@ -47,8 +47,12 @@
#define ALIAS(x) __attribute__((weak, alias (#x))) #define ALIAS(x) __attribute__((weak, alias (#x)))
#endif #endif
#ifndef ALLOCFUNC #ifndef ALLOCFUNC
#if defined(__COVERITY__)
#define ALLOCFUNC(a, b)
#else
#define ALLOCFUNC(dealloc, dealloc_arg) __attribute__((__malloc__(dealloc, dealloc_arg))) #define ALLOCFUNC(dealloc, dealloc_arg) __attribute__((__malloc__(dealloc, dealloc_arg)))
#endif #endif
#endif
#ifndef PRINTF #ifndef PRINTF
#define PRINTF(first, args...) __attribute__((__format__(printf, first, ## args))) #define PRINTF(first, args...) __attribute__((__format__(printf, first, ## args)))
#endif #endif

View File

@ -33,8 +33,8 @@ extern EFI_GUID EFI_SECURE_BOOT_DB_GUID;
extern EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID; extern EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID;
extern EFI_GUID SECURITY_PROTOCOL_GUID; extern EFI_GUID SECURITY_PROTOCOL_GUID;
extern EFI_GUID SECURITY2_PROTOCOL_GUID; extern EFI_GUID SECURITY2_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;
#endif /* SHIM_GUID_H */ #endif /* SHIM_GUID_H */

View File

@ -59,6 +59,9 @@ struct mok_state_variable {
UINT8 **addend; UINT8 **addend;
UINT32 *addend_size; UINT32 *addend_size;
UINT8 **user_cert;
UINT32 *user_cert_size;
/* /*
* build_cert is our build-time cert. Like addend, this is added * build_cert is our build-time cert. Like addend, this is added
* to the input variable, as part of the runtime variable, so that * to the input variable, as part of the runtime variable, so that
@ -97,5 +100,10 @@ struct mok_variable_config_entry {
UINT8 data[]; UINT8 data[];
}; };
/*
* bit definitions for MokPolicy
*/
#define MOK_POLICY_REQUIRE_NX 1
#endif /* !SHIM_MOK_H_ */ #endif /* !SHIM_MOK_H_ */
// vim:fenc=utf-8:tw=75:noet // vim:fenc=utf-8:tw=75:noet

View File

@ -14,8 +14,12 @@ EFI_STATUS
read_header(void *data, unsigned int datasize, read_header(void *data, unsigned int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context); PE_COFF_LOADER_IMAGE_CONTEXT *context);
EFI_STATUS verify_image(void *data, unsigned int datasize,
EFI_LOADED_IMAGE *li,
PE_COFF_LOADER_IMAGE_CONTEXT *context);
EFI_STATUS EFI_STATUS
handle_sbat(char *SBATBase, size_t SBATSize); verify_sbat_section(char *SBATBase, size_t SBATSize);
EFI_STATUS EFI_STATUS
handle_image (void *data, unsigned int datasize, handle_image (void *data, unsigned int datasize,

View File

@ -17,10 +17,14 @@
#include "wincert.h" #include "wincert.h"
#define SIGNATURE_16(A, B) ((A) | (B << 8)) #define SIGNATURE_16(A, B) \
#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16)) ((UINT16)(((UINT16)(A)) | (((UINT16)(B)) << ((UINT16)8))))
#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ #define SIGNATURE_32(A, B, C, D) \
(SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32)) ((UINT32)(((UINT32)SIGNATURE_16(A, B)) | \
(((UINT32)SIGNATURE_16(C, D)) << (UINT32)16)))
#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
((UINT64)((UINT64)SIGNATURE_32(A, B, C, D) | \
((UINT64)(SIGNATURE_32(E, F, G, H)) << (UINT64)32)))
#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))))
@ -236,6 +240,24 @@ typedef struct {
EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
} EFI_IMAGE_OPTIONAL_HEADER64; } EFI_IMAGE_OPTIONAL_HEADER64;
#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0001 0x0001
#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0002 0x0002
#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0004 0x0004
#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0008 0x0008
#if 0 /* This is not in the PE spec. */
#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0010 0x0010
#endif
#define EFI_IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020
#define EFI_IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040
#define EFI_IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080
#define EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
#define EFI_IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200
#define EFI_IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
#define EFI_IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
#define EFI_IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000
#define EFI_IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
#define EFI_IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000
#define EFI_IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
/// ///
/// @attention /// @attention
@ -303,16 +325,31 @@ typedef struct {
// //
// Section Flags Values // Section Flags Values
// //
#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 ///< Reserved. #define EFI_IMAGE_SCN_RESERVED_00000000 0x00000000
#define EFI_IMAGE_SCN_RESERVED_00000001 0x00000001
#define EFI_IMAGE_SCN_RESERVED_00000002 0x00000002
#define EFI_IMAGE_SCN_RESERVED_00000004 0x00000004
#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008
#define EFI_IMAGE_SCN_RESERVED_00000010 0x00000010
#define EFI_IMAGE_SCN_CNT_CODE 0x00000020 #define EFI_IMAGE_SCN_CNT_CODE 0x00000020
#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 #define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 #define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100
#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 ///< Reserved. #define EFI_IMAGE_SCN_LNK_INFO 0x00000200
#define EFI_IMAGE_SCN_LNK_INFO 0x00000200 ///< Section contains comments or some other type of information. #define EFI_IMAGE_SCN_RESERVED_00000400 0x00000400
#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 ///< Section contents will not become part of image. #define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800
#define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000 #define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000
#define EFI_IMAGE_SCN_RESERVED_00002000 0x00002000
#define EFI_IMAGE_SCN_RESERVED_00004000 0x00004000
#define EFI_IMAGE_SCN_GPREL 0x00008000
/*
* PE 9.3 says both IMAGE_SCN_MEM_PURGEABLE and IMAGE_SCN_MEM_16BIT are
* 0x00020000, but I think it's wrong. --pjones
*/
#define EFI_IMAGE_SCN_MEM_PURGEABLE 0x00010000 // "Reserved for future use."
#define EFI_IMAGE_SCN_MEM_16BIT 0x00020000 // "Reserved for future use."
#define EFI_IMAGE_SCN_MEM_LOCKED 0x00040000 // "Reserved for future use."
#define EFI_IMAGE_SCN_MEM_PRELOAD 0x00080000 // "Reserved for future use."
#define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000 #define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000
#define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000 #define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000
#define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000 #define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000
@ -320,7 +357,14 @@ typedef struct {
#define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000 #define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000
#define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000 #define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000
#define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000 #define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000
#define EFI_IMAGE_SCN_ALIGN_128BYTES 0x00800000
#define EFI_IMAGE_SCN_ALIGN_256BYTES 0x00900000
#define EFI_IMAGE_SCN_ALIGN_512BYTES 0x00a00000
#define EFI_IMAGE_SCN_ALIGN_1024BYTES 0x00b00000
#define EFI_IMAGE_SCN_ALIGN_2048BYTES 0x00c00000
#define EFI_IMAGE_SCN_ALIGN_4096BYTES 0x00d00000
#define EFI_IMAGE_SCN_ALIGN_8192BYTES 0x00e00000
#define EFI_IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
#define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000 #define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000
#define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000 #define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000
#define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000 #define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000

View File

@ -8,8 +8,35 @@
#define SBAT_VAR_SIG "sbat," #define SBAT_VAR_SIG "sbat,"
#define SBAT_VAR_VERSION "1," #define SBAT_VAR_VERSION "1,"
#define SBAT_VAR_DATE "2021030218" #define SBAT_VAR_ORIGINAL_DATE "2021030218"
#define SBAT_VAR SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_DATE "\n" #define SBAT_VAR_ORIGINAL \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_ORIGINAL_DATE "\n"
#if defined(ENABLE_SHIM_DEVEL)
#define SBAT_VAR_PREVIOUS_DATE "2022020101"
#define SBAT_VAR_PREVIOUS_REVOCATIONS "component,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 "2022050100"
#define SBAT_VAR_LATEST_REVOCATIONS "component,2\nothercomponent,2\n"
#define SBAT_VAR_LATEST \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \
SBAT_VAR_LATEST_REVOCATIONS
#else /* !ENABLE_SHIM_DEVEL */
#define SBAT_VAR_PREVIOUS_DATE SBAT_VAR_ORIGINAL_DATE
#define SBAT_VAR_PREVIOUS_REVOCATIONS
#define SBAT_VAR_PREVIOUS \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_PREVIOUS_DATE "\n" \
SBAT_VAR_PREVIOUS_REVOCATIONS
#define SBAT_VAR_LATEST_DATE "2022052400"
#define SBAT_VAR_LATEST_REVOCATIONS "shim,2\ngrub,2\n"
#define SBAT_VAR_LATEST \
SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_LATEST_DATE "\n" \
SBAT_VAR_LATEST_REVOCATIONS
#endif /* ENABLE_SHIM_DEVEL */
#define UEFI_VAR_NV_BS \ #define UEFI_VAR_NV_BS \
(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS) (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)
@ -33,6 +60,13 @@
#define SBAT_VAR_ATTRS UEFI_VAR_NV_BS #define SBAT_VAR_ATTRS UEFI_VAR_NV_BS
#endif #endif
#define SBAT_POLICY L"SbatPolicy"
#define SBAT_POLICY8 "SbatPolicy"
#define SBAT_POLICY_LATEST 1
#define SBAT_POLICY_PREVIOUS 2
#define SBAT_POLICY_RESET 3
extern UINTN _sbat, _esbat; extern UINTN _sbat, _esbat;
struct sbat_var_entry { struct sbat_var_entry {
@ -51,7 +85,8 @@ extern list_t sbat_var;
EFI_STATUS parse_sbat_var(list_t *entries); EFI_STATUS parse_sbat_var(list_t *entries);
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(void);
bool preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes); bool preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize,
UINT32 attributes, char *sbar_var);
struct sbat_section_entry { struct sbat_section_entry {
const CHAR8 *component_name; const CHAR8 *component_name;

View File

@ -102,5 +102,9 @@ static const unsigned char test_data_efivars_1_SbatLevelRT[] = {
0x32, 0x31, 0x30, 0x33, 0x30, 0x32, 0x31, 0x38, 0x0a 0x32, 0x31, 0x30, 0x33, 0x30, 0x32, 0x31, 0x38, 0x0a
}; };
static const unsigned char test_data_efivars_1_MokListTrustedRT[] ={
0x01
};
#endif /* !TEST_DATA_EFIVARS_1_H_ */ #endif /* !TEST_DATA_EFIVARS_1_H_ */
// vim:fenc=utf-8:tw=75:noet // vim:fenc=utf-8:tw=75:noet

View File

@ -50,6 +50,9 @@ CFLAGS = $(OPTIMIZATIONS) -std=gnu11 \
# of the "include" directory # of the "include" directory
CFLAGS += -isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include-fixed) 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)
export CFLAGS_LTO CFLAGS_GCOV export CFLAGS_LTO CFLAGS_GCOV
libefi-test.a : libefi-test.a :

View File

@ -41,6 +41,10 @@ CFLAGS = $(FEATUREFLAGS) \
$(INCLUDES) \ $(INCLUDES) \
$(DEFINES) $(DEFINES)
ifneq ($(origin ENABLE_SHIM_DEVEL),undefined)
CFLAGS += -DENABLE_SHIM_DEVEL
endif
lib.a: $(LIBFILES) lib.a: $(LIBFILES)
$(AR) rcs lib.a $(LIBFILES) $(AR) rcs lib.a $(LIBFILES)

View File

@ -122,6 +122,30 @@ console_print_at(UINTN col, UINTN row, const CHAR16 *fmt, ...)
return ret; return ret;
} }
static struct {
CHAR16 up_left;
CHAR16 up_right;
CHAR16 down_left;
CHAR16 down_right;
CHAR16 horizontal;
CHAR16 vertical;
} boxdraw[2] = {
{
BOXDRAW_UP_LEFT,
BOXDRAW_UP_RIGHT,
BOXDRAW_DOWN_LEFT,
BOXDRAW_DOWN_RIGHT,
BOXDRAW_HORIZONTAL,
BOXDRAW_VERTICAL
}, {
'+',
'+',
'+',
'+',
'-',
'|'
}
};
void void
console_print_box_at(CHAR16 *str_arr[], int highlight, console_print_box_at(CHAR16 *str_arr[], int highlight,
@ -133,6 +157,7 @@ console_print_box_at(CHAR16 *str_arr[], int highlight,
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut; SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
UINTN rows, cols; UINTN rows, cols;
CHAR16 *Line; CHAR16 *Line;
bool char_set;
if (lines == 0) if (lines == 0)
return; return;
@ -181,10 +206,16 @@ console_print_box_at(CHAR16 *str_arr[], int highlight,
return; return;
} }
SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL); /* test if boxdraw characters work */
co->SetCursorPosition(co, start_col, start_row);
Line[0] = boxdraw[0].up_left;
Line[1] = L'\0';
char_set = co->OutputString(co, Line) == 0 ? 0 : 1;
Line[0] = BOXDRAW_DOWN_RIGHT; SetMem16 (Line, size_cols * 2, boxdraw[char_set].horizontal);
Line[size_cols - 1] = BOXDRAW_DOWN_LEFT;
Line[0] = boxdraw[char_set].down_right;
Line[size_cols - 1] = boxdraw[char_set].down_left;
Line[size_cols] = L'\0'; Line[size_cols] = L'\0';
co->SetCursorPosition(co, start_col, start_row); co->SetCursorPosition(co, start_col, start_row);
co->OutputString(co, Line); co->OutputString(co, Line);
@ -204,8 +235,8 @@ console_print_box_at(CHAR16 *str_arr[], int highlight,
int line = i - start; int line = i - start;
SetMem16 (Line, size_cols*2, L' '); SetMem16 (Line, size_cols*2, L' ');
Line[0] = BOXDRAW_VERTICAL; Line[0] = boxdraw[char_set].vertical;
Line[size_cols - 1] = BOXDRAW_VERTICAL; Line[size_cols - 1] = boxdraw[char_set].vertical;
Line[size_cols] = L'\0'; Line[size_cols] = L'\0';
if (line >= 0 && line < lines) { if (line >= 0 && line < lines) {
CHAR16 *s = str_arr[line]; CHAR16 *s = str_arr[line];
@ -227,9 +258,9 @@ console_print_box_at(CHAR16 *str_arr[], int highlight,
EFI_BACKGROUND_BLUE); EFI_BACKGROUND_BLUE);
} }
SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL); SetMem16 (Line, size_cols * 2, boxdraw[char_set].horizontal);
Line[0] = BOXDRAW_UP_RIGHT; Line[0] = boxdraw[char_set].up_right;
Line[size_cols - 1] = BOXDRAW_UP_LEFT; Line[size_cols - 1] = boxdraw[char_set].up_left;
Line[size_cols] = L'\0'; Line[size_cols] = L'\0';
co->SetCursorPosition(co, start_col, i); co->SetCursorPosition(co, start_col, i);
co->OutputString(co, Line); co->OutputString(co, Line);
@ -522,7 +553,6 @@ console_mode_handle(VOID)
efi_status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop); efi_status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
console_error(L"Locate graphic output protocol fail", efi_status);
return; return;
} }
@ -702,7 +732,7 @@ setup_verbosity(VOID)
UINTN verbose_check_size; UINTN verbose_check_size;
verbose_check_size = sizeof(verbose); verbose_check_size = sizeof(verbose);
efi_status = get_variable(L"SHIM_VERBOSE", &verbose_check_ptr, efi_status = get_variable(VERBOSE_VAR_NAME, &verbose_check_ptr,
&verbose_check_size, SHIM_LOCK_GUID); &verbose_check_size, SHIM_LOCK_GUID);
if (!EFI_ERROR(efi_status)) { if (!EFI_ERROR(efi_status)) {
verbose = *(__typeof__(verbose) *)verbose_check_ptr; verbose = *(__typeof__(verbose) *)verbose_check_ptr;

View File

@ -32,6 +32,6 @@ EFI_GUID EFI_SECURE_BOOT_DB_GUID = { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc,
EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID = SIMPLE_FILE_SYSTEM_PROTOCOL;
EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } }; EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } };
EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } };
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} };

View File

@ -445,7 +445,7 @@ free_var(struct mock_variable *var)
static bool static bool
mock_sv_attrs_match(UINT32 old, UINT32 new) mock_sv_attrs_match(UINT32 old, UINT32 new)
{ {
UINT32 mask = ~EFI_VARIABLE_APPEND_WRITE; UINT32 mask = ~((UINT32)EFI_VARIABLE_APPEND_WRITE);
return (old & mask) == (new & mask); return (old & mask) == (new & mask);
} }

40
mok.c
View File

@ -84,6 +84,7 @@ categorize_deauthorized(struct mok_state_variable *v)
#define MOK_MIRROR_DELETE_FIRST 0x02 #define MOK_MIRROR_DELETE_FIRST 0x02
#define MOK_VARIABLE_MEASURE 0x04 #define MOK_VARIABLE_MEASURE 0x04
#define MOK_VARIABLE_LOG 0x08 #define MOK_VARIABLE_LOG 0x08
#define MOK_VARIABLE_INVERSE 0x10
struct mok_state_variable mok_state_variable_data[] = { struct mok_state_variable mok_state_variable_data[] = {
{.name = L"MokList", {.name = L"MokList",
@ -97,6 +98,8 @@ struct mok_state_variable mok_state_variable_data[] = {
.categorize_addend = categorize_authorized, .categorize_addend = categorize_authorized,
.addend = &vendor_authorized, .addend = &vendor_authorized,
.addend_size = &vendor_authorized_size, .addend_size = &vendor_authorized_size,
.user_cert = &user_cert,
.user_cert_size = &user_cert_size,
#if defined(ENABLE_SHIM_CERT) #if defined(ENABLE_SHIM_CERT)
.build_cert = &build_cert, .build_cert = &build_cert,
.build_cert_size = &build_cert_size, .build_cert_size = &build_cert_size,
@ -176,10 +179,24 @@ struct mok_state_variable mok_state_variable_data[] = {
.no_attr = EFI_VARIABLE_RUNTIME_ACCESS, .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
.flags = MOK_MIRROR_DELETE_FIRST | .flags = MOK_MIRROR_DELETE_FIRST |
MOK_VARIABLE_MEASURE | MOK_VARIABLE_MEASURE |
MOK_VARIABLE_INVERSE |
MOK_VARIABLE_LOG, MOK_VARIABLE_LOG,
.pcr = 14, .pcr = 14,
.state = &trust_mok_list, .state = &trust_mok_list,
}, },
{.name = L"MokPolicy",
.name8 = "MokPolicy",
.rtname = L"MokPolicyRT",
.rtname8 = "MokPolicyRT",
.guid = &SHIM_LOCK_GUID,
.yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
.no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
.flags = MOK_MIRROR_DELETE_FIRST |
MOK_VARIABLE_LOG,
.pcr = 14,
.state = &mok_policy,
},
{ NULL, } { NULL, }
}; };
size_t n_mok_state_variables = sizeof(mok_state_variable_data) / sizeof(mok_state_variable_data[0]); size_t n_mok_state_variables = sizeof(mok_state_variable_data) / sizeof(mok_state_variable_data[0]);
@ -586,7 +603,8 @@ mirror_one_mok_variable(struct mok_state_variable *v,
dprint(L"FullDataSize:0x%lx FullData:0x%llx\n", dprint(L"FullDataSize:0x%lx FullData:0x%llx\n",
FullDataSize, FullData); FullDataSize, FullData);
} }
if (v->user_cert_size)
FullDataSize += *v->user_cert_size;
} }
/* /*
@ -700,6 +718,10 @@ mirror_one_mok_variable(struct mok_state_variable *v,
dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n", dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
FullDataSize, FullData, p, p-(uintptr_t)FullData); FullDataSize, FullData, p, p-(uintptr_t)FullData);
} }
if (v->user_cert_size) {
CopyMem(p, *v->user_cert, *v->user_cert_size);
p += *v->user_cert_size;
}
} }
/* /*
@ -846,7 +868,16 @@ EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
efi_status = get_variable_attr(v->name, efi_status = get_variable_attr(v->name,
&v->data, &v->data_size, &v->data, &v->data_size,
*v->guid, &attrs); *v->guid, &attrs);
if (efi_status == EFI_NOT_FOUND) { if (efi_status == EFI_NOT_FOUND &&
v->flags & MOK_VARIABLE_INVERSE) {
v->data = AllocateZeroPool(4);
if (!v->data) {
perror(L"Out of memory\n");
return EFI_OUT_OF_RESOURCES;
}
v->data[0] = 0x01;
v->data_size = 1;
} else if (efi_status == EFI_NOT_FOUND) {
v->data = NULL; v->data = NULL;
v->data_size = 0; v->data_size = 0;
} else if (EFI_ERROR(efi_status)) { } else if (EFI_ERROR(efi_status)) {
@ -868,6 +899,11 @@ EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
attrs, v->no_attr); attrs, v->no_attr);
delete = TRUE; delete = TRUE;
} }
if (v->flags & MOK_VARIABLE_INVERSE) {
FreePool(v->data);
v->data = NULL;
v->data_size = 0;
}
} }
} }
if (delete == TRUE) { if (delete == TRUE) {

364
pe.c
View File

@ -696,6 +696,7 @@ read_header(void *data, unsigned int datasize,
EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data; EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize; unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
unsigned long FileAlignment = 0; unsigned long FileAlignment = 0;
UINT16 DllFlags;
if (datasize < sizeof (PEHdr->Pe32)) { if (datasize < sizeof (PEHdr->Pe32)) {
perror(L"Invalid image\n"); perror(L"Invalid image\n");
@ -790,13 +791,21 @@ read_header(void *data, unsigned int datasize,
context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint; context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
DllFlags = PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics;
} else { } else {
context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase; context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint; context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; 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)); context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
if (context->ImageSize < context->SizeOfHeaders) { if (context->ImageSize < context->SizeOfHeaders) {
@ -820,7 +829,7 @@ read_header(void *data, unsigned int datasize,
} }
EFI_STATUS EFI_STATUS
handle_sbat(char *SBATBase, size_t SBATSize) verify_sbat_section(char *SBATBase, size_t SBATSize)
{ {
unsigned int i; unsigned int i;
EFI_STATUS efi_status; EFI_STATUS efi_status;
@ -834,7 +843,12 @@ handle_sbat(char *SBATBase, size_t SBATSize)
if (SBATBase == NULL || SBATSize == 0) { if (SBATBase == NULL || SBATSize == 0) {
dprint(L"No .sbat section data\n"); dprint(L"No .sbat section data\n");
return EFI_SECURITY_VIOLATION; /*
* SBAT is mandatory for binaries loaded by shim, but optional
* for binaries loaded outside of shim but verified via the
* protocol.
*/
return in_protocol ? EFI_SUCCESS : EFI_SECURITY_VIOLATION;
} }
sbat_size = SBATSize + 1; sbat_size = SBATSize + 1;
@ -873,6 +887,201 @@ err:
return efi_status; return efi_status;
} }
static inline uint64_t
shim_mem_attrs_to_uefi_mem_attrs (uint64_t attrs)
{
uint64_t ret = EFI_MEMORY_RP |
EFI_MEMORY_RO |
EFI_MEMORY_XP;
if (attrs & MEM_ATTR_R)
ret &= ~EFI_MEMORY_RP;
if (attrs & MEM_ATTR_W)
ret &= ~EFI_MEMORY_RO;
if (attrs & MEM_ATTR_X)
ret &= ~EFI_MEMORY_XP;
return ret;
}
static inline uint64_t
uefi_mem_attrs_to_shim_mem_attrs (uint64_t attrs)
{
uint64_t ret = MEM_ATTR_R |
MEM_ATTR_W |
MEM_ATTR_X;
if (attrs & EFI_MEMORY_RP)
ret &= ~MEM_ATTR_R;
if (attrs & EFI_MEMORY_RO)
ret &= ~MEM_ATTR_W;
if (attrs & EFI_MEMORY_XP)
ret &= ~MEM_ATTR_X;
return ret;
}
static EFI_STATUS
get_mem_attrs (uintptr_t addr, size_t size, uint64_t *attrs)
{
EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL;
EFI_PHYSICAL_ADDRESS physaddr = addr;
EFI_STATUS efi_status;
efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID,
(VOID **)&proto);
if (EFI_ERROR(efi_status) || !proto)
return efi_status;
if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) {
dprint(L"%a called on 0x%llx-0x%llx and attrs 0x%llx\n",
__func__, (unsigned long long)physaddr,
(unsigned long long)(physaddr+size-1),
attrs);
return EFI_SUCCESS;
}
efi_status = proto->GetMemoryAttributes(proto, physaddr, size, attrs);
*attrs = uefi_mem_attrs_to_shim_mem_attrs (*attrs);
return efi_status;
}
static EFI_STATUS
update_mem_attrs(uintptr_t addr, uint64_t size,
uint64_t set_attrs, uint64_t clear_attrs)
{
EFI_MEMORY_ATTRIBUTE_PROTOCOL *proto = NULL;
EFI_PHYSICAL_ADDRESS physaddr = addr;
EFI_STATUS efi_status, ret;
uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs;
efi_status = LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID,
(VOID **)&proto);
if (EFI_ERROR(efi_status) || !proto)
return efi_status;
efi_status = get_mem_attrs (addr, size, &before);
if (EFI_ERROR(efi_status))
dprint(L"get_mem_attrs(0x%llx, 0x%llx, 0x%llx) -> 0x%lx\n",
(unsigned long long)addr, (unsigned long long)size,
&before, efi_status);
if (physaddr & 0xfff || size & 0xfff || size == 0) {
dprint(L"%a called on 0x%llx-0x%llx (size 0x%llx) +%a%a%a -%a%a%a\n",
__func__, (unsigned long long)physaddr,
(unsigned long long)(physaddr + size - 1),
(unsigned long long)size,
(set_attrs & MEM_ATTR_R) ? "r" : "",
(set_attrs & MEM_ATTR_W) ? "w" : "",
(set_attrs & MEM_ATTR_X) ? "x" : "",
(clear_attrs & MEM_ATTR_R) ? "r" : "",
(clear_attrs & MEM_ATTR_W) ? "w" : "",
(clear_attrs & MEM_ATTR_X) ? "x" : "");
return 0;
}
uefi_set_attrs = shim_mem_attrs_to_uefi_mem_attrs (set_attrs);
dprint("translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_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);
efi_status = EFI_SUCCESS;
if (uefi_set_attrs)
efi_status = proto->SetMemoryAttributes(proto, physaddr, size, uefi_set_attrs);
if (!EFI_ERROR(efi_status) && uefi_clear_attrs)
efi_status = proto->ClearMemoryAttributes(proto, physaddr, size, uefi_clear_attrs);
ret = efi_status;
efi_status = get_mem_attrs (addr, size, &after);
if (EFI_ERROR(efi_status))
dprint(L"get_mem_attrs(0x%llx, %llu, 0x%llx) -> 0x%lx\n",
(unsigned long long)addr, (unsigned long long)size,
&after, efi_status);
dprint(L"set +%a%a%a -%a%a%a on 0x%llx-0x%llx before:%c%c%c after:%c%c%c\n",
(set_attrs & MEM_ATTR_R) ? "r" : "",
(set_attrs & MEM_ATTR_W) ? "w" : "",
(set_attrs & MEM_ATTR_X) ? "x" : "",
(clear_attrs & MEM_ATTR_R) ? "r" : "",
(clear_attrs & MEM_ATTR_W) ? "w" : "",
(clear_attrs & MEM_ATTR_X) ? "x" : "",
(unsigned long long)addr, (unsigned long long)(addr + size - 1),
(before & MEM_ATTR_R) ? 'r' : '-',
(before & MEM_ATTR_W) ? 'w' : '-',
(before & MEM_ATTR_X) ? 'x' : '-',
(after & MEM_ATTR_R) ? 'r' : '-',
(after & MEM_ATTR_W) ? 'w' : '-',
(after & MEM_ATTR_X) ? 'x' : '-');
return ret;
}
EFI_STATUS verify_image(void *data, unsigned int datasize,
EFI_LOADED_IMAGE *li,
PE_COFF_LOADER_IMAGE_CONTEXT *context)
{
EFI_STATUS efi_status;
UINT8 sha1hash[SHA1_DIGEST_SIZE];
UINT8 sha256hash[SHA256_DIGEST_SIZE];
/*
* The binary header contains relevant context and section pointers
*/
efi_status = read_header(data, datasize, context);
if (EFI_ERROR(efi_status)) {
perror(L"Failed to read header: %r\n", efi_status);
return efi_status;
}
/*
* Perform the image verification before we start copying data around
* in order to load it.
*/
if (secure_mode()) {
efi_status = verify_buffer(data, datasize,
context, sha256hash, sha1hash);
if (EFI_ERROR(efi_status)) {
if (verbose)
console_print(L"Verification failed: %r\n", efi_status);
else
console_error(L"Verification failed", efi_status);
return efi_status;
} else if (verbose)
console_print(L"Verification succeeded\n");
}
/*
* Calculate the hash for the TPM measurement.
* XXX: We're computing these twice in secure boot mode when the
* buffers already contain the previously computed hashes. Also,
* this is only useful for the TPM1.2 case. We should try to fix
* this in a follow-up.
*/
efi_status = generate_hash(data, datasize, context, sha256hash,
sha1hash);
if (EFI_ERROR(efi_status))
return efi_status;
/* Measure the binary into the TPM */
#ifdef REQUIRE_TPM
efi_status =
#endif
tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize,
(EFI_PHYSICAL_ADDRESS)(UINTN)context->ImageAddress,
li->FilePath, sha1hash, 4);
#ifdef REQUIRE_TPM
if (efi_status != EFI_SUCCESS) {
return efi_status;
}
#endif
return EFI_SUCCESS;
}
/* /*
* Once the image has been loaded it needs to be validated and relocated * Once the image has been loaded it needs to be validated and relocated
*/ */
@ -888,6 +1097,7 @@ handle_image (void *data, unsigned int datasize,
int i; int i;
EFI_IMAGE_SECTION_HEADER *Section; EFI_IMAGE_SECTION_HEADER *Section;
char *base, *end; char *base, *end;
UINT32 size;
PE_COFF_LOADER_IMAGE_CONTEXT context; PE_COFF_LOADER_IMAGE_CONTEXT context;
unsigned int alignment, alloc_size; unsigned int alignment, alloc_size;
int found_entry_point = 0; int found_entry_point = 0;
@ -904,7 +1114,31 @@ handle_image (void *data, unsigned int datasize,
} }
/* /*
* We only need to verify the binary if we're in secure mode * Perform the image verification before we start copying data around
* in order to load it.
*/
if (secure_mode ()) {
efi_status = verify_buffer(data, datasize, &context, sha256hash,
sha1hash);
if (EFI_ERROR(efi_status)) {
if (verbose)
console_print(L"Verification failed: %r\n", efi_status);
else
console_error(L"Verification failed", efi_status);
return efi_status;
} else {
if (verbose)
console_print(L"Verification succeeded\n");
}
}
/*
* Calculate the hash for the TPM measurement.
* XXX: We're computing these twice in secure boot mode when the
* buffers already contain the previously computed hashes. Also,
* this is only useful for the TPM1.2 case. We should try to fix
* this in a follow-up.
*/ */
efi_status = generate_hash(data, datasize, &context, sha256hash, efi_status = generate_hash(data, datasize, &context, sha256hash,
sha1hash); sha1hash);
@ -954,6 +1188,11 @@ handle_image (void *data, unsigned int datasize,
} }
buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment); buffer = (void *)ALIGN_VALUE((unsigned long)*alloc_address, alignment);
dprint(L"Loading 0x%llx bytes at 0x%llx\n",
(unsigned long long)context.ImageSize,
(unsigned long long)(uintptr_t)buffer);
update_mem_attrs((uintptr_t)buffer, alloc_size, MEM_ATTR_R|MEM_ATTR_W,
MEM_ATTR_X);
CopyMem(buffer, data, context.SizeOfHeaders); CopyMem(buffer, data, context.SizeOfHeaders);
@ -980,9 +1219,6 @@ handle_image (void *data, unsigned int datasize,
EFI_IMAGE_SECTION_HEADER *RelocSection = NULL; EFI_IMAGE_SECTION_HEADER *RelocSection = NULL;
char *SBATBase = NULL;
size_t SBATSize = 0;
/* /*
* Copy the executable's sections to their desired offsets * Copy the executable's sections to their desired offsets
*/ */
@ -993,6 +1229,20 @@ handle_image (void *data, unsigned int datasize,
!Section->Misc.VirtualSize) !Section->Misc.VirtualSize)
continue; continue;
/*
* Skip sections that aren't marked readable.
*/
if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_READ))
continue;
if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) &&
(Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) &&
(Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) &&
(mok_policy & MOK_POLICY_REQUIRE_NX)) {
perror(L"Section %d is writable and executable\n", i);
return EFI_UNSUPPORTED;
}
base = ImageAddress (buffer, context.ImageSize, base = ImageAddress (buffer, context.ImageSize,
Section->VirtualAddress); Section->VirtualAddress);
end = ImageAddress (buffer, context.ImageSize, end = ImageAddress (buffer, context.ImageSize,
@ -1027,33 +1277,6 @@ handle_image (void *data, unsigned int datasize,
RelocBaseEnd == end) { RelocBaseEnd == end) {
RelocSection = Section; RelocSection = Section;
} }
} else if (CompareMem(Section->Name, ".sbat\0\0\0", 8) == 0) {
if (SBATBase || SBATSize) {
perror(L"Image has multiple SBAT sections\n");
return EFI_UNSUPPORTED;
}
if (Section->NumberOfRelocations != 0 ||
Section->PointerToRelocations != 0) {
perror(L"SBAT section has relocations\n");
return EFI_UNSUPPORTED;
}
/* The virtual size corresponds to the size of the SBAT
* metadata and isn't necessarily a multiple of the file
* alignment. The on-disk size is a multiple of the file
* alignment and is zero padded. Make sure that the
* on-disk size is at least as large as virtual size,
* and ignore the section if it isn't. */
if (Section->SizeOfRawData &&
Section->SizeOfRawData >= Section->Misc.VirtualSize &&
base && end) {
SBATBase = base;
/* +1 because of size vs last byte location */
SBATSize = end - base + 1;
dprint(L"sbat section base:0x%lx size:0x%lx\n",
SBATBase, SBATSize);
}
} }
if (Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) { if (Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) {
@ -1084,32 +1307,15 @@ handle_image (void *data, unsigned int datasize,
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
if (Section->SizeOfRawData > 0) size = Section->Misc.VirtualSize;
CopyMem(base, data + Section->PointerToRawData, if (size > Section->SizeOfRawData)
Section->SizeOfRawData); size = Section->SizeOfRawData;
if (Section->SizeOfRawData < Section->Misc.VirtualSize) if (size > 0)
ZeroMem(base + Section->SizeOfRawData, CopyMem(base, data + Section->PointerToRawData, size);
Section->Misc.VirtualSize - Section->SizeOfRawData);
}
}
if (secure_mode ()) { if (size < Section->Misc.VirtualSize)
efi_status = handle_sbat(SBATBase, SBATSize); ZeroMem(base + size, Section->Misc.VirtualSize - size);
if (!EFI_ERROR(efi_status))
efi_status = verify_buffer(data, datasize,
&context, sha256hash, sha1hash);
if (EFI_ERROR(efi_status)) {
if (verbose)
console_print(L"Verification failed: %r\n", efi_status);
else
console_error(L"Verification failed", efi_status);
return efi_status;
} else {
if (verbose)
console_print(L"Verification succeeded\n");
} }
} }
@ -1133,6 +1339,50 @@ handle_image (void *data, unsigned int datasize,
} }
} }
/*
* Now set the page permissions appropriately.
*/
Section = context.FirstSection;
for (i = 0; i < context.NumberOfSections; i++, Section++) {
uint64_t set_attrs = MEM_ATTR_R;
uint64_t clear_attrs = MEM_ATTR_W|MEM_ATTR_X;
uintptr_t addr;
uint64_t length;
/*
* Skip discardable sections with zero size
*/
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) &&
!Section->Misc.VirtualSize)
continue;
/*
* Skip sections that aren't marked readable.
*/
if (!(Section->Characteristics & EFI_IMAGE_SCN_MEM_READ))
continue;
base = ImageAddress (buffer, context.ImageSize,
Section->VirtualAddress);
end = ImageAddress (buffer, context.ImageSize,
Section->VirtualAddress
+ Section->Misc.VirtualSize - 1);
addr = (uintptr_t)base;
length = (uintptr_t)end - (uintptr_t)base + 1;
if (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) {
set_attrs |= MEM_ATTR_W;
clear_attrs &= ~MEM_ATTR_W;
}
if (Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) {
set_attrs |= MEM_ATTR_X;
clear_attrs &= ~MEM_ATTR_X;
}
update_mem_attrs(addr, length, set_attrs, clear_attrs);
}
/* /*
* grub needs to know its location and size in memory, so fix up * grub needs to know its location and size in memory, so fix up
* the loaded image protocol values * the loaded image protocol values

View File

@ -11,6 +11,7 @@
#include <getopt.h> #include <getopt.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -41,6 +42,8 @@ static int verbosity;
0; \ 0; \
}) })
static bool set_nx_compat = false;
typedef uint8_t UINT8; typedef uint8_t UINT8;
typedef uint16_t UINT16; typedef uint16_t UINT16;
typedef uint32_t UINT32; typedef uint32_t UINT32;
@ -174,7 +177,7 @@ load_pe(const char *const file, void *const data, const size_t datasize,
} }
if (FileAlignment % 2 != 0) if (FileAlignment % 2 != 0)
errx(1, "%s: Invalid file alignment %ld", file, FileAlignment); errx(1, "%s: Invalid file alignment %zu", file, FileAlignment);
if (FileAlignment == 0) if (FileAlignment == 0)
FileAlignment = 0x200; FileAlignment = 0x200;
@ -190,7 +193,7 @@ load_pe(const char *const file, void *const data, const size_t datasize,
ctx->NumberOfRvaAndSizes, EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES); ctx->NumberOfRvaAndSizes, EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES);
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < ctx->NumberOfRvaAndSizes) if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < ctx->NumberOfRvaAndSizes)
errx(1, "%s: invalid number of RVAs (%lu entries, max is %d)", errx(1, "%s: invalid number of RVAs (%lu entries, max is %d)",
file, ctx->NumberOfRvaAndSizes, file, (unsigned long)ctx->NumberOfRvaAndSizes,
EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES); EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES);
if (mul(sizeof(EFI_IMAGE_DATA_DIRECTORY), if (mul(sizeof(EFI_IMAGE_DATA_DIRECTORY),
@ -233,12 +236,12 @@ load_pe(const char *const file, void *const data, const size_t datasize,
if (mul(ctx->NumberOfRvaAndSizes, if (mul(ctx->NumberOfRvaAndSizes,
sizeof(EFI_IMAGE_DATA_DIRECTORY), &sz1)) sizeof(EFI_IMAGE_DATA_DIRECTORY), &sz1))
debug(ERROR, debug(ERROR,
"ctx->NumberOfRvaAndSizes (%zu) * sizeof(EFI_IMAGE_DATA_DIRECTORY) overflows\n", "ctx->NumberOfRvaAndSizes (%ld) * sizeof(EFI_IMAGE_DATA_DIRECTORY) overflows\n",
ctx->NumberOfRvaAndSizes); (unsigned long)ctx->NumberOfRvaAndSizes);
else else
debug(ERROR, debug(ERROR,
"ctx->NumberOfRvaAndSizes (%zu) * sizeof(EFI_IMAGE_DATA_DIRECTORY) = %zu\n", "ctx->NumberOfRvaAndSizes (%ld) * sizeof(EFI_IMAGE_DATA_DIRECTORY) = %zu\n",
ctx->NumberOfRvaAndSizes, sz1); (unsigned long)ctx->NumberOfRvaAndSizes, sz1);
debug(ERROR, debug(ERROR,
"space after image header:%zu data directory size:%zu\n", "space after image header:%zu data directory size:%zu\n",
sz0, sz1); sz0, sz1);
@ -271,7 +274,7 @@ load_pe(const char *const file, void *const data, const size_t datasize,
if (sub(ctx->SizeOfHeaders, SectionHeaderOffset, &sz0) || if (sub(ctx->SizeOfHeaders, SectionHeaderOffset, &sz0) ||
div(sz0, EFI_IMAGE_SIZEOF_SECTION_HEADER, &sz0) || div(sz0, EFI_IMAGE_SIZEOF_SECTION_HEADER, &sz0) ||
(sz0 < ctx->NumberOfSections)) { (sz0 < ctx->NumberOfSections)) {
debug(ERROR, "(%zu - %zu) / %d >= %d\n", ctx->SizeOfHeaders, debug(ERROR, "(%zu - %zu) / %d >= %d\n", (size_t)ctx->SizeOfHeaders,
SectionHeaderOffset, EFI_IMAGE_SIZEOF_SECTION_HEADER, SectionHeaderOffset, EFI_IMAGE_SIZEOF_SECTION_HEADER,
ctx->NumberOfSections); ctx->NumberOfSections);
errx(1, "%s: image sections overflow section headers", file); errx(1, "%s: image sections overflow section headers", file);
@ -330,6 +333,33 @@ load_pe(const char *const file, void *const data, const size_t datasize,
errx(1, "%s: Security directory extends past end", file); errx(1, "%s: Security directory extends past end", file);
} }
static void
set_dll_characteristics(PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
{
uint16_t oldflags, newflags;
if (image_is_64_bit(ctx->PEHdr)) {
oldflags = ctx->PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics;
} else {
oldflags = ctx->PEHdr->Pe32.OptionalHeader.DllCharacteristics;
}
if (set_nx_compat)
newflags = oldflags | EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
else
newflags = oldflags & ~(uint16_t)EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
if (oldflags == newflags)
return;
debug(INFO, "Updating DLL Characteristics from 0x%04hx to 0x%04hx\n",
oldflags, newflags);
if (image_is_64_bit(ctx->PEHdr)) {
ctx->PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics = newflags;
} else {
ctx->PEHdr->Pe32.OptionalHeader.DllCharacteristics = newflags;
}
}
static void static void
fix_timestamp(PE_COFF_LOADER_IMAGE_CONTEXT *ctx) fix_timestamp(PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
{ {
@ -417,6 +447,8 @@ handle_one(char *f)
load_pe(f, map, sz, &ctx); load_pe(f, map, sz, &ctx);
set_dll_characteristics(&ctx);
fix_timestamp(&ctx); fix_timestamp(&ctx);
fix_checksum(&ctx, map, sz); fix_checksum(&ctx, map, sz);
@ -426,7 +458,7 @@ handle_one(char *f)
warn("msync(%p, %zu, MS_SYNC) failed", map, sz); warn("msync(%p, %zu, MS_SYNC) failed", map, sz);
failed = 1; failed = 1;
} }
munmap(map, sz); rc = munmap(map, sz);
if (rc < 0) { if (rc < 0) {
warn("munmap(%p, %zu) failed", map, sz); warn("munmap(%p, %zu) failed", map, sz);
failed = 1; failed = 1;
@ -449,6 +481,8 @@ static void __attribute__((__noreturn__)) usage(int status)
fprintf(out, "Options:\n"); fprintf(out, "Options:\n");
fprintf(out, " -q Be more quiet\n"); fprintf(out, " -q Be more quiet\n");
fprintf(out, " -v Be more verbose\n"); fprintf(out, " -v Be more verbose\n");
fprintf(out, " -N Disable the NX compatibility flag\n");
fprintf(out, " -n Enable the NX compatibility flag\n");
fprintf(out, " -h Print this help text and exit\n"); fprintf(out, " -h Print this help text and exit\n");
exit(status); exit(status);
@ -464,6 +498,12 @@ int main(int argc, char **argv)
{.name = "usage", {.name = "usage",
.val = '?', .val = '?',
}, },
{.name = "disable-nx-compat",
.val = 'N',
},
{.name = "enable-nx-compat",
.val = 'n',
},
{.name = "quiet", {.name = "quiet",
.val = 'q', .val = 'q',
}, },
@ -474,12 +514,18 @@ int main(int argc, char **argv)
}; };
int longindex = -1; int longindex = -1;
while ((i = getopt_long(argc, argv, "hqsv", options, &longindex)) != -1) { while ((i = getopt_long(argc, argv, "hNnqv", options, &longindex)) != -1) {
switch (i) { switch (i) {
case 'h': case 'h':
case '?': case '?':
usage(longindex == -1 ? 1 : 0); usage(longindex == -1 ? 1 : 0);
break; break;
case 'N':
set_nx_compat = false;
break;
case 'n':
set_nx_compat = true;
break;
case 'q': case 'q':
verbosity = MAX(verbosity - 1, MIN_VERBOSITY); verbosity = MAX(verbosity - 1, MIN_VERBOSITY);
break; break;

141
sbat.c
View File

@ -113,13 +113,14 @@ cleanup_sbat_section_entries(size_t n, struct sbat_section_entry **entries)
} }
EFI_STATUS EFI_STATUS
verify_single_entry(struct sbat_section_entry *entry, struct sbat_var_entry *sbat_var_entry) verify_single_entry(struct sbat_section_entry *entry, struct sbat_var_entry *sbat_var_entry, bool *found)
{ {
UINT16 sbat_gen, sbat_var_gen; UINT16 sbat_gen, sbat_var_gen;
if (strcmp((const char *)entry->component_name, (const char *)sbat_var_entry->component_name) == 0) { if (strcmp((const char *)entry->component_name, (const char *)sbat_var_entry->component_name) == 0) {
dprint(L"component %a has a matching SBAT variable entry, verifying\n", dprint(L"component %a has a matching SBAT variable entry, verifying\n",
entry->component_name); entry->component_name);
*found = true;
/* /*
* atoi returns zero for failed conversion, so essentially * atoi returns zero for failed conversion, so essentially
@ -172,10 +173,13 @@ verify_sbat_helper(list_t *local_sbat_var, size_t n, struct sbat_section_entry *
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
list_for_each(pos, local_sbat_var) { list_for_each(pos, local_sbat_var) {
bool found = false;
sbat_var_entry = list_entry(pos, struct sbat_var_entry, list); sbat_var_entry = list_entry(pos, struct sbat_var_entry, list);
efi_status = verify_single_entry(entries[i], sbat_var_entry); efi_status = verify_single_entry(entries[i], sbat_var_entry, &found);
if (EFI_ERROR(efi_status)) if (EFI_ERROR(efi_status))
goto out; goto out;
if (found)
break;
} }
} }
@ -285,6 +289,7 @@ parse_sbat_var(list_t *entries)
UINT8 *data = 0; UINT8 *data = 0;
UINTN datasize; UINTN datasize;
EFI_STATUS efi_status; EFI_STATUS efi_status;
list_t *pos = NULL;
if (!entries) { if (!entries) {
dprint(L"entries is NULL\n"); dprint(L"entries is NULL\n");
@ -301,7 +306,20 @@ parse_sbat_var(list_t *entries)
* We've intentionally made sure there's a NUL byte on all variable * We've intentionally made sure there's a NUL byte on all variable
* allocations, so use that here. * allocations, so use that here.
*/ */
return parse_sbat_var_data(entries, data, datasize+1); efi_status = parse_sbat_var_data(entries, data, datasize+1);
if (EFI_ERROR(efi_status))
return efi_status;
dprint(L"SBAT variable entries:\n");
list_for_each(pos, entries) {
struct sbat_var_entry *entry;
entry = list_entry(pos, struct sbat_var_entry, list);
dprint(L"%a, %a, %a\n", entry->component_name,
entry->component_generation, entry->sbat_datestamp);
}
return efi_status;
} }
static bool static bool
@ -315,12 +333,64 @@ check_sbat_var_attributes(UINT32 attributes)
#endif #endif
} }
bool static char *
preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes) nth_sbat_field(char *str, size_t limit, int n)
{ {
return check_sbat_var_attributes(attributes) && size_t i;
sbatsize >= strlen(SBAT_VAR_SIG "1") && for (i = 0; i < limit && str[i] != '\0'; i++) {
!strncmp((const char *)sbat, SBAT_VAR_SIG, strlen(SBAT_VAR_SIG)); if (n == 0)
return &str[i];
if (str[i] == ',')
n--;
}
return &str[i];
}
bool
preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes,
char *sbat_var)
{
char *sbatc = (char *)sbat;
char *current_version, *new_version,
*current_datestamp, *new_datestamp;
int current_version_len, new_version_len;
/* current metadata is not currupt somehow */
if (!check_sbat_var_attributes(attributes) ||
sbatsize < strlen(SBAT_VAR_ORIGINAL) ||
strncmp(sbatc, SBAT_VAR_SIG, strlen(SBAT_VAR_SIG)))
return false;
/* current metadata version not newer */
current_version = nth_sbat_field(sbatc, sbatsize, 1);
new_version = nth_sbat_field(sbat_var, strlen(sbat_var)+1, 1);
current_datestamp = nth_sbat_field(sbatc, sbatsize, 2);
new_datestamp = nth_sbat_field(sbat_var, strlen(sbat_var)+1, 2);
current_version_len = current_datestamp - current_version - 1;
new_version_len = new_datestamp - new_version - 1;
if (current_version_len > new_version_len ||
(current_version_len == new_version_len &&
strncmp(current_version, new_version, new_version_len) > 0))
return true;
/* current datestamp is not newer or idential */
if (strncmp(current_datestamp, new_datestamp,
strlen(SBAT_VAR_ORIGINAL_DATE)) >= 0)
return true;
return false;
}
static void
clear_sbat_policy()
{
EFI_STATUS efi_status = EFI_SUCCESS;
efi_status = del_variable(SBAT_POLICY, SHIM_LOCK_GUID);
if (EFI_ERROR(efi_status))
console_error(L"Could not reset SBAT Policy", efi_status);
} }
EFI_STATUS EFI_STATUS
@ -330,7 +400,49 @@ set_sbat_uefi_variable(void)
UINT32 attributes = 0; UINT32 attributes = 0;
UINT8 *sbat = NULL; UINT8 *sbat = NULL;
UINT8 *sbat_policy = NULL;
UINTN sbatsize = 0; UINTN sbatsize = 0;
UINTN sbat_policysize = 0;
char *sbat_var = NULL;
bool reset_sbat = false;
efi_status = get_variable_attr(SBAT_POLICY, &sbat_policy,
&sbat_policysize, SHIM_LOCK_GUID,
&attributes);
if (EFI_ERROR(efi_status)) {
dprint("Default sbat policy: previous\n");
sbat_var = SBAT_VAR_PREVIOUS;
} else {
switch (*sbat_policy) {
case SBAT_POLICY_LATEST:
dprint("Custom sbat policy: latest\n");
sbat_var = SBAT_VAR_LATEST;
clear_sbat_policy();
break;
case SBAT_POLICY_PREVIOUS:
dprint("Custom sbat policy: previous\n");
sbat_var = SBAT_VAR_PREVIOUS;
break;
case SBAT_POLICY_RESET:
if (secure_mode()) {
console_print(L"Cannot reset SBAT policy: Secure Boot is enabled.\n");
sbat_var = SBAT_VAR_PREVIOUS;
} else {
dprint(L"Custom SBAT policy: reset OK\n");
reset_sbat = true;
sbat_var = SBAT_VAR_ORIGINAL;
}
clear_sbat_policy();
break;
default:
console_error(L"SBAT policy state %llu is invalid",
EFI_INVALID_PARAMETER);
sbat_var = SBAT_VAR_PREVIOUS;
clear_sbat_policy();
break;
}
}
efi_status = get_variable_attr(SBAT_VAR_NAME, &sbat, &sbatsize, efi_status = get_variable_attr(SBAT_VAR_NAME, &sbat, &sbatsize,
SHIM_LOCK_GUID, &attributes); SHIM_LOCK_GUID, &attributes);
@ -342,8 +454,9 @@ set_sbat_uefi_variable(void)
*/ */
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
dprint(L"SBAT read failed %r\n", efi_status); dprint(L"SBAT read failed %r\n", efi_status);
} else if (preserve_sbat_uefi_variable(sbat, sbatsize, attributes)) { } else if (preserve_sbat_uefi_variable(sbat, sbatsize, attributes, sbat_var)
dprint(L"%s variable is %d bytes, attributes are 0x%08x\n", && !reset_sbat) {
dprint(L"preserving %s variable it is %d bytes, attributes are 0x%08x\n",
SBAT_VAR_NAME, sbatsize, attributes); SBAT_VAR_NAME, sbatsize, attributes);
FreePool(sbat); FreePool(sbat);
return EFI_SUCCESS; return EFI_SUCCESS;
@ -365,7 +478,7 @@ set_sbat_uefi_variable(void)
/* set variable */ /* set variable */
efi_status = set_variable(SBAT_VAR_NAME, SHIM_LOCK_GUID, SBAT_VAR_ATTRS, efi_status = set_variable(SBAT_VAR_NAME, SHIM_LOCK_GUID, SBAT_VAR_ATTRS,
sizeof(SBAT_VAR)-1, SBAT_VAR); strlen(sbat_var), sbat_var);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
dprint(L"%s variable writing failed %r\n", SBAT_VAR_NAME, dprint(L"%s variable writing failed %r\n", SBAT_VAR_NAME,
efi_status); efi_status);
@ -380,10 +493,10 @@ set_sbat_uefi_variable(void)
return efi_status; return efi_status;
} }
if (sbatsize != strlen(SBAT_VAR) || if (sbatsize != strlen(sbat_var) ||
strncmp((const char *)sbat, SBAT_VAR, strlen(SBAT_VAR)) != 0) { strncmp((const char *)sbat, sbat_var, strlen(sbat_var)) != 0) {
dprint("new sbatsize is %d, expected %d\n", sbatsize, dprint("new sbatsize is %d, expected %d\n", sbatsize,
strlen(SBAT_VAR)); strlen(sbat_var));
efi_status = EFI_INVALID_PARAMETER; efi_status = EFI_INVALID_PARAMETER;
} else { } else {
dprint(L"%s variable initialization succeeded\n", SBAT_VAR_NAME); dprint(L"%s variable initialization succeeded\n", SBAT_VAR_NAME);

260
shim.c
View File

@ -559,9 +559,9 @@ verify_one_signature(WIN_CERTIFICATE_EFI_PKCS *sig,
* Check that the signature is valid and matches the binary * Check that the signature is valid and matches the binary
*/ */
EFI_STATUS EFI_STATUS
verify_buffer (char *data, int datasize, verify_buffer_authenticode (char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context, PE_COFF_LOADER_IMAGE_CONTEXT *context,
UINT8 *sha256hash, UINT8 *sha1hash) UINT8 *sha256hash, UINT8 *sha1hash)
{ {
EFI_STATUS ret_efi_status; EFI_STATUS ret_efi_status;
size_t size = datasize; size_t size = datasize;
@ -695,6 +695,71 @@ verify_buffer (char *data, int datasize,
return ret_efi_status; return ret_efi_status;
} }
/*
* Check that the binary is permitted to load by SBAT.
*/
EFI_STATUS
verify_buffer_sbat (char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context)
{
int i;
EFI_IMAGE_SECTION_HEADER *Section;
char *SBATBase = NULL;
size_t SBATSize = 0;
Section = context->FirstSection;
for (i = 0; i < context->NumberOfSections; i++, Section++) {
if (CompareMem(Section->Name, ".sbat\0\0\0", 8) != 0)
continue;
if (SBATBase || SBATSize) {
perror(L"Image has multiple SBAT sections\n");
return EFI_UNSUPPORTED;
}
if (Section->NumberOfRelocations != 0 ||
Section->PointerToRelocations != 0) {
perror(L"SBAT section has relocations\n");
return EFI_UNSUPPORTED;
}
/* The virtual size corresponds to the size of the SBAT
* metadata and isn't necessarily a multiple of the file
* alignment. The on-disk size is a multiple of the file
* alignment and is zero padded. Make sure that the
* on-disk size is at least as large as virtual size,
* and ignore the section if it isn't. */
if (Section->SizeOfRawData &&
Section->SizeOfRawData >= Section->Misc.VirtualSize) {
SBATBase = ImageAddress(data, datasize,
Section->PointerToRawData);
SBATSize = Section->SizeOfRawData;
dprint(L"sbat section base:0x%lx size:0x%lx\n",
SBATBase, SBATSize);
}
}
return verify_sbat_section(SBATBase, SBATSize);
}
/*
* Check that the signature is valid and matches the binary and that
* the binary is permitted to load by SBAT.
*/
EFI_STATUS
verify_buffer (char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
UINT8 *sha256hash, UINT8 *sha1hash)
{
EFI_STATUS efi_status;
efi_status = verify_buffer_sbat(data, datasize, context);
if (EFI_ERROR(efi_status))
return efi_status;
return verify_buffer_authenticode(data, datasize, context, sha256hash, sha1hash);
}
static int static int
is_removable_media_path(EFI_LOADED_IMAGE *li) is_removable_media_path(EFI_LOADED_IMAGE *li)
{ {
@ -988,17 +1053,12 @@ restore_loaded_image(VOID)
/* /*
* Load and run an EFI executable * Load and run an EFI executable
*/ */
EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath) EFI_STATUS read_image(EFI_HANDLE image_handle, CHAR16 *ImagePath,
CHAR16 **PathName, void **data, int *datasize)
{ {
EFI_STATUS efi_status; EFI_STATUS efi_status;
EFI_IMAGE_ENTRY_POINT entry_point;
EFI_PHYSICAL_ADDRESS alloc_address;
UINTN alloc_pages;
CHAR16 *PathName = NULL;
void *sourcebuffer = NULL; void *sourcebuffer = NULL;
UINT64 sourcesize = 0; UINT64 sourcesize = 0;
void *data = NULL;
int datasize = 0;
/* /*
* We need to refer to the loaded image protocol on the running * We need to refer to the loaded image protocol on the running
@ -1014,11 +1074,11 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
/* /*
* Build a new path from the existing one plus the executable name * Build a new path from the existing one plus the executable name
*/ */
efi_status = generate_path_from_image_path(shim_li, ImagePath, &PathName); efi_status = generate_path_from_image_path(shim_li, ImagePath, PathName);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Unable to generate path %s: %r\n", ImagePath, perror(L"Unable to generate path %s: %r\n", ImagePath,
efi_status); efi_status);
goto done; return efi_status;
} }
if (findNetboot(shim_li->DeviceHandle)) { if (findNetboot(shim_li->DeviceHandle)) {
@ -1034,8 +1094,8 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
efi_status); efi_status);
return efi_status; return efi_status;
} }
data = sourcebuffer; *data = sourcebuffer;
datasize = sourcesize; *datasize = sourcesize;
} else if (find_httpboot(shim_li->DeviceHandle)) { } else if (find_httpboot(shim_li->DeviceHandle)) {
efi_status = httpboot_fetch_buffer (image_handle, efi_status = httpboot_fetch_buffer (image_handle,
&sourcebuffer, &sourcebuffer,
@ -1045,26 +1105,45 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
efi_status); efi_status);
return efi_status; return efi_status;
} }
data = sourcebuffer; *data = sourcebuffer;
datasize = sourcesize; *datasize = sourcesize;
} else { } else {
/* /*
* Read the new executable off disk * Read the new executable off disk
*/ */
efi_status = load_image(shim_li, &data, &datasize, PathName); efi_status = load_image(shim_li, data, datasize, *PathName);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Failed to load image %s: %r\n", perror(L"Failed to load image %s: %r\n",
PathName, efi_status); PathName, efi_status);
PrintErrors(); PrintErrors();
ClearErrors(); ClearErrors();
goto done; return efi_status;
} }
} }
if (datasize < 0) { if (*datasize < 0)
efi_status = EFI_INVALID_PARAMETER; efi_status = EFI_INVALID_PARAMETER;
return efi_status;
}
/*
* Load and run an EFI executable
*/
EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
{
EFI_STATUS efi_status;
EFI_IMAGE_ENTRY_POINT entry_point;
EFI_PHYSICAL_ADDRESS alloc_address;
UINTN alloc_pages;
CHAR16 *PathName = NULL;
void *data = NULL;
int datasize = 0;
efi_status = read_image(image_handle, ImagePath, &PathName, &data,
&datasize);
if (EFI_ERROR(efi_status))
goto done; goto done;
}
/* /*
* We need to modify the loaded image protocol entry before running * We need to modify the loaded image protocol entry before running
@ -1312,6 +1391,127 @@ uninstall_shim_protocols(void)
#endif #endif
} }
EFI_STATUS
load_cert_file(EFI_HANDLE image_handle, CHAR16 *filename, CHAR16 *PathName)
{
EFI_STATUS efi_status;
EFI_LOADED_IMAGE li;
PE_COFF_LOADER_IMAGE_CONTEXT context;
EFI_IMAGE_SECTION_HEADER *Section;
EFI_SIGNATURE_LIST *certlist;
void *pointer;
UINT32 original;
int datasize = 0;
void *data = NULL;
int i;
efi_status = read_image(image_handle, filename, &PathName,
&data, &datasize);
if (EFI_ERROR(efi_status))
return efi_status;
memset(&li, 0, sizeof(li));
memcpy(&li.FilePath[0], filename, MIN(StrSize(filename), sizeof(li.FilePath)));
efi_status = verify_image(data, datasize, &li, &context);
if (EFI_ERROR(efi_status))
return efi_status;
Section = context.FirstSection;
for (i = 0; i < context.NumberOfSections; i++, Section++) {
if (CompareMem(Section->Name, ".db\0\0\0\0\0", 8) == 0) {
original = user_cert_size;
if (Section->SizeOfRawData < sizeof(EFI_SIGNATURE_LIST)) {
continue;
}
pointer = ImageAddress(data, datasize,
Section->PointerToRawData);
if (!pointer) {
continue;
}
certlist = pointer;
user_cert_size += certlist->SignatureListSize;;
user_cert = ReallocatePool(user_cert, original,
user_cert_size);
memcpy(user_cert + original, pointer,
certlist->SignatureListSize);
}
}
FreePool(data);
return EFI_SUCCESS;
}
/* Read additional certificates from files (after verifying signatures) */
EFI_STATUS
load_certs(EFI_HANDLE image_handle)
{
EFI_STATUS efi_status;
EFI_LOADED_IMAGE *li = NULL;
CHAR16 *PathName = NULL;
EFI_FILE *root, *dir;
EFI_FILE_INFO *info;
EFI_HANDLE device;
EFI_FILE_IO_INTERFACE *drive;
UINTN buffersize = 0;
void *buffer = NULL;
efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
(void **)&li);
if (EFI_ERROR(efi_status)) {
perror(L"Unable to init protocol\n");
return efi_status;
}
efi_status = generate_path_from_image_path(li, L"", &PathName);
if (EFI_ERROR(efi_status))
goto done;
device = li->DeviceHandle;
efi_status = gBS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
(void **)&drive);
if (EFI_ERROR(efi_status)) {
perror(L"Failed to find fs: %r\n", efi_status);
goto done;
}
efi_status = drive->OpenVolume(drive, &root);
if (EFI_ERROR(efi_status)) {
perror(L"Failed to open fs: %r\n", efi_status);
goto done;
}
efi_status = root->Open(root, &dir, PathName, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR(efi_status)) {
perror(L"Failed to open %s - %r\n", PathName, efi_status);
goto done;
}
while (1) {
int old = buffersize;
efi_status = dir->Read(dir, &buffersize, buffer);
if (efi_status == EFI_BUFFER_TOO_SMALL) {
buffer = ReallocatePool(buffer, old, buffersize);
continue;
} else if (EFI_ERROR(efi_status)) {
perror(L"Failed to read directory %s - %r\n", PathName,
efi_status);
goto done;
}
info = (EFI_FILE_INFO *)buffer;
if (buffersize == 0 || !info)
goto done;
if (StrnCaseCmp(info->FileName, L"shim_certificate", 16) == 0) {
load_cert_file(image_handle, info->FileName, PathName);
}
}
done:
FreePool(buffer);
FreePool(PathName);
return efi_status;
}
EFI_STATUS EFI_STATUS
shim_init(void) shim_init(void)
{ {
@ -1385,17 +1585,10 @@ debug_hook(void)
register volatile UINTN x = 0; register volatile UINTN x = 0;
extern char _text, _data; extern char _text, _data;
const CHAR16 * const debug_var_name =
#ifdef ENABLE_SHIM_DEVEL
L"SHIM_DEVEL_DEBUG";
#else
L"SHIM_DEBUG";
#endif
if (x) if (x)
return; return;
efi_status = get_variable(debug_var_name, &data, &dataSize, efi_status = get_variable(DEBUG_VAR_NAME, &data, &dataSize,
SHIM_LOCK_GUID); SHIM_LOCK_GUID);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
return; return;
@ -1409,7 +1602,7 @@ debug_hook(void)
console_print(L"Pausing for debugger attachment.\n"); console_print(L"Pausing for debugger attachment.\n");
console_print(L"To disable this, remove the EFI variable %s-%g .\n", console_print(L"To disable this, remove the EFI variable %s-%g .\n",
debug_var_name, &SHIM_LOCK_GUID); DEBUG_VAR_NAME, &SHIM_LOCK_GUID);
x = 1; x = 1;
while (x++) { while (x++) {
/* Make this so it can't /totally/ DoS us. */ /* Make this so it can't /totally/ DoS us. */
@ -1542,7 +1735,7 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
goto die; goto die;
} }
efi_status = handle_sbat(sbat_start, sbat_end - sbat_start - 1); efi_status = verify_sbat_section(sbat_start, sbat_end - sbat_start - 1);
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
perror(L"Verifiying shim SBAT data failed: %r\n", perror(L"Verifiying shim SBAT data failed: %r\n",
efi_status); efi_status);
@ -1554,6 +1747,13 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
init_openssl(); init_openssl();
if (secure_mode()) {
efi_status = load_certs(global_image_handle);
if (EFI_ERROR(efi_status)) {
LogError(L"Failed to load addon certificates\n");
}
}
/* /*
* Before we do anything else, validate our non-volatile, * Before we do anything else, validate our non-volatile,
* boot-services-only state variables are what we think they are. * boot-services-only state variables are what we think they are.

19
shim.h
View File

@ -195,6 +195,10 @@
#include "Cryptlib/Include/OpenSslSupport.h" #include "Cryptlib/Include/OpenSslSupport.h"
#endif #endif
#define MEM_ATTR_R 4
#define MEM_ATTR_W 2
#define MEM_ATTR_X 1
INTERFACE_DECL(_SHIM_LOCK); INTERFACE_DECL(_SHIM_LOCK);
typedef typedef
@ -248,6 +252,9 @@ extern UINT8 *vendor_authorized;
extern UINT32 vendor_deauthorized_size; extern UINT32 vendor_deauthorized_size;
extern UINT8 *vendor_deauthorized; extern UINT8 *vendor_deauthorized;
extern UINT32 user_cert_size;
extern UINT8 *user_cert;
#if defined(ENABLE_SHIM_CERT) #if defined(ENABLE_SHIM_CERT)
extern UINT32 build_cert_size; extern UINT32 build_cert_size;
extern UINT8 *build_cert; extern UINT8 *build_cert;
@ -256,6 +263,8 @@ extern UINT8 *build_cert;
extern UINT8 user_insecure_mode; extern UINT8 user_insecure_mode;
extern UINT8 ignore_db; extern UINT8 ignore_db;
extern UINT8 trust_mok_list; extern UINT8 trust_mok_list;
extern UINT8 mok_policy;
extern UINT8 in_protocol; extern UINT8 in_protocol;
extern void *load_options; extern void *load_options;
extern UINT32 load_options_size; extern UINT32 load_options_size;
@ -284,6 +293,16 @@ verify_buffer (char *data, int datasize,
#define LogError(fmt, ...) #define LogError(fmt, ...)
#endif #endif
#ifdef ENABLE_SHIM_DEVEL
#define FALLBACK_VERBOSE_VAR_NAME L"FALLBACK_DEVEL_VERBOSE"
#define VERBOSE_VAR_NAME L"SHIM_DEVEL_VERBOSE"
#define DEBUG_VAR_NAME L"SHIM_DEVEL_DEBUG"
#else
#define FALLBACK_VERBOSE_VAR_NAME L"FALLBACK_VERBOSE"
#define VERBOSE_VAR_NAME L"SHIM_VERBOSE"
#define DEBUG_VAR_NAME L"SHIM_DEBUG"
#endif
char *translate_slashes(char *out, const char *str); char *translate_slashes(char *out, const char *str);
#endif /* SHIM_H_ */ #endif /* SHIM_H_ */

View File

@ -184,6 +184,10 @@ test_mok_mirror_0(void)
.data_size = sizeof(test_data_efivars_1_SbatLevelRT), .data_size = sizeof(test_data_efivars_1_SbatLevelRT),
.data = test_data_efivars_1_SbatLevelRT .data = test_data_efivars_1_SbatLevelRT
}, },
{.name = "MokListTrustedRT",
.data_size = sizeof(test_data_efivars_1_MokListTrustedRT),
.data = test_data_efivars_1_MokListTrustedRT
},
{.name = { 0, }, {.name = { 0, },
.data_size = 0, .data_size = 0,
.data = NULL, .data = NULL,

View File

@ -14,6 +14,11 @@
list_t sbat_var; list_t sbat_var;
BOOLEAN
secure_mode() {
return 1;
}
#if 0 #if 0
/* /*
* Mock test helpers * Mock test helpers
@ -965,11 +970,96 @@ err:
int int
test_preserve_sbat_uefi_variable_good(void) test_preserve_sbat_uefi_variable_good(void)
{ {
char sbat[] = "sbat,1,\ncomponent,2,\n"; char sbat[] = "sbat,1,2021030218\ncomponent,2,\n";
char sbatvar[] = "sbat,1,2021030218\ncomponent,2,\n";
size_t sbat_size = sizeof(sbat); size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS; UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes)) if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return 0;
else
return -1;
}
int
test_preserve_sbat_uefi_variable_version_newer(void)
{
char sbat[] = "sbat,2,2022030218\ncomponent,2,\n";
char sbatvar[] = "sbat,1,2021030218\ncomponent,2,\n";
size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return 0;
else
return -1;
}
int
test_preserve_sbat_uefi_variable_version_newerlonger(void)
{
char sbat[] = "sbat,10,2022030218\ncomponent,2,\n";
char sbatvar[] = "sbat,2,2021030218\ncomponent,2,\n";
size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return 0;
else
return -1;
}
int
test_preserve_sbat_uefi_variable_version_older(void)
{
char sbat[] = "sbat,1,2021030218\ncomponent,2,\n";
char sbatvar[] = "sbat,2,2022030218\ncomponent,2,\n";
size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return -1;
else
return 0;
}
int
test_preserve_sbat_uefi_variable_version_olderlonger(void)
{
char sbat[] = "sbat,2,2021030218\ncomponent,2,\n";
char sbatvar[] = "sbat,10,2022030218\ncomponent,2,\n";
size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return -1;
else
return 0;
}
int
test_preserve_sbat_uefi_variable_newer(void)
{
char sbat[] = "sbat,1,2021030218\ncomponent,2,\n";
char sbatvar[] = "sbat,1,2025030218\ncomponent,5,\ncomponent,3";
size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return -1;
else
return 0;
}
int
test_preserve_sbat_uefi_variable_older(void)
{
char sbat[] = "sbat,1,2025030218\ncomponent,2,\ncomponent,3";
char sbatvar[] = "sbat,1,2020030218\ncomponent,1,\n";
size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return 0; return 0;
else else
return -1; return -1;
@ -978,11 +1068,12 @@ test_preserve_sbat_uefi_variable_good(void)
int int
test_preserve_sbat_uefi_variable_bad_sig(void) test_preserve_sbat_uefi_variable_bad_sig(void)
{ {
char sbat[] = "bad_sig,1,\ncomponent,2,\n"; char sbat[] = "bad_sig,1,2021030218\ncomponent,2,\n";
char sbatvar[] = "sbat,1,2021030218\n";
size_t sbat_size = sizeof(sbat); size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS; UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes)) if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return -1; return -1;
else else
return 0; return 0;
@ -991,11 +1082,12 @@ test_preserve_sbat_uefi_variable_bad_sig(void)
int int
test_preserve_sbat_uefi_variable_bad_attr(void) test_preserve_sbat_uefi_variable_bad_attr(void)
{ {
char sbat[] = "sbat,1,\ncomponent,2,\n"; char sbat[] = "sbat,1,2021030218\ncomponent,2,\n";
char sbatvar[] = "sbat,1,2021030218\n";
size_t sbat_size = sizeof(sbat); size_t sbat_size = sizeof(sbat);
UINT32 attributes = 0; UINT32 attributes = 0;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes)) if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return -1; return -1;
else else
return 0; return 0;
@ -1005,10 +1097,11 @@ int
test_preserve_sbat_uefi_variable_bad_short(void) test_preserve_sbat_uefi_variable_bad_short(void)
{ {
char sbat[] = "sba"; char sbat[] = "sba";
char sbatvar[] = "sbat,1,2021030218\n";
size_t sbat_size = sizeof(sbat); size_t sbat_size = sizeof(sbat);
UINT32 attributes = SBAT_VAR_ATTRS; UINT32 attributes = SBAT_VAR_ATTRS;
if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes)) if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return -1; return -1;
else else
return 0; return 0;
@ -1052,9 +1145,15 @@ main(void)
test(test_parse_and_verify); test(test_parse_and_verify);
test(test_preserve_sbat_uefi_variable_good); test(test_preserve_sbat_uefi_variable_good);
test(test_preserve_sbat_uefi_variable_newer);
test(test_preserve_sbat_uefi_variable_older);
test(test_preserve_sbat_uefi_variable_bad_sig); test(test_preserve_sbat_uefi_variable_bad_sig);
test(test_preserve_sbat_uefi_variable_bad_attr); test(test_preserve_sbat_uefi_variable_bad_attr);
test(test_preserve_sbat_uefi_variable_bad_short); test(test_preserve_sbat_uefi_variable_bad_short);
test(test_preserve_sbat_uefi_variable_version_newer);
test(test_preserve_sbat_uefi_variable_version_newerlonger);
test(test_preserve_sbat_uefi_variable_version_older);
test(test_preserve_sbat_uefi_variable_version_olderlonger);
return 0; return 0;
} }

View File

@ -926,12 +926,15 @@ static int
test_strncpy(void) test_strncpy(void)
{ {
char s[] = "0123456789abcdef\0000"; char s[] = "0123456789abcdef\0000";
char s0[4096+4096]; char s0[4096];
char *s1 = &s0[4096]; char s1[4096];
memset(s0, 0, sizeof(s0)); memset(s0, 0, sizeof(s0));
memcpy(s0, s, sizeof(s)); memcpy(s0, s, sizeof(s));
#if __GNUC_PREREQ(8, 1)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstringop-truncation"
#endif
memset(s1, 0, 4096); memset(s1, 0, 4096);
assert_equal_return(strncpy(s1, s0, 0), s1, -1, "got %p expected %p\n"); assert_equal_return(strncpy(s1, s0, 0), s1, -1, "got %p expected %p\n");
assert_equal_return(strlen(s1), 0, -1, "got %d expected %d\n"); assert_equal_return(strlen(s1), 0, -1, "got %d expected %d\n");
@ -1030,7 +1033,9 @@ test_strncpy(void)
assert_equal_return(s1[16], '\000', -1, "got %#02hhx expected %02hhx\n"); assert_equal_return(s1[16], '\000', -1, "got %#02hhx expected %02hhx\n");
assert_equal_return(s1[17], '0', -1, "got %#02hhx expected %02hhx\n"); assert_equal_return(s1[17], '0', -1, "got %#02hhx expected %02hhx\n");
assert_equal_return(s1[18], '1', -1, "got %#02hhx expected %02hhx\n"); assert_equal_return(s1[18], '1', -1, "got %#02hhx expected %02hhx\n");
#if __GNUC_PREREQ(8, 1)
# pragma GCC diagnostic pop
#endif
return 0; return 0;
} }
@ -1038,12 +1043,12 @@ static int
test_strcat(void) test_strcat(void)
{ {
char s[] = "0123456789abcdef\0000"; char s[] = "0123456789abcdef\0000";
char s0[8192]; char s0[4096];
char *s1 = &s0[4096]; char s1[4096];
char *s2; char *s2;
char s3[] = "0123456789abcdef0123456789abcdef\000\000\000\000\000"; char s3[] = "0123456789abcdef0123456789abcdef\000\000\000\000\000";
memset(s0, 0, 8192); memset(s0, 0, sizeof(s0));
memcpy(s0, s, sizeof(s)); memcpy(s0, s, sizeof(s));
memset(s1, 0, 4096); memset(s1, 0, 4096);

6
test.c
View File

@ -259,6 +259,12 @@ console_print(const CHAR16 *fmt, ...)
return 0; return 0;
} }
void
console_error(CHAR16 *err, EFI_STATUS efi_status)
{
return;
}
#ifndef HAVE_START_IMAGE #ifndef HAVE_START_IMAGE
EFI_STATUS EFI_STATUS
start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath) start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)