diff -pruN 15.3-3/commit 15.4-7/commit
--- 15.3-3/commit	2021-03-23 18:42:26.000000000 +0000
+++ 15.4-7/commit	2021-03-30 21:04:30.000000000 +0000
@@ -1 +1 @@
-630b8dedfd8434353bce80ff89f63fd3113b086d
\ No newline at end of file
+20e4d9486fcae54ee44d2323ae342ffe68c920e6
\ No newline at end of file
diff -pruN 15.3-3/csv.c 15.4-7/csv.c
--- 15.3-3/csv.c	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/csv.c	2021-03-30 20:55:03.000000000 +0000
@@ -55,8 +55,11 @@ parse_csv_data(char *data, char *data_en
 	size_t max = 0;
 	char *end = data_end;
 
-	if (!data || !end || end <= data || !n_columns || !list)
+	if (!data || !end || end <= data || !n_columns || !list) {
+		dprint(L"data:0x%lx end:0x%lx n_columns:%lu list:0x%lx\n",
+		       data, end, n_columns, list);
 		return EFI_INVALID_PARAMETER;
+	}
 
 	max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
 
diff -pruN 15.3-3/debian/changelog 15.4-7/debian/changelog
--- 15.3-3/debian/changelog	2021-03-24 13:21:02.000000000 +0000
+++ 15.4-7/debian/changelog	2021-07-12 07:53:54.000000000 +0000
@@ -1,3 +1,62 @@
+shim (15.4-7) unstable; urgency=high
+
+  * Tweak how we call grub-install; don't abort on error. Not ideal
+    behaviour either, but don't break upgrades. Copy the behaviour
+    from the grub packages here. Closes: #990966
+
+ -- Steve McIntyre <93sam@debian.org>  Mon, 12 Jul 2021 08:53:54 +0100
+
+shim (15.4-6) unstable; urgency=high
+
+  * Add arm64 patch to tweak section layout and stop crashing
+    problems. Upstream issue #371. Closes: #990082, #990190
+  * In insecure mode, don't abort if we can't create the MokListXRT
+    variable. Upstream issue #372. Closes: #989962, #990158
+
+ -- Steve McIntyre <93sam@debian.org>  Wed, 23 Jun 2021 19:03:54 +0100
+
+shim (15.4-5) unstable; urgency=medium
+
+  * Add defensive code around calls to db_get. Don't fail if they
+    return errors.
+
+ -- Steve McIntyre <93sam@debian.org>  Thu, 06 May 2021 00:37:49 +0100
+
+shim (15.4-4) unstable; urgency=medium
+
+  * Fix up those maintainer scripts - if we're not running on an EFI
+    system then exit cleanly.
+
+ -- Steve McIntyre <93sam@debian.org>  Tue, 04 May 2021 17:53:21 +0100
+
+shim (15.4-3) unstable; urgency=medium
+
+  * Add maintainer scripts to the template packages to manage
+    installing and removing fbXXX.efi and mmXXX.efi when we
+    install/remove the shim-helpers-$arch-signed packages.
+    Closes: #966845
+
+ -- Steve McIntyre <93sam@debian.org>  Mon, 03 May 2021 20:48:49 +0100
+
+shim (15.4-2) unstable; urgency=medium
+
+  * Add two further patches from upstream:
+    + fix import_one_mok_state() after split
+    + Don't call QueryVariableInfo() on EFI 1.10 machines (e.g. older
+      Intel Mac machines)
+
+ -- Steve McIntyre <93sam@debian.org>  Wed, 21 Apr 2021 00:23:02 +0100
+
+shim (15.4-1) unstable; urgency=medium
+
+  * New upstream release fixing more bugs: SBAT and arm64 support
+  * Print sha256 checksums of the EFI binaries when the build is done
+  * Add two patches from upstream:
+    + fix i386 binary relocations
+    + allocate MOK config table as BootServicesData
+
+ -- Steve McIntyre <93sam@debian.org>  Wed, 31 Mar 2021 18:25:00 +0100
+
 shim (15.3-3) unstable; urgency=medium
 
   * Update the timestamp for the 15.3-2 upload.
@@ -10,7 +69,7 @@ shim (15.3-2) unstable; urgency=medium
 
   * Add missing build-dep on xxd for build-time unit tests
 
- -- Steve McIntyre <93sam@debian.org>  wed, 24 Mar 2021 02:21:53 +0000
+ -- Steve McIntyre <93sam@debian.org>  Wed, 24 Mar 2021 02:21:53 +0000
 
 shim (15.3-1) unstable; urgency=medium
 
diff -pruN 15.3-3/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch 15.4-7/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch
--- 15.3-3/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/patches/Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch	2021-04-21 00:04:51.000000000 +0000
@@ -0,0 +1,62 @@
+From 8b59591775a0412863aab9596ab87bdd493a9c1e Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Sat, 10 Apr 2021 16:05:23 -0400
+Subject: [PATCH] Don't call QueryVariableInfo() on EFI 1.10 machines
+
+The EFI 1.10 spec (and presumably earlier revisions as well) didn't have
+RT->QueryVariableInfo(), and on Chris Murphy's MacBookPro8,2 , that
+memory appears to be initialized randomly.
+
+This patch changes it to not call RT->QueryVariableInfo() if the
+EFI_RUNTIME_SERVICES table's major revision is less than two, and
+assumes our maximum variable size is 1024 in that case.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ mok.c | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+diff --git a/mok.c b/mok.c
+index 9b8fc2bc..beac0ff6 100644
+--- a/mok.c
++++ b/mok.c
+@@ -261,6 +261,9 @@ static const uint8_t null_sha256[32] = { 0, };
+ 
+ typedef UINTN SIZE_T;
+ 
++#define EFI_MAJOR_VERSION(tablep) ((UINT16)((((tablep)->Hdr.Revision) >> 16) & 0xfffful))
++#define EFI_MINOR_VERSION(tablep) ((UINT16)(((tablep)->Hdr.Revision) & 0xfffful))
++
+ static EFI_STATUS
+ get_max_var_sz(UINT32 attrs, SIZE_T *max_var_szp)
+ {
+@@ -270,11 +273,21 @@ get_max_var_sz(UINT32 attrs, SIZE_T *max_var_szp)
+ 	uint64_t max_var_sz = 0;
+ 
+ 	*max_var_szp = 0;
+-	efi_status = gRT->QueryVariableInfo(attrs, &max_storage_sz,
+-					    &remaining_sz, &max_var_sz);
+-	if (EFI_ERROR(efi_status)) {
+-		perror(L"Could not get variable storage info: %r\n", efi_status);
+-		return efi_status;
++	if (EFI_MAJOR_VERSION(gRT) < 2) {
++		dprint(L"EFI %d.%d; no RT->QueryVariableInfo().  Using 1024!\n",
++		       EFI_MAJOR_VERSION(gRT), EFI_MINOR_VERSION(gRT));
++		max_var_sz = remaining_sz = max_storage_sz = 1024;
++		efi_status = EFI_SUCCESS;
++	} else {
++		dprint(L"calling RT->QueryVariableInfo() at 0x%lx\n",
++		       gRT->QueryVariableInfo);
++		efi_status = gRT->QueryVariableInfo(attrs, &max_storage_sz,
++						    &remaining_sz, &max_var_sz);
++		if (EFI_ERROR(efi_status)) {
++			perror(L"Could not get variable storage info: %r\n",
++			       efi_status);
++			return efi_status;
++		}
+ 	}
+ 
+ 	/*
+-- 
+2.20.1
+
diff -pruN 15.3-3/debian/patches/fix_arm64_rela_sections.patch 15.4-7/debian/patches/fix_arm64_rela_sections.patch
--- 15.3-3/debian/patches/fix_arm64_rela_sections.patch	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/patches/fix_arm64_rela_sections.patch	2021-06-22 21:59:41.000000000 +0000
@@ -0,0 +1,132 @@
+From 9828f65f3e9de29da7bc70cb71069cc1d7ca1b4a Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Wed, 16 Jun 2021 16:13:32 +0800
+Subject: [PATCH] arm/aa64: fix the size of .rela* sections
+
+The previous commit(*) merged .rel* and .dyn* into .rodata, and this
+made ld to generate the wrong size for .rela* sections that covered
+other unrelated sections. When the EFI image was loaded, _relocate()
+went through the unexpected data and may cause unexpected crash.
+This commit moves .rel* and .dyn* out of .rodata in the ld script but
+also moves the related variables, such as _evrodata, _rodata_size,
+and _rodata_vsize, to the end of the new .dyn section, so that the
+crafted pe-coff section header for .rodata still covers our new
+.rela and .dyn sections.
+
+(*) 212ba30544f ("arm/aa64 targets: put .rel* and .dyn* in .rodata")
+
+Fix issue: https://github.com/rhboot/shim/issues/371
+
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ Makefile            |  4 ++--
+ elf_aarch64_efi.lds | 24 ++++++++++++++++--------
+ elf_arm_efi.lds     | 24 ++++++++++++++++--------
+ 3 files changed, 34 insertions(+), 18 deletions(-)
+
+Index: shim.git/Makefile
+===================================================================
+--- shim.git.orig/Makefile
++++ shim.git/Makefile
+@@ -244,7 +244,7 @@ endif
+ 	$(OBJCOPY) -D -j .text -j .sdata -j .data -j .data.ident \
+ 		-j .dynamic -j .rodata -j .rel* \
+ 		-j .rela* -j .reloc -j .eh_frame \
+-		-j .vendor_cert -j .sbat \
++		-j .vendor_cert -j .dyn -j .sbat \
+ 		$(FORMAT) $< $@
+ 	# I am tired of wasting my time fighting binutils timestamp code.
+ 	dd conv=notrunc bs=1 count=4 seek=$(TIMESTAMP_LOCATION) if=/dev/zero of=$@
+@@ -260,7 +260,7 @@ ifneq ($(OBJCOPY_GTE224),1)
+ endif
+ 	$(OBJCOPY) -D -j .text -j .sdata -j .data \
+ 		-j .dynamic -j .rodata -j .rel* \
+-		-j .rela* -j .reloc -j .eh_frame -j .sbat \
++		-j .rela* -j .dyn -j .reloc -j .eh_frame -j .sbat \
+ 		-j .debug_info -j .debug_abbrev -j .debug_aranges \
+ 		-j .debug_line -j .debug_str -j .debug_ranges \
+ 		-j .note.gnu.build-id \
+Index: shim.git/elf_aarch64_efi.lds
+===================================================================
+--- shim.git.orig/elf_aarch64_efi.lds
++++ shim.git/elf_aarch64_efi.lds
+@@ -70,21 +70,29 @@ SECTIONS
+   .rodata :
+   {
+     _rodata = .;
+-    *(.rela.dyn)
+-    *(.rela.plt)
+-    *(.rela.got)
+-    *(.rela.data)
+-    *(.rela.data*)
+-
+     *(.rodata*)
+     *(.srodata)
+-    *(.dynsym)
+-    *(.dynstr)
+     . = ALIGN(16);
+     *(.note.gnu.build-id)
+     . = ALIGN(4096);
+     *(.vendor_cert)
+     *(.data.ident)
++    . = ALIGN(4096);
++  }
++  . = ALIGN(4096);
++  .rela :
++  {
++    *(.rela.dyn)
++    *(.rela.plt)
++    *(.rela.got)
++    *(.rela.data)
++    *(.rela.data*)
++  }
++  . = ALIGN(4096);
++  .dyn :
++  {
++    *(.dynsym)
++    *(.dynstr)
+     _evrodata = .;
+     . = ALIGN(4096);
+   }
+Index: shim.git/elf_arm_efi.lds
+===================================================================
+--- shim.git.orig/elf_arm_efi.lds
++++ shim.git/elf_arm_efi.lds
+@@ -70,21 +70,29 @@ SECTIONS
+   .rodata :
+   {
+     _rodata = .;
+-    *(.rel.dyn)
+-    *(.rel.plt)
+-    *(.rel.got)
+-    *(.rel.data)
+-    *(.rel.data*)
+-
+     *(.rodata*)
+     *(.srodata)
+-    *(.dynsym)
+-    *(.dynstr)
+     . = ALIGN(16);
+     *(.note.gnu.build-id)
+     . = ALIGN(4096);
+     *(.vendor_cert)
+     *(.data.ident)
++    . = ALIGN(4096);
++  }
++  . = ALIGN(4096);
++  .rela :
++  {
++    *(.rela.dyn)
++    *(.rela.plt)
++    *(.rela.got)
++    *(.rela.data)
++    *(.rela.data*)
++  }
++  . = ALIGN(4096);
++  .dyn :
++  {
++    *(.dynsym)
++    *(.dynstr)
+     _evrodata = .;
+     . = ALIGN(4096);
+   }
diff -pruN 15.3-3/debian/patches/fix-broken-ia32-reloc.patch 15.4-7/debian/patches/fix-broken-ia32-reloc.patch
--- 15.3-3/debian/patches/fix-broken-ia32-reloc.patch	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/patches/fix-broken-ia32-reloc.patch	2021-03-31 19:58:04.000000000 +0000
@@ -0,0 +1,27 @@
+commit 1bea91ba72165d97c3b453cf769cb4bc5c07207a
+Author: Peter Jones <pjones@redhat.com>
+Date:   Wed Mar 31 14:54:52 2021 -0400
+
+    Fix a broken file header on ia32
+    
+    Commit c6281c6a195edee61185 needs to have included a ". = ALIGN(4096)"
+    directive before .reloc, but fails to do so.
+    
+    As a result, binutils, which does not care about the actual binary
+    format's constraints in any way, does not enforce the section alignment,
+    and it will not load.
+    
+    Signed-off-by: Peter Jones <pjones@redhat.com>
+
+diff --git a/elf_ia32_efi.lds b/elf_ia32_efi.lds
+index 742e0a47..497a3a15 100644
+--- a/elf_ia32_efi.lds
++++ b/elf_ia32_efi.lds
+@@ -15,6 +15,7 @@ SECTIONS
+    *(.gnu.linkonce.t.*)
+    _etext = .;
+   }
++  . = ALIGN(4096);
+   .reloc :
+   {
+    *(.reloc)
diff -pruN 15.3-3/debian/patches/fix-import_one_mok_state.patch 15.4-7/debian/patches/fix-import_one_mok_state.patch
--- 15.3-3/debian/patches/fix-import_one_mok_state.patch	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/patches/fix-import_one_mok_state.patch	2021-04-21 00:04:46.000000000 +0000
@@ -0,0 +1,36 @@
+commit 822d07ad4f07ef66fe447a130e1027c88d02a394
+Author: Adam Williamson <awilliam@redhat.com>
+Date:   Thu Apr 8 22:39:02 2021 -0700
+
+    Fix handling of ignore_db and user_insecure_mode
+    
+    In 65be350308783a8ef537246c8ad0545b4e6ad069, import_mok_state() is split
+    up into a function that manages the whole mok state, and one that
+    handles the state machine for an individual state variable.
+    Unfortunately, the code that initializes the global ignore_db and
+    user_insecure_mode was copied from import_mok_state() into the new
+    import_one_mok_state() function, and thus re-initializes that state each
+    time it processes a MoK state variable, before even assessing if that
+    variable is set.  As a result, we never honor either flag, and the
+    machine owner cannot disable trusting the system firmware's db/dbx
+    databases or disable validation altogether.
+    
+    This patch removes the extra re-initialization, allowing those variables
+    to be set properly.
+    
+    Signed-off-by: Adam Williamson <awilliam@redhat.com>
+
+diff --git a/mok.c b/mok.c
+index 5ad9072b..9e37d6ab 100644
+--- a/mok.c
++++ b/mok.c
+@@ -888,9 +888,6 @@ EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
+ 	EFI_STATUS ret = EFI_SUCCESS;
+ 	EFI_STATUS efi_status;
+ 
+-	user_insecure_mode = 0;
+-	ignore_db = 0;
+-
+ 	UINT32 attrs = 0;
+ 	BOOLEAN delete = FALSE;
+ 
diff -pruN 15.3-3/debian/patches/MOK-BootServicesData.patch 15.4-7/debian/patches/MOK-BootServicesData.patch
--- 15.3-3/debian/patches/MOK-BootServicesData.patch	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/patches/MOK-BootServicesData.patch	2021-04-14 20:45:09.000000000 +0000
@@ -0,0 +1,34 @@
+commit 4068fd42c891ea6ebdec056f461babc6e4048844
+Author: Gary Lin <glin@suse.com>
+Date:   Thu Apr 8 16:23:03 2021 +0800
+
+    mok: allocate MOK config table as BootServicesData
+    
+    Linux kernel is picky when reserving the memory for x86 and it only
+    expects BootServicesData:
+    
+    https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/platform/efi/quirks.c?h=v5.11#n254
+    
+    Otherwise, the following error would show during system boot:
+    
+    Apr 07 12:31:56.743925 localhost kernel: efi: Failed to lookup EFI memory descriptor for 0x000000003dcf8000
+    
+    Although BootServicesData would be reclaimed after ExitBootService(),
+    linux kernel reserves MOK config table when it detects the existence of
+    the table, so it's fine to allocate the table as BootServicesData.
+    
+    Signed-off-by: Gary Lin <glin@suse.com>
+
+diff --git a/mok.c b/mok.c
+index 9e37d6ab..9b8fc2bc 100644
+--- a/mok.c
++++ b/mok.c
+@@ -999,7 +999,7 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
+ 		npages = ALIGN_VALUE(config_sz, PAGE_SIZE) >> EFI_PAGE_SHIFT;
+ 		config_table = NULL;
+ 		efi_status = gBS->AllocatePages(AllocateAnyPages,
+-						EfiRuntimeServicesData,
++						EfiBootServicesData,
+ 						npages,
+ 						(EFI_PHYSICAL_ADDRESS *)&config_table);
+ 		if (EFI_ERROR(efi_status) || !config_table) {
diff -pruN 15.3-3/debian/patches/relax_check_for_import_mok_state.patch 15.4-7/debian/patches/relax_check_for_import_mok_state.patch
--- 15.3-3/debian/patches/relax_check_for_import_mok_state.patch	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/patches/relax_check_for_import_mok_state.patch	2021-06-22 22:02:18.000000000 +0000
@@ -0,0 +1,53 @@
+From: Gary Lin <glin@suse.com>
+Date: Tue, 11 May 2021 10:41:43 +0800
+Subject: Relax the check for import_mok_state()
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+An openSUSE user reported(*) that shim 15.4 failed to boot the system
+with the following message:
+
+  "Could not create MokListXRT: Out of Resources"
+
+In the beginning, I thought it's caused by the growing size of
+vendor-dbx. However, we found the following messages after set
+SHIM_VERBOSE:
+
+  max_var_sz:8000 remaining_sz:85EC max_storage_sz:9000
+  SetVariable(“MokListXRT”, ... varsz=0x1404) = Out of Resources
+
+Even though the firmware claimed the remaining storage size is 0x85EC
+and the maximum variable size is 0x8000, it still rejected MokListXRT
+with size 0x1404. It seems that the return values from QueryVariableInfo()
+are not reliable. Since this firmware didn't really support Secure Boot,
+the variable mirroring is not so critical, so we can just accept the
+failure of import_mok_state() and continue boot.
+
+(*) https://bugzilla.suse.com/show_bug.cgi?id=1185261
+
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ shim.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/shim.c b/shim.c
+index c5cfbb8..40e4894 100644
+--- a/shim.c
++++ b/shim.c
+@@ -1973,10 +1973,13 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
+ 	 * boot-services-only state variables are what we think they are.
+ 	 */
+ 	efi_status = import_mok_state(image_handle);
+-	if (!secure_mode() && efi_status == EFI_INVALID_PARAMETER) {
++	if (!secure_mode() &&
++	    (efi_status == EFI_INVALID_PARAMETER ||
++	     efi_status == EFI_OUT_OF_RESOURCES)) {
+ 		/*
+ 		 * Make copy failures fatal only if secure_mode is enabled, or
+-		 * the error was anything else than EFI_INVALID_PARAMETER.
++		 * the error was anything else than EFI_INVALID_PARAMETER or
++		 * EFI_OUT_OF_RESOURCES.
+ 		 * There are non-secureboot firmware implementations that don't
+ 		 * reserve enough EFI variable memory to fit the variable.
+ 		 */
diff -pruN 15.3-3/debian/patches/series 15.4-7/debian/patches/series
--- 15.3-3/debian/patches/series	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/patches/series	2021-06-22 22:02:18.000000000 +0000
@@ -0,0 +1,6 @@
+fix-import_one_mok_state.patch
+fix-broken-ia32-reloc.patch
+MOK-BootServicesData.patch
+Don-t-call-QueryVariableInfo-on-EFI-1.10-machines.patch
+relax_check_for_import_mok_state.patch
+fix_arm64_rela_sections.patch
diff -pruN 15.3-3/debian/rules 15.4-7/debian/rules
--- 15.3-3/debian/rules	2021-03-24 13:15:07.000000000 +0000
+++ 15.4-7/debian/rules	2021-06-23 20:50:41.000000000 +0000
@@ -37,7 +37,7 @@ export EFI_ARCH := ia32
 endif
 
 COMMON_OPTIONS += \
-	RELEASE=15.3 \
+	RELEASE=$(plain_upstream_version) \
 	COMMIT_ID=XXXX \
 	MAKELEVEL=0 \
 	ENABLE_HTTPBOOT=true \
@@ -65,13 +65,13 @@ $(SBAT_DATA): $(SBAT_IN)
 
 override_dh_auto_clean:
 	dh_auto_clean -- MAKELEVEL=0
-	rm -f $(DBX_LIST) $(SBAT_DATA) sbat.*.csv
+	rm -f $(DBX_LIST) $(SBAT_DATA) sbat.*.csv BOOT*.CSV test-csv test-sbat test-str
 
 override_dh_auto_build: $(DBX_LIST) $(SBAT_DATA)
-	dh_auto_build -- $(COMMON_OPTIONS)
+	dh_auto_build -- INSTALL=install $(COMMON_OPTIONS)
 
 override_dh_auto_install:
-	dh_auto_install --destdir=debian/tmp -- $(COMMON_OPTIONS)
+	dh_auto_install --destdir=debian/tmp -- INSTALL=install $(COMMON_OPTIONS)
 	# Remove the copy of the source that's installed - we have git
 	# already...
 	rm -rf debian/tmp/usr
@@ -79,6 +79,7 @@ override_dh_auto_install:
 	# not needed for our build and causes debhelper to complain
 	rm -f debian/tmp/boot/efi/EFI/BOOT/BOOT*.EFI
 	./debian/signing-template.generate
+	sha256sum *.efi
 
 generate-gnu-efi:
 	git -C gnu-efi archive --prefix=gnu-efi/ HEAD | xz -9 \
diff -pruN 15.3-3/debian/signing-template/@final_pkg_name@.postinst.in 15.4-7/debian/signing-template/@final_pkg_name@.postinst.in
--- 15.3-3/debian/signing-template/@final_pkg_name@.postinst.in	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/signing-template/@final_pkg_name@.postinst.in	2021-07-12 07:53:54.000000000 +0000
@@ -0,0 +1,93 @@
+#! /bin/sh
+set -e
+
+# If we're not on an EFI system, do nothing
+if [ ! -d /sys/firmware/efi ]; then
+    exit 0
+fi
+
+# Must load the confmodule for our template to be installed correctly.
+. /usr/share/debconf/confmodule
+
+# Select the right target architecture for grub-install
+ARCH=@arch@
+case ${ARCH} in
+    i386|amd64)
+	FW_SIZE=$(cat /sys/firmware/efi/fw_platform_size)
+	if [ "$FW_SIZE"x = "32"x ]; then
+	    GRUB_EFI_TARGET="i386-efi"
+	elif [ "$FW_SIZE"x = "64"x ]; then
+	    GRUB_EFI_TARGET="x86_64-efi"
+	else
+	    echo "Unable to read a valid value from fw_platform_size, ABORT"
+	    exit 1
+	fi
+	;;
+    arm64)
+	GRUB_EFI_TARGET="arm64-efi"
+	;;
+    *)
+	echo "Unsupported dpkg architecture ${ARCH} in $0. ABORT"
+	exit 1
+	;;
+esac
+
+# Pull out a config value from /etc/default/grub
+config_item ()
+{
+    if [ -f /etc/default/grub ]; then
+	. /etc/default/grub || return
+	for x in /etc/default/grub.d/*.cfg; do
+	    if [ -e "$x" ]; then
+		. "$x"
+	    fi
+	done
+    fi
+    eval echo "\$$1"
+}
+
+run_grub_install()
+{
+    if ! grub-install $@ ; then
+        echo "Failed: grub-install $@" >&2
+        echo "WARNING: Bootloader is not properly installed, system may not be bootable" >&2
+    fi
+}
+
+case $1 in
+    configure)
+	bootloader_id="$(config_item GRUB_DISTRIBUTOR | tr A-Z a-z | \
+			 cut -d' ' -f1)"
+	case $bootloader_id in
+	    kubuntu) bootloader_id=ubuntu ;;
+	esac
+
+	# Call grub-install to make sure we're added to the ESP as
+	# needed
+	if [ "$bootloader_id" ] && \
+	   [ -d "/boot/efi/EFI/$bootloader_id" ] && \
+	   which grub-install >/dev/null 2>&1
+	then
+	    # Check for some of the options that matter, so we can
+	    # call grub-install safely without dropping them
+	    OPTIONS=""
+
+	    db_get grub2/force_efi_extra_removable || RET=false
+	    if [ "$RET" = true ]; then
+		OPTIONS="$OPTIONS --force-extra-removable"
+	    fi
+
+	    db_get grub2/update_nvram || RET=true
+	    if [ "$RET" = false ]; then
+		OPTIONS="$OPTIONS --no-nvram"
+	    fi
+
+	    run_grub_install --target=${GRUB_EFI_TARGET} $OPTIONS
+	fi
+	;;
+esac
+
+#DEBHELPER#
+
+exit 0
+
diff -pruN 15.3-3/debian/signing-template/@final_pkg_name@.postrm.in 15.4-7/debian/signing-template/@final_pkg_name@.postrm.in
--- 15.3-3/debian/signing-template/@final_pkg_name@.postrm.in	1970-01-01 00:00:00.000000000 +0000
+++ 15.4-7/debian/signing-template/@final_pkg_name@.postrm.in	2021-05-07 23:09:57.000000000 +0000
@@ -0,0 +1,57 @@
+#! /bin/sh
+set -e
+
+# If we're not on an EFI system, do nothing
+if [ ! -d /sys/firmware/efi ]; then
+    exit 0
+fi
+
+case @arch@ in
+    i386)
+	SHIM_REMOVE="mmia32.efi fbia32.efi";;
+    amd64)
+	SHIM_REMOVE="mmx64.efi fbx64.efi";;
+    arm64)
+	SHIM_REMOVE="mmaa64.efi fbaa64.efi";;
+    *)
+	echo "Unsupported dpkg architecture @arch@ in $0. ABORT"
+	exit 1
+	;;
+esac
+
+# Pull out a config value from /etc/default/grub
+config_item ()
+{
+    if [ -f /etc/default/grub ]; then
+	. /etc/default/grub || return
+	for x in /etc/default/grub.d/*.cfg; do
+	    if [ -e "$x" ]; then
+		. "$x"
+	    fi
+	done
+    fi
+    eval echo "\$$1"
+}
+
+case $1 in
+    remove|purge)
+	bootloader_id="$(config_item GRUB_DISTRIBUTOR | tr A-Z a-z | \
+			 cut -d' ' -f1)"
+	case $bootloader_id in
+	    kubuntu) bootloader_id=ubuntu ;;
+	esac
+
+	# If we're being removed, remove the copies installed in the
+	# ESP. grub-install doesn't clean those up for us.
+	if [ "$bootloader_id" ] && \
+	   [ -d "/boot/efi/EFI/$bootloader_id" ]; then
+
+	    cd /boot/efi/EFI/$bootloader_id
+	    rm -f $SHIM_REMOVE
+	fi
+	;;
+esac
+
+#DEBHELPER#
+
+exit 0
diff -pruN 15.3-3/debian/signing-template.generate 15.4-7/debian/signing-template.generate
--- 15.3-3/debian/signing-template.generate	2021-03-24 01:00:17.000000000 +0000
+++ 15.4-7/debian/signing-template.generate	2021-05-03 20:30:23.000000000 +0000
@@ -6,6 +6,8 @@ urgency="$(dpkg-parsechangelog -S Urgenc
 date="$(dpkg-parsechangelog -S Date)"
 version_binary="$(dpkg-parsechangelog -S Version)"
 version_mangled="$(dpkg-parsechangelog -S Version | tr '-' '+')"
+pkg_name="shim-helpers-${DEB_HOST_ARCH}-signed-template"
+final_pkg_name="${pkg_name%-template}"
 
 subst () {
 	sed \
@@ -16,11 +18,11 @@ subst () {
 		-e "s/@distribution@/${distribution}/g" \
 		-e "s/@urgency@/${urgency}/g" \
 		-e "s/@date@/${date}/g" \
+		-e "s/@final_pkg_name@/${final_pkg_name}/g" \
 		"$@"
 }
 
 template='./debian/signing-template'
-pkg_name="shim-helpers-${DEB_HOST_ARCH}-signed-template"
 pkg_dir="debian/${pkg_name}/usr/share/code-signing/${pkg_name}"
 pkg_deb="${pkg_dir}/source-template/debian"
 
@@ -31,7 +33,7 @@ find "${template}" -type f -printf '%P\n
 while read path
 do
 	src="${template}/${path}"
-	dst="${pkg_deb}/${path}"
+	dst=$(echo "${pkg_deb}/${path}" | subst)
 
 	install -o 0 -g 0 -m 0755 -d "${dst%/*}"
 	subst < "${src}" > "${dst%.in}"
diff -pruN 15.3-3/elf_aarch64_efi.lds 15.4-7/elf_aarch64_efi.lds
--- 15.3-3/elf_aarch64_efi.lds	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/elf_aarch64_efi.lds	2021-03-30 20:55:03.000000000 +0000
@@ -9,24 +9,12 @@ SECTIONS
     *(.text)
     *(.text.*)
     *(.gnu.linkonce.t.*)
-    *(.srodata)
-    *(.rodata*)
-    . = ALIGN(16);
-    _etext = .;
-  }
-
-  . = ALIGN(4096);
-  .dynamic  : { *(.dynamic) }
-
-  . = ALIGN(4096);
-  .note.gnu.build-id : {
-    *(.note.gnu.build-id)
-  }
-
-  . = ALIGN(4096);
-  .data.ident : {
-    *(.data.ident)
+    _evtext = .;
+    . = ALIGN(4096);
   }
+  _etext = .;
+  _text_size = . - _text;
+  _text_vsize = _evtext - _text;
 
   . = ALIGN(4096);
   .data :
@@ -39,6 +27,8 @@ SECTIONS
    *(.got.plt)
    *(.got)
 
+   *(.dynamic)
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    . = ALIGN(16);
@@ -48,44 +38,61 @@ SECTIONS
    *(.dynbss)
    *(.bss)
    *(COMMON)
-   . = ALIGN(16);
+   _evdata = .;
+   . = ALIGN(4096);
    _bss_end = .;
   }
+  _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);
-  .vendor_cert :
+  .sbat :
   {
-    *(.vendor_cert)
+    _sbat = .;
+    *(.sbat)
+    *(.sbat.*)
+    _esbat = .;
+    . = ALIGN(4096);
+    _epsbat = .;
   }
+  _sbat_size = _epsbat - _sbat;
+  _sbat_vsize = _esbat - _sbat;
+
   . = ALIGN(4096);
-  .rela :
+  .rodata :
   {
+    _rodata = .;
     *(.rela.dyn)
     *(.rela.plt)
     *(.rela.got)
     *(.rela.data)
     *(.rela.data*)
+
+    *(.rodata*)
+    *(.srodata)
+    *(.dynsym)
+    *(.dynstr)
+    . = ALIGN(16);
+    *(.note.gnu.build-id)
+    . = ALIGN(4096);
+    *(.vendor_cert)
+    *(.data.ident)
+    _evrodata = .;
+    . = ALIGN(4096);
   }
-  _edata = .;
-  _data_size = . - _data;
-  . = ALIGN(4096);
-  .sbat :
-  {
-    _sbat = .;
-    *(.sbat)
-    *(.sbat.*)
-  }
-  _esbat = .;
-  _sbat_vsize = . - _sbat;
-  . = ALIGN(4096);
-  _sbat_size = . - _sbat;
+  _erodata = .;
+  _rodata_size = . - _rodata;
+  _rodata_vsize = _evrodata - _rodata;
   _alldata_size = . - _data;
 
-  . = ALIGN(4096);
-  .dynsym   : { *(.dynsym) }
-  . = ALIGN(4096);
-  .dynstr   : { *(.dynstr) }
-  . = ALIGN(4096);
   /DISCARD/ :
   {
     *(.rel.reloc)
diff -pruN 15.3-3/elf_arm_efi.lds 15.4-7/elf_arm_efi.lds
--- 15.3-3/elf_arm_efi.lds	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/elf_arm_efi.lds	2021-03-30 20:55:03.000000000 +0000
@@ -9,22 +9,12 @@ SECTIONS
     *(.text)
     *(.text.*)
     *(.gnu.linkonce.t.*)
-    *(.srodata)
-    *(.rodata*)
-    . = ALIGN(16);
-    _etext = .;
-  }
-  .dynamic  : { *(.dynamic) }
-
-  . = ALIGN(4096);
-  .note.gnu.build-id : {
-    *(.note.gnu.build-id)
-  }
-
-  . = ALIGN(4096);
-  .data.ident : {
-    *(.data.ident)
+    _evtext = .;
+    . = ALIGN(4096);
   }
+  _etext = .;
+  _text_size = . - _text;
+  _text_vsize = _evtext - _text;
 
   . = ALIGN(4096);
   .data :
@@ -33,10 +23,12 @@ SECTIONS
    *(.sdata)
    *(.data)
    *(.data1)
-   *(.data*)
+   *(.data.*)
    *(.got.plt)
    *(.got)
 
+   *(.dynamic)
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    . = ALIGN(16);
@@ -46,44 +38,61 @@ SECTIONS
    *(.dynbss)
    *(.bss)
    *(COMMON)
-   . = ALIGN(16);
+   _evdata = .;
+   . = ALIGN(4096);
    _bss_end = .;
   }
+  _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);
-  .vendor_cert :
+  .sbat :
   {
-    *(.vendor_cert)
+    _sbat = .;
+    *(.sbat)
+    *(.sbat.*)
+    _esbat = .;
+    . = ALIGN(4096);
+    _epsbat = .;
   }
+  _sbat_size = _epsbat - _sbat;
+  _sbat_vsize = _esbat - _sbat;
+
   . = ALIGN(4096);
-  .rel :
+  .rodata :
   {
+    _rodata = .;
     *(.rel.dyn)
     *(.rel.plt)
     *(.rel.got)
     *(.rel.data)
     *(.rel.data*)
+
+    *(.rodata*)
+    *(.srodata)
+    *(.dynsym)
+    *(.dynstr)
+    . = ALIGN(16);
+    *(.note.gnu.build-id)
+    . = ALIGN(4096);
+    *(.vendor_cert)
+    *(.data.ident)
+    _evrodata = .;
+    . = ALIGN(4096);
   }
-  _edata = .;
-  _data_size = . - _data;
-  . = ALIGN(4096);
-  .sbat :
-  {
-    _sbat = .;
-    *(.sbat)
-    *(.sbat.*)
-  }
-  _esbat = .;
-  _sbat_vsize = . - _sbat;
-  . = ALIGN(4096);
-  _sbat_size = . - _sbat;
+  _erodata = .;
+  _rodata_size = . - _rodata;
+  _rodata_vsize = _evrodata - _rodata;
   _alldata_size = . - _data;
 
-  . = ALIGN(4096);
-  .dynsym   : { *(.dynsym) }
-  . = ALIGN(4096);
-  .dynstr   : { *(.dynstr) }
-  . = ALIGN(4096);
   /DISCARD/ :
   {
     *(.rel.reloc)
diff -pruN 15.3-3/.github/workflows/pullrequest.yml 15.4-7/.github/workflows/pullrequest.yml
--- 15.3-3/.github/workflows/pullrequest.yml	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/.github/workflows/pullrequest.yml	2021-03-30 20:55:03.000000000 +0000
@@ -110,14 +110,24 @@ jobs:
         id: update-submodules
         run: |
           make update
+      - name: Make a build directory for ${{ matrix.distro }} for ${{ matrix.efiarch }}
+        id: builddir
+        run: |
+          rm -rf build-${{ matrix.distro }}-${{ matrix.efiarch }}
+          mkdir build-${{ matrix.distro }}-${{ matrix.efiarch }}
+          cd build-${{ matrix.distro }}-${{ matrix.efiarch }}
       - name: Do the build on ${{ matrix.distro }} for ${{ matrix.efiarch }}
         id: build
         run: |
-          make -s CROSS_COMPILE=${{ matrix.gccarch }}-linux-gnu- ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true clean all || make CROSS_COMPILE=${{ matrix.gccarch }}-linux-gnu- ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true clean all
+          pwd
+          cd build-${{ matrix.distro }}-${{ matrix.efiarch }}
+          make TOPDIR=.. -f ../Makefile CROSS_COMPILE=${{ matrix.gccarch }}-linux-gnu- ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true all
       - name: Install on ${{ matrix.distro }} for ${{ matrix.efiarch }}
         id: install
         run: |
-          make -s CROSS_COMPILE=${{ matrix.gccarch }}-linux-gnu- ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true install || make CROSS_COMPILE=${{ matrix.gccarch }}-linux-gnu- ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true install
+          pwd
+          cd build-${{ matrix.distro }}-${{ matrix.efiarch }}
+          make TOPDIR=.. -f ../Makefile CROSS_COMPILE=${{ matrix.gccarch }}-linux-gnu- ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true install
           echo 'results:'
           find /destdir -type f
 
@@ -190,17 +200,21 @@ jobs:
         id: update-submodules
         run: |
           make update
+      - name: Do 'make clean' on ${{ matrix.distro }} for ${{ matrix.efiarch }}
+        id: clean
+        run: |
+          make ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true clean
       - name: Run tests on ${{ matrix.distro }} for ${{ matrix.efiarch }}
         id: test
         run: |
-          make -s ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true test || make ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true test
+          make ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true test
       - name: Do the build on ${{ matrix.distro }} for ${{ matrix.efiarch }}
         id: build
         run: |
-          make -s ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true clean all || make ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true clean all
+          make ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true all
       - name: Install on ${{ matrix.distro }} for ${{ matrix.efiarch }}
         id: install
         run: |
-          make -s ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true install || make ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true install
+          make ARCH=${{ matrix.makearch }} PREFIX=/usr DESTDIR=/destdir EFIDIR=test ENABLE_SHIM_HASH=true install
           echo 'results:'
           find /destdir -type f
diff -pruN 15.3-3/gnu-efi/gnuefi/crt0-efi-aarch64.S 15.4-7/gnu-efi/gnuefi/crt0-efi-aarch64.S
--- 15.3-3/gnu-efi/gnuefi/crt0-efi-aarch64.S	2021-03-21 17:06:19.000000000 +0000
+++ 15.4-7/gnu-efi/gnuefi/crt0-efi-aarch64.S	2021-03-26 22:41:36.000000000 +0000
@@ -31,7 +31,7 @@ pe_header:
 	.short 	0
 coff_header:
 	.short	0xaa64				// AArch64
-	.short	3				// nr_sections
+	.short	4				// nr_sections
 	.long	0 				// TimeDateStamp
 	.long	0				// PointerToSymbolTable
 	.long	1				// NumberOfSymbols
@@ -44,7 +44,7 @@ optional_header:
 	.short	0x20b				// PE32+ format
 	.byte	0x02				// MajorLinkerVersion
 	.byte	0x14				// MinorLinkerVersion
-	.long	_data - _start			// SizeOfCode
+	.long	_text_size			// SizeOfCode
 	.long	_alldata_size			// SizeOfInitializedData
 	.long	0				// SizeOfUninitializedData
 	.long	_start - ImageBase		// AddressOfEntryPoint
@@ -62,7 +62,7 @@ extra_header_fields:
 	.short	0				// MinorSubsystemVersion
 	.long	0				// Win32VersionValue
 
-	.long	_esbat - ImageBase		// SizeOfImage
+	.long	_erodata - ImageBase		// SizeOfImage
 
 	// Everything before the kernel image is considered part of the header
 	.long	_start - ImageBase		// SizeOfHeaders
@@ -86,19 +86,22 @@ extra_header_fields:
 	// Section table
 section_table:
 	.ascii	".text\0\0\0"
-	.long	_data - _start		// VirtualSize
+	.long	_evtext - _start	// VirtualSize
 	.long	_start - ImageBase	// VirtualAddress
-	.long	_data - _start		// SizeOfRawData
+	.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_size		// VirtualSize
+	.long	_data_vsize		// VirtualSize
 	.long	_data - ImageBase	// VirtualAddress
 	.long	_data_size		// SizeOfRawData
 	.long	_data - ImageBase	// PointerToRawData
@@ -107,9 +110,12 @@ section_table:
 	.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"
+	.ascii	".sbat\0\0\0"
 	.long	_sbat_vsize		// VirtualSize
 	.long	_sbat - ImageBase	// VirtualAddress
 	.long	_sbat_size		// SizeOfRawData
@@ -119,6 +125,24 @@ section_table:
 	.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)
 
 	.align		12
diff -pruN 15.3-3/gnu-efi/gnuefi/crt0-efi-arm.S 15.4-7/gnu-efi/gnuefi/crt0-efi-arm.S
--- 15.3-3/gnu-efi/gnuefi/crt0-efi-arm.S	2021-03-21 17:06:19.000000000 +0000
+++ 15.4-7/gnu-efi/gnuefi/crt0-efi-arm.S	2021-03-26 22:41:36.000000000 +0000
@@ -31,7 +31,7 @@ pe_header:
 	.short 	0
 coff_header:
 	.short	0x1c2				// Mixed ARM/Thumb
-	.short	3				// nr_sections
+	.short	4				// nr_sections
 	.long	0 				// TimeDateStamp
 	.long	0				// PointerToSymbolTable
 	.long	1				// NumberOfSymbols
@@ -45,17 +45,17 @@ optional_header:
 	.short	0x10b				// PE32+ format
 	.byte	0x02				// MajorLinkerVersion
 	.byte	0x14				// MinorLinkerVersion
-	.long	_data - _start			// SizeOfCode
+	.long	_text_size			// SizeOfCode
 	.long	_alldata_size			// SizeOfInitializedData
 	.long	0				// SizeOfUninitializedData
 	.long	_start - ImageBase		// AddressOfEntryPoint
 	.long	_start - ImageBase		// BaseOfCode
-	.long	0				// BaseOfData
+	.long	_data - ImageBase		// BaseOfData
 
 extra_header_fields:
 	.long	0				// ImageBase
-	.long	0x20				// SectionAlignment
-	.long	0x8				// FileAlignment
+	.long	0x800				// SectionAlignment
+	.long	0x200				// FileAlignment
 	.short	0				// MajorOperatingSystemVersion
 	.short	0				// MinorOperatingSystemVersion
 	.short	0				// MajorImageVersion
@@ -64,7 +64,7 @@ extra_header_fields:
 	.short	0				// MinorSubsystemVersion
 	.long	0				// Win32VersionValue
 
-	.long	_esbat - ImageBase		// SizeOfImage
+	.long	_erodata - ImageBase		// SizeOfImage
 
 	// Everything before the kernel image is considered part of the header
 	.long	_start - ImageBase		// SizeOfHeaders
@@ -88,6 +88,7 @@ extra_header_fields:
 	// Section table
 section_table:
 
+#if 0
 	/*
 	 * The EFI application loader requires a relocation section
 	 * because EFI applications must be relocatable.  This is a
@@ -105,23 +106,37 @@ section_table:
 	.short	0			// NumberOfRelocations
 	.short	0			// NumberOfLineNumbers
 	.long	0x42100040		// Characteristics (section flags)
+#endif
 
-
-	.ascii	".text"
-	.byte	0
-	.byte	0
-	.byte	0        		// end of 0 padding of section name
-	.long	_edata - _start		// VirtualSize
+	.ascii	".text\0\0\0"
+	.long	_evtext - _start	// VirtualSize
 	.long	_start - ImageBase	// VirtualAddress
-	.long	_edata - _start		// SizeOfRawData
+	.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)
-	.long	0xe0500020	// Characteristics (section flags)
+	/*
+	 * 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
@@ -133,9 +148,28 @@ section_table:
 	.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)
 
 
+	.align 11
 _start:
 	stmfd		sp!, {r0-r2, lr}
 
diff -pruN 15.3-3/gnu-efi/Make.defaults 15.4-7/gnu-efi/Make.defaults
--- 15.3-3/gnu-efi/Make.defaults	2021-03-21 17:06:19.000000000 +0000
+++ 15.4-7/gnu-efi/Make.defaults	2021-03-26 22:41:36.000000000 +0000
@@ -92,7 +92,7 @@ endif
 #
 # Where to build the package
 #
-OBJDIR       := $(TOPDIR)/$(ARCH)
+OBJDIR       := $(abspath .)/$(ARCH)
 
 #
 # Variables below derived from variables above
diff -pruN 15.3-3/include/sbat.h 15.4-7/include/sbat.h
--- 15.3-3/include/sbat.h	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/include/sbat.h	2021-03-30 20:55:03.000000000 +0000
@@ -20,16 +20,16 @@
 	(UEFI_VAR_NV_BS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
 
 #if defined(ENABLE_SHIM_DEVEL)
-#define SBAT_VAR_NAME L"SBAT_DEVEL"
-#define SBAT_VAR_NAME8 "SBAT_DEVEL"
-#define SBAT_RT_VAR_NAME L"SbatRT_DEVEL"
-#define SBAT_RT_VAR_NAME8 "SbatRT_DEVEL"
+#define SBAT_VAR_NAME L"SbatLevel_DEVEL"
+#define SBAT_VAR_NAME8 "SbatLevel_DEVEL"
+#define SBAT_RT_VAR_NAME L"SbatLevelRT_DEVEL"
+#define SBAT_RT_VAR_NAME8 "SbatLevelRT_DEVEL"
 #define SBAT_VAR_ATTRS UEFI_VAR_NV_BS_RT
 #else
-#define SBAT_VAR_NAME L"SBAT"
-#define SBAT_VAR_NAME8 "SBAT"
-#define SBAT_RT_VAR_NAME L"SbatRT"
-#define SBAT_RT_VAR_NAME8 "SbatRT"
+#define SBAT_VAR_NAME L"SbatLevel"
+#define SBAT_VAR_NAME8 "SbatLevel"
+#define SBAT_RT_VAR_NAME L"SbatLevelRT"
+#define SBAT_RT_VAR_NAME8 "SbatLevelRT"
 #define SBAT_VAR_ATTRS UEFI_VAR_NV_BS
 #endif
 
@@ -51,6 +51,7 @@ extern list_t sbat_var;
 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);
 
 struct sbat_section_entry {
 	const CHAR8 *component_name;
diff -pruN 15.3-3/lib/Makefile 15.4-7/lib/Makefile
--- 15.3-3/lib/Makefile	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/lib/Makefile	2021-03-30 20:55:03.000000000 +0000
@@ -1,6 +1,6 @@
 TARGET = lib.a
 
-LIBFILES_UNSORTED := $(foreach x,$(wildcard *.c),$(patsubst %.c,%.o,$(x)))
+LIBFILES_UNSORTED := $(patsubst %.c,%.o,$(subst $(TOPDIR)/lib/,,$(wildcard $(TOPDIR)/lib/*.c)))
 LIBFILES := $(sort $(LIBFILES_UNSORTED))
 
 CRYPTDIR	= $(TOPDIR)/Cryptlib
diff -pruN 15.3-3/Make.defaults 15.4-7/Make.defaults
--- 15.3-3/Make.defaults	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/Make.defaults	2021-03-30 20:55:03.000000000 +0000
@@ -1,6 +1,7 @@
 
 # load the local configuration if it exists
 -include Make.local
+-include $(TOPDIR)/Make.local
 
 COMPILER	?= gcc
 CC		= $(CROSS_COMPILE)$(COMPILER)
diff -pruN 15.3-3/Makefile 15.4-7/Makefile
--- 15.3-3/Makefile	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/Makefile	2021-03-30 20:55:03.000000000 +0000
@@ -1,7 +1,7 @@
 default : all
 
 NAME		= shim
-VERSION		= 15.3
+VERSION		= 15.4
 ifneq ($(origin RELEASE),undefined)
 DASHRELEASE	?= -$(RELEASE)
 else
@@ -45,7 +45,7 @@ MOK_OBJS = MokManager.o PasswordCrypt.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
 ORIG_FALLBACK_SRCS = fallback.c
-SBATPATH = data/sbat.csv
+SBATPATH = $(TOPDIR)/data/sbat.csv
 
 ifeq ($(SOURCE_DATE_EPOCH),)
 	UNAME=$(shell uname -s -m -p -i -o)
@@ -111,7 +111,7 @@ sbat.%.csv : data/sbat.%.csv
 	$(DOS2UNIX) $(D2UFLAGS) $< $@
 	tail -c1 $@ | read -r _ || echo >> $@ # ensure a trailing newline
 
-VENDOR_SBATS := $(foreach x,$(wildcard data/sbat.*.csv),$(notdir $(x)))
+VENDOR_SBATS := $(sort $(foreach x,$(wildcard $(TOPDIR)/data/sbat.*.csv data/sbat.*.csv),$(notdir $(x))))
 
 sbat_data.o : | $(SBATPATH) $(VENDOR_SBATS)
 sbat_data.o : /dev/null
@@ -146,21 +146,23 @@ $(MMSONAME): $(MOK_OBJS) $(LIBS)
 
 gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a: CFLAGS+=-DGNU_EFI_USE_EXTERNAL_STDARG
 gnu-efi/$(ARCH_GNUEFI)/gnuefi/libgnuefi.a gnu-efi/$(ARCH_GNUEFI)/lib/libefi.a:
+	mkdir -p gnu-efi/lib gnu-efi/gnuefi
 	$(MAKE) -C gnu-efi \
 		ARCH=$(ARCH_GNUEFI) TOPDIR=$(TOPDIR)/gnu-efi \
+		-f $(TOPDIR)/gnu-efi/Makefile \
 		lib gnuefi inc
 
 Cryptlib/libcryptlib.a:
 	for i in Hash Hmac Cipher Rand Pk Pem SysCall; do mkdir -p Cryptlib/$$i; done
-	$(MAKE) VPATH=$(TOPDIR)/Cryptlib -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile
+	$(MAKE) TOPDIR=$(TOPDIR) VPATH=$(TOPDIR)/Cryptlib -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile
 
 Cryptlib/OpenSSL/libopenssl.a:
 	for i in x509v3 x509 txt_db stack sha rsa rc4 rand pkcs7 pkcs12 pem ocsp objects modes md5 lhash kdf hmac evp err dso dh conf comp cmac buffer bn bio async/arch asn1 aes; do mkdir -p Cryptlib/OpenSSL/crypto/$$i; done
-	$(MAKE) VPATH=$(TOPDIR)/Cryptlib/OpenSSL -C Cryptlib/OpenSSL -f $(TOPDIR)/Cryptlib/OpenSSL/Makefile
+	$(MAKE) TOPDIR=$(TOPDIR) VPATH=$(TOPDIR)/Cryptlib/OpenSSL -C Cryptlib/OpenSSL -f $(TOPDIR)/Cryptlib/OpenSSL/Makefile
 
 lib/lib.a: | $(TOPDIR)/lib/Makefile $(wildcard $(TOPDIR)/include/*.[ch])
-	if [ ! -d lib ]; then mkdir lib ; fi
-	$(MAKE) VPATH=$(TOPDIR)/lib -C lib -f $(TOPDIR)/lib/Makefile lib.a
+	mkdir -p lib
+	$(MAKE) VPATH=$(TOPDIR)/lib TOPDIR=$(TOPDIR) -C lib -f $(TOPDIR)/lib/Makefile
 
 buildid : $(TOPDIR)/buildid.c
 	$(HOSTCC) -I/usr/include -Og -g3 -Wall -Werror -Wextra -o $@ $< -lelf
@@ -223,6 +225,7 @@ endif
 install-as-data : install-deps
 	$(INSTALL) -d -m 0755 $(DESTDIR)/$(DATATARGETDIR)
 	$(INSTALL) -m 0644 $(SHIMNAME) $(DESTDIR)/$(DATATARGETDIR)/
+	$(INSTALL) -m 0644 $(BOOTCSVNAME) $(DESTDIR)/$(DATATARGETDIR)/
 ifneq ($(origin ENABLE_SHIM_HASH),undefined)
 	$(INSTALL) -m 0644 $(SHIMHASHNAME) $(DESTDIR)/$(DATATARGETDIR)/
 endif
@@ -239,7 +242,7 @@ ifneq ($(OBJCOPY_GTE224),1)
 	$(error objcopy >= 2.24 is required)
 endif
 	$(OBJCOPY) -D -j .text -j .sdata -j .data -j .data.ident \
-		-j .dynamic -j .dynsym -j .rel* \
+		-j .dynamic -j .rodata -j .rel* \
 		-j .rela* -j .reloc -j .eh_frame \
 		-j .vendor_cert -j .sbat \
 		$(FORMAT) $< $@
@@ -256,7 +259,7 @@ ifneq ($(OBJCOPY_GTE224),1)
 	$(error objcopy >= 2.24 is required)
 endif
 	$(OBJCOPY) -D -j .text -j .sdata -j .data \
-		-j .dynamic -j .dynsym -j .rel* \
+		-j .dynamic -j .rodata -j .rel* \
 		-j .rela* -j .reloc -j .eh_frame -j .sbat \
 		-j .debug_info -j .debug_abbrev -j .debug_aranges \
 		-j .debug_line -j .debug_str -j .debug_ranges \
@@ -275,35 +278,46 @@ else
 endif
 
 test :
-	@make -f include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" all
+	@make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" all
 
 $(patsubst %.c,%,$(wildcard test-*.c)) :
-	@make -f include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" $@
+	@make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" $@
 
 .PHONY : $(patsubst %.c,%,$(wildcard test-*.c)) test
 
 clean-test-objs:
-	@make -f include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" clean
+	@make -f $(TOPDIR)/include/test.mk EFI_INCLUDES="$(EFI_INCLUDES)" ARCH_DEFINES="$(ARCH_DEFINES)" clean
 
 clean-gnu-efi:
-	$(MAKE) -C gnu-efi \
-		ARCH=$(ARCH_GNUEFI) TOPDIR=$(TOPDIR)/gnu-efi \
-		clean
+	@if [ -d gnu-efi ] ; then \
+		$(MAKE) -C gnu-efi \
+			ARCH=$(ARCH_GNUEFI) TOPDIR=$(TOPDIR)/gnu-efi \
+			-f $(TOPDIR)/gnu-efi/Makefile \
+			clean ; \
+	fi
+
+clean-lib-objs:
+	@if [ -d lib ] ; then \
+		$(MAKE) -C lib TOPDIR=$(TOPDIR) -f $(TOPDIR)/lib/Makefile clean ; \
+	fi
 
 clean-shim-objs:
-	$(MAKE) -C lib -f $(TOPDIR)/lib/Makefile clean
 	@rm -rvf $(TARGET) *.o $(SHIM_OBJS) $(MOK_OBJS) $(FALLBACK_OBJS) $(KEYS) certdb $(BOOTCSVNAME)
 	@rm -vf *.debug *.so *.efi *.efi.* *.tar.* version.c buildid
 	@rm -vf Cryptlib/*.[oa] Cryptlib/*/*.[oa]
 	@if [ -d .git ] ; then git clean -f -d -e 'Cryptlib/OpenSSL/*'; fi
 
 clean-openssl-objs:
-	$(MAKE) -C Cryptlib/OpenSSL -f $(TOPDIR)/Cryptlib/OpenSSL/Makefile clean
+	@if [ -d Cryptlib/OpenSSL ] ; then \
+		$(MAKE) -C Cryptlib/OpenSSL -f $(TOPDIR)/Cryptlib/OpenSSL/Makefile clean ; \
+	fi
 
 clean-cryptlib-objs:
-	$(MAKE) -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile clean
+	@if [ -d Cryptlib ] ; then \
+		$(MAKE) -C Cryptlib -f $(TOPDIR)/Cryptlib/Makefile clean ; \
+	fi
 
-clean: clean-shim-objs clean-test-objs clean-gnu-efi clean-openssl-objs clean-cryptlib-objs
+clean: clean-shim-objs clean-test-objs clean-gnu-efi clean-openssl-objs clean-cryptlib-objs clean-lib-objs
 
 GITTAG = $(VERSION)
 
diff -pruN 15.3-3/pe.c 15.4-7/pe.c
--- 15.3-3/pe.c	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/pe.c	2021-03-30 20:55:03.000000000 +0000
@@ -1054,6 +1054,8 @@ handle_image (void *data, unsigned int d
 				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);
 			}
 		}
 
diff -pruN 15.3-3/sbat.c 15.4-7/sbat.c
--- 15.3-3/sbat.c	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/sbat.c	2021-03-30 20:55:03.000000000 +0000
@@ -18,14 +18,20 @@ parse_sbat_section(char *section_base, s
 	size_t n;
 	char *strtab;
 
-	if (!section_base || !section_size || !n_entries || !entriesp)
+	if (!section_base || !section_size || !n_entries || !entriesp) {
+		dprint(L"section_base:0x%lx section_size:0x%lx\n",
+		       section_base, section_size);
+		dprint(L"n_entries:0x%lx entriesp:0x%lx\n",
+		       n_entries, entriesp);
 		return EFI_INVALID_PARAMETER;
+	}
 
 	INIT_LIST_HEAD(&csv);
 
 	efi_status =
 		parse_csv_data(section_base, end, SBAT_SECTION_COLUMNS, &csv);
 	if (EFI_ERROR(efi_status)) {
+		dprint(L"parse_csv_data failed: %r\n", efi_status);
 		return efi_status;
 	}
 
@@ -38,6 +44,8 @@ parse_sbat_section(char *section_base, s
 
 		if (row->n_columns < SBAT_SECTION_COLUMNS) {
 			efi_status = EFI_INVALID_PARAMETER;
+			dprint(L"row->n_columns:%lu SBAT_SECTION_COLUMNS:%lu\n",
+			       row->n_columns, SBAT_SECTION_COLUMNS);
 			goto err;
 		}
 
@@ -45,6 +53,7 @@ parse_sbat_section(char *section_base, s
 		allocsz += sizeof(struct sbat_section_entry);
 		for (i = 0; i < row->n_columns; i++) {
 			if (row->columns[i][0] == '\000') {
+				dprint(L"row[%lu].columns[%lu][0] == '\\000'\n", n, i);
 				efi_status = EFI_INVALID_PARAMETER;
 				goto err;
 			}
@@ -120,8 +129,8 @@ verify_single_entry(struct sbat_section_
 		sbat_var_gen = atoi((const char *)sbat_var_entry->component_generation);
 
 		if (sbat_gen < sbat_var_gen) {
-			dprint(L"component %a, generation %d, was revoked by SBAT variable",
-			       entry->component_name, sbat_gen);
+			dprint(L"component %a, generation %d, was revoked by %s variable\n",
+			       entry->component_name, sbat_gen, SBAT_VAR_NAME);
 			LogError(L"image did not pass SBAT verification\n");
 			return EFI_SECURITY_VIOLATION;
 		}
@@ -139,7 +148,7 @@ cleanup_sbat_var(list_t *entries)
 	list_for_each_safe(pos, tmp, entries) {
 		entry = list_entry(pos, struct sbat_var_entry, list);
 
-		if ((uintptr_t)entry < (uintptr_t)first && entry != NULL)
+		if (first == NULL || (uintptr_t)entry < (uintptr_t)first)
 			first = entry;
 
 		list_del(&entry->list);
@@ -157,7 +166,7 @@ verify_sbat_helper(list_t *local_sbat_va
 	struct sbat_var_entry *sbat_var_entry;
 
 	if (list_empty(local_sbat_var)) {
-		dprint(L"SBAT variable not present\n");
+		dprint(L"%s variable not present\n", SBAT_VAR_NAME);
 		return EFI_SUCCESS;
 	}
 
@@ -239,10 +248,10 @@ parse_sbat_var_data(list_t *entry_list,
 
 	INIT_LIST_HEAD(entry_list);
 
-	entries = (struct sbat_var_entry **)strtab;
-	strtab += sizeof(struct sbat_var_entry *) * n;
 	entry = (struct sbat_var_entry *)strtab;
 	strtab += sizeof(struct sbat_var_entry) * n;
+	entries = (struct sbat_var_entry **)strtab;
+	strtab += sizeof(struct sbat_var_entry *) * n;
 	n = 0;
 
 	list_for_each(pos, &csv) {
@@ -277,8 +286,10 @@ parse_sbat_var(list_t *entries)
 	UINTN datasize;
 	EFI_STATUS efi_status;
 
-	if (!entries)
+	if (!entries) {
+		dprint(L"entries is NULL\n");
 		return EFI_INVALID_PARAMETER;
+	}
 
 	efi_status = get_variable(SBAT_VAR_NAME, &data, &datasize, SHIM_LOCK_GUID);
 	if (EFI_ERROR(efi_status)) {
@@ -304,6 +315,14 @@ check_sbat_var_attributes(UINT32 attribu
 #endif
 }
 
+bool
+preserve_sbat_uefi_variable(UINT8 *sbat, UINTN sbatsize, UINT32 attributes)
+{
+	return check_sbat_var_attributes(attributes) &&
+	       sbatsize >= strlen(SBAT_VAR_SIG "1") &&
+	       !strncmp((const char *)sbat, SBAT_VAR_SIG, strlen(SBAT_VAR_SIG));
+}
+
 EFI_STATUS
 set_sbat_uefi_variable(void)
 {
@@ -316,19 +335,16 @@ set_sbat_uefi_variable(void)
 	efi_status = get_variable_attr(SBAT_VAR_NAME, &sbat, &sbatsize,
 				       SHIM_LOCK_GUID, &attributes);
 	/*
-	 * Always set the SBAT UEFI variable if it fails to read.
+	 * Always set the SbatLevel UEFI variable if it fails to read.
 	 *
-	 * Don't try to set the SBAT UEFI variable if attributes match and
-	 * the signature matches.
+	 * Don't try to set the SbatLevel UEFI variable if attributes match
+	 * and the signature matches.
 	 */
 	if (EFI_ERROR(efi_status)) {
 		dprint(L"SBAT read failed %r\n", efi_status);
-	} else if (check_sbat_var_attributes(attributes) &&
-		   sbatsize >= strlen(SBAT_VAR_SIG "1") &&
-		   strncmp((const char *)sbat, SBAT_VAR_SIG,
-	                   strlen(SBAT_VAR_SIG))) {
-		dprint("SBAT variable is %d bytes, attributes are 0x%08x\n",
-		       sbatsize, attributes);
+	} else if (preserve_sbat_uefi_variable(sbat, sbatsize, attributes)) {
+		dprint(L"%s variable is %d bytes, attributes are 0x%08x\n",
+		       SBAT_VAR_NAME, sbatsize, attributes);
 		FreePool(sbat);
 		return EFI_SUCCESS;
 	} else {
@@ -341,7 +357,8 @@ set_sbat_uefi_variable(void)
 		efi_status = set_variable(SBAT_VAR_NAME, SHIM_LOCK_GUID,
 		                          attributes, 0, "");
 		if (EFI_ERROR(efi_status)) {
-			dprint(L"SBAT variable delete failed %r\n", efi_status);
+			dprint(L"%s variable delete failed %r\n", SBAT_VAR_NAME,
+					efi_status);
 			return efi_status;
 		}
 	}
@@ -350,7 +367,8 @@ set_sbat_uefi_variable(void)
 	efi_status = set_variable(SBAT_VAR_NAME, SHIM_LOCK_GUID, SBAT_VAR_ATTRS,
 	                          sizeof(SBAT_VAR)-1, SBAT_VAR);
 	if (EFI_ERROR(efi_status)) {
-		dprint(L"SBAT variable writing failed %r\n", efi_status);
+		dprint(L"%s variable writing failed %r\n", SBAT_VAR_NAME,
+				efi_status);
 		return efi_status;
 	}
 
@@ -358,7 +376,7 @@ set_sbat_uefi_variable(void)
 	efi_status = get_variable(SBAT_VAR_NAME, &sbat, &sbatsize,
 				  SHIM_LOCK_GUID);
 	if (EFI_ERROR(efi_status)) {
-		dprint(L"SBAT read failed %r\n", efi_status);
+		dprint(L"%s read failed %r\n", SBAT_VAR_NAME, efi_status);
 		return efi_status;
 	}
 
@@ -368,7 +386,7 @@ set_sbat_uefi_variable(void)
 		       strlen(SBAT_VAR));
 		efi_status = EFI_INVALID_PARAMETER;
 	} else {
-		dprint(L"SBAT variable initialization succeeded\n");
+		dprint(L"%s variable initialization succeeded\n", SBAT_VAR_NAME);
 	}
 
 	FreePool(sbat);
diff -pruN 15.3-3/shim.c 15.4-7/shim.c
--- 15.3-3/shim.c	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/shim.c	2021-03-30 20:55:03.000000000 +0000
@@ -1895,7 +1895,7 @@ efi_main (EFI_HANDLE passed_image_handle
 		L"shim_init() failed",
 		L"import of SBAT data failed",
 		L"SBAT self-check failed",
-		L"SBAT UEFI variable setting failed",
+		SBAT_VAR_NAME L" UEFI variable setting failed",
 		NULL
 	};
 	enum {
@@ -1935,12 +1935,12 @@ efi_main (EFI_HANDLE passed_image_handle
 
 	efi_status = set_sbat_uefi_variable();
 	if (EFI_ERROR(efi_status) && secure_mode()) {
-		perror(L"SBAT variable initialization failed\n");
+		perror(L"%s variable initialization failed\n", SBAT_VAR_NAME);
 		msg = SET_SBAT;
 		goto die;
 	} else if (EFI_ERROR(efi_status)) {
-		dprint(L"SBAT variable initialization failed: %r\n",
-		       efi_status);
+		dprint(L"%s variable initialization failed: %r\n",
+		       SBAT_VAR_NAME, efi_status);
 	}
 
 	if (secure_mode()) {
@@ -1950,19 +1950,20 @@ efi_main (EFI_HANDLE passed_image_handle
 		INIT_LIST_HEAD(&sbat_var);
 		efi_status = parse_sbat_var(&sbat_var);
 		if (EFI_ERROR(efi_status)) {
-			perror(L"Parsing SBAT variable failed: %r\n",
-				efi_status);
+			perror(L"Parsing %s variable failed: %r\n",
+				SBAT_VAR_NAME, efi_status);
 			msg = IMPORT_SBAT;
 			goto die;
 		}
 
-		efi_status = handle_sbat(sbat_start, sbat_end - sbat_start);
+		efi_status = handle_sbat(sbat_start, sbat_end - sbat_start - 1);
 		if (EFI_ERROR(efi_status)) {
 			perror(L"Verifiying shim SBAT data failed: %r\n",
 			       efi_status);
 			msg = SBAT_SELF_CHECK;
 			goto die;
 		}
+		dprint(L"SBAT self-check succeeded\n");
 	}
 
 	init_openssl();
diff -pruN 15.3-3/test-sbat.c 15.4-7/test-sbat.c
--- 15.3-3/test-sbat.c	2021-03-23 18:39:44.000000000 +0000
+++ 15.4-7/test-sbat.c	2021-03-30 20:55:03.000000000 +0000
@@ -319,6 +319,7 @@ test_parse_sbat_section_too_many_elem(vo
 	struct sbat_section_entry *test_entries[] = {
 		&test_section_entry1, &test_section_entry2,
 	};
+	int rc = -1;
 
 	status = parse_sbat_section(section_base, section_size, &n, &entries);
 	assert_equal_return(status, EFI_SUCCESS, -1, "got %#hhx expected %#hhx\n");
@@ -341,10 +342,10 @@ test_parse_sbat_section_too_many_elem(vo
 #undef mkassert
 	}
 	assert_equal_goto(n, 2, fail, "got %zu expected %d\n");
-	return 0;
+	rc = 0;
 fail:
 	cleanup_sbat_section_entries(n, entries);
-	return -1;
+	return rc;
 }
 
 /*
@@ -439,14 +440,19 @@ test_verify_sbat_null_sbat_section(void)
 	list_t test_sbat_var;
 	size_t n = 0;
 	struct sbat_section_entry **entries = NULL;
+	int rc = -1;
 
 	INIT_LIST_HEAD(&test_sbat_var);
 	status = parse_sbat_var_data(&test_sbat_var, sbat_var_data, sizeof(sbat_var_data));
-	assert_equal_return(status, EFI_SUCCESS, -1, "got %#x expected %#x\n");
+	assert_equal_goto(status, EFI_SUCCESS, err, "got %#x expected %#x\n");
 
-	status = verify_sbat_helper(&sbat_var, n, entries);
-	assert_equal_return(status, EFI_SUCCESS, -1, "got %#x expected %#x\n");
-	return 0;
+	status = verify_sbat_helper(&test_sbat_var, n, entries);
+	assert_equal_goto(status, EFI_SUCCESS, err, "got %#x expected %#x\n");
+	rc = 0;
+err:
+	cleanup_sbat_var(&test_sbat_var);
+
+	return rc;
 }
 
 #if 0
@@ -902,6 +908,7 @@ test_parse_and_verify(void)
 	struct sbat_section_entry *test_entries[] = {
 		&test_section_entry1, &test_section_entry2,
 	};
+	int rc = -1;
 
 	status = parse_sbat_section(sbat_section, sizeof(sbat_section)-1,
 	                            &n_section_entries, &section_entries);
@@ -940,16 +947,71 @@ test_parse_and_verify(void)
 
 	INIT_LIST_HEAD(&sbat_var);
 	status = parse_sbat_var_data(&sbat_var, sbat_var_alloced, sbat_var_data_size);
+	free(sbat_var_alloced);
 	if (status != EFI_SUCCESS || list_empty(&sbat_var))
 		return -1;
 
 	status = verify_sbat(n_section_entries, section_entries);
+	assert_equal_goto(status, EFI_SECURITY_VIOLATION, err, "expected %#x got %#x\n");
 
-	assert_equal_return(status, EFI_SECURITY_VIOLATION, -1, "expected %#x got %#x\n");
-	cleanup_sbat_var(&sbat_var);
+	rc = 0;
+err:
 	cleanup_sbat_section_entries(n_section_entries, section_entries);
+	cleanup_sbat_var(&sbat_var);
 
-	return 0;
+	return rc;
+}
+
+int
+test_preserve_sbat_uefi_variable_good(void)
+{
+	char sbat[] = "sbat,1,\ncomponent,2,\n";
+	size_t sbat_size = sizeof(sbat);
+	UINT32 attributes = SBAT_VAR_ATTRS;
+
+	if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes))
+		return 0;
+	else
+		return -1;
+}
+
+int
+test_preserve_sbat_uefi_variable_bad_sig(void)
+{
+	char sbat[] = "bad_sig,1,\ncomponent,2,\n";
+	size_t sbat_size = sizeof(sbat);
+	UINT32 attributes = SBAT_VAR_ATTRS;
+
+	if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes))
+		return -1;
+	else
+		return 0;
+}
+
+int
+test_preserve_sbat_uefi_variable_bad_attr(void)
+{
+	char sbat[] = "sbat,1,\ncomponent,2,\n";
+	size_t sbat_size = sizeof(sbat);
+	UINT32 attributes = 0;
+
+	if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes))
+		return -1;
+	else
+		return 0;
+}
+
+int
+test_preserve_sbat_uefi_variable_bad_short(void)
+{
+	char sbat[] = "sba";
+	size_t sbat_size = sizeof(sbat);
+	UINT32 attributes = SBAT_VAR_ATTRS;
+
+	if (preserve_sbat_uefi_variable(sbat, sbat_size, attributes))
+		return -1;
+	else
+		return 0;
 }
 
 int
@@ -989,6 +1051,11 @@ main(void)
 #endif
 	test(test_parse_and_verify);
 
+	test(test_preserve_sbat_uefi_variable_good);
+	test(test_preserve_sbat_uefi_variable_bad_sig);
+	test(test_preserve_sbat_uefi_variable_bad_attr);
+	test(test_preserve_sbat_uefi_variable_bad_short);
+
 	return 0;
 }
 
