name: ${{ matrix.distro }} ${{ matrix.efiarch }} cross-build
strategy:
+ fail-fast: false
matrix:
include:
- arch: amd64
efiarch: aa64
gccarch: aarch64
makearch: aarch64
- distro: f35
- - arch: amd64
- efiarch: aa64
- gccarch: aarch64
- makearch: aarch64
- distro: f34
+ distro: f36
- arch: amd64
efiarch: aa64
gccarch: aarch64
makearch: aarch64
- distro: f33
- - arch: amd64
- efiarch: aa64
- gccarch: aarch64
- makearch: aarch64
- distro: f32
- - arch: amd64
- efiarch: arm
- gccarch: arm
- makearch: arm
distro: f35
- arch: amd64
efiarch: arm
gccarch: arm
makearch: arm
- distro: f34
+ distro: f36
- arch: amd64
efiarch: arm
gccarch: arm
makearch: arm
- distro: f33
+ distro: f35
- arch: amd64
efiarch: arm
gccarch: arm
makearch: arm
- distro: f32
- - arch: amd64
- efiarch: x64
- gccarch: x86_64
- makearch: x86_64
- distro: f35
+ distro: f34
- arch: amd64
efiarch: x64
gccarch: x86_64
makearch: x86_64
- distro: f34
+ distro: f36
- arch: amd64
efiarch: x64
gccarch: x86_64
makearch: x86_64
- distro: f33
+ distro: f35
- arch: amd64
efiarch: x64
gccarch: x86_64
makearch: x86_64
- distro: f32
- - arch: amd64
- efiarch: ia32
- gccarch: x86_64
- makearch: ia32
- distro: f35
+ distro: f34
- arch: amd64
efiarch: ia32
gccarch: x86_64
makearch: ia32
- distro: f34
+ distro: f36
- arch: amd64
efiarch: ia32
gccarch: x86_64
makearch: ia32
- distro: f33
+ distro: f35
- arch: amd64
efiarch: ia32
gccarch: x86_64
makearch: ia32
- distro: f32
+ distro: f34
steps:
- name: Checkout
- arch: amd64
efiarch: x64
makearch: x86_64
- distro: f35
+ distro: f36
- arch: amd64
efiarch: x64
makearch: x86_64
- distro: f34
+ distro: f35
- arch: amd64
efiarch: x64
makearch: x86_64
- distro: f33
+ distro: f34
- arch: amd64
efiarch: x64
makearch: x86_64
- distro: f32
+ distro: centos9
- arch: amd64
efiarch: x64
makearch: x86_64
- arch: amd64
efiarch: ia32
makearch: ia32
- distro: f35
+ distro: f36
- arch: amd64
efiarch: ia32
makearch: ia32
- distro: f34
- - arch: amd64
- efiarch: ia32
- makearch: ia32
- distro: f33
+ distro: f35
- arch: amd64
efiarch: ia32
makearch: ia32
- distro: f32
+ distro: f34
- arch: amd64
efiarch: ia32
makearch: ia32
[submodule "gnu-efi"]
path = gnu-efi
url = https://github.com/rhboot/gnu-efi.git
- branch = shim-15.5
+ branch = shim-15.6
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
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
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
--- /dev/null
+
+# 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
+
ARCH_GNUEFI ?= aarch64
ARCH_SUFFIX ?= aa64
ARCH_SUFFIX_UPPER ?= AA64
- FORMAT := -O binary
- SUBSYSTEM := 0xa
- ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
+ ARCH_LDFLAGS ?=
ARCH_CFLAGS ?=
endif
ifeq ($(ARCH),arm)
$(eval override $(1)+=$(x)))))
endef
+%.o : %.S
+ $(CC) $(CFLAGS) -c -o $@ $<
+
# vim:filetype=make
default : all
NAME = shim
-VERSION = 15.5
+VERSION = 15.6
ifneq ($(origin RELEASE),undefined)
DASHRELEASE ?= -$(RELEASE)
else
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
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
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
endif
shim.o: $(wildcard $(TOPDIR)/*.h)
-cert.o : $(TOPDIR)/cert.S
- $(CC) $(CFLAGS) -c -o $@ $<
-
sbat.%.csv : data/sbat.%.csv
$(DOS2UNIX) $(D2UFLAGS) $< $@
tail -c1 $@ | read -r _ || echo >> $@ # ensure a trailing newline
mkdir -p gnu-efi/lib gnu-efi/gnuefi
$(MAKE) -C gnu-efi \
COMPILER="$(COMPILER)" \
+ CCC_CC="$(COMPILER)" \
CC="$(CC)" \
ARCH=$(ARCH_GNUEFI) \
TOPDIR=$(TOPDIR)/gnu-efi \
LibDeleteVariable(L"MokListTrustedNew", &SHIM_LOCK_GUID);
return EFI_ABORTED;
}
-
if (var->MokTMLState == 0) {
efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS,
- 1, &dbval);
+ 0, NULL);
if (EFI_ERROR(efi_status)) {
- console_notify(L"Failed to set MokListTrusted state");
+ console_notify(L"Failed to delete MokListTrusted state");
return efi_status;
}
} else {
efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS,
- 0, NULL);
+ 1, &dbval);
if (EFI_ERROR(efi_status)) {
- console_notify(L"Failed to delete MokListTrusted state");
+ console_notify(L"Failed to set MokListTrusted state");
return efi_status;
}
}
-
return EFI_SUCCESS;
}
-f2c598bb2218da966872ba3e0c6e7e830dca6ef0
\ No newline at end of file
+505cdb678b319fcf9a7fdee77c0f091b4147cbe5
\ No newline at end of file
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
ENTRY(_start)
SECTIONS
{
- .text 0x0 : {
- _text = .;
- *(.text.head)
- *(.text)
- *(.text.*)
- *(.gnu.linkonce.t.*)
- _evtext = .;
- . = ALIGN(4096);
+ . = 0;
+ ImageBase = .;
+ .hash : { *(.hash) } /* this MUST come first! */
+ . = ALIGN(4096);
+ .eh_frame :
+ {
+ *(.eh_frame)
+ }
+ . = 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);
.data :
{
_data = .;
- *(.sdata)
- *(.data)
- *(.data1)
- *(.data.*)
+ *(.rodata*)
*(.got.plt)
*(.got)
-
- *(.dynamic)
-
+ *(.data*)
+ *(.sdata)
/* the EFI loader doesn't seem to like a .bss section, so we stick
it all into .data: */
- . = ALIGN(16);
- _bss = .;
*(.sbss)
*(.scommon)
*(.dynbss)
*(.bss)
*(COMMON)
- _evdata = .;
- . = ALIGN(4096);
- _bss_end = .;
+ *(.rel.local)
}
- _edata = .;
- _data_vsize = _evdata - _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);
- .sbat :
+ .vendor_cert :
{
- _sbat = .;
- *(.sbat)
- *(.sbat.*)
- _esbat = .;
- . = ALIGN(4096);
- _epsbat = .;
+ *(.vendor_cert)
}
- _sbat_size = _epsbat - _sbat;
- _sbat_vsize = _esbat - _sbat;
-
. = ALIGN(4096);
- .rodata :
- {
- _rodata = .;
- *(.rodata*)
- *(.srodata)
- . = ALIGN(16);
- *(.note.gnu.build-id)
- . = ALIGN(4096);
- *(.vendor_cert)
- *(.data.ident)
- . = ALIGN(4096);
- }
+ .dynamic : { *(.dynamic) }
. = ALIGN(4096);
.rela :
{
- *(.rela.dyn)
- *(.rela.plt)
- *(.rela.got)
- *(.rela.data)
*(.rela.data*)
+ *(.rela.got*)
+ *(.rela.stab*)
}
+ _edata = .;
+ _data_size = . - _data;
. = ALIGN(4096);
- .dyn :
+ .sbat :
{
- *(.dynsym)
- *(.dynstr)
- _evrodata = .;
- . = ALIGN(4096);
+ _sbat = .;
+ *(.sbat)
+ *(.sbat.*)
}
- _erodata = .;
- _rodata_size = . - _rodata;
- _rodata_vsize = _evrodata - _rodata;
- _alldata_size = . - _data;
+ _esbat = .;
+ _sbat_size = . - _sbat;
- /DISCARD/ :
+ . = ALIGN(4096);
+ .dynsym : { *(.dynsym) }
+ . = ALIGN(4096);
+ .dynstr : { *(.dynstr) }
+ . = ALIGN(4096);
+ .ignored.reloc :
{
- *(.rel.reloc)
+ *(.rela.reloc)
*(.eh_frame)
*(.note.GNU-stack)
}
.comment 0 : { *(.comment) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
}
if (state != -1)
return state;
- efi_status = get_variable(L"FALLBACK_VERBOSE",
+ efi_status = get_variable(FALLBACK_VERBOSE_VAR_NAME,
&data, &dataSize, SHIM_LOCK_GUID);
if (EFI_ERROR(efi_status)) {
state = 0;
register volatile int x = 0;
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);
if (EFI_ERROR(efi_status)) {
return;
UINT32 vendor_deauthorized_size = 0;
UINT8 *vendor_deauthorized = NULL;
+UINT32 user_cert_size;
+UINT8 *user_cert;
+
#if defined(ENABLE_SHIM_CERT)
UINT32 build_cert_size;
UINT8 *build_cert;
UINT8 user_insecure_mode;
UINT8 ignore_db;
UINT8 trust_mok_list;
+UINT8 mok_policy = 0;
UINT32 verbose = 0;
# Set HAVE_EFI_OBJCOPY if objcopy understands --target efi-[app|bsdrv|rtdrv],
# otherwise we need to compose the PE/COFF header using the assembler
#
-ifneq ($(ARCH),aarch64)
ifneq ($(ARCH),arm)
ifneq ($(ARCH),mips64el)
export HAVE_EFI_OBJCOPY=y
endif
endif
-endif
ifeq ($(ARCH),arm)
CFLAGS += -marm
* 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
+
+ .globl _start
_start:
stp x29, x30, [sp, #-32]!
mov x29, sp
0: ldp x29, x30, [sp], #32
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
.data
.dummy0:
.dummy1:
- .long 0
+ .4byte 0
#define IMAGE_REL_ABSOLUTE 0
.section .reloc, "a"
- .long .dummy1-.dummy0 // Page RVA
- .long 10 // Block Size (2*4+2)
- .word (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
+ .4byte .dummy1-.dummy0 // Page RVA
+ .4byte 10 // Block Size (2*4+2)
+ .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
call efi_main
addq $8, %rsp
-.exit:
ret
// hand-craft a dummy .reloc section so EFI knows it's a relocatable executable:
.data
.dummy0:
.dummy1:
- .long 0
+ .4byte 0
#define IMAGE_REL_ABSOLUTE 0
.section .reloc, "a"
- .long .dummy1-.dummy0 // Page RVA
- .long 10 // Block Size (2*4+2)
- .word (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
-
+ .4byte .dummy1-.dummy0 // Page RVA
+ .4byte 10 // Block Size (2*4+2)
+ .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
#define EFI_MEMORY_WC 0x0000000000000002
#define EFI_MEMORY_WT 0x0000000000000004
#define EFI_MEMORY_WB 0x0000000000000008
-#define EFI_MEMORY_UCE 0x0000000000000010
-
-// physical memory protection on range
+#define EFI_MEMORY_UCE 0x0000000000000010
#define EFI_MEMORY_WP 0x0000000000001000
+
+// physical memory protection on range
#define EFI_MEMORY_RP 0x0000000000002000
#define EFI_MEMORY_XP 0x0000000000004000
+#define EFI_MEMORY_RO 0x0000000000020000
// range requires a runtime mapping
#define EFI_MEMORY_RUNTIME 0x8000000000000000
EFI_EBC_GET_VERSION GetVersion;
} 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
#define ALIAS(x) __attribute__((weak, alias (#x)))
#endif
#ifndef ALLOCFUNC
+#if defined(__COVERITY__)
+#define ALLOCFUNC(a, b)
+#else
#define ALLOCFUNC(dealloc, dealloc_arg) __attribute__((__malloc__(dealloc, dealloc_arg)))
#endif
+#endif
#ifndef PRINTF
#define PRINTF(first, args...) __attribute__((__format__(printf, first, ## args)))
#endif
extern EFI_GUID EFI_SIMPLE_FILE_SYSTEM_GUID;
extern EFI_GUID SECURITY_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 MOK_VARIABLE_STORE;
#endif /* SHIM_GUID_H */
UINT8 **addend;
UINT32 *addend_size;
+ UINT8 **user_cert;
+ UINT32 *user_cert_size;
+
/*
* build_cert is our build-time cert. Like addend, this is added
* to the input variable, as part of the runtime variable, so that
UINT8 data[];
};
+/*
+ * bit definitions for MokPolicy
+ */
+#define MOK_POLICY_REQUIRE_NX 1
+
#endif /* !SHIM_MOK_H_ */
// vim:fenc=utf-8:tw=75:noet
read_header(void *data, unsigned int datasize,
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
-handle_sbat(char *SBATBase, size_t SBATSize);
+verify_sbat_section(char *SBATBase, size_t SBATSize);
EFI_STATUS
handle_image (void *data, unsigned int datasize,
\r
#include "wincert.h"\r
\r
-#define SIGNATURE_16(A, B) ((A) | (B << 8))\r
-#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))\r
-#define SIGNATURE_64(A, B, C, D, E, F, G, H) \\r
- (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32))\r
+#define SIGNATURE_16(A, B) \\r
+ ((UINT16)(((UINT16)(A)) | (((UINT16)(B)) << ((UINT16)8))))\r
+#define SIGNATURE_32(A, B, C, D) \\r
+ ((UINT32)(((UINT32)SIGNATURE_16(A, B)) | \\r
+ (((UINT32)SIGNATURE_16(C, D)) << (UINT32)16)))\r
+#define SIGNATURE_64(A, B, C, D, E, F, G, H) \\r
+ ((UINT64)((UINT64)SIGNATURE_32(A, B, C, D) | \\r
+ ((UINT64)(SIGNATURE_32(E, F, G, H)) << (UINT64)32)))\r
\r
#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))\r
#define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment))))\r
EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];\r
} EFI_IMAGE_OPTIONAL_HEADER64;\r
\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0001 0x0001\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0002 0x0002\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0004 0x0004\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0008 0x0008\r
+#if 0 /* This is not in the PE spec. */\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_RESERVED_0010 0x0010\r
+#endif\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000\r
+#define EFI_IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000\r
\r
///\r
/// @attention\r
//\r
// Section Flags Values\r
//\r
-#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 ///< Reserved.\r
+#define EFI_IMAGE_SCN_RESERVED_00000000 0x00000000\r
+#define EFI_IMAGE_SCN_RESERVED_00000001 0x00000001\r
+#define EFI_IMAGE_SCN_RESERVED_00000002 0x00000002\r
+#define EFI_IMAGE_SCN_RESERVED_00000004 0x00000004\r
+#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008\r
+#define EFI_IMAGE_SCN_RESERVED_00000010 0x00000010\r
#define EFI_IMAGE_SCN_CNT_CODE 0x00000020\r
#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040\r
#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080\r
-\r
-#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 ///< Reserved.\r
-#define EFI_IMAGE_SCN_LNK_INFO 0x00000200 ///< Section contains comments or some other type of information.\r
-#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 ///< Section contents will not become part of image.\r
+#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100\r
+#define EFI_IMAGE_SCN_LNK_INFO 0x00000200\r
+#define EFI_IMAGE_SCN_RESERVED_00000400 0x00000400\r
+#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800\r
#define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000\r
-\r
+#define EFI_IMAGE_SCN_RESERVED_00002000 0x00002000\r
+#define EFI_IMAGE_SCN_RESERVED_00004000 0x00004000\r
+#define EFI_IMAGE_SCN_GPREL 0x00008000\r
+/*\r
+ * PE 9.3 says both IMAGE_SCN_MEM_PURGEABLE and IMAGE_SCN_MEM_16BIT are\r
+ * 0x00020000, but I think it's wrong. --pjones\r
+ */\r
+#define EFI_IMAGE_SCN_MEM_PURGEABLE 0x00010000 // "Reserved for future use."\r
+#define EFI_IMAGE_SCN_MEM_16BIT 0x00020000 // "Reserved for future use."\r
+#define EFI_IMAGE_SCN_MEM_LOCKED 0x00040000 // "Reserved for future use."\r
+#define EFI_IMAGE_SCN_MEM_PRELOAD 0x00080000 // "Reserved for future use."\r
#define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000\r
#define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000\r
#define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000\r
#define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000\r
#define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000\r
#define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000\r
-\r
+#define EFI_IMAGE_SCN_ALIGN_128BYTES 0x00800000\r
+#define EFI_IMAGE_SCN_ALIGN_256BYTES 0x00900000\r
+#define EFI_IMAGE_SCN_ALIGN_512BYTES 0x00a00000\r
+#define EFI_IMAGE_SCN_ALIGN_1024BYTES 0x00b00000\r
+#define EFI_IMAGE_SCN_ALIGN_2048BYTES 0x00c00000\r
+#define EFI_IMAGE_SCN_ALIGN_4096BYTES 0x00d00000\r
+#define EFI_IMAGE_SCN_ALIGN_8192BYTES 0x00e00000\r
+#define EFI_IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000\r
#define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000\r
#define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000\r
#define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000\r
#define SBAT_VAR_SIG "sbat,"
#define SBAT_VAR_VERSION "1,"
-#define SBAT_VAR_DATE "2021030218"
-#define SBAT_VAR SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_DATE "\n"
+#define SBAT_VAR_ORIGINAL_DATE "2021030218"
+#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 \
(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)
#define SBAT_VAR_ATTRS UEFI_VAR_NV_BS
#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;
struct sbat_var_entry {
EFI_STATUS parse_sbat_var(list_t *entries);
void cleanup_sbat_var(list_t *entries);
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 {
const CHAR8 *component_name;
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_ */
// vim:fenc=utf-8:tw=75:noet
# of the "include" directory
CFLAGS += -isystem $(shell $(CC) $(ARCH_CFLAGS) -print-file-name=include-fixed)
+# And on Debian also check the multi-arch include path
+CFLAGS += -isystem /usr/include/$(shell $(CC) $(ARCH_CFLAGS) -print-multiarch)
+
export CFLAGS_LTO CFLAGS_GCOV
libefi-test.a :
$(INCLUDES) \
$(DEFINES)
+ifneq ($(origin ENABLE_SHIM_DEVEL),undefined)
+CFLAGS += -DENABLE_SHIM_DEVEL
+endif
+
lib.a: $(LIBFILES)
$(AR) rcs lib.a $(LIBFILES)
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
console_print_box_at(CHAR16 *str_arr[], int highlight,
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
UINTN rows, cols;
CHAR16 *Line;
+ bool char_set;
if (lines == 0)
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;
+
+ SetMem16 (Line, size_cols * 2, boxdraw[char_set].horizontal);
- Line[0] = BOXDRAW_DOWN_RIGHT;
- 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';
co->SetCursorPosition(co, start_col, start_row);
co->OutputString(co, Line);
int line = i - start;
SetMem16 (Line, size_cols*2, L' ');
- Line[0] = BOXDRAW_VERTICAL;
- Line[size_cols - 1] = BOXDRAW_VERTICAL;
+ Line[0] = boxdraw[char_set].vertical;
+ Line[size_cols - 1] = boxdraw[char_set].vertical;
Line[size_cols] = L'\0';
if (line >= 0 && line < lines) {
CHAR16 *s = str_arr[line];
EFI_BACKGROUND_BLUE);
}
- SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
- Line[0] = BOXDRAW_UP_RIGHT;
- Line[size_cols - 1] = BOXDRAW_UP_LEFT;
+ SetMem16 (Line, size_cols * 2, boxdraw[char_set].horizontal);
+ Line[0] = boxdraw[char_set].up_right;
+ Line[size_cols - 1] = boxdraw[char_set].up_left;
Line[size_cols] = L'\0';
co->SetCursorPosition(co, start_col, i);
co->OutputString(co, Line);
efi_status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
if (EFI_ERROR(efi_status)) {
- console_error(L"Locate graphic output protocol fail", efi_status);
return;
}
UINTN verbose_check_size;
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);
if (!EFI_ERROR(efi_status)) {
verbose = *(__typeof__(verbose) *)verbose_check_ptr;
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 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 MOK_VARIABLE_STORE = {0xc451ed2b, 0x9694, 0x45d3, {0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89} };
static bool
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);
}
#define MOK_MIRROR_DELETE_FIRST 0x02
#define MOK_VARIABLE_MEASURE 0x04
#define MOK_VARIABLE_LOG 0x08
+#define MOK_VARIABLE_INVERSE 0x10
struct mok_state_variable mok_state_variable_data[] = {
{.name = L"MokList",
.categorize_addend = categorize_authorized,
.addend = &vendor_authorized,
.addend_size = &vendor_authorized_size,
+ .user_cert = &user_cert,
+ .user_cert_size = &user_cert_size,
#if defined(ENABLE_SHIM_CERT)
.build_cert = &build_cert,
.build_cert_size = &build_cert_size,
.no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
.flags = MOK_MIRROR_DELETE_FIRST |
MOK_VARIABLE_MEASURE |
+ MOK_VARIABLE_INVERSE |
MOK_VARIABLE_LOG,
.pcr = 14,
.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, }
};
size_t n_mok_state_variables = sizeof(mok_state_variable_data) / sizeof(mok_state_variable_data[0]);
dprint(L"FullDataSize:0x%lx FullData:0x%llx\n",
FullDataSize, FullData);
}
-
+ if (v->user_cert_size)
+ FullDataSize += *v->user_cert_size;
}
/*
dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
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;
+ }
}
/*
efi_status = get_variable_attr(v->name,
&v->data, &v->data_size,
*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_size = 0;
} else if (EFI_ERROR(efi_status)) {
attrs, v->no_attr);
delete = TRUE;
}
+ if (v->flags & MOK_VARIABLE_INVERSE) {
+ FreePool(v->data);
+ v->data = NULL;
+ v->data_size = 0;
+ }
}
}
if (delete == TRUE) {
EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
unsigned long FileAlignment = 0;
+ UINT16 DllFlags;
if (datasize < sizeof (PEHdr->Pe32)) {
perror(L"Invalid image\n");
context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint;
context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
context->SecDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+ DllFlags = PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics;
} else {
context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase;
context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
context->SecDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+ DllFlags = PEHdr->Pe32.OptionalHeader.DllCharacteristics;
}
+ if ((mok_policy & MOK_POLICY_REQUIRE_NX) &&
+ !(DllFlags & EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT)) {
+ perror(L"Policy requires NX, but image does not support NX\n");
+ return EFI_UNSUPPORTED;
+ }
+
context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER));
if (context->ImageSize < context->SizeOfHeaders) {
}
EFI_STATUS
-handle_sbat(char *SBATBase, size_t SBATSize)
+verify_sbat_section(char *SBATBase, size_t SBATSize)
{
unsigned int i;
EFI_STATUS efi_status;
if (SBATBase == NULL || SBATSize == 0) {
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;
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
*/
int i;
EFI_IMAGE_SECTION_HEADER *Section;
char *base, *end;
+ UINT32 size;
PE_COFF_LOADER_IMAGE_CONTEXT context;
unsigned int alignment, alloc_size;
int found_entry_point = 0;
}
/*
- * 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,
sha1hash);
}
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);
EFI_IMAGE_SECTION_HEADER *RelocSection = NULL;
- char *SBATBase = NULL;
- size_t SBATSize = 0;
-
/*
* Copy the executable's sections to their desired offsets
*/
!Section->Misc.VirtualSize)
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,
Section->VirtualAddress);
end = ImageAddress (buffer, context.ImageSize,
RelocBaseEnd == end) {
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) {
return EFI_UNSUPPORTED;
}
- if (Section->SizeOfRawData > 0)
- CopyMem(base, data + Section->PointerToRawData,
- Section->SizeOfRawData);
-
- if (Section->SizeOfRawData < Section->Misc.VirtualSize)
- ZeroMem(base + Section->SizeOfRawData,
- Section->Misc.VirtualSize - Section->SizeOfRawData);
- }
- }
-
- if (secure_mode ()) {
- efi_status = handle_sbat(SBATBase, SBATSize);
+ size = Section->Misc.VirtualSize;
+ if (size > Section->SizeOfRawData)
+ size = Section->SizeOfRawData;
- if (!EFI_ERROR(efi_status))
- efi_status = verify_buffer(data, datasize,
- &context, sha256hash, sha1hash);
+ if (size > 0)
+ CopyMem(base, data + Section->PointerToRawData, size);
- 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");
+ if (size < Section->Misc.VirtualSize)
+ ZeroMem(base + size, Section->Misc.VirtualSize - size);
}
}
}
}
+ /*
+ * 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
* the loaded image protocol values
#include <getopt.h>
#include <inttypes.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
0; \
})
+static bool set_nx_compat = false;
+
typedef uint8_t UINT8;
typedef uint16_t UINT16;
typedef uint32_t UINT32;
}
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)
FileAlignment = 0x200;
ctx->NumberOfRvaAndSizes, EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES);
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < ctx->NumberOfRvaAndSizes)
errx(1, "%s: invalid number of RVAs (%lu entries, max is %d)",
- file, ctx->NumberOfRvaAndSizes,
+ file, (unsigned long)ctx->NumberOfRvaAndSizes,
EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES);
if (mul(sizeof(EFI_IMAGE_DATA_DIRECTORY),
if (mul(ctx->NumberOfRvaAndSizes,
sizeof(EFI_IMAGE_DATA_DIRECTORY), &sz1))
debug(ERROR,
- "ctx->NumberOfRvaAndSizes (%zu) * sizeof(EFI_IMAGE_DATA_DIRECTORY) overflows\n",
- ctx->NumberOfRvaAndSizes);
+ "ctx->NumberOfRvaAndSizes (%ld) * sizeof(EFI_IMAGE_DATA_DIRECTORY) overflows\n",
+ (unsigned long)ctx->NumberOfRvaAndSizes);
else
debug(ERROR,
- "ctx->NumberOfRvaAndSizes (%zu) * sizeof(EFI_IMAGE_DATA_DIRECTORY) = %zu\n",
- ctx->NumberOfRvaAndSizes, sz1);
+ "ctx->NumberOfRvaAndSizes (%ld) * sizeof(EFI_IMAGE_DATA_DIRECTORY) = %zu\n",
+ (unsigned long)ctx->NumberOfRvaAndSizes, sz1);
debug(ERROR,
"space after image header:%zu data directory size:%zu\n",
sz0, sz1);
if (sub(ctx->SizeOfHeaders, SectionHeaderOffset, &sz0) ||
div(sz0, EFI_IMAGE_SIZEOF_SECTION_HEADER, &sz0) ||
(sz0 < ctx->NumberOfSections)) {
- debug(ERROR, "(%zu - %zu) / %d >= %d\n", ctx->SizeOfHeaders,
+ debug(ERROR, "(%zu - %zu) / %d >= %d\n", (size_t)ctx->SizeOfHeaders,
SectionHeaderOffset, EFI_IMAGE_SIZEOF_SECTION_HEADER,
ctx->NumberOfSections);
errx(1, "%s: image sections overflow section headers", 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
fix_timestamp(PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
{
load_pe(f, map, sz, &ctx);
+ set_dll_characteristics(&ctx);
+
fix_timestamp(&ctx);
fix_checksum(&ctx, map, sz);
warn("msync(%p, %zu, MS_SYNC) failed", map, sz);
failed = 1;
}
- munmap(map, sz);
+ rc = munmap(map, sz);
if (rc < 0) {
warn("munmap(%p, %zu) failed", map, sz);
failed = 1;
fprintf(out, "Options:\n");
fprintf(out, " -q Be more quiet\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");
exit(status);
{.name = "usage",
.val = '?',
},
+ {.name = "disable-nx-compat",
+ .val = 'N',
+ },
+ {.name = "enable-nx-compat",
+ .val = 'n',
+ },
{.name = "quiet",
.val = 'q',
},
};
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) {
case 'h':
case '?':
usage(longindex == -1 ? 1 : 0);
break;
+ case 'N':
+ set_nx_compat = false;
+ break;
+ case 'n':
+ set_nx_compat = true;
+ break;
case 'q':
verbosity = MAX(verbosity - 1, MIN_VERBOSITY);
break;
}
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;
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",
entry->component_name);
+ *found = true;
/*
* atoi returns zero for failed conversion, so essentially
for (i = 0; i < n; i++) {
list_for_each(pos, local_sbat_var) {
+ bool found = false;
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))
goto out;
+ if (found)
+ break;
}
}
UINT8 *data = 0;
UINTN datasize;
EFI_STATUS efi_status;
+ list_t *pos = NULL;
if (!entries) {
dprint(L"entries is NULL\n");
* We've intentionally made sure there's a NUL byte on all variable
* 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
#endif
}
+static char *
+nth_sbat_field(char *str, size_t limit, int n)
+{
+ size_t i;
+ for (i = 0; i < limit && str[i] != '\0'; i++) {
+ if (n == 0)
+ return &str[i];
+ if (str[i] == ',')
+ n--;
+ }
+ return &str[i];
+}
+
bool
-preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes)
+preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes,
+ char *sbat_var)
{
- return check_sbat_var_attributes(attributes) &&
- sbatsize >= strlen(SBAT_VAR_SIG "1") &&
- !strncmp((const char *)sbat, SBAT_VAR_SIG, strlen(SBAT_VAR_SIG));
+ 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
UINT32 attributes = 0;
UINT8 *sbat = NULL;
+ UINT8 *sbat_policy = NULL;
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,
SHIM_LOCK_GUID, &attributes);
*/
if (EFI_ERROR(efi_status)) {
dprint(L"SBAT read failed %r\n", efi_status);
- } else if (preserve_sbat_uefi_variable(sbat, sbatsize, attributes)) {
- dprint(L"%s variable is %d bytes, attributes are 0x%08x\n",
+ } else if (preserve_sbat_uefi_variable(sbat, sbatsize, attributes, sbat_var)
+ && !reset_sbat) {
+ dprint(L"preserving %s variable it is %d bytes, attributes are 0x%08x\n",
SBAT_VAR_NAME, sbatsize, attributes);
FreePool(sbat);
return EFI_SUCCESS;
/* set variable */
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)) {
dprint(L"%s variable writing failed %r\n", SBAT_VAR_NAME,
efi_status);
return efi_status;
}
- if (sbatsize != strlen(SBAT_VAR) ||
- strncmp((const char *)sbat, SBAT_VAR, strlen(SBAT_VAR)) != 0) {
+ if (sbatsize != strlen(sbat_var) ||
+ strncmp((const char *)sbat, sbat_var, strlen(sbat_var)) != 0) {
dprint("new sbatsize is %d, expected %d\n", sbatsize,
- strlen(SBAT_VAR));
+ strlen(sbat_var));
efi_status = EFI_INVALID_PARAMETER;
} else {
dprint(L"%s variable initialization succeeded\n", SBAT_VAR_NAME);
* Check that the signature is valid and matches the binary
*/
EFI_STATUS
-verify_buffer (char *data, int datasize,
- PE_COFF_LOADER_IMAGE_CONTEXT *context,
- UINT8 *sha256hash, UINT8 *sha1hash)
+verify_buffer_authenticode (char *data, int datasize,
+ PE_COFF_LOADER_IMAGE_CONTEXT *context,
+ UINT8 *sha256hash, UINT8 *sha1hash)
{
EFI_STATUS ret_efi_status;
size_t size = datasize;
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
is_removable_media_path(EFI_LOADED_IMAGE *li)
{
/*
* 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_IMAGE_ENTRY_POINT entry_point;
- EFI_PHYSICAL_ADDRESS alloc_address;
- UINTN alloc_pages;
- CHAR16 *PathName = NULL;
void *sourcebuffer = NULL;
UINT64 sourcesize = 0;
- void *data = NULL;
- int datasize = 0;
/*
* We need to refer to the loaded image protocol on the running
/*
* 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)) {
perror(L"Unable to generate path %s: %r\n", ImagePath,
efi_status);
- goto done;
+ return efi_status;
}
if (findNetboot(shim_li->DeviceHandle)) {
efi_status);
return efi_status;
}
- data = sourcebuffer;
- datasize = sourcesize;
+ *data = sourcebuffer;
+ *datasize = sourcesize;
} else if (find_httpboot(shim_li->DeviceHandle)) {
efi_status = httpboot_fetch_buffer (image_handle,
&sourcebuffer,
efi_status);
return efi_status;
}
- data = sourcebuffer;
- datasize = sourcesize;
+ *data = sourcebuffer;
+ *datasize = sourcesize;
} else {
/*
* 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)) {
perror(L"Failed to load image %s: %r\n",
PathName, efi_status);
PrintErrors();
ClearErrors();
- goto done;
+ return efi_status;
}
}
- if (datasize < 0) {
+ if (*datasize < 0)
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;
- }
/*
* We need to modify the loaded image protocol entry before running
#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
shim_init(void)
{
register volatile UINTN x = 0;
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)
return;
- efi_status = get_variable(debug_var_name, &data, &dataSize,
+ efi_status = get_variable(DEBUG_VAR_NAME, &data, &dataSize,
SHIM_LOCK_GUID);
if (EFI_ERROR(efi_status)) {
return;
console_print(L"Pausing for debugger attachment.\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;
while (x++) {
/* Make this so it can't /totally/ DoS us. */
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)) {
perror(L"Verifiying shim SBAT data failed: %r\n",
efi_status);
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,
* boot-services-only state variables are what we think they are.
#include "Cryptlib/Include/OpenSslSupport.h"
#endif
+#define MEM_ATTR_R 4
+#define MEM_ATTR_W 2
+#define MEM_ATTR_X 1
+
INTERFACE_DECL(_SHIM_LOCK);
typedef
extern UINT32 vendor_deauthorized_size;
extern UINT8 *vendor_deauthorized;
+extern UINT32 user_cert_size;
+extern UINT8 *user_cert;
+
#if defined(ENABLE_SHIM_CERT)
extern UINT32 build_cert_size;
extern UINT8 *build_cert;
extern UINT8 user_insecure_mode;
extern UINT8 ignore_db;
extern UINT8 trust_mok_list;
+extern UINT8 mok_policy;
+
extern UINT8 in_protocol;
extern void *load_options;
extern UINT32 load_options_size;
#define LogError(fmt, ...)
#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);
#endif /* SHIM_H_ */
.data_size = sizeof(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, },
.data_size = 0,
.data = NULL,
list_t sbat_var;
+BOOLEAN
+secure_mode() {
+ return 1;
+}
+
#if 0
/*
* Mock test helpers
int
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);
+ 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_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))
+ if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return 0;
else
return -1;
int
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);
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;
else
return 0;
int
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);
UINT32 attributes = 0;
- if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes))
+ if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes, sbatvar))
return -1;
else
return 0;
test_preserve_sbat_uefi_variable_bad_short(void)
{
char sbat[] = "sba";
+ char sbatvar[] = "sbat,1,2021030218\n";
size_t sbat_size = sizeof(sbat);
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;
else
return 0;
test(test_parse_and_verify);
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_attr);
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;
}
test_strncpy(void)
{
char s[] = "0123456789abcdef\0000";
- char s0[4096+4096];
- char *s1 = &s0[4096];
+ char s0[4096];
+ char s1[4096];
memset(s0, 0, sizeof(s0));
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);
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(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[18], '1', -1, "got %#02hhx expected %02hhx\n");
-
+#if __GNUC_PREREQ(8, 1)
+# pragma GCC diagnostic pop
+#endif
return 0;
}
test_strcat(void)
{
char s[] = "0123456789abcdef\0000";
- char s0[8192];
- char *s1 = &s0[4096];
+ char s0[4096];
+ char s1[4096];
char *s2;
char s3[] = "0123456789abcdef0123456789abcdef\000\000\000\000\000";
- memset(s0, 0, 8192);
+ memset(s0, 0, sizeof(s0));
memcpy(s0, s, sizeof(s));
memset(s1, 0, 4096);
return 0;
}
+void
+console_error(CHAR16 *err, EFI_STATUS efi_status)
+{
+ return;
+}
+
#ifndef HAVE_START_IMAGE
EFI_STATUS
start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)