Merge ~ubuntu-uefi-team/grub/+git/ubuntu:ubuntu into ~ubuntu-core-dev/grub/+git/ubuntu:ubuntu

Proposed by Mate Kukri
Status: Merged
Merge reported by: Mate Kukri
Merged at revision: f1625e10dda448f9592c1f2b3142a43cf9b5d46b
Proposed branch: ~ubuntu-uefi-team/grub/+git/ubuntu:ubuntu
Merge into: ~ubuntu-core-dev/grub/+git/ubuntu:ubuntu
Diff against target: 2339 lines (+1674/-237)
24 files modified
debian/build-efi-images (+6/-0)
debian/changelog (+26/-0)
debian/control (+2/-0)
debian/grub-sort-version (+2/-2)
debian/patches/grub-sort-version.patch (+16/-1)
debian/patches/kern-efi-mm-Change-grub_efi_allocate_pages_real-to-call-s.patch (+36/-0)
debian/patches/kern-efi-mm-Change-grub_efi_mm_add_regions-to-keep-track-.patch (+69/-0)
debian/patches/kern-efi-mm-Detect-calls-to-grub_efi_drop_alloc-with-wron.patch (+34/-0)
debian/patches/nx/efi-Disallow-fallback-to-legacy-Linux-loader-when-shim-sa.patch (+116/-0)
debian/patches/nx/modules-Don-t-allocate-space-for-non-allocable-sections.patch (+37/-0)
debian/patches/nx/modules-load-module-sections-at-page-aligned-addresses.patch (+390/-0)
debian/patches/nx/modules-strip-.llvm_addrsig-sections-and-similar.patch (+41/-0)
debian/patches/nx/nx-add-memory-attribute-get-set-API.patch (+252/-0)
debian/patches/nx/nx-set-page-permissions-for-loaded-modules.patch (+222/-0)
debian/patches/nx/nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch (+49/-0)
debian/patches/nx/peimage-Add-memory-attribute-support.patch (+132/-0)
debian/patches/secure-boot/efi-use-peimage-shim.patch (+151/-227)
debian/patches/series (+11/-0)
debian/patches/suse-grub.texi-add-net_bootp6-document.patch (+3/-3)
debian/patches/ubuntu-fix-lzma-decompressor-objcopy.patch (+1/-1)
debian/patches/ubuntu-support-initrd-less-boot.patch (+1/-1)
debian/rules (+3/-0)
debian/sbat.ubuntu.csv.in (+2/-2)
debian/test_grub_sort_version.py (+72/-0)
Reviewer Review Type Date Requested Status
Julian Andres Klode Pending
Review via email: mp+461796@code.launchpad.net
To post a comment you must log in.
f8ebfa5... by Mate Kukri

Increase SBAT level to "grub.ubuntu,2" and "grub.peimage,2"

4858769... by Mate Kukri

Revert peimage to re-use GRUB's image handle (LP: #2057679) (LP: #2054127)

peimage sometimes has to load things such as systemd-stub that will pass
their ImageHandle to the firmware's LoadImage() as ParentImageHandle.

Such a ParentImageHandle must always come from the firmware itself,
otherwise LoadImage() asserts.

Reverting to the old implementation also fixes LP: #2054127 as systab
hook installation will again be done in StartImage().

0efc7d0... by Mate Kukri

d/build-efi-images: Make sure downstream didn't remove peimage SBAT entry

2e09b0d... by Mate Kukri

releasing package grub2 version 2.12-1ubuntu5

67b61d4... by Mate Kukri

Add 2.12-1ubuntu6 to changelog

4be2e5f... by Mate Kukri

releasing package grub2 version 2.12-1ubuntu7

44ab0d1... by Mate Kukri

peimage: Ignore empty sections when checking for bounds

These checks were assuming empty sections to overlap, this is wrong, and
was preventing things like Xen from booting.

21fab0b... by Mate Kukri

peimage: Make sure partially loaded images are unloaded on error

83485b1... by Mate Kukri

Cherry-pick upstream efi mm patches to avoid crashing at exit on Mu

f1625e1... by Mate Kukri

Implement support for UEFI NX mitigation

- Cherry-picked relevant upstream NX patches
- Implemented support for NX in peimage

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/build-efi-images b/debian/build-efi-images
2index d17e225..2f847f2 100755
3--- a/debian/build-efi-images
4+++ b/debian/build-efi-images
5@@ -33,6 +33,12 @@ efi_name="$6"
6 sbat_csv="$7"
7 efi_vendor="${8:-$(dpkg-vendor --query vendor | tr '[:upper:]' '[:lower:]')}"
8
9+# make sure downstreams didn't mess up sbat.csv
10+if ! grep -q ^grub.peimage $sbat_csv; then
11+ echo Missing sbat entry for "grub.peimage" >&2
12+ exit 1
13+fi
14+
15 # mkfs.msdos may not be on the default PATH.
16 export PATH="$PATH:/sbin:/usr/sbin"
17
18diff --git a/debian/changelog b/debian/changelog
19index bc37a14..b9aae02 100644
20--- a/debian/changelog
21+++ b/debian/changelog
22@@ -1,3 +1,29 @@
23+grub2 (2.12-1ubuntu7) noble; urgency=medium
24+
25+ * d/p/grub-sort-version.patch: Also patch grub-mkconfig to export GRUB_FLAVOUR_ORDER
26+ * d/grub-sort-version: Update regex to correctly match kernel flavour
27+ * d/grub-sort-version: Append `-0` to abi strings before passing to python-apt (Fixes LP: #2041827)
28+ * debian/: Add tests for grub-sort-version
29+ * Revert peimage to re-use GRUB's image handle (LP: #2057679) (LP: #2054127)
30+ * Increase SBAT level to "grub.ubuntu,2" and "grub.peimage,2"
31+ * d/build-efi-images: Make sure downstream didn't remove peimage SBAT entry
32+ * SECURITY UPDATE: Use-after-free in peimage module [LP: #2054127]
33+ - CVE-2024-2312
34+
35+ -- Mate Kukri <mate.kukri@canonical.com> Thu, 04 Apr 2024 11:12:35 +0100
36+
37+grub2 (2.12-1ubuntu6) noble; urgency=medium
38+
39+ * No-change rebuild for CVE-2024-3094
40+
41+ -- Steve Langasek <steve.langasek@ubuntu.com> Sun, 31 Mar 2024 08:54:41 +0000
42+
43+grub2 (2.12-1ubuntu5) noble; urgency=medium
44+
45+ * No-change rebuild for libefivar1t64 on riscv64.
46+
47+ -- Steve Langasek <steve.langasek@ubuntu.com> Thu, 07 Mar 2024 09:18:17 +0000
48+
49 grub2 (2.12-1ubuntu4) noble; urgency=medium
50
51 * d/grub-multi-install: Treat missing `cloud_style_installation` debconf as
52diff --git a/debian/control b/debian/control
53index efd46e3..3cc18db 100644
54--- a/debian/control
55+++ b/debian/control
56@@ -7,6 +7,8 @@ Uploaders: Felix Zielcke <fzielcke@z-51.de>, Jordi Mallach <jordi@debian.org>, S
57 Build-Depends: debhelper-compat (= 13),
58 patchutils,
59 python3,
60+ python3-apt,
61+ python3-pytest,
62 flex,
63 bison,
64 gawk,
65diff --git a/debian/grub-sort-version b/debian/grub-sort-version
66index 6e47231..40a6eda 100755
67--- a/debian/grub-sort-version
68+++ b/debian/grub-sort-version
69@@ -28,7 +28,7 @@ class KernelABI:
70 if self._index != other._index:
71 # Ordering is reversed, what should be considered highest comes first.
72 return self._index > other._index
73- return apt_pkg.version_compare(self.abi, other.abi) < 0
74+ return apt_pkg.version_compare(f"{self.abi}-0", f"{other.abi}-0") < 0
75
76
77 def main() -> None:
78@@ -43,7 +43,7 @@ def main() -> None:
79
80 order = []
81 for flavour in os.environ.get("GRUB_FLAVOUR_ORDER", "").split():
82- order.append(re.compile(f"[0-9]*-{flavour}$"))
83+ order.append(re.compile(f"[\\s\\S]*-{flavour}(\\s*\\d*)$"))
84
85 versions = [KernelABI(line.rstrip(), order) for line in sys.stdin]
86 versions.sort(reverse=args.reverse)
87diff --git a/debian/patches/grub-sort-version.patch b/debian/patches/grub-sort-version.patch
88index d885c50..8e6385c 100644
89--- a/debian/patches/grub-sort-version.patch
90+++ b/debian/patches/grub-sort-version.patch
91@@ -6,9 +6,24 @@ We need to have support for GRUB_FLAVOUR_ORDER and it's arguably
92 the easiest way to hook this in, although you might be able to
93 write this as an awk script or something.
94 ---
95+ util/grub-mkconfig.in | 3 ++-
96 util/grub-mkconfig_lib.in | 15 +--------------
97- 1 file changed, 1 insertion(+), 14 deletions(-)
98+ 2 files changed, 3 insertions(+), 15 deletions(-)
99
100+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
101+index 46b036b..0b1adf5 100644
102+--- a/util/grub-mkconfig.in
103++++ b/util/grub-mkconfig.in
104+@@ -270,7 +270,8 @@ export GRUB_DEFAULT \
105+ GRUB_RECORDFAIL_TIMEOUT \
106+ GRUB_RECOVERY_TITLE \
107+ GRUB_FORCE_PARTUUID \
108+- GRUB_DISABLE_INITRD
109++ GRUB_DISABLE_INITRD \
110++ GRUB_FLAVOUR_ORDER
111+
112+ if test "x${grub_cfg}" != "x"; then
113+ rm -f "${grub_cfg}.new"
114 diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
115 index 121df9a..cabac83 100644
116 --- a/util/grub-mkconfig_lib.in
117diff --git a/debian/patches/kern-efi-mm-Change-grub_efi_allocate_pages_real-to-call-s.patch b/debian/patches/kern-efi-mm-Change-grub_efi_allocate_pages_real-to-call-s.patch
118new file mode 100644
119index 0000000..0764e5e
120--- /dev/null
121+++ b/debian/patches/kern-efi-mm-Change-grub_efi_allocate_pages_real-to-call-s.patch
122@@ -0,0 +1,36 @@
123+From: Mate Kukri <mate.kukri@canonical.com>
124+Date: Tue, 11 Jun 2024 15:21:33 +0100
125+Subject: kern/efi/mm: Change grub_efi_allocate_pages_real() to call
126+ semantically correct free function
127+
128+If the firmware happens to return 0 as an address of allocated pages,
129+grub_efi_allocate_pages_real() tries to allocate a new set of pages,
130+and then free the ones at address 0.
131+
132+However at that point grub_efi_store_alloc() wasn't yet called, so
133+freeing the pages at 0 using grub_efi_free_pages() which calls
134+grub_efi_drop_alloc() isn't necessary, so let's call b->free_pages()
135+instead.
136+
137+The call to grub_efi_drop_alloc() doesn't seem particularly harmful,
138+because it seems to do nothing if the allocation it is asked to drop
139+isn't on the list, but the call to it is obviously unnecessary here.
140+
141+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
142+---
143+ grub-core/kern/efi/mm.c | 2 +-
144+ 1 file changed, 1 insertion(+), 1 deletion(-)
145+
146+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
147+index 4fec188..6613191 100644
148+--- a/grub-core/kern/efi/mm.c
149++++ b/grub-core/kern/efi/mm.c
150+@@ -150,7 +150,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
151+ so reallocate another one. */
152+ address = GRUB_EFI_MAX_USABLE_ADDRESS;
153+ status = b->allocate_pages (alloctype, memtype, pages, &address);
154+- grub_efi_free_pages (0, pages);
155++ b->free_pages (0, pages);
156+ if (status != GRUB_EFI_SUCCESS)
157+ {
158+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
159diff --git a/debian/patches/kern-efi-mm-Change-grub_efi_mm_add_regions-to-keep-track-.patch b/debian/patches/kern-efi-mm-Change-grub_efi_mm_add_regions-to-keep-track-.patch
160new file mode 100644
161index 0000000..96bebaf
162--- /dev/null
163+++ b/debian/patches/kern-efi-mm-Change-grub_efi_mm_add_regions-to-keep-track-.patch
164@@ -0,0 +1,69 @@
165+From: Mate Kukri <mate.kukri@canonical.com>
166+Date: Tue, 11 Jun 2024 15:19:48 +0100
167+Subject: kern/efi/mm: Change grub_efi_mm_add_regions() to keep track of map
168+ allocation size
169+
170+If the map was too big for the initial allocation, it was freed and replaced
171+with a bigger one, but the free call still used the hard-coded size.
172+
173+Seems like this wasn't hit for a long time, because most firmware maps
174+fit into 12K.
175+
176+This bug was trigerred on Project Mu firmware with a big memory map, and
177+results in the heap getting trashed and the firmware ASSERTING on
178+corrupted heap guard values when GRUB exits.
179+
180+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
181+---
182+ grub-core/kern/efi/mm.c | 14 +++++++-------
183+ 1 file changed, 7 insertions(+), 7 deletions(-)
184+
185+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
186+index 6a6fba8..4fec188 100644
187+--- a/grub-core/kern/efi/mm.c
188++++ b/grub-core/kern/efi/mm.c
189+@@ -574,13 +574,15 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
190+ grub_efi_memory_descriptor_t *memory_map_end;
191+ grub_efi_memory_descriptor_t *filtered_memory_map;
192+ grub_efi_memory_descriptor_t *filtered_memory_map_end;
193++ grub_efi_uintn_t alloc_size;
194+ grub_efi_uintn_t map_size;
195+ grub_efi_uintn_t desc_size;
196+ grub_err_t err;
197+ int mm_status;
198+
199+ /* Prepare a memory region to store two memory maps. */
200+- memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
201++ alloc_size = 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE);
202++ memory_map = grub_efi_allocate_any_pages (alloc_size);
203+ if (! memory_map)
204+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map");
205+
206+@@ -591,14 +593,13 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
207+
208+ if (mm_status == 0)
209+ {
210+- grub_efi_free_pages
211+- ((grub_efi_physical_address_t) ((grub_addr_t) memory_map),
212+- 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
213++ grub_efi_free_pages ((grub_efi_physical_address_t) (grub_addr_t) memory_map, alloc_size);
214+
215+ /* Freeing/allocating operations may increase memory map size. */
216+ map_size += desc_size * 32;
217+
218+- memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size));
219++ alloc_size = 2 * BYTES_TO_PAGES (map_size);
220++ memory_map = grub_efi_allocate_any_pages (alloc_size);
221+ if (! memory_map)
222+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map");
223+
224+@@ -642,8 +643,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
225+ #endif
226+
227+ /* Release the memory maps. */
228+- grub_efi_free_pages ((grub_addr_t) memory_map,
229+- 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
230++ grub_efi_free_pages ((grub_efi_physical_address_t) (grub_addr_t) memory_map, alloc_size);
231+
232+ return GRUB_ERR_NONE;
233+ }
234diff --git a/debian/patches/kern-efi-mm-Detect-calls-to-grub_efi_drop_alloc-with-wron.patch b/debian/patches/kern-efi-mm-Detect-calls-to-grub_efi_drop_alloc-with-wron.patch
235new file mode 100644
236index 0000000..9de1acd
237--- /dev/null
238+++ b/debian/patches/kern-efi-mm-Detect-calls-to-grub_efi_drop_alloc-with-wron.patch
239@@ -0,0 +1,34 @@
240+From: Mate Kukri <mate.kukri@canonical.com>
241+Date: Wed, 12 Jun 2024 09:29:29 +0100
242+Subject: kern/efi/mm: Detect calls to grub_efi_drop_alloc() with wrong page
243+ counts
244+
245+Silently keeping entries in the list if the address matches, but the
246+page count doesn't is a bad idea, and can lead to double frees.
247+
248+grub_efi_free_pages() have already freed parts of this block by this
249+point, and thus keeping the whole block in the list and freeing it again
250+at exit can lead to double frees.
251+
252+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
253+---
254+ grub-core/kern/efi/mm.c | 6 ++++--
255+ 1 file changed, 4 insertions(+), 2 deletions(-)
256+
257+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
258+index 6613191..d45d0e2 100644
259+--- a/grub-core/kern/efi/mm.c
260++++ b/grub-core/kern/efi/mm.c
261+@@ -95,8 +95,10 @@ grub_efi_drop_alloc (grub_efi_physical_address_t address,
262+
263+ for (eap = NULL, ea = efi_allocated_memory; ea; eap = ea, ea = ea->next)
264+ {
265+- if (ea->address != address || ea->pages != pages)
266+- continue;
267++ if (ea->address != address)
268++ continue;
269++ if (ea->pages != pages)
270++ grub_fatal ("grub_efi_drop_alloc() called with wrong page count");
271+
272+ /* Remove the current entry from the list. */
273+ if (eap)
274diff --git a/debian/patches/nx/efi-Disallow-fallback-to-legacy-Linux-loader-when-shim-sa.patch b/debian/patches/nx/efi-Disallow-fallback-to-legacy-Linux-loader-when-shim-sa.patch
275new file mode 100644
276index 0000000..ecb6371
277--- /dev/null
278+++ b/debian/patches/nx/efi-Disallow-fallback-to-legacy-Linux-loader-when-shim-sa.patch
279@@ -0,0 +1,116 @@
280+From: Mate Kukri <mate.kukri@canonical.com>
281+Date: Fri, 31 May 2024 13:00:37 +0100
282+Subject: efi: Disallow fallback to legacy Linux loader when shim says NX is
283+ required.
284+
285+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
286+---
287+ grub-core/kern/efi/sb.c | 28 ++++++++++++++++++++++++++++
288+ grub-core/loader/efi/linux.c | 13 ++++++++-----
289+ include/grub/efi/api.h | 2 ++
290+ include/grub/efi/sb.h | 2 ++
291+ 4 files changed, 40 insertions(+), 5 deletions(-)
292+
293+diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
294+index 80cfa08..8eb6bce 100644
295+--- a/grub-core/kern/efi/sb.c
296++++ b/grub-core/kern/efi/sb.c
297+@@ -218,3 +218,31 @@ grub_shim_lock_verifier_setup (void)
298+ grub_env_set ("shim_lock", "y");
299+ grub_env_export ("shim_lock");
300+ }
301++
302++int
303++grub_efi_check_nx_required (void)
304++{
305++ int nx_required = 1; /* assume required, unless we can prove otherwise */
306++ grub_efi_status_t status;
307++ grub_size_t mok_policy_sz = 0;
308++ char *mok_policy = NULL;
309++ grub_uint32_t mok_policy_attrs = 0;
310++
311++ status = grub_efi_get_variable_with_attributes ("MokPolicy",
312++ &(grub_guid_t) GRUB_EFI_SHIM_LOCK_GUID,
313++ &mok_policy_sz,
314++ (void **)&mok_policy,
315++ &mok_policy_attrs);
316++ if (status != GRUB_EFI_SUCCESS ||
317++ mok_policy_sz != 1 ||
318++ mok_policy == NULL ||
319++ mok_policy_attrs != GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS)
320++ goto out;
321++
322++ nx_required = !!(mok_policy[0] & GRUB_MOK_POLICY_NX_REQUIRED);
323++
324++ out:
325++ grub_free (mok_policy);
326++
327++ return nx_required;
328++}
329+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
330+index 2b891d6..47ef165 100644
331+--- a/grub-core/loader/efi/linux.c
332++++ b/grub-core/loader/efi/linux.c
333+@@ -29,6 +29,7 @@
334+ #include <grub/efi/fdtload.h>
335+ #include <grub/efi/memory.h>
336+ #include <grub/efi/pe32.h>
337++#include <grub/efi/sb.h>
338+ #include <grub/i18n.h>
339+ #include <grub/lib/cmdline.h>
340+ #include <grub/verify.h>
341+@@ -473,21 +474,23 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
342+
343+ kernel_size = grub_file_size (file);
344+
345+- if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE)
346+ #if !defined(__i386__) && !defined(__x86_64__)
347++ if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE)
348+ goto fail;
349+ #else
350+- goto fallback;
351+-
352+- if (!initrd_use_loadfile2)
353++ if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE ||
354++ !initrd_use_loadfile2)
355+ {
356++ /* We cannot use the legacy loader when NX is required */
357++ if (grub_efi_check_nx_required())
358++ goto fail;
359++
360+ /*
361+ * This is a EFI stub image but it is too old to implement the LoadFile2
362+ * based initrd loading scheme, and Linux/x86 does not support the DT
363+ * based method either. So fall back to the x86-specific loader that
364+ * enters Linux in EFI mode but without going through its EFI stub.
365+ */
366+-fallback:
367+ grub_file_close (file);
368+ return grub_cmd_linux_x86_legacy (cmd, argc, argv);
369+ }
370+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
371+index 699bccf..343f968 100644
372+--- a/include/grub/efi/api.h
373++++ b/include/grub/efi/api.h
374+@@ -2023,6 +2023,8 @@ struct grub_efi_dt_fixup
375+ };
376+ typedef struct grub_efi_dt_fixup grub_efi_dt_fixup_t;
377+
378++#define GRUB_MOK_POLICY_NX_REQUIRED 0x1
379++
380+ struct grub_efi_shim_lock_protocol
381+ {
382+ /*
383+diff --git a/include/grub/efi/sb.h b/include/grub/efi/sb.h
384+index 30c4335..83ba311 100644
385+--- a/include/grub/efi/sb.h
386++++ b/include/grub/efi/sb.h
387+@@ -33,6 +33,8 @@ EXPORT_FUNC (grub_efi_get_secureboot) (void);
388+
389+ extern void
390+ grub_shim_lock_verifier_setup (void);
391++extern int
392++EXPORT_FUNC (grub_efi_check_nx_required) (void);
393+ #else
394+ static inline grub_uint8_t
395+ grub_efi_get_secureboot (void)
396diff --git a/debian/patches/nx/modules-Don-t-allocate-space-for-non-allocable-sections.patch b/debian/patches/nx/modules-Don-t-allocate-space-for-non-allocable-sections.patch
397new file mode 100644
398index 0000000..4721e2d
399--- /dev/null
400+++ b/debian/patches/nx/modules-Don-t-allocate-space-for-non-allocable-sections.patch
401@@ -0,0 +1,37 @@
402+From: Peter Jones <pjones@redhat.com>
403+Date: Mon, 21 Mar 2022 16:56:10 -0400
404+Subject: modules: Don't allocate space for non-allocable sections.
405+
406+Currently when loading grub modules, we allocate space for all sections,
407+including those without SHF_ALLOC set. We then copy the sections that
408+/do/ have SHF_ALLOC set into the allocated memory, leaving some of our
409+allocation untouched forever. Additionally, on platforms with GOT
410+fixups and trampolines, we currently compute alignment round-ups for the
411+sections and sections with sh_size = 0.
412+
413+This patch removes the extra space from the allocation computation, and
414+makes the allocation computation loop skip empty sections as the loading
415+loop does.
416+
417+Signed-off-by: Peter Jones <pjones@redhat.com>
418+Signed-off-by: Jan Setje-Eilers <jan.setjeeilers@oracle.com>
419+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
420+Reviewed-By: Vladimir Serbinenko
421+---
422+ grub-core/kern/dl.c | 3 +++
423+ 1 file changed, 3 insertions(+)
424+
425+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
426+index 0bf40ca..37db9fa 100644
427+--- a/grub-core/kern/dl.c
428++++ b/grub-core/kern/dl.c
429+@@ -237,6 +237,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
430+ i < e->e_shnum;
431+ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
432+ {
433++ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
434++ continue;
435++
436+ tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
437+ if (talign < s->sh_addralign)
438+ talign = s->sh_addralign;
439diff --git a/debian/patches/nx/modules-load-module-sections-at-page-aligned-addresses.patch b/debian/patches/nx/modules-load-module-sections-at-page-aligned-addresses.patch
440new file mode 100644
441index 0000000..a652ea3
442--- /dev/null
443+++ b/debian/patches/nx/modules-load-module-sections-at-page-aligned-addresses.patch
444@@ -0,0 +1,390 @@
445+From: Mate Kukri <mate.kukri@canonical.com>
446+Date: Mon, 21 Mar 2022 17:45:40 -0400
447+Subject: modules: load module sections at page-aligned addresses
448+
449+Currently we load module sections at whatever alignment gcc+ld happened
450+to dump into the ELF section header, which is often less then the page
451+size. Since NX protections are page based, this alignment must be
452+rounded up to page size on platforms supporting NX protections.
453+
454+This patch switches most EFI platforms to load module sections at 4kB
455+page-aligned addresses. To do so, it adds an new per-arch function,
456+grub_arch_dl_min_alignment(), which returns the alignment needed for
457+dynamically loaded sections (in bytes). Currently it sets it to 4096
458+when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and
459+1-byte alignment on everything else.
460+
461+It then changes the allocation size computation and the loader code in
462+grub_dl_load_segments() to align the locations and sizes up to these
463+boundaries, and fills any added padding with zeros.
464+
465+All of this happens before relocations are applied, so the relocations
466+factor that in with no change.
467+
468+Original-Author: Peter Jones <pjones@redhat.com>
469+Original-Author: Laszlo Ersek <lersek@redhat.com>
470+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
471+---
472+ docs/grub-dev.texi | 6 ++---
473+ grub-core/kern/arm/dl.c | 13 +++++++++++
474+ grub-core/kern/arm64/dl.c | 13 +++++++++++
475+ grub-core/kern/dl.c | 53 +++++++++++++++++++++++++++++++--------------
476+ grub-core/kern/emu/full.c | 13 +++++++++++
477+ grub-core/kern/i386/dl.c | 13 +++++++++++
478+ grub-core/kern/ia64/dl.c | 9 ++++++++
479+ grub-core/kern/mips/dl.c | 8 +++++++
480+ grub-core/kern/powerpc/dl.c | 9 ++++++++
481+ grub-core/kern/riscv/dl.c | 13 +++++++++++
482+ grub-core/kern/sparc64/dl.c | 9 ++++++++
483+ grub-core/kern/x86_64/dl.c | 13 +++++++++++
484+ include/grub/dl.h | 2 ++
485+ 13 files changed, 155 insertions(+), 19 deletions(-)
486+
487+diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
488+index 1276c59..2f782cd 100644
489+--- a/docs/grub-dev.texi
490++++ b/docs/grub-dev.texi
491+@@ -996,9 +996,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files
492+ (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c).
493+ At this stage you will also need to add dummy dl.c and cache.S with functions
494+ grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t
495+-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and
496+-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They
497+-won't be used for now.
498++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t
499++grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void
500++*address, grub_size_t len) (cache.S). They won't be used for now.
501+
502+ You will need to create directory include/$cpu/$platform and a file
503+ include/$cpu/types.h. The latter following this template:
504+diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c
505+index eab9d17..9260737 100644
506+--- a/grub-core/kern/arm/dl.c
507++++ b/grub-core/kern/arm/dl.c
508+@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr)
509+
510+ return GRUB_ERR_NONE;
511+ }
512++
513++/*
514++ * Tell the loader what our minimum section alignment is.
515++ */
516++grub_size_t
517++grub_arch_dl_min_alignment (void)
518++{
519++#ifdef GRUB_MACHINE_EFI
520++ return 4096;
521++#else
522++ return 1;
523++#endif
524++}
525+diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c
526+index a2b5789..95c6d5b 100644
527+--- a/grub-core/kern/arm64/dl.c
528++++ b/grub-core/kern/arm64/dl.c
529+@@ -196,3 +196,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
530+
531+ return GRUB_ERR_NONE;
532+ }
533++
534++/*
535++ * Tell the loader what our minimum section alignment is.
536++ */
537++grub_size_t
538++grub_arch_dl_min_alignment (void)
539++{
540++#ifdef GRUB_MACHINE_EFI
541++ return 4096;
542++#else
543++ return 1;
544++#endif
545++}
546+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
547+index 37db9fa..8338f74 100644
548+--- a/grub-core/kern/dl.c
549++++ b/grub-core/kern/dl.c
550+@@ -224,25 +224,35 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
551+ {
552+ unsigned i;
553+ const Elf_Shdr *s;
554+- grub_size_t tsize = 0, talign = 1;
555++ grub_size_t tsize = 0, talign = 1, arch_addralign = 1;
556+ #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
557+ !defined (__loongarch__)
558+ grub_size_t tramp;
559++ grub_size_t tramp_align;
560+ grub_size_t got;
561++ grub_size_t got_align;
562+ grub_err_t err;
563+ #endif
564+ char *ptr;
565+
566++ arch_addralign = grub_arch_dl_min_alignment ();
567++
568+ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
569+ i < e->e_shnum;
570+ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
571+ {
572++ grub_size_t sh_addralign;
573++ grub_size_t sh_size;
574++
575+ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
576+ continue;
577+
578+- tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
579+- if (talign < s->sh_addralign)
580+- talign = s->sh_addralign;
581++ sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
582++ sh_size = ALIGN_UP(s->sh_size, sh_addralign);
583++
584++ tsize = ALIGN_UP (tsize, sh_addralign) + sh_size;
585++ if (talign < sh_addralign)
586++ talign = sh_addralign;
587+ }
588+
589+ #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
590+@@ -250,12 +260,18 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
591+ err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
592+ if (err)
593+ return err;
594+- tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
595+- if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
596+- talign = GRUB_ARCH_DL_TRAMP_ALIGN;
597+- tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
598+- if (talign < GRUB_ARCH_DL_GOT_ALIGN)
599+- talign = GRUB_ARCH_DL_GOT_ALIGN;
600++ tramp_align = GRUB_ARCH_DL_TRAMP_ALIGN;
601++ if (tramp_align < arch_addralign)
602++ tramp_align = arch_addralign;
603++ tsize += ALIGN_UP (tramp, tramp_align);
604++ if (talign < tramp_align)
605++ talign = tramp_align;
606++ got_align = GRUB_ARCH_DL_GOT_ALIGN;
607++ if (got_align < arch_addralign)
608++ got_align = arch_addralign;
609++ tsize += ALIGN_UP (got, got_align);
610++ if (talign < got_align)
611++ talign = got_align;
612+ #endif
613+
614+ #ifdef GRUB_MACHINE_EMU
615+@@ -272,6 +288,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
616+ i < e->e_shnum;
617+ i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
618+ {
619++ grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
620++ grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign);
621++
622+ if (s->sh_flags & SHF_ALLOC)
623+ {
624+ grub_dl_segment_t seg;
625+@@ -284,17 +303,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
626+ {
627+ void *addr;
628+
629+- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
630++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign);
631+ addr = ptr;
632+- ptr += s->sh_size;
633++ ptr += sh_size;
634+
635+ switch (s->sh_type)
636+ {
637+ case SHT_PROGBITS:
638+ grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
639++ grub_memset ((char *)addr + s->sh_size, 0,
640++ sh_size - s->sh_size);
641+ break;
642+ case SHT_NOBITS:
643+- grub_memset (addr, 0, s->sh_size);
644++ grub_memset (addr, 0, sh_size);
645+ break;
646+ }
647+
648+@@ -303,7 +324,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
649+ else
650+ seg->addr = 0;
651+
652+- seg->size = s->sh_size;
653++ seg->size = sh_size;
654+ seg->section = i;
655+ seg->next = mod->segment;
656+ mod->segment = seg;
657+@@ -311,11 +332,11 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
658+ }
659+ #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
660+ !defined (__loongarch__)
661+- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
662++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, tramp_align);
663+ mod->tramp = ptr;
664+ mod->trampptr = ptr;
665+ ptr += tramp;
666+- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
667++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, got_align);
668+ mod->got = ptr;
669+ mod->gotptr = ptr;
670+ ptr += got;
671+diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c
672+index e8d63b1..1de1c28 100644
673+--- a/grub-core/kern/emu/full.c
674++++ b/grub-core/kern/emu/full.c
675+@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void)
676+ }
677+ #endif
678+
679++
680++/*
681++ * Tell the loader what our minimum section alignment is.
682++ */
683++grub_size_t
684++grub_arch_dl_min_alignment (void)
685++{
686++#ifdef GRUB_MACHINE_EFI
687++ return 4096;
688++#else
689++ return 1;
690++#endif
691++}
692+diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c
693+index 1346da5..d6b4681 100644
694+--- a/grub-core/kern/i386/dl.c
695++++ b/grub-core/kern/i386/dl.c
696+@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
697+
698+ return GRUB_ERR_NONE;
699+ }
700++
701++/*
702++ * Tell the loader what our minimum section alignment is.
703++ */
704++grub_size_t
705++grub_arch_dl_min_alignment (void)
706++{
707++#ifdef GRUB_MACHINE_EFI
708++ return 4096;
709++#else
710++ return 1;
711++#endif
712++}
713+diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c
714+index db59300..92d82c5 100644
715+--- a/grub-core/kern/ia64/dl.c
716++++ b/grub-core/kern/ia64/dl.c
717+@@ -148,3 +148,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
718+ }
719+ return GRUB_ERR_NONE;
720+ }
721++
722++/*
723++ * Tell the loader what our minimum section alignment is.
724++ */
725++grub_size_t
726++grub_arch_dl_min_alignment (void)
727++{
728++ return 1;
729++}
730+diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c
731+index 5b02f97..db41189 100644
732+--- a/grub-core/kern/mips/dl.c
733++++ b/grub-core/kern/mips/dl.c
734+@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void)
735+ grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0);
736+ }
737+
738++/*
739++ * Tell the loader what our minimum section alignment is.
740++ */
741++grub_size_t
742++grub_arch_dl_min_alignment (void)
743++{
744++ return 1;
745++}
746+diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c
747+index 7b6418e..0eb8bc5 100644
748+--- a/grub-core/kern/powerpc/dl.c
749++++ b/grub-core/kern/powerpc/dl.c
750+@@ -167,3 +167,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
751+
752+ return GRUB_ERR_NONE;
753+ }
754++
755++/*
756++ * Tell the loader what our minimum section alignment is.
757++ */
758++grub_size_t
759++grub_arch_dl_min_alignment (void)
760++{
761++ return 1;
762++}
763+diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c
764+index 896653b..1fa085b 100644
765+--- a/grub-core/kern/riscv/dl.c
766++++ b/grub-core/kern/riscv/dl.c
767+@@ -344,3 +344,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
768+
769+ return GRUB_ERR_NONE;
770+ }
771++
772++/*
773++ * Tell the loader what our minimum section alignment is.
774++ */
775++grub_size_t
776++grub_arch_dl_min_alignment (void)
777++{
778++#ifdef GRUB_MACHINE_EFI
779++ return 4096;
780++#else
781++ return 1;
782++#endif
783++}
784+diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c
785+index f3d9601..f054f08 100644
786+--- a/grub-core/kern/sparc64/dl.c
787++++ b/grub-core/kern/sparc64/dl.c
788+@@ -189,3 +189,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
789+
790+ return GRUB_ERR_NONE;
791+ }
792++
793++/*
794++ * Tell the loader what our minimum section alignment is.
795++ */
796++grub_size_t
797++grub_arch_dl_min_alignment (void)
798++{
799++ return 1;
800++}
801+diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c
802+index e5a8bdc..a105dc5 100644
803+--- a/grub-core/kern/x86_64/dl.c
804++++ b/grub-core/kern/x86_64/dl.c
805+@@ -119,3 +119,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
806+
807+ return GRUB_ERR_NONE;
808+ }
809++
810++/*
811++ * Tell the loader what our minimum section alignment is.
812++ */
813++grub_size_t
814++grub_arch_dl_min_alignment (void)
815++{
816++#ifdef GRUB_MACHINE_EFI
817++ return 4096;
818++#else
819++ return 1;
820++#endif
821++}
822+diff --git a/include/grub/dl.h b/include/grub/dl.h
823+index cd1f46c..e890210 100644
824+--- a/include/grub/dl.h
825++++ b/include/grub/dl.h
826+@@ -264,6 +264,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr);
827+ grub_err_t
828+ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
829+ Elf_Shdr *s, grub_dl_segment_t seg);
830++grub_size_t
831++grub_arch_dl_min_alignment (void);
832+ #endif
833+
834+ #if defined (_mips)
835diff --git a/debian/patches/nx/modules-strip-.llvm_addrsig-sections-and-similar.patch b/debian/patches/nx/modules-strip-.llvm_addrsig-sections-and-similar.patch
836new file mode 100644
837index 0000000..a60c07b
838--- /dev/null
839+++ b/debian/patches/nx/modules-strip-.llvm_addrsig-sections-and-similar.patch
840@@ -0,0 +1,41 @@
841+From: Peter Jones <pjones@redhat.com>
842+Date: Thu, 24 Feb 2022 16:40:11 -0500
843+Subject: modules: strip .llvm_addrsig sections and similar.
844+
845+Currently grub modules built with clang or gcc have several sections
846+which we don't actually need or support.
847+
848+We already have a list of section to skip in genmod.sh, and this patch
849+adds the following sections to that list (as well as a few newlines):
850+
851+.note.gnu.property
852+.llvm*
853+
854+Note that the glob there won't work without a new enough linker, but the
855+failure is just reversion to the status quo, so that's not a big problem.
856+
857+Signed-off-by: Peter Jones <pjones@redhat.com>
858+Signed-off-by: Jan Setje-Eilers <jan.setjeeilers@oracle.com>
859+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
860+Reviewed-By: Vladimir Serbinenko
861+---
862+ grub-core/genmod.sh.in | 5 ++++-
863+ 1 file changed, 4 insertions(+), 1 deletion(-)
864+
865+diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in
866+index e57c4d9..337753c 100644
867+--- a/grub-core/genmod.sh.in
868++++ b/grub-core/genmod.sh.in
869+@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then
870+ @TARGET_STRIP@ --strip-unneeded \
871+ -K grub_mod_init -K grub_mod_fini \
872+ -K _grub_mod_init -K _grub_mod_fini \
873+- -R .note.gnu.gold-version -R .note.GNU-stack \
874++ -R .note.GNU-stack \
875++ -R .note.gnu.gold-version \
876++ -R .note.gnu.property \
877+ -R .gnu.build.attributes \
878++ -R '.llvm*' \
879+ -R .rel.gnu.build.attributes \
880+ -R .rela.gnu.build.attributes \
881+ -R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \
882diff --git a/debian/patches/nx/nx-add-memory-attribute-get-set-API.patch b/debian/patches/nx/nx-add-memory-attribute-get-set-API.patch
883new file mode 100644
884index 0000000..cf58691
885--- /dev/null
886+++ b/debian/patches/nx/nx-add-memory-attribute-get-set-API.patch
887@@ -0,0 +1,252 @@
888+From: Mate Kukri <mate.kukri@canonical.com>
889+Date: Tue, 22 Mar 2022 10:56:21 -0400
890+Subject: nx: add memory attribute get/set API
891+
892+For NX, we need to set the page access permission attributes for write
893+and execute permissions.
894+
895+This patch adds two new primitives, grub_set_mem_attrs() and
896+grub_clear_mem_attrs(), and associated constant definitions, to be used
897+for that purpose.
898+
899+For most platforms, it adds a dummy implementation that returns
900+GRUB_ERR_NONE.
901+
902+On EFI platforms, it implements the primitives using the EFI
903+Memory Attribute Protocol (defined in UEFI 2.10 specification).
904+
905+Original-Author: Peter Jones <pjones@redhat.com>
906+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
907+---
908+ grub-core/kern/efi/mm.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++
909+ include/grub/efi/api.h | 25 ++++++++++
910+ include/grub/mm.h | 33 +++++++++++++
911+ 3 files changed, 185 insertions(+)
912+
913+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
914+index d45d0e2..790094c 100644
915+--- a/grub-core/kern/efi/mm.c
916++++ b/grub-core/kern/efi/mm.c
917+@@ -689,3 +689,130 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
918+ return GRUB_ERR_NONE;
919+ }
920+ #endif
921++
922++static inline grub_uint64_t
923++grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs)
924++{
925++ grub_uint64_t ret = GRUB_EFI_MEMORY_RP |
926++ GRUB_EFI_MEMORY_RO |
927++ GRUB_EFI_MEMORY_XP;
928++
929++ if (attrs & GRUB_MEM_ATTR_R)
930++ ret &= ~GRUB_EFI_MEMORY_RP;
931++
932++ if (attrs & GRUB_MEM_ATTR_W)
933++ ret &= ~GRUB_EFI_MEMORY_RO;
934++
935++ if (attrs & GRUB_MEM_ATTR_X)
936++ ret &= ~GRUB_EFI_MEMORY_XP;
937++
938++ return ret;
939++}
940++
941++static inline grub_uint64_t
942++uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs)
943++{
944++ grub_uint64_t ret = GRUB_MEM_ATTR_R |
945++ GRUB_MEM_ATTR_W |
946++ GRUB_MEM_ATTR_X;
947++
948++ if (attrs & GRUB_EFI_MEMORY_RP)
949++ ret &= ~GRUB_MEM_ATTR_R;
950++
951++ if (attrs & GRUB_EFI_MEMORY_RO)
952++ ret &= ~GRUB_MEM_ATTR_W;
953++
954++ if (attrs & GRUB_EFI_MEMORY_XP)
955++ ret &= ~GRUB_MEM_ATTR_X;
956++
957++ return ret;
958++}
959++
960++grub_err_t
961++grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs)
962++{
963++ grub_efi_memory_attribute_protocol_t *proto;
964++ grub_efi_physical_address_t physaddr = addr;
965++ grub_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
966++ grub_efi_status_t efi_status;
967++
968++ if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL)
969++ {
970++ return grub_error (GRUB_ERR_BAD_ARGUMENT,
971++ N_("grub_get_mem_attrs() called with invalid arguments"));
972++ }
973++
974++ proto = grub_efi_locate_protocol (&protocol_guid, 0);
975++ if (!proto)
976++ {
977++ /* No protocol -> do nothing, all memory is RWX in boot services */
978++ *attrs = GRUB_MEM_ATTR_R | GRUB_MEM_ATTR_W | GRUB_MEM_ATTR_X;
979++ return GRUB_ERR_NONE;
980++ }
981++
982++ efi_status = proto->get_memory_attributes(proto, physaddr, size, attrs);
983++ if (efi_status != GRUB_EFI_SUCCESS)
984++ {
985++ return grub_error (GRUB_ERR_BAD_ARGUMENT,
986++ N_("grub_get_mem_attrs() called with invalid arguments"));
987++ }
988++
989++ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs);
990++
991++ grub_dprintf ("nx", "get 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR":%c%c%c\n",
992++ addr, addr + size - 1,
993++ (*attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
994++ (*attrs & GRUB_MEM_ATTR_W) ? 'w' : '-',
995++ (*attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
996++
997++ return GRUB_ERR_NONE;
998++}
999++
1000++grub_err_t
1001++grub_update_mem_attrs (grub_addr_t addr, grub_size_t size,
1002++ grub_uint64_t set_attrs, grub_uint64_t clear_attrs)
1003++{
1004++ grub_efi_memory_attribute_protocol_t *proto;
1005++ grub_efi_physical_address_t physaddr = addr;
1006++ grub_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
1007++ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS;
1008++ grub_uint64_t uefi_set_attrs, uefi_clear_attrs;
1009++
1010++
1011++ if (physaddr & 0xfff || size & 0xfff || size == 0)
1012++ {
1013++ return grub_error (GRUB_ERR_BAD_ARGUMENT,
1014++ N_("grub_update_mem_attrs() called with invalid arguments"));
1015++ }
1016++
1017++ proto = grub_efi_locate_protocol (&protocol_guid, 0);
1018++ if (!proto)
1019++ {
1020++ /* No protocol -> do nothing, all memory is RWX in boot services */
1021++ return GRUB_ERR_NONE;
1022++ }
1023++
1024++ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs);
1025++ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs);
1026++ if (uefi_set_attrs)
1027++ efi_status = proto->set_memory_attributes(proto, physaddr, size, uefi_set_attrs);
1028++ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs)
1029++ efi_status = proto->clear_memory_attributes(proto, physaddr, size, uefi_clear_attrs);
1030++
1031++ if (efi_status != GRUB_EFI_SUCCESS)
1032++ {
1033++ return grub_error (GRUB_ERR_BAD_ARGUMENT,
1034++ N_("grub_update_mem_attrs() called with invalid arguments"));
1035++ }
1036++
1037++ grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR"\n",
1038++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
1039++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
1040++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
1041++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
1042++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
1043++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
1044++ addr, addr + size - 1);
1045++
1046++ return GRUB_ERR_NONE;
1047++}
1048+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
1049+index a89bf3d..699bccf 100644
1050+--- a/include/grub/efi/api.h
1051++++ b/include/grub/efi/api.h
1052+@@ -393,6 +393,11 @@
1053+ {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } \
1054+ }
1055+
1056++#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \
1057++ { 0xf4560cf6, 0x40ec, 0x4b4a, \
1058++ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \
1059++ }
1060++
1061+ struct grub_efi_sal_system_table
1062+ {
1063+ grub_uint32_t signature;
1064+@@ -2214,4 +2219,24 @@ struct initrd_media_device_path {
1065+ } GRUB_PACKED;
1066+ typedef struct initrd_media_device_path initrd_media_device_path_t;
1067+
1068++struct grub_efi_memory_attribute_protocol
1069++{
1070++ grub_efi_status_t (__grub_efi_api *get_memory_attributes) (
1071++ struct grub_efi_memory_attribute_protocol *this,
1072++ grub_efi_physical_address_t base_address,
1073++ grub_efi_uint64_t length,
1074++ grub_efi_uint64_t *attributes);
1075++ grub_efi_status_t (__grub_efi_api *set_memory_attributes) (
1076++ struct grub_efi_memory_attribute_protocol *this,
1077++ grub_efi_physical_address_t base_address,
1078++ grub_efi_uint64_t length,
1079++ grub_efi_uint64_t attributes);
1080++ grub_efi_status_t (__grub_efi_api *clear_memory_attributes) (
1081++ struct grub_efi_memory_attribute_protocol *this,
1082++ grub_efi_physical_address_t base_address,
1083++ grub_efi_uint64_t length,
1084++ grub_efi_uint64_t attributes);
1085++};
1086++typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t;
1087++
1088+ #endif /* ! GRUB_EFI_API_HEADER */
1089+diff --git a/include/grub/mm.h b/include/grub/mm.h
1090+index f3bf87f..dcccfe3 100644
1091+--- a/include/grub/mm.h
1092++++ b/include/grub/mm.h
1093+@@ -23,6 +23,7 @@
1094+ #include <grub/err.h>
1095+ #include <grub/types.h>
1096+ #include <grub/symbol.h>
1097++#include <grub/err.h>
1098+ #include <config.h>
1099+
1100+ #ifndef NULL
1101+@@ -56,6 +57,38 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size);
1102+ void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size);
1103+ #endif
1104+
1105++#define GRUB_MEM_ATTR_R 0x0000000000000004LLU
1106++#define GRUB_MEM_ATTR_W 0x0000000000000002LLU
1107++#define GRUB_MEM_ATTR_X 0x0000000000000001LLU
1108++
1109++#ifdef GRUB_MACHINE_EFI
1110++grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr,
1111++ grub_size_t size,
1112++ grub_uint64_t *attrs);
1113++grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr,
1114++ grub_size_t size,
1115++ grub_uint64_t set_attrs,
1116++ grub_uint64_t clear_attrs);
1117++#else /* !GRUB_MACHINE_EFI */
1118++static inline grub_err_t
1119++grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
1120++ grub_size_t size __attribute__((__unused__)),
1121++ grub_uint64_t *attrs __attribute__((__unused__)))
1122++{
1123++ *attrs = GRUB_MEM_ATTR_R | GRUB_MEM_ATTR_W | GRUB_MEM_ATTR_X;
1124++ return GRUB_ERR_NONE;
1125++}
1126++
1127++static inline grub_err_t
1128++grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
1129++ grub_size_t size __attribute__((__unused__)),
1130++ grub_uint64_t set_attrs __attribute__((__unused__)),
1131++ grub_uint64_t clear_attrs __attribute__((__unused__)))
1132++{
1133++ return GRUB_ERR_NONE;
1134++}
1135++#endif /* GRUB_MACHINE_EFI */
1136++
1137+ void grub_mm_check_real (const char *file, int line);
1138+ #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__);
1139+
1140diff --git a/debian/patches/nx/nx-set-page-permissions-for-loaded-modules.patch b/debian/patches/nx/nx-set-page-permissions-for-loaded-modules.patch
1141new file mode 100644
1142index 0000000..f4eecc9
1143--- /dev/null
1144+++ b/debian/patches/nx/nx-set-page-permissions-for-loaded-modules.patch
1145@@ -0,0 +1,222 @@
1146+From: Mate Kukri <mate.kukri@canonical.com>
1147+Date: Mon, 21 Mar 2022 17:46:35 -0400
1148+Subject: nx: set page permissions for loaded modules.
1149+
1150+For NX, we need to set write and executable permissions on the sections
1151+of grub modules when we load them.
1152+
1153+On sections with SHF_ALLOC set, which is typically everything except
1154+.modname and the symbol and string tables, this patch clears the Read
1155+Only flag on sections that have the ELF flag SHF_WRITE set, and clears
1156+the No eXecute flag on sections with SHF_EXECINSTR set. In all other
1157+cases it sets both flags.
1158+
1159+Original-Author: Peter Jones <pjones@redhat.com>
1160+Original-Author: Robbie Harwood <rharwood@redhat.com>
1161+Original-Author: Laszlo Ersek <lersek@redhat.com>
1162+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
1163+---
1164+ grub-core/kern/dl.c | 104 +++++++++++++++++++++++++++++++++++++++++++++-------
1165+ include/grub/dl.h | 46 +++++++++++++++++++++++
1166+ 2 files changed, 137 insertions(+), 13 deletions(-)
1167+
1168+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
1169+index 8338f74..3341d78 100644
1170+--- a/grub-core/kern/dl.c
1171++++ b/grub-core/kern/dl.c
1172+@@ -616,25 +616,97 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
1173+ grub_dl_segment_t seg;
1174+ grub_err_t err;
1175+
1176+- /* Find the target segment. */
1177+- for (seg = mod->segment; seg; seg = seg->next)
1178+- if (seg->section == s->sh_info)
1179+- break;
1180++ seg = grub_dl_find_segment(mod, s->sh_info);
1181++ if (!seg)
1182++ continue;
1183+
1184+- if (seg)
1185+- {
1186+- if (!mod->symtab)
1187+- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
1188++ if (!mod->symtab)
1189++ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
1190+
1191+- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
1192+- if (err)
1193+- return err;
1194+- }
1195++ err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
1196++ if (err)
1197++ return err;
1198+ }
1199+
1200+ return GRUB_ERR_NONE;
1201+ }
1202+
1203++/* Only define this on EFI to save space in core */
1204++#ifdef GRUB_MACHINE_EFI
1205++static grub_err_t
1206++grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
1207++{
1208++ unsigned i;
1209++ const Elf_Shdr *s;
1210++ const Elf_Ehdr *e = ehdr;
1211++ grub_err_t err;
1212++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
1213++ grub_size_t arch_addralign = grub_arch_dl_min_alignment ();
1214++ grub_addr_t tgaddr;
1215++ grub_size_t tgsz;
1216++#endif
1217++
1218++ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
1219++ i < e->e_shnum;
1220++ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
1221++ {
1222++ grub_dl_segment_t seg;
1223++ grub_uint64_t set_attrs = GRUB_MEM_ATTR_R;
1224++ grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X;
1225++
1226++ seg = grub_dl_find_segment(mod, i);
1227++ if (!seg)
1228++ continue;
1229++
1230++ if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC))
1231++ continue;
1232++
1233++ if (s->sh_flags & SHF_WRITE)
1234++ {
1235++ set_attrs |= GRUB_MEM_ATTR_W;
1236++ clear_attrs &= ~GRUB_MEM_ATTR_W;
1237++ }
1238++
1239++ if (s->sh_flags & SHF_EXECINSTR)
1240++ {
1241++ set_attrs |= GRUB_MEM_ATTR_X;
1242++ clear_attrs &= ~GRUB_MEM_ATTR_X;
1243++ }
1244++
1245++ err = grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size,
1246++ set_attrs, clear_attrs);
1247++ if (err != GRUB_ERR_NONE)
1248++ return err;
1249++ }
1250++
1251++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
1252++ tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got);
1253++ tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr;
1254++
1255++ if (tgsz)
1256++ {
1257++ tgsz = ALIGN_UP(tgsz, arch_addralign);
1258++
1259++ if (tgaddr < (grub_addr_t)mod->base ||
1260++ tgsz > (grub_addr_t)-1 - tgaddr ||
1261++ tgaddr + tgsz > (grub_addr_t)mod->base + mod->sz)
1262++ return grub_error (GRUB_ERR_BUG,
1263++ "BUG: trying to protect pages outside of module "
1264++ "allocation (\"%s\"): module base %p, size 0x%"
1265++ PRIxGRUB_SIZE "; tramp/GOT base 0x%" PRIxGRUB_ADDR
1266++ ", size 0x%" PRIxGRUB_SIZE,
1267++ mod->name, mod->base, mod->sz, tgaddr, tgsz);
1268++ err = grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X,
1269++ GRUB_MEM_ATTR_W);
1270++ if (err != GRUB_ERR_NONE)
1271++ return err;
1272++ }
1273++#endif
1274++
1275++ return GRUB_ERR_NONE;
1276++}
1277++#endif
1278++
1279+ /* Load a module from core memory. */
1280+ grub_dl_t
1281+ grub_dl_load_core_noinit (void *addr, grub_size_t size)
1282+@@ -668,6 +740,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
1283+ mod->ref_count = 1;
1284+
1285+ grub_dprintf ("modules", "relocating to %p\n", mod);
1286++
1287+ /* Me, Vladimir Serbinenko, hereby I add this module check as per new
1288+ GNU module policy. Note that this license check is informative only.
1289+ Modules have to be licensed under GPLv3 or GPLv3+ (optionally
1290+@@ -681,7 +754,12 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
1291+ || grub_dl_resolve_dependencies (mod, e)
1292+ || grub_dl_load_segments (mod, e)
1293+ || grub_dl_resolve_symbols (mod, e)
1294+- || grub_dl_relocate_symbols (mod, e))
1295++ || grub_dl_relocate_symbols (mod, e)
1296++#ifdef GRUB_MACHINE_EFI
1297++ || grub_dl_set_mem_attrs (mod, e))
1298++#else
1299++ )
1300++#endif
1301+ {
1302+ mod->fini = 0;
1303+ grub_dl_unload (mod);
1304+diff --git a/include/grub/dl.h b/include/grub/dl.h
1305+index e890210..00aaa9c 100644
1306+--- a/include/grub/dl.h
1307++++ b/include/grub/dl.h
1308+@@ -27,6 +27,7 @@
1309+ #include <grub/elf.h>
1310+ #include <grub/list.h>
1311+ #include <grub/misc.h>
1312++#include <grub/mm.h>
1313+ #endif
1314+
1315+ /*
1316+@@ -254,6 +255,51 @@ grub_dl_is_persistent (grub_dl_t mod)
1317+ return mod->persistent;
1318+ }
1319+
1320++#pragma GCC diagnostic ignored "-Wcast-align"
1321++
1322++static inline const char *
1323++grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s)
1324++{
1325++ Elf_Shdr *str_s;
1326++ const char *str;
1327++
1328++ str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
1329++ str = (char *) e + str_s->sh_offset;
1330++
1331++ return str + s->sh_name;
1332++}
1333++
1334++static inline long
1335++grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
1336++{
1337++ Elf_Shdr *s;
1338++ const char *str;
1339++ unsigned i;
1340++
1341++ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
1342++ str = (char *) e + s->sh_offset;
1343++
1344++ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
1345++ i < e->e_shnum;
1346++ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
1347++ if (grub_strcmp (str + s->sh_name, name) == 0)
1348++ return (long)i;
1349++ return -1;
1350++}
1351++
1352++/* Return the segment for a section of index N */
1353++static inline grub_dl_segment_t
1354++grub_dl_find_segment (grub_dl_t mod, unsigned n)
1355++{
1356++ grub_dl_segment_t seg;
1357++
1358++ for (seg = mod->segment; seg; seg = seg->next)
1359++ if (seg->section == n)
1360++ return seg;
1361++
1362++ return NULL;
1363++}
1364++
1365+ #endif
1366+
1367+ grub_err_t grub_dl_register_symbol (const char *name, void *addr,
1368diff --git a/debian/patches/nx/nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch b/debian/patches/nx/nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
1369new file mode 100644
1370index 0000000..95f90f0
1371--- /dev/null
1372+++ b/debian/patches/nx/nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
1373@@ -0,0 +1,49 @@
1374+From: Mate Kukri <mate.kukri@canonical.com>
1375+Date: Tue, 22 Mar 2022 10:57:20 -0400
1376+Subject: nx: set the nx compatible flag in EFI grub images
1377+
1378+For NX, we need the grub binary to announce that it is compatible with
1379+the NX feature. This implies that when loading the executable grub
1380+image, several attributes are true:
1381+
1382+- the binary doesn't need an executable stack
1383+- the binary doesn't need sections to be both executable and writable
1384+- the binary knows how to use the EFI Memory Attributes protocol on code
1385+ it is loading.
1386+
1387+This patch
1388+- adds a definition for the PE DLL Characteristics flag GRUB_PE32_NX_COMPAT
1389+- changes grub-mkimage to set that flag.
1390+
1391+Original-Author: Peter Jones <pjones@redhat.com>
1392+Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
1393+---
1394+ include/grub/efi/pe32.h | 2 ++
1395+ util/mkimage.c | 1 +
1396+ 2 files changed, 3 insertions(+)
1397+
1398+diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
1399+index 4e6e9d2..9887e14 100644
1400+--- a/include/grub/efi/pe32.h
1401++++ b/include/grub/efi/pe32.h
1402+@@ -231,6 +231,8 @@ struct grub_pe64_optional_header
1403+
1404+ #define GRUB_PE32_SUBSYSTEM_EFI_APPLICATION 10
1405+
1406++#define GRUB_PE32_NX_COMPAT 0x0100
1407++
1408+ #define GRUB_PE32_NUM_DATA_DIRECTORIES 16
1409+
1410+ struct grub_pe32_section_table
1411+diff --git a/util/mkimage.c b/util/mkimage.c
1412+index ee0e6f6..dfd757a 100644
1413+--- a/util/mkimage.c
1414++++ b/util/mkimage.c
1415+@@ -1403,6 +1403,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
1416+ #pragma GCC diagnostic push
1417+ #pragma GCC diagnostic ignored "-Wdangling-pointer"
1418+ #endif
1419++ PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT);
1420+ PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size);
1421+ PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address);
1422+ PE_OHDR (o32, o64, image_base) = 0;
1423diff --git a/debian/patches/nx/peimage-Add-memory-attribute-support.patch b/debian/patches/nx/peimage-Add-memory-attribute-support.patch
1424new file mode 100644
1425index 0000000..8950430
1426--- /dev/null
1427+++ b/debian/patches/nx/peimage-Add-memory-attribute-support.patch
1428@@ -0,0 +1,132 @@
1429+From: Mate Kukri <mate.kukri@canonical.com>
1430+Date: Wed, 12 Jun 2024 15:08:04 +0100
1431+Subject: peimage: Add memory attribute support
1432+
1433+---
1434+ grub-core/loader/efi/peimage.c | 68 ++++++++++++++++++++++++++++++++++++++++--
1435+ 1 file changed, 65 insertions(+), 3 deletions(-)
1436+
1437+diff --git a/grub-core/loader/efi/peimage.c b/grub-core/loader/efi/peimage.c
1438+index e28f020..22d7e1a 100644
1439+--- a/grub-core/loader/efi/peimage.c
1440++++ b/grub-core/loader/efi/peimage.c
1441+@@ -8,6 +8,7 @@
1442+ #include <grub/efi/efi.h>
1443+ #include <grub/efi/pe32.h>
1444+ #include <grub/efi/peimage.h>
1445++#include <grub/efi/sb.h>
1446+ #include <grub/env.h>
1447+ #include <grub/misc.h>
1448+ #include <grub/mm.h>
1449+@@ -22,6 +23,7 @@ struct image_info
1450+ void *data;
1451+ grub_efi_uint32_t data_size;
1452+ grub_efi_device_path_t *file_path;
1453++ grub_efi_uint8_t nx_compat;
1454+ grub_efi_uint16_t machine;
1455+ grub_efi_uint16_t num_sections;
1456+ struct grub_pe32_section_table *section;
1457+@@ -145,6 +147,8 @@ check_pe_header (struct image_info *info)
1458+ grub_error (GRUB_ERR_BAD_OS, "expected EFI application");
1459+ return GRUB_EFI_LOAD_ERROR;
1460+ }
1461++ info->nx_compat =
1462++ (pe32_header->dll_characteristics & GRUB_PE32_NX_COMPAT) != 0;
1463+ info->section_alignment = pe32_header->section_alignment;
1464+ info->image_base = pe32_header->image_base;
1465+ info->image_size = pe32_header->image_size;
1466+@@ -171,6 +175,8 @@ check_pe_header (struct image_info *info)
1467+ grub_error (GRUB_ERR_BAD_OS, "expected EFI application");
1468+ return GRUB_EFI_LOAD_ERROR;
1469+ }
1470++ info->nx_compat =
1471++ (pe64_header->dll_characteristics & GRUB_PE32_NX_COMPAT) != 0;
1472+ info->section_alignment = pe64_header->section_alignment;
1473+ info->image_base = pe64_header->image_base;
1474+ info->image_size = pe64_header->image_size;
1475+@@ -196,6 +202,19 @@ check_pe_header (struct image_info *info)
1476+ return GRUB_EFI_LOAD_ERROR;
1477+ }
1478+
1479++ /* NOTE: shim_lock->verify() also enforces this, so this
1480++ * check won't be hit when used with shim */
1481++ if (grub_efi_check_nx_required() && !info->nx_compat)
1482++ {
1483++ grub_error (GRUB_ERR_BAD_OS, "NX policy violation");
1484++ return GRUB_EFI_SECURITY_VIOLATION;
1485++ }
1486++ if (info->nx_compat && info->section_alignment < GRUB_EFI_PAGE_SIZE)
1487++ {
1488++ grub_error (GRUB_ERR_BAD_OS, "NX compatible image with sub-page section alignment");
1489++ return GRUB_EFI_LOAD_ERROR;
1490++ }
1491++
1492+ if ((unsigned long)info->section
1493+ + info->num_sections * sizeof (*info->section)
1494+ > (unsigned long)info->data + info->data_size)
1495+@@ -221,6 +240,9 @@ load_sections (struct image_info *info)
1496+ {
1497+ struct grub_pe32_section_table *section;
1498+ unsigned long align_mask = 0xfff;
1499++ grub_addr_t section_addr;
1500++ grub_err_t err;
1501++ grub_uint64_t section_set_mem_attr, section_clear_mem_attr;
1502+
1503+ /* Section alignment must be a power of two */
1504+ if (info->section_alignment & (info->section_alignment - 1))
1505+@@ -264,12 +286,52 @@ load_sections (struct image_info *info)
1506+ return GRUB_EFI_LOAD_ERROR;
1507+ }
1508+
1509+- grub_memset ((void *)((unsigned long)info->image_addr + section->virtual_address),
1510+- 0, section->virtual_size);
1511++ section_addr = (grub_addr_t)info->image_addr + section->virtual_address;
1512++
1513++ grub_memset ((void *) section_addr, 0, section->virtual_size);
1514+ grub_memcpy (
1515+- (void *)((unsigned long)info->image_addr + section->virtual_address),
1516++ (void *) section_addr,
1517+ (void *)((unsigned long)info->data + section->raw_data_offset),
1518+ section->raw_data_size);
1519++
1520++ if (!info->nx_compat)
1521++ continue;
1522++
1523++ if (section_addr & (GRUB_EFI_PAGE_SIZE - 1))
1524++ {
1525++ grub_error (GRUB_ERR_BAD_OS, "NX compatible image with badly aligned section");
1526++ return GRUB_EFI_LOAD_ERROR;
1527++ }
1528++
1529++ if ((section->characteristics & GRUB_PE32_SCN_MEM_WRITE) && (section->characteristics & GRUB_PE32_SCN_MEM_EXECUTE))
1530++ {
1531++ grub_error (GRUB_ERR_BAD_OS, "NX compatible image with W|X section");
1532++ return GRUB_EFI_LOAD_ERROR;
1533++ }
1534++
1535++ section_set_mem_attr = 0;
1536++ section_clear_mem_attr = 0;
1537++ if (section->characteristics & GRUB_PE32_SCN_MEM_READ)
1538++ section_set_mem_attr |= GRUB_MEM_ATTR_R;
1539++ else
1540++ section_clear_mem_attr |= GRUB_MEM_ATTR_R;
1541++ if (section->characteristics & GRUB_PE32_SCN_MEM_WRITE)
1542++ section_set_mem_attr |= GRUB_MEM_ATTR_W;
1543++ else
1544++ section_clear_mem_attr |= GRUB_MEM_ATTR_W;
1545++ if (section->characteristics & GRUB_PE32_SCN_MEM_EXECUTE)
1546++ section_set_mem_attr |= GRUB_MEM_ATTR_X;
1547++ else
1548++ section_clear_mem_attr |= GRUB_MEM_ATTR_X;
1549++
1550++ err = grub_update_mem_attrs (section_addr,
1551++ GRUB_EFI_BYTES_TO_PAGES(section->virtual_size) * GRUB_EFI_PAGE_SIZE,
1552++ section_set_mem_attr, section_clear_mem_attr);
1553++ if (err != GRUB_ERR_NONE)
1554++ {
1555++ grub_error (GRUB_ERR_BAD_OS, "Failed to set PE section memory attributes");
1556++ return GRUB_EFI_LOAD_ERROR;
1557++ }
1558+ }
1559+
1560+ info->entry_point = (void *)((unsigned long)info->entry_point
1561diff --git a/debian/patches/secure-boot/efi-use-peimage-shim.patch b/debian/patches/secure-boot/efi-use-peimage-shim.patch
1562index 505f92f..c05440e 100644
1563--- a/debian/patches/secure-boot/efi-use-peimage-shim.patch
1564+++ b/debian/patches/secure-boot/efi-use-peimage-shim.patch
1565@@ -30,9 +30,9 @@ Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
1566 Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
1567 ---
1568 grub-core/Makefile.core.def | 12 +
1569- grub-core/loader/efi/peimage.c | 902 +++++++++++++++++++++++++++++++++++++++++
1570+ grub-core/loader/efi/peimage.c | 826 +++++++++++++++++++++++++++++++++++++++++
1571 include/grub/efi/peimage.h | 19 +
1572- 3 files changed, 933 insertions(+)
1573+ 3 files changed, 857 insertions(+)
1574 create mode 100644 grub-core/loader/efi/peimage.c
1575 create mode 100644 include/grub/efi/peimage.h
1576
1577@@ -61,10 +61,10 @@ index 333d3fe..c3ad031 100644
1578 efi = loader/efi/fdt.c;
1579 diff --git a/grub-core/loader/efi/peimage.c b/grub-core/loader/efi/peimage.c
1580 new file mode 100644
1581-index 0000000..0387277
1582+index 0000000..e28f020
1583 --- /dev/null
1584 +++ b/grub-core/loader/efi/peimage.c
1585-@@ -0,0 +1,902 @@
1586+@@ -0,0 +1,826 @@
1587 +/* peimage.c - load EFI PE binaries (for Secure Boot support) */
1588 +
1589 +// SPDX-License-Identifier: GPL-3.0+
1590@@ -82,33 +82,39 @@ index 0000000..0387277
1591 +
1592 +GRUB_MOD_LICENSE ("GPLv3+");
1593 +
1594-+
1595 +static grub_dl_t my_mod;
1596 +
1597 +struct image_info
1598 +{
1599-+ grub_efi_loaded_image_t loaded_image;
1600-+
1601-+ grub_efi_device_path_t *orig_file_path;
1602-+
1603 + void *data;
1604 + grub_efi_uint32_t data_size;
1605++ grub_efi_device_path_t *file_path;
1606 + grub_efi_uint16_t machine;
1607 + grub_efi_uint16_t num_sections;
1608 + struct grub_pe32_section_table *section;
1609 + struct grub_pe32_data_directory *reloc;
1610 + grub_uint64_t image_base;
1611 + grub_uint32_t section_alignment;
1612++ grub_uint32_t image_size;
1613 + grub_uint32_t header_size;
1614 + void *alloc_addr;
1615 + grub_uint32_t alloc_pages;
1616-+
1617++ void *image_addr;
1618 + grub_efi_status_t (__grub_efi_api *entry_point) (
1619-+ grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
1620++ grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
1621++};
1622 +
1623++static struct
1624++{
1625 + grub_jmp_buf jmp;
1626++ grub_efi_handle_t image_handle;
1627 + grub_efi_status_t exit_status;
1628-+};
1629++ grub_efi_status_t (__grub_efi_api *exit) (grub_efi_handle_t image_handle,
1630++ grub_efi_status_t exit_status,
1631++ grub_efi_uintn_t exit_data_size,
1632++ grub_efi_char16_t *exit_data);
1633++} started_image;
1634++
1635 +
1636 +static grub_uint16_t machines[] = {
1637 +#if defined(__x86_64__)
1638@@ -126,19 +132,6 @@ index 0000000..0387277
1639 +#endif
1640 +};
1641 +
1642-+// Forward declare unload_image handler
1643-+static grub_efi_status_t __grub_efi_api
1644-+do_unload_image (grub_efi_handle_t image_handle);
1645-+
1646-+// Original exit handler
1647-+static grub_efi_status_t (__grub_efi_api *exit_orig) (
1648-+ grub_efi_handle_t image_handle, grub_efi_status_t exit_status,
1649-+ grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data);
1650-+
1651-+// Original unload_image handler
1652-+static grub_efi_status_t (__grub_efi_api *unload_image_orig) (
1653-+ grub_efi_handle_t image_handle);
1654-+
1655 +/**
1656 + * check_machine_type() - check if the machine type matches the architecture
1657 + *
1658@@ -221,7 +214,7 @@ index 0000000..0387277
1659 + }
1660 + info->section_alignment = pe32_header->section_alignment;
1661 + info->image_base = pe32_header->image_base;
1662-+ info->loaded_image.image_size = pe32_header->image_size;
1663++ info->image_size = pe32_header->image_size;
1664 + info->entry_point = (void *)(unsigned long)pe32_header->entry_addr;
1665 + info->header_size = pe32_header->header_size;
1666 + if (info->data_size < info->header_size)
1667@@ -247,7 +240,7 @@ index 0000000..0387277
1668 + }
1669 + info->section_alignment = pe64_header->section_alignment;
1670 + info->image_base = pe64_header->image_base;
1671-+ info->loaded_image.image_size = pe64_header->image_size;
1672++ info->image_size = pe64_header->image_size;
1673 + info->entry_point = (void *)(unsigned long)pe64_header->entry_addr;
1674 + info->header_size = pe64_header->header_size;
1675 + if (info->data_size < info->header_size)
1676@@ -306,8 +299,7 @@ index 0000000..0387277
1677 + if (info->section_alignment > align_mask)
1678 + align_mask = info->section_alignment - 1;
1679 +
1680-+ info->alloc_pages = GRUB_EFI_BYTES_TO_PAGES (info->loaded_image.image_size
1681-+ + (align_mask & ~0xfffUL));
1682++ info->alloc_pages = GRUB_EFI_BYTES_TO_PAGES (info->image_size + (align_mask & ~0xfffUL));
1683 +
1684 + info->alloc_addr = grub_efi_allocate_pages_real (
1685 + GRUB_EFI_MAX_USABLE_ADDRESS, info->alloc_pages,
1686@@ -315,44 +307,40 @@ index 0000000..0387277
1687 + if (!info->alloc_addr)
1688 + return GRUB_EFI_OUT_OF_RESOURCES;
1689 +
1690-+ info->loaded_image.image_base
1691++ info->image_addr
1692 + = (void *)(((unsigned long)info->alloc_addr + align_mask) & ~align_mask);
1693 +
1694-+ grub_memcpy (info->loaded_image.image_base, info->data, info->header_size);
1695++ grub_memcpy (info->image_addr, info->data, info->header_size);
1696 + for (section = &info->section[0];
1697 + section < &info->section[info->num_sections]; ++section)
1698 + {
1699-+ if (section->virtual_address < info->header_size
1700-+ || (section->raw_data_size
1701-+ && section->raw_data_offset < info->header_size))
1702++ if ((section->raw_data_size && section->raw_data_offset < info->header_size)
1703++ || (section->virtual_size && section->virtual_address < info->header_size))
1704 + {
1705 + grub_error (GRUB_ERR_BAD_OS, "section inside header");
1706 + return GRUB_EFI_LOAD_ERROR;
1707 + }
1708-+ if (section->raw_data_offset + section->raw_data_size > info->data_size)
1709++ if (section->raw_data_size && section->raw_data_offset + section->raw_data_size > info->data_size)
1710 + {
1711 + grub_error (GRUB_ERR_BAD_OS, "truncated image");
1712 + return GRUB_EFI_LOAD_ERROR;
1713 + }
1714-+ if (section->virtual_address + section->virtual_size
1715-+ > info->loaded_image.image_size)
1716++ if (section->virtual_size && section->virtual_address + section->virtual_size > info->image_size)
1717 + {
1718 + grub_error (GRUB_ERR_BAD_OS, "section outside image");
1719 + return GRUB_EFI_LOAD_ERROR;
1720 + }
1721 +
1722-+ grub_memset ((void *)((unsigned long)info->loaded_image.image_base
1723-+ + section->virtual_address),
1724++ grub_memset ((void *)((unsigned long)info->image_addr + section->virtual_address),
1725 + 0, section->virtual_size);
1726 + grub_memcpy (
1727-+ (void *)((unsigned long)info->loaded_image.image_base
1728-+ + section->virtual_address),
1729++ (void *)((unsigned long)info->image_addr + section->virtual_address),
1730 + (void *)((unsigned long)info->data + section->raw_data_offset),
1731 + section->raw_data_size);
1732 + }
1733 +
1734 + info->entry_point = (void *)((unsigned long)info->entry_point
1735-+ + (unsigned long)info->loaded_image.image_base);
1736++ + (unsigned long)info->image_addr);
1737 +
1738 + grub_dprintf ("linux", "sections loaded\n");
1739 +
1740@@ -560,7 +548,7 @@ index 0000000..0387277
1741 + return GRUB_EFI_SUCCESS;
1742 + }
1743 +
1744-+ if (info->reloc->rva + info->reloc->size > info->loaded_image.image_size)
1745++ if (info->reloc->rva + info->reloc->size > info->image_size)
1746 + {
1747 + grub_error (GRUB_ERR_BAD_OS, "relocation block outside image");
1748 + return GRUB_EFI_LOAD_ERROR;
1749@@ -570,10 +558,9 @@ index 0000000..0387277
1750 + * The relocations are based on the difference between
1751 + * actual load address and the preferred base address.
1752 + */
1753-+ offset = (unsigned long)info->loaded_image.image_base - info->image_base;
1754++ offset = (unsigned long)info->image_addr - info->image_base;
1755 +
1756-+ block = (void *)((unsigned long)info->loaded_image.image_base
1757-+ + info->reloc->rva);
1758++ block = (void *)((unsigned long)info->image_addr + info->reloc->rva);
1759 + reloc_end = (void *)((unsigned long)block + info->reloc->size);
1760 +
1761 + for (; block < reloc_end;
1762@@ -585,7 +572,7 @@ index 0000000..0387277
1763 +
1764 + for (; reloc_entry < block_end; ++reloc_entry)
1765 + {
1766-+ void *addr = (void *)((unsigned long)info->loaded_image.image_base
1767++ void *addr = (void *)((unsigned long)info->image_addr
1768 + + block->page_rva + (*reloc_entry & 0xfff));
1769 +
1770 + reloc_type = *reloc_entry >> 12;
1771@@ -687,254 +674,203 @@ index 0000000..0387277
1772 +bad_reloc:
1773 + grub_error (GRUB_ERR_BAD_OS, "unsupported relocation type %d, rva 0x%08lx\n",
1774 + *reloc_entry >> 12,
1775-+ (unsigned long)reloc_entry
1776-+ - (unsigned long)info->loaded_image.image_base);
1777++ (unsigned long)reloc_entry - (unsigned long)info->image_addr);
1778 + return GRUB_EFI_LOAD_ERROR;
1779 +}
1780 +
1781 +/**
1782-+ * exit_hook() - replacement for EFI_BOOT_SERVICES.Exit()
1783++ * efi_exit() - replacement for EFI_BOOT_SERVICES.Exit()
1784 + *
1785 + * This function is inserted into system table to trap invocations of
1786 + * EFI_BOOT_SERVICES.Exit(). If Exit() is called with our handle
1787 + * return to our start routine using a long jump.
1788 + *
1789-+ * @image_handle: handle of the application as passed on entry
1790-+ * @exit_status: the images exit code
1791-+ * @exit_data_size: size of @exit_data
1792-+ * @exit_data: null terminated string followed by optional data
1793++ * @image_handle: handle of the application as passed on entry
1794++ * @exit_status: the images exit code
1795++ * @exit_data_size: size of @exit_data
1796++ * @exit_data: null terminated string followed by optional data
1797 + */
1798 +static grub_efi_status_t __grub_efi_api
1799-+exit_hook (grub_efi_handle_t image_handle, grub_efi_status_t exit_status,
1800-+ grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data)
1801++efi_exit (grub_efi_handle_t image_handle, grub_efi_status_t exit_status,
1802++ grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data)
1803 +{
1804-+ struct image_info *info;
1805++ grub_efi_system_table->boot_services->exit = started_image.exit;
1806 +
1807 + if (!image_handle)
1808 + return GRUB_EFI_INVALID_PARAMETER;
1809 +
1810-+ info = grub_efi_open_protocol (image_handle,
1811-+ &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID,
1812-+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
1813-+ if (!info)
1814++ if (image_handle != started_image.image_handle)
1815 + {
1816 + grub_dprintf ("linux", "delegating Exit()\n");
1817-+ return exit_orig (image_handle, exit_status, exit_data_size,
1818-+ (grub_efi_char16_t *)exit_data);
1819++ return started_image.exit (image_handle, exit_status, exit_data_size,
1820++ (grub_efi_char16_t *)exit_data);
1821 + }
1822 +
1823-+ info->exit_status = exit_status;
1824++ started_image.exit_status = exit_status;
1825 +
1826 + if (exit_status != GRUB_EFI_SUCCESS)
1827 + {
1828 + grub_printf ("Application failed, r = %d\n",
1829 + (int)exit_status & 0x7fffffff);
1830 + if (exit_data_size && exit_data)
1831-+ {
1832++ {
1833 + grub_printf ("exit message: ");
1834 + for (grub_efi_uintn_t pos = 0;
1835 + exit_data[pos] && pos < exit_data_size / 2; ++pos)
1836 + grub_printf ("%C", exit_data[pos]);
1837 + grub_printf ("\n");
1838-+ }
1839++ }
1840 + }
1841 + if (exit_data_size && exit_data)
1842 + {
1843 + /* exit data must be freed by the caller */
1844 + grub_efi_system_table->boot_services->free_pool (exit_data);
1845 + }
1846-+ grub_longjmp (info->jmp, 1);
1847++ grub_longjmp (started_image.jmp, 1);
1848 +}
1849 +
1850++static grub_efi_status_t __grub_efi_api
1851++do_unload_image (grub_efi_handle_t image_handle);
1852++
1853 +/**
1854-+ * unload_image_hook() - replacement for EFI_BOOT_SERVICES.UnloadImage()
1855-+ *
1856-+ * peimage only supports loading EFI Applications, which cannot be correctly
1857-+ * unloaded while running.
1858++ * start_image() - our implementation of StartImage()
1859 + *
1860-+ * Installing this hooks prevents that from happening.
1861++ * As we do not load the image via LoadImage() we need our own implementation
1862++ * of StartImage() to launch the PE-COFF image.
1863 + */
1864-+static grub_efi_status_t __grub_efi_api
1865-+unload_image_hook (grub_efi_handle_t image_handle)
1866++static grub_efi_status_t
1867++start_image (struct image_info *info)
1868 +{
1869-+ if (grub_efi_open_protocol (image_handle,
1870-+ &(grub_guid_t) GRUB_PEIMAGE_MARKER_GUID,
1871-+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL))
1872-+ return GRUB_EFI_UNSUPPORTED;
1873++ int ret;
1874++ grub_efi_status_t status;
1875++ grub_efi_loaded_image_t *loaded_image;
1876 +
1877-+ return unload_image_orig(image_handle);
1878-+}
1879++ /*
1880++ * NOTE: We cannot easily comply with the UEFI specification and provide the
1881++ * child its own handle, otherwise things can go horribly wrong if said custom
1882++ * handle is passed to the firmware by child images
1883++ */
1884++ started_image.image_handle = grub_efi_image_handle;
1885 +
1886-+static grub_efi_status_t __grub_efi_api
1887-+do_load_image (grub_efi_boolean_t boot_policy __attribute__ ((unused)),
1888-+ grub_efi_handle_t parent_image_handle,
1889-+ grub_efi_device_path_t *file_path, void *source_buffer,
1890-+ grub_efi_uintn_t source_size, grub_efi_handle_t *image_handle)
1891-+{
1892-+ grub_efi_status_t status;
1893-+ struct image_info *info;
1894++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
1895++ if (loaded_image)
1896++ {
1897++ loaded_image->image_base = info->image_addr;
1898++ loaded_image->image_size = info->image_size;
1899++
1900++ // Pass just the file path portion to the loaded image
1901++ loaded_image->file_path = info->file_path;
1902++ while (loaded_image->file_path &&
1903++ (loaded_image->file_path->type != GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
1904++ || loaded_image->file_path->subtype != GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE))
1905++ loaded_image->file_path = GRUB_EFI_NEXT_DEVICE_PATH (loaded_image->file_path);
1906++ }
1907++ else
1908++ {
1909++ grub_dprintf ("linux", "Loaded image protocol missing\n");
1910++ }
1911 +
1912-+ info = grub_efi_allocate_pages_real (
1913-+ GRUB_EFI_MAX_USABLE_ADDRESS, GRUB_EFI_BYTES_TO_PAGES (sizeof *info),
1914-+ GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA);
1915-+ if (!info)
1916-+ return GRUB_EFI_OUT_OF_RESOURCES;
1917++ ret = grub_setjmp (started_image.jmp);
1918++ if (ret)
1919++ {
1920++ do_unload_image(started_image.image_handle);
1921++ started_image.image_handle = NULL;
1922++ return started_image.exit_status;
1923++ }
1924 +
1925-+ grub_memset (info, 0, sizeof *info);
1926++ started_image.exit = grub_efi_system_table->boot_services->exit;
1927++ grub_efi_system_table->boot_services->exit = efi_exit;
1928 +
1929-+ info->data = source_buffer;
1930-+ info->data_size = source_size;
1931++ grub_dprintf (
1932++ "linux",
1933++ "Executing image loaded at 0x%lx\nEntry point 0x%lx\nSize 0x%08x\n",
1934++ (unsigned long)info->image_addr, (unsigned long)info->entry_point,
1935++ info->image_size);
1936 +
1937-+ // Save original device path
1938-+ if (file_path)
1939-+ info->orig_file_path = grub_efi_duplicate_device_path (file_path);
1940++ /* Invalidate the instruction cache */
1941++ grub_arch_sync_caches (info->image_addr, info->image_size);
1942 +
1943-+ // Split out file path
1944-+ while (file_path
1945-+ && (file_path->type != GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
1946-+ || file_path->subtype != GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE))
1947-+ file_path = GRUB_EFI_NEXT_DEVICE_PATH (file_path);
1948-+ if (file_path)
1949-+ info->loaded_image.file_path = grub_efi_duplicate_device_path (file_path);
1950++ status = info->entry_point (started_image.image_handle, grub_efi_system_table);
1951 +
1952-+ // Process PE image
1953-+ status = check_pe_header (info);
1954-+ if (status != GRUB_EFI_SUCCESS)
1955-+ goto err;
1956++ grub_dprintf ("linux", "Application returned\n");
1957 +
1958-+ status = load_sections (info);
1959-+ if (status != GRUB_EFI_SUCCESS)
1960-+ goto err;
1961++ return efi_exit (started_image.image_handle, status, 0, NULL);
1962++}
1963++
1964++static struct image_info info;
1965++
1966++/* TODO: move the creation of the load options here */
1967++static grub_efi_status_t __grub_efi_api
1968++do_load_image (grub_efi_boolean_t boot_policy __attribute__ ((unused)),
1969++ grub_efi_handle_t parent_image_handle __attribute__ ((unused)),
1970++ grub_efi_device_path_t *file_path,
1971++ void *source_buffer, grub_efi_uintn_t source_size,
1972++ grub_efi_handle_t *image_handle)
1973++{
1974++ grub_efi_status_t ret = GRUB_EFI_SUCCESS;
1975++ if (info.data != NULL)
1976++ {
1977++ grub_error (GRUB_ERR_BAD_OS, "cannot load multiple images");
1978++ return GRUB_EFI_LOAD_ERROR;
1979++ }
1980++
1981++ grub_dl_ref (my_mod);
1982++
1983++ info = (struct image_info){
1984++ .data = source_buffer,
1985++ .data_size = source_size,
1986++ .file_path = grub_efi_duplicate_device_path(file_path),
1987++ };
1988 +
1989-+ status = relocate (info);
1990-+ if (status != GRUB_EFI_SUCCESS)
1991++ ret = check_pe_header (&info);
1992++ if (ret != GRUB_EFI_SUCCESS)
1993 + goto err;
1994 +
1995-+ // Setup EFI_LOADED_IMAGE_PROTOCOL
1996-+ info->loaded_image.revision = GRUB_EFI_LOADED_IMAGE_REVISION;
1997-+ info->loaded_image.parent_handle = parent_image_handle;
1998-+ info->loaded_image.system_table = grub_efi_system_table;
1999-+ info->loaded_image.image_code_type = GRUB_EFI_LOADER_CODE;
2000-+ info->loaded_image.image_data_type = GRUB_EFI_LOADER_DATA;
2001-+
2002-+ // Instruct EFI to create a new handle
2003-+ *image_handle = NULL;
2004-+ status
2005-+ = grub_efi_system_table->boot_services
2006-+ ->install_multiple_protocol_interfaces (
2007-+ image_handle, &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID, info,
2008-+ &(grub_guid_t)GRUB_EFI_LOADED_IMAGE_GUID, &info->loaded_image,
2009-+ &(grub_guid_t)GRUB_EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID,
2010-+ info->orig_file_path, NULL);
2011-+ if (status != GRUB_EFI_SUCCESS)
2012++ ret = load_sections (&info);
2013++ if (ret != GRUB_EFI_SUCCESS)
2014 + goto err;
2015 +
2016-+ // Increment module refcount
2017-+ grub_dl_ref (my_mod);
2018++ ret = relocate (&info);
2019++ if (ret != GRUB_EFI_SUCCESS)
2020++ goto err;
2021 +
2022-+ return status;
2023++ *image_handle = grub_efi_image_handle;
2024++ return GRUB_EFI_SUCCESS;
2025 +
2026 +err:
2027-+ if (info->alloc_addr)
2028-+ grub_efi_free_pages ((unsigned long)info->alloc_addr, info->alloc_pages);
2029-+ if (info->loaded_image.file_path)
2030-+ grub_free (info->loaded_image.file_path);
2031-+ if (info->orig_file_path)
2032-+ grub_free (info->orig_file_path);
2033-+ grub_efi_free_pages ((unsigned long)info,
2034-+ GRUB_EFI_BYTES_TO_PAGES (sizeof *info));
2035-+ return status;
2036++ /* NOTE: do_unload_image() doesn't care about image_handle */
2037++ do_unload_image (NULL);
2038++ return ret;
2039 +}
2040 +
2041 +static grub_efi_status_t __grub_efi_api
2042-+do_start_image (grub_efi_handle_t image_handle,
2043++do_start_image (grub_efi_handle_t image_handle __attribute__ ((unused)),
2044 + grub_efi_uintn_t *exit_data_size __attribute__ ((unused)),
2045 + grub_efi_char16_t **exit_data __attribute__ ((unused)))
2046 +{
2047-+ grub_efi_status_t status;
2048-+ struct image_info *info;
2049-+
2050-+ info = grub_efi_open_protocol (image_handle,
2051-+ &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID,
2052-+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
2053-+ if (!info)
2054++ if (info.data == NULL)
2055 + {
2056 + grub_error (GRUB_ERR_BAD_OS, "image not loaded");
2057 + return GRUB_EFI_LOAD_ERROR;
2058 + }
2059-+
2060-+ if (grub_setjmp (info->jmp))
2061-+ {
2062-+ status = info->exit_status;
2063-+ do_unload_image (image_handle);
2064-+ }
2065-+ else
2066-+ {
2067-+ grub_dprintf ("linux",
2068-+ "Executing image loaded at 0x%lx\n"
2069-+ "Entry point 0x%lx\n"
2070-+ "Size 0x%lx\n",
2071-+ (unsigned long)info->loaded_image.image_base,
2072-+ (unsigned long)info->entry_point,
2073-+ (unsigned long)info->loaded_image.image_size);
2074-+
2075-+ /* Invalidate the instruction cache */
2076-+ grub_arch_sync_caches (info->loaded_image.image_base,
2077-+ info->loaded_image.image_size);
2078-+
2079-+ status = info->entry_point (image_handle, grub_efi_system_table);
2080-+
2081-+ grub_dprintf ("linux", "Application returned\n");
2082-+
2083-+ /* converge to the same exit path as if the image called
2084-+ * boot_services->exit itself */
2085-+ exit_hook (image_handle, status, 0, NULL);
2086-+
2087-+ /* image_handle is always valid above, thus exit_hook cannot
2088-+ * return to here. if only GRUB had assert :(
2089-+ grub_assert (false && "entered unreachable code");
2090-+ */
2091-+ }
2092-+
2093-+ return status;
2094++ return start_image (&info);
2095 +}
2096 +
2097 +static grub_efi_status_t __grub_efi_api
2098-+do_unload_image (grub_efi_handle_t image_handle)
2099++do_unload_image (grub_efi_handle_t image_handle __attribute__ ((unused)))
2100 +{
2101-+ grub_efi_status_t status;
2102-+ struct image_info *info;
2103-+
2104-+ info = grub_efi_open_protocol (image_handle,
2105-+ &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID,
2106-+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
2107-+ if (!info)
2108++ if (info.data == NULL)
2109 + {
2110 + grub_error (GRUB_ERR_BAD_OS, "image not loaded");
2111 + return GRUB_EFI_LOAD_ERROR;
2112 + }
2113-+
2114-+ status
2115-+ = grub_efi_system_table->boot_services
2116-+ ->uninstall_multiple_protocol_interfaces (
2117-+ image_handle, &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID, info,
2118-+ &(grub_guid_t)GRUB_EFI_LOADED_IMAGE_GUID, &info->loaded_image,
2119-+ &(grub_guid_t)GRUB_EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID,
2120-+ info->orig_file_path, NULL);
2121-+ if (status != GRUB_EFI_SUCCESS)
2122-+ return GRUB_EFI_LOAD_ERROR;
2123-+
2124-+ if (info->alloc_addr)
2125-+ grub_efi_free_pages ((unsigned long)info->alloc_addr, info->alloc_pages);
2126-+ if (info->loaded_image.file_path)
2127-+ grub_free (info->loaded_image.file_path);
2128-+ if (info->orig_file_path)
2129-+ grub_free (info->orig_file_path);
2130-+
2131-+ grub_efi_free_pages ((unsigned long)info,
2132-+ GRUB_EFI_BYTES_TO_PAGES (sizeof *info));
2133++ if (info.alloc_addr)
2134++ grub_efi_free_pages ((unsigned long)info.alloc_addr, info.alloc_pages);
2135++ if (info.file_path)
2136++ grub_free(info.file_path);
2137 +
2138 + grub_dl_unref (my_mod);
2139++ info = (struct image_info){};
2140 +
2141 + return GRUB_EFI_SUCCESS;
2142 +}
2143@@ -949,22 +885,10 @@ index 0000000..0387277
2144 +{
2145 + grub_efi_register_loader (&peimage_loader);
2146 + my_mod = mod;
2147-+
2148-+ // Hook exit handler
2149-+ exit_orig = grub_efi_system_table->boot_services->exit;
2150-+ grub_efi_system_table->boot_services->exit = exit_hook;
2151-+ // Hook unload_image handler
2152-+ unload_image_orig = grub_efi_system_table->boot_services->unload_image;
2153-+ grub_efi_system_table->boot_services->unload_image = unload_image_hook;
2154 +}
2155 +
2156 +GRUB_MOD_FINI (peimage)
2157 +{
2158-+ // Restore exit handler
2159-+ grub_efi_system_table->boot_services->exit = exit_orig;
2160-+ // Restore unload_image handler
2161-+ grub_efi_system_table->boot_services->unload_image = unload_image_orig;
2162-+
2163 + grub_efi_unregister_loader (&peimage_loader);
2164 +}
2165 diff --git a/include/grub/efi/peimage.h b/include/grub/efi/peimage.h
2166diff --git a/debian/patches/series b/debian/patches/series
2167index 05de63a..ad6da55 100644
2168--- a/debian/patches/series
2169+++ b/debian/patches/series
2170@@ -111,3 +111,14 @@ Revert-kern-ieee1275-init-ppc64-Return-allocated-address-.patch
2171 Revert-kern-ieee1275-init-ppc64-Decide-by-request-whether.patch
2172 Revert-kern-ieee1275-init-ppc64-Introduce-a-request-for-r.patch
2173 grub-install-efi-title.patch
2174+kern-efi-mm-Change-grub_efi_mm_add_regions-to-keep-track-.patch
2175+kern-efi-mm-Change-grub_efi_allocate_pages_real-to-call-s.patch
2176+kern-efi-mm-Detect-calls-to-grub_efi_drop_alloc-with-wron.patch
2177+nx/modules-strip-.llvm_addrsig-sections-and-similar.patch
2178+nx/modules-Don-t-allocate-space-for-non-allocable-sections.patch
2179+nx/modules-load-module-sections-at-page-aligned-addresses.patch
2180+nx/nx-add-memory-attribute-get-set-API.patch
2181+nx/nx-set-page-permissions-for-loaded-modules.patch
2182+nx/nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
2183+nx/efi-Disallow-fallback-to-legacy-Linux-loader-when-shim-sa.patch
2184+nx/peimage-Add-memory-attribute-support.patch
2185diff --git a/debian/patches/suse-grub.texi-add-net_bootp6-document.patch b/debian/patches/suse-grub.texi-add-net_bootp6-document.patch
2186index a8a46b4..a84bdfb 100644
2187--- a/debian/patches/suse-grub.texi-add-net_bootp6-document.patch
2188+++ b/debian/patches/suse-grub.texi-add-net_bootp6-document.patch
2189@@ -13,10 +13,10 @@ Patch-Name: suse-grub.texi-add-net_bootp6-document.patch
2190 1 file changed, 17 insertions(+)
2191
2192 diff --git a/docs/grub.texi b/docs/grub.texi
2193-index 584f6dc..4e6fb8d 100644
2194+index c2682be..c332de3 100644
2195 --- a/docs/grub.texi
2196 +++ b/docs/grub.texi
2197-@@ -5982,6 +5982,7 @@ Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}).
2198+@@ -5973,6 +5973,7 @@ Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}).
2199 * net_add_dns:: Add a DNS server
2200 * net_add_route:: Add routing entry
2201 * net_bootp:: Perform a bootp/DHCP autoconfiguration
2202@@ -24,7 +24,7 @@ index 584f6dc..4e6fb8d 100644
2203 * net_del_addr:: Remove IP address from interface
2204 * net_del_dns:: Remove a DNS server
2205 * net_del_route:: Remove a route entry
2206-@@ -6107,6 +6108,22 @@ Sets environment variable @samp{net_}@var{<card>}@samp{_boot_file}
2207+@@ -6098,6 +6099,22 @@ Sets environment variable @samp{net_}@var{<card>}@samp{_boot_file}
2208
2209 @end deffn
2210
2211diff --git a/debian/patches/ubuntu-fix-lzma-decompressor-objcopy.patch b/debian/patches/ubuntu-fix-lzma-decompressor-objcopy.patch
2212index 311f938..2300117 100644
2213--- a/debian/patches/ubuntu-fix-lzma-decompressor-objcopy.patch
2214+++ b/debian/patches/ubuntu-fix-lzma-decompressor-objcopy.patch
2215@@ -15,7 +15,7 @@ Signed-off-by: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
2216 1 file changed, 1 insertion(+), 1 deletion(-)
2217
2218 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
2219-index c3ad031..3d98edf 100644
2220+index 7b49f77..ae5c558 100644
2221 --- a/grub-core/Makefile.core.def
2222 +++ b/grub-core/Makefile.core.def
2223 @@ -569,7 +569,7 @@ image = {
2224diff --git a/debian/patches/ubuntu-support-initrd-less-boot.patch b/debian/patches/ubuntu-support-initrd-less-boot.patch
2225index aac23f6..c883c7c 100644
2226--- a/debian/patches/ubuntu-support-initrd-less-boot.patch
2227+++ b/debian/patches/ubuntu-support-initrd-less-boot.patch
2228@@ -16,7 +16,7 @@ Patch-Name: ubuntu-support-initrd-less-boot.patch
2229 3 files changed, 25 insertions(+), 4 deletions(-)
2230
2231 diff --git a/docs/grub.texi b/docs/grub.texi
2232-index b4825b7..584f6dc 100644
2233+index 990d8c7..c2682be 100644
2234 --- a/docs/grub.texi
2235 +++ b/docs/grub.texi
2236 @@ -1615,6 +1615,19 @@ This option sets the English text of the string that will be displayed in
2237diff --git a/debian/rules b/debian/rules
2238index f806fec..5e2b379 100755
2239--- a/debian/rules
2240+++ b/debian/rules
2241@@ -253,6 +253,9 @@ debian/stamps/configure-grub-common: debian/stamps/configure-grub-$(COMMON_PLATF
2242 touch $@
2243
2244 debian/stamps/build-grub-common: debian/stamps/build-grub-$(COMMON_PLATFORM)
2245+ifeq ($(with_check), yes)
2246+ pytest -q debian/test_grub_sort_version.py
2247+endif
2248 touch $@
2249
2250 debian/stamps/configure-grub-none debian/stamps/configure-grub-pc debian/stamps/configure-grub-ieee1275 debian/stamps/configure-grub-coreboot debian/stamps/configure-grub-emu debian/stamps/configure-grub-uboot debian/stamps/configure-grub-yeeloong:
2251diff --git a/debian/sbat.ubuntu.csv.in b/debian/sbat.ubuntu.csv.in
2252index f33b573..0df0cc2 100644
2253--- a/debian/sbat.ubuntu.csv.in
2254+++ b/debian/sbat.ubuntu.csv.in
2255@@ -1,4 +1,4 @@
2256 sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
2257 grub,4,Free Software Foundation,grub,@UPSTREAM_VERSION@,https://www.gnu.org/software/grub/
2258-grub.ubuntu,1,Ubuntu,grub2,@DEB_VERSION@,https://www.ubuntu.com/
2259-grub.peimage,1,Canonical,grub2,@DEB_VERSION@,https://salsa.debian.org/grub-team/grub/-/blob/master/debian/patches/secure-boot/efi-use-peimage-shim.patch
2260+grub.ubuntu,2,Ubuntu,grub2,@DEB_VERSION@,https://www.ubuntu.com/
2261+grub.peimage,2,Canonical,grub2,@DEB_VERSION@,https://salsa.debian.org/grub-team/grub/-/blob/master/debian/patches/secure-boot/efi-use-peimage-shim.patch
2262diff --git a/debian/test_grub_sort_version.py b/debian/test_grub_sort_version.py
2263new file mode 100755
2264index 0000000..8718ff4
2265--- /dev/null
2266+++ b/debian/test_grub_sort_version.py
2267@@ -0,0 +1,72 @@
2268+import os
2269+import pytest
2270+import subprocess
2271+
2272+GRUB_SORT_VERSION = "debian/grub-sort-version"
2273+
2274+def assert_grub_sort_version(input, output, flavour_order=""):
2275+ env = os.environ.copy()
2276+ env["LC_ALL"] = "C"
2277+ env["GRUB_FLAVOUR_ORDER"] = flavour_order
2278+ # Assert the output is as expected
2279+ result = subprocess.run([GRUB_SORT_VERSION], env=env,
2280+ input=input, encoding="utf-8", capture_output=True)
2281+ assert result.returncode == 0
2282+ print(result.stdout)
2283+ assert result.stdout == output
2284+ # Then do the same in reverse mode too
2285+ result = subprocess.run([GRUB_SORT_VERSION, "-r"], env=env,
2286+ input=input, encoding="utf-8", capture_output=True)
2287+ assert result.returncode == 0
2288+ assert result.stdout == "\n".join(output.rstrip().split("\n")[::-1]) + "\n"
2289+
2290+def test_empty_line():
2291+ INPUT = """/boot/vmlinuz-6.5.0-10-generic 2
2292+/boot/vmlinuz-6.5.0-9-generic 2
2293+ 2
2294+"""
2295+
2296+ OUTPUT = """ 2
2297+/boot/vmlinuz-6.5.0-9-generic 2
2298+/boot/vmlinuz-6.5.0-10-generic 2
2299+"""
2300+
2301+ assert_grub_sort_version(INPUT, OUTPUT)
2302+
2303+def test_custom_kernels():
2304+ INPUT = """/boot/vmlinuz-6.6.0 2
2305+/boot/vmlinuz-6.5.0-10-generic 2
2306+/boot/vmlinuz-6.5.0-9-generic 2
2307+/boot/vmlinuz-6.5.9 2
2308+/boot/vmlinuz-6.5.8 2
2309+"""
2310+
2311+ OUTPUT = """/boot/vmlinuz-6.5.0-9-generic 2
2312+/boot/vmlinuz-6.5.0-10-generic 2
2313+/boot/vmlinuz-6.5.8 2
2314+/boot/vmlinuz-6.5.9 2
2315+/boot/vmlinuz-6.6.0 2
2316+"""
2317+
2318+ assert_grub_sort_version(INPUT, OUTPUT)
2319+
2320+def test_flavour_order():
2321+ INPUT = """/boot/vmlinuz-6.5.0-10-generic 2
2322+/boot/vmlinuz-6.5.0-9-generic 2
2323+/boot/vmlinuz-6.5.0-9-aaa 2
2324+/boot/vmlinuz-6.5.0-9-aaa 1
2325+/boot/vmlinuz-6.5.8 2
2326+/boot/vmlinuz-6.5.9 2
2327+/boot/vmlinuz-6.6.0 2
2328+"""
2329+
2330+ OUTPUT = """/boot/vmlinuz-6.5.8 2
2331+/boot/vmlinuz-6.5.9 2
2332+/boot/vmlinuz-6.6.0 2
2333+/boot/vmlinuz-6.5.0-9-aaa 1
2334+/boot/vmlinuz-6.5.0-9-aaa 2
2335+/boot/vmlinuz-6.5.0-9-generic 2
2336+/boot/vmlinuz-6.5.0-10-generic 2
2337+"""
2338+
2339+ assert_grub_sort_version(INPUT, OUTPUT, flavour_order="generic aaa")

Subscribers

People subscribed via source and target branches