!24 master: fix shim occasionally crashes in _relocate() on AArch64
From: @hugel Reviewed-by: @zhujianwei001 Signed-off-by: @zhujianwei001
This commit is contained in:
commit
44b407b974
135
backport-arm-aa64-fix-the-size-of-.rela-sections.patch
Normal file
135
backport-arm-aa64-fix-the-size-of-.rela-sections.patch
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
From 34e3ef205c5d65139eacba8891fa773c03174679 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lin <glin@suse.com>
|
||||||
|
Date: Wed, 16 Jun 2021 16:13:32 +0800
|
||||||
|
Subject: [PATCH] arm/aa64: fix the size of .rela* sections
|
||||||
|
|
||||||
|
The previous commit(*) merged .rel* and .dyn* into .rodata, and this
|
||||||
|
made ld to generate the wrong size for .rela* sections that covered
|
||||||
|
other unrelated sections. When the EFI image was loaded, _relocate()
|
||||||
|
went through the unexpected data and may cause unexpected crash.
|
||||||
|
This commit moves .rel* and .dyn* out of .rodata in the ld script but
|
||||||
|
also moves the related variables, such as _evrodata, _rodata_size,
|
||||||
|
and _rodata_vsize, to the end of the new .dyn section, so that the
|
||||||
|
crafted pe-coff section header for .rodata still covers our new
|
||||||
|
.rela and .dyn sections.
|
||||||
|
|
||||||
|
(*) 212ba30544f ("arm/aa64 targets: put .rel* and .dyn* in .rodata")
|
||||||
|
|
||||||
|
Fix issue: https://github.com/rhboot/shim/issues/371
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lin <glin@suse.com>
|
||||||
|
---
|
||||||
|
Makefile | 4 ++--
|
||||||
|
elf_aarch64_efi.lds | 24 ++++++++++++++++--------
|
||||||
|
elf_arm_efi.lds | 24 ++++++++++++++++--------
|
||||||
|
3 files changed, 34 insertions(+), 18 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/Makefile b/Makefile
|
||||||
|
index 050c921..45db2b5 100644
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -247,7 +247,7 @@ ifneq ($(OBJCOPY_GTE224),1)
|
||||||
|
endif
|
||||||
|
$(OBJCOPY) -D -j .text -j .sdata -j .data -j .data.ident \
|
||||||
|
-j .dynamic -j .rodata -j .rel* \
|
||||||
|
- -j .rela* -j .reloc -j .eh_frame \
|
||||||
|
+ -j .rela* -j .dyn -j .reloc -j .eh_frame \
|
||||||
|
-j .vendor_cert -j .sbat \
|
||||||
|
$(FORMAT) $< $@
|
||||||
|
# I am tired of wasting my time fighting binutils timestamp code.
|
||||||
|
@@ -263,7 +263,7 @@ ifneq ($(OBJCOPY_GTE224),1)
|
||||||
|
endif
|
||||||
|
$(OBJCOPY) -D -j .text -j .sdata -j .data \
|
||||||
|
-j .dynamic -j .rodata -j .rel* \
|
||||||
|
- -j .rela* -j .reloc -j .eh_frame -j .sbat \
|
||||||
|
+ -j .rela* -j .dyn -j .reloc -j .eh_frame -j .sbat \
|
||||||
|
-j .debug_info -j .debug_abbrev -j .debug_aranges \
|
||||||
|
-j .debug_line -j .debug_str -j .debug_ranges \
|
||||||
|
-j .note.gnu.build-id \
|
||||||
|
diff --git a/elf_aarch64_efi.lds b/elf_aarch64_efi.lds
|
||||||
|
index 353b24a..42825fd 100644
|
||||||
|
--- a/elf_aarch64_efi.lds
|
||||||
|
+++ b/elf_aarch64_efi.lds
|
||||||
|
@@ -70,21 +70,29 @@ SECTIONS
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
_rodata = .;
|
||||||
|
- *(.rela.dyn)
|
||||||
|
- *(.rela.plt)
|
||||||
|
- *(.rela.got)
|
||||||
|
- *(.rela.data)
|
||||||
|
- *(.rela.data*)
|
||||||
|
-
|
||||||
|
*(.rodata*)
|
||||||
|
*(.srodata)
|
||||||
|
- *(.dynsym)
|
||||||
|
- *(.dynstr)
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.note.gnu.build-id)
|
||||||
|
. = ALIGN(4096);
|
||||||
|
*(.vendor_cert)
|
||||||
|
*(.data.ident)
|
||||||
|
+ . = ALIGN(4096);
|
||||||
|
+ }
|
||||||
|
+ . = ALIGN(4096);
|
||||||
|
+ .rela :
|
||||||
|
+ {
|
||||||
|
+ *(.rela.dyn)
|
||||||
|
+ *(.rela.plt)
|
||||||
|
+ *(.rela.got)
|
||||||
|
+ *(.rela.data)
|
||||||
|
+ *(.rela.data*)
|
||||||
|
+ }
|
||||||
|
+ . = ALIGN(4096);
|
||||||
|
+ .dyn :
|
||||||
|
+ {
|
||||||
|
+ *(.dynsym)
|
||||||
|
+ *(.dynstr)
|
||||||
|
_evrodata = .;
|
||||||
|
. = ALIGN(4096);
|
||||||
|
}
|
||||||
|
diff --git a/elf_arm_efi.lds b/elf_arm_efi.lds
|
||||||
|
index e4e29bd..5334621 100644
|
||||||
|
--- a/elf_arm_efi.lds
|
||||||
|
+++ b/elf_arm_efi.lds
|
||||||
|
@@ -70,21 +70,29 @@ SECTIONS
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
_rodata = .;
|
||||||
|
- *(.rel.dyn)
|
||||||
|
- *(.rel.plt)
|
||||||
|
- *(.rel.got)
|
||||||
|
- *(.rel.data)
|
||||||
|
- *(.rel.data*)
|
||||||
|
-
|
||||||
|
*(.rodata*)
|
||||||
|
*(.srodata)
|
||||||
|
- *(.dynsym)
|
||||||
|
- *(.dynstr)
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.note.gnu.build-id)
|
||||||
|
. = ALIGN(4096);
|
||||||
|
*(.vendor_cert)
|
||||||
|
*(.data.ident)
|
||||||
|
+ . = ALIGN(4096);
|
||||||
|
+ }
|
||||||
|
+ . = ALIGN(4096);
|
||||||
|
+ .rela :
|
||||||
|
+ {
|
||||||
|
+ *(.rela.dyn)
|
||||||
|
+ *(.rela.plt)
|
||||||
|
+ *(.rela.got)
|
||||||
|
+ *(.rela.data)
|
||||||
|
+ *(.rela.data*)
|
||||||
|
+ }
|
||||||
|
+ . = ALIGN(4096);
|
||||||
|
+ .dyn :
|
||||||
|
+ {
|
||||||
|
+ *(.dynsym)
|
||||||
|
+ *(.dynstr)
|
||||||
|
_evrodata = .;
|
||||||
|
. = ALIGN(4096);
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
From b1fead0f7c9a09634057317a7bd2a5c94258e5df Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lin <glin@suse.com>
|
||||||
|
Date: Wed, 30 Jun 2021 16:34:51 +0800
|
||||||
|
Subject: [PATCH] mok: delete the existing RT variables only when
|
||||||
|
only_first=TRUE
|
||||||
|
|
||||||
|
For the firmware without the variable writing issues, MOK variables are
|
||||||
|
mirrored when only_first=TRUE. However, LibDeleteVariable() was called
|
||||||
|
in maybe_mirror_one_mok_variable() when only_first=FALSE, and this
|
||||||
|
could delete MOK variables that were just mirrored in the first round.
|
||||||
|
|
||||||
|
This bug was hidden since LibDeleteVariable() deletes BS+RT+NV variables
|
||||||
|
while we mirror MOK variables as BS+RT, and the firmware refused to
|
||||||
|
delete the mirrored MOK variable due to mismatching attributes. However,
|
||||||
|
some firmwares, such as VMWare, didn't enforce the attribute check and
|
||||||
|
just deleted the variables with matched name and GUID. In such system,
|
||||||
|
MokListRT was always removed before it reached OS.
|
||||||
|
|
||||||
|
Fixes: https://github.com/rhboot/shim/issues/386
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lin <glin@suse.com>
|
||||||
|
---
|
||||||
|
mok.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/mok.c b/mok.c
|
||||||
|
index 454672b..84e51f3 100644
|
||||||
|
--- a/mok.c
|
||||||
|
+++ b/mok.c
|
||||||
|
@@ -868,7 +868,7 @@ maybe_mirror_one_mok_variable(struct mok_state_variable *v,
|
||||||
|
BOOLEAN present = FALSE;
|
||||||
|
|
||||||
|
if (v->rtname) {
|
||||||
|
- if (!only_first && (v->flags & MOK_MIRROR_DELETE_FIRST)) {
|
||||||
|
+ if (only_first && (v->flags & MOK_MIRROR_DELETE_FIRST)) {
|
||||||
|
dprint(L"deleting \"%s\"\n", v->rtname);
|
||||||
|
efi_status = LibDeleteVariable(v->rtname, v->guid);
|
||||||
|
dprint(L"LibDeleteVariable(\"%s\",...) => %r\n", v->rtname, efi_status);
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
||||||
43
backport-mok-relax-the-maximum-variable-size-check.patch
Normal file
43
backport-mok-relax-the-maximum-variable-size-check.patch
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
From 3f327f546c219634b24cfd9abe9ec987bbb6ad14 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lin <glin@suse.com>
|
||||||
|
Date: Wed, 5 May 2021 11:25:07 +0800
|
||||||
|
Subject: [PATCH] mok: relax the maximum variable size check
|
||||||
|
|
||||||
|
Some UEFI environment such as u-boot doesn't implement
|
||||||
|
QueryVariableInfo(), so we couldn't rely on the function to estimate the
|
||||||
|
available space for RT variables. All we can do is to call SetVariable()
|
||||||
|
directly and check the return value of SetVariable().
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lin <glin@suse.com>
|
||||||
|
---
|
||||||
|
mok.c | 9 +++++++--
|
||||||
|
1 file changed, 7 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/mok.c b/mok.c
|
||||||
|
index db18093..454672b 100644
|
||||||
|
--- a/mok.c
|
||||||
|
+++ b/mok.c
|
||||||
|
@@ -364,13 +364,18 @@ mirror_mok_db(CHAR16 *name, CHAR8 *name8, EFI_GUID *guid, UINT32 attrs,
|
||||||
|
SIZE_T max_var_sz;
|
||||||
|
|
||||||
|
efi_status = get_max_var_sz(attrs, &max_var_sz);
|
||||||
|
- if (EFI_ERROR(efi_status)) {
|
||||||
|
+ if (EFI_ERROR(efi_status) && efi_status != EFI_UNSUPPORTED) {
|
||||||
|
LogError(L"Could not get maximum variable size: %r",
|
||||||
|
efi_status);
|
||||||
|
return efi_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (FullDataSize <= max_var_sz) {
|
||||||
|
+ /* Some UEFI environment such as u-boot doesn't implement
|
||||||
|
+ * QueryVariableInfo() and we will only get EFI_UNSUPPORTED when
|
||||||
|
+ * querying the available space. In this case, we just mirror
|
||||||
|
+ * the variable directly. */
|
||||||
|
+ if (FullDataSize <= max_var_sz || efi_status == EFI_UNSUPPORTED) {
|
||||||
|
+ efi_status = EFI_SUCCESS;
|
||||||
|
if (only_first)
|
||||||
|
efi_status = SetVariable(name, guid, attrs,
|
||||||
|
FullDataSize, FullData);
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
||||||
402
backport-shim-another-attempt-to-fix-load-options-handling.patch
Normal file
402
backport-shim-another-attempt-to-fix-load-options-handling.patch
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
From 4d64389c6c941d21548b06423b8131c872e3c3c7 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Chris Coulson <chris.coulson@canonical.com>
|
||||||
|
Date: Mon, 7 Jun 2021 16:34:18 +0100
|
||||||
|
Subject: [PATCH] shim: another attempt to fix load options handling
|
||||||
|
|
||||||
|
The load options handling is quite complicated and tries to accomodate
|
||||||
|
several scenarios, but there are currently multiple issues:
|
||||||
|
|
||||||
|
- If the supplied LoadOptions is an EFI_LOAD_OPTION structure,
|
||||||
|
second_stage gets initialized to the entire contents of the OptionalData
|
||||||
|
field and load_options is initialized to NULL, which means it isn't
|
||||||
|
possible to pass additional options to the second stage loader (and it
|
||||||
|
looks like the intention is for this to be supported).
|
||||||
|
|
||||||
|
- If the supplied LoadOptions contains 2 or more strings, the code seems
|
||||||
|
to assume that shim was executed from the UEFI shell and that the first
|
||||||
|
argument is the path of the shim executable, so it's ignored. But this
|
||||||
|
breaks the ability to pass additional options to the second stage loader
|
||||||
|
from BDS on firmware implementations that initialize LoadOptions to just
|
||||||
|
the OptionalData field of the EFI_LOAD_OPTION, which is what EDK2 seems
|
||||||
|
to do.
|
||||||
|
|
||||||
|
This is moot anyway because this case (strings == 2) doesn't actually seem
|
||||||
|
to work, as nothing sets loader_len and therefore second_stage is not set
|
||||||
|
to the custom loader path.
|
||||||
|
|
||||||
|
- If the supplied LoadOptions contains a single string that isn't shim's
|
||||||
|
path, nothing sets loader_len and therefore second_stage isn't set at the
|
||||||
|
end of set_second_stage.
|
||||||
|
|
||||||
|
- set_second_stage replaces L' ' characters with L'\0' - whilst this is
|
||||||
|
useful to NULL terminate the path for the second stage, it doesn't seem
|
||||||
|
quite right to do this for the remaining LoadOptions data. Grub's
|
||||||
|
chainloader command supplies additional arguments as a NULL-terminated
|
||||||
|
space-delimited string via LoadOptions. Making it NULL-delimited seems to
|
||||||
|
be incompatible with the kernel's commandline handling, which wouldn't
|
||||||
|
work for scenarios where you might want to direct-boot a kernel image
|
||||||
|
(wrapped in systemd's EFI stub) from shim.
|
||||||
|
|
||||||
|
- handle_image passes the original LoadOptions to the second stage if
|
||||||
|
load_options is NULL, which means that the second stage currently always
|
||||||
|
gets shim's load options.
|
||||||
|
|
||||||
|
I've made an attempt to try to fix things. After the initial
|
||||||
|
checks in set_second_stage, it now does this:
|
||||||
|
|
||||||
|
- Tries to parse LoadOptions as an EFI_LOAD_OPTION in order to extract
|
||||||
|
the OptionalData if it is.
|
||||||
|
- If it's not an EFI_LOAD_OPTION, check if the first string is the
|
||||||
|
current shim path and ignore it if it is (the UEFI shell case).
|
||||||
|
- Split LoadOptions in to a single NULL terminated string (used to
|
||||||
|
initialize second_stage) and the unmodified remaining data (used to
|
||||||
|
initialize load_options and load_options_size).
|
||||||
|
|
||||||
|
I've also modified handle_image to always set LoadOptions and
|
||||||
|
LoadOptionsSize. If shim is executed with no options, or is only
|
||||||
|
executed with a single option to override the second stage loader
|
||||||
|
path, the second stage is executed with LoadOptions = NULL and
|
||||||
|
LoadOptionsSize = 0 now.
|
||||||
|
|
||||||
|
I've tested this on EDK2 and I can load a custom loader with extra
|
||||||
|
options from both BDS and the UEFI shell:
|
||||||
|
|
||||||
|
FS0:\> shimx64.efi test.efi
|
||||||
|
LoadOptionsSize: 0
|
||||||
|
LoadOptions: (null)
|
||||||
|
FS0:\> shimx64.efi test.efi
|
||||||
|
LoadOptionsSize: 0
|
||||||
|
LoadOptions: (null)
|
||||||
|
FS0:\> shimx64.efi test.efi foo bar
|
||||||
|
LoadOptionsSize: 16
|
||||||
|
LoadOptions: foo bar
|
||||||
|
---
|
||||||
|
include/ucs2.h | 27 -------
|
||||||
|
pe.c | 6 +-
|
||||||
|
shim.c | 200 ++++++++++++++++++++++---------------------------
|
||||||
|
3 files changed, 92 insertions(+), 141 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/ucs2.h b/include/ucs2.h
|
||||||
|
index e43c341..ee038ce 100644
|
||||||
|
--- a/include/ucs2.h
|
||||||
|
+++ b/include/ucs2.h
|
||||||
|
@@ -81,31 +81,4 @@ is_all_nuls(UINT8 *data, UINTN data_size)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline UINTN
|
||||||
|
-__attribute__((__unused__))
|
||||||
|
-count_ucs2_strings(UINT8 *data, UINTN data_size)
|
||||||
|
-{
|
||||||
|
- UINTN pos = 0;
|
||||||
|
- UINTN last_nul_pos = 0;
|
||||||
|
- UINTN num_nuls = 0;
|
||||||
|
- UINTN i;
|
||||||
|
-
|
||||||
|
- if (data_size % 2 != 0)
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
- for (i = pos; i < data_size; i++) {
|
||||||
|
- if (i % 2 != 0) {
|
||||||
|
- if (data[i] != 0)
|
||||||
|
- return 0;
|
||||||
|
- } else if (data[i] == 0) {
|
||||||
|
- last_nul_pos = i;
|
||||||
|
- num_nuls++;
|
||||||
|
- }
|
||||||
|
- pos = i;
|
||||||
|
- }
|
||||||
|
- if (num_nuls > 0 && last_nul_pos != pos - 1)
|
||||||
|
- return 0;
|
||||||
|
- return num_nuls;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
#endif /* SHIM_UCS2_H */
|
||||||
|
diff --git a/pe.c b/pe.c
|
||||||
|
index 365e32a..13bc397 100644
|
||||||
|
--- a/pe.c
|
||||||
|
+++ b/pe.c
|
||||||
|
@@ -1144,10 +1144,8 @@ handle_image (void *data, unsigned int datasize,
|
||||||
|
li->ImageSize = context.ImageSize;
|
||||||
|
|
||||||
|
/* Pass the load options to the second stage loader */
|
||||||
|
- if ( load_options ) {
|
||||||
|
- li->LoadOptions = load_options;
|
||||||
|
- li->LoadOptionsSize = load_options_size;
|
||||||
|
- }
|
||||||
|
+ li->LoadOptions = load_options;
|
||||||
|
+ li->LoadOptionsSize = load_options_size;
|
||||||
|
|
||||||
|
if (!found_entry_point) {
|
||||||
|
perror(L"Entry point is not within sections\n");
|
||||||
|
diff --git a/shim.c b/shim.c
|
||||||
|
index 40e4894..ecf6ee5 100644
|
||||||
|
--- a/shim.c
|
||||||
|
+++ b/shim.c
|
||||||
|
@@ -1241,9 +1241,13 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
|
||||||
|
return efi_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Extract the OptionalData and OptionalData fields from an
|
||||||
|
+ * EFI_LOAD_OPTION.
|
||||||
|
+ */
|
||||||
|
static inline EFI_STATUS
|
||||||
|
-get_load_option_optional_data(UINT8 *data, UINTN data_size,
|
||||||
|
- UINT8 **od, UINTN *ods)
|
||||||
|
+get_load_option_optional_data(VOID *data, UINT32 data_size,
|
||||||
|
+ VOID **od, UINT32 *ods)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If it's not at least Attributes + FilePathListLength +
|
||||||
|
@@ -1253,7 +1257,8 @@ get_load_option_optional_data(UINT8 *data, UINTN data_size,
|
||||||
|
if (data_size < (sizeof(UINT32) + sizeof(UINT16) + 2 + 4))
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
- UINT8 *cur = data + sizeof(UINT32);
|
||||||
|
+ UINT8 *start = (UINT8 *)data;
|
||||||
|
+ UINT8 *cur = start + sizeof(UINT32);
|
||||||
|
UINT16 fplistlen = *(UINT16 *)cur;
|
||||||
|
/*
|
||||||
|
* If there's not enough space for the file path list and the
|
||||||
|
@@ -1263,8 +1268,8 @@ get_load_option_optional_data(UINT8 *data, UINTN data_size,
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
cur += sizeof(UINT16);
|
||||||
|
- UINTN limit = data_size - (cur - data) - fplistlen;
|
||||||
|
- UINTN i;
|
||||||
|
+ UINT32 limit = data_size - (cur - start) - fplistlen;
|
||||||
|
+ UINT32 i;
|
||||||
|
for (i = 0; i < limit ; i++) {
|
||||||
|
/* If the description isn't valid UCS2-LE, it's not valid. */
|
||||||
|
if (i % 2 != 0) {
|
||||||
|
@@ -1380,6 +1385,57 @@ done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Split the supplied load options in to a NULL terminated
|
||||||
|
+ * string representing the path of the second stage loader,
|
||||||
|
+ * and return a pointer to the remaining load options data
|
||||||
|
+ * and its remaining size.
|
||||||
|
+ *
|
||||||
|
+ * This expects the supplied load options to begin with a
|
||||||
|
+ * string that is either NULL terminated or terminated with
|
||||||
|
+ * a space and some optional data. It will return NULL if
|
||||||
|
+ * the supplied load options contains no spaces or NULL
|
||||||
|
+ * terminators.
|
||||||
|
+ */
|
||||||
|
+static CHAR16 *
|
||||||
|
+split_load_options(VOID *in, UINT32 in_size,
|
||||||
|
+ VOID **remaining,
|
||||||
|
+ UINT32 *remaining_size) {
|
||||||
|
+ UINTN i;
|
||||||
|
+ CHAR16 *arg0 = NULL;
|
||||||
|
+ CHAR16 *start = (CHAR16 *)in;
|
||||||
|
+
|
||||||
|
+ /* Skip spaces */
|
||||||
|
+ for (i = 0; i < in_size / sizeof(CHAR16); i++) {
|
||||||
|
+ if (*start != L' ')
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ start++;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ in_size -= ((VOID *)start - in);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Ensure that the first argument is NULL terminated by
|
||||||
|
+ * replacing L' ' with L'\0'.
|
||||||
|
+ */
|
||||||
|
+ for (i = 0; i < in_size / sizeof(CHAR16); i++) {
|
||||||
|
+ if (start[i] == L' ' || start[i] == L'\0') {
|
||||||
|
+ start[i] = L'\0';
|
||||||
|
+ arg0 = (CHAR16 *)start;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (arg0) {
|
||||||
|
+ UINTN skip = i + 1;
|
||||||
|
+ *remaining_size = in_size - (skip * sizeof(CHAR16));
|
||||||
|
+ *remaining = *remaining_size > 0 ? start + skip : NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return arg0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Check the load options to specify the second stage loader
|
||||||
|
*/
|
||||||
|
@@ -1387,20 +1443,11 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
|
||||||
|
{
|
||||||
|
EFI_STATUS efi_status;
|
||||||
|
EFI_LOADED_IMAGE *li = NULL;
|
||||||
|
- CHAR16 *start = NULL;
|
||||||
|
- UINTN remaining_size = 0;
|
||||||
|
+ VOID *remaining = NULL;
|
||||||
|
+ UINT32 remaining_size;
|
||||||
|
CHAR16 *loader_str = NULL;
|
||||||
|
- UINTN loader_len = 0;
|
||||||
|
- unsigned int i;
|
||||||
|
- UINTN second_stage_len;
|
||||||
|
|
||||||
|
- second_stage_len = (StrLen(DEFAULT_LOADER) + 1) * sizeof(CHAR16);
|
||||||
|
- second_stage = AllocatePool(second_stage_len);
|
||||||
|
- if (!second_stage) {
|
||||||
|
- perror(L"Could not allocate %lu bytes\n", second_stage_len);
|
||||||
|
- return EFI_OUT_OF_RESOURCES;
|
||||||
|
- }
|
||||||
|
- StrCpy(second_stage, DEFAULT_LOADER);
|
||||||
|
+ second_stage = DEFAULT_LOADER;
|
||||||
|
load_options = NULL;
|
||||||
|
load_options_size = 0;
|
||||||
|
|
||||||
|
@@ -1499,105 +1546,44 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * Check and see if this is just a list of strings. If it's an
|
||||||
|
- * EFI_LOAD_OPTION, it'll be 0, since we know EndEntire device path
|
||||||
|
- * won't pass muster as UCS2-LE.
|
||||||
|
- *
|
||||||
|
- * If there are 3 strings, we're launched from the shell most likely,
|
||||||
|
- * But we actually only care about the second one.
|
||||||
|
+ * See if this is an EFI_LOAD_OPTION and extract the optional
|
||||||
|
+ * data if it is. This will return an error if it is not a valid
|
||||||
|
+ * EFI_LOAD_OPTION.
|
||||||
|
*/
|
||||||
|
- UINTN strings = count_ucs2_strings(li->LoadOptions,
|
||||||
|
- li->LoadOptionsSize);
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * In some cases we get strings == 1 because BDS is using L' ' as the
|
||||||
|
- * delimeter:
|
||||||
|
- * 0000:74 00 65 00 73 00 74 00 2E 00 65 00 66 00 69 00 t.e.s.t...e.f.i.
|
||||||
|
- * 0016:20 00 6F 00 6E 00 65 00 20 00 74 00 77 00 6F 00 ..o.n.e...t.w.o.
|
||||||
|
- * 0032:20 00 74 00 68 00 72 00 65 00 65 00 00 00 ..t.h.r.e.e...
|
||||||
|
- *
|
||||||
|
- * If so replace it with NULs since the code already handles that
|
||||||
|
- * case.
|
||||||
|
- */
|
||||||
|
- if (strings == 1) {
|
||||||
|
- UINT16 *cur = start = li->LoadOptions;
|
||||||
|
-
|
||||||
|
- /* replace L' ' with L'\0' if we find any */
|
||||||
|
- for (i = 0; i < li->LoadOptionsSize / 2; i++) {
|
||||||
|
- if (cur[i] == L' ')
|
||||||
|
- cur[i] = L'\0';
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* redo the string count */
|
||||||
|
- strings = count_ucs2_strings(li->LoadOptions,
|
||||||
|
- li->LoadOptionsSize);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * If it's not string data, try it as an EFI_LOAD_OPTION.
|
||||||
|
- */
|
||||||
|
- if (strings == 0) {
|
||||||
|
- /*
|
||||||
|
- * We at least didn't find /enough/ strings. See if it works
|
||||||
|
- * as an EFI_LOAD_OPTION.
|
||||||
|
- */
|
||||||
|
- efi_status = get_load_option_optional_data(li->LoadOptions,
|
||||||
|
- li->LoadOptionsSize,
|
||||||
|
- (UINT8 **)&start,
|
||||||
|
- &loader_len);
|
||||||
|
- if (EFI_ERROR(efi_status))
|
||||||
|
- return EFI_SUCCESS;
|
||||||
|
-
|
||||||
|
- remaining_size = 0;
|
||||||
|
- } else if (strings >= 2) {
|
||||||
|
+ efi_status = get_load_option_optional_data(li->LoadOptions,
|
||||||
|
+ li->LoadOptionsSize,
|
||||||
|
+ &li->LoadOptions,
|
||||||
|
+ &li->LoadOptionsSize);
|
||||||
|
+ if (EFI_ERROR(efi_status)) {
|
||||||
|
/*
|
||||||
|
+ * it's not an EFI_LOAD_OPTION, so it's probably just a string
|
||||||
|
+ * or list of strings.
|
||||||
|
+ *
|
||||||
|
* UEFI shell copies the whole line of the command into
|
||||||
|
- * LoadOptions. We ignore the string before the first L'\0',
|
||||||
|
- * i.e. the name of this program.
|
||||||
|
+ * LoadOptions. We ignore the first string, i.e. the name of this
|
||||||
|
+ * program in this case.
|
||||||
|
*/
|
||||||
|
- UINT16 *cur = li->LoadOptions;
|
||||||
|
- for (i = 1; i < li->LoadOptionsSize / 2; i++) {
|
||||||
|
- if (cur[i - 1] == L'\0') {
|
||||||
|
- start = &cur[i];
|
||||||
|
- remaining_size = li->LoadOptionsSize - (i * 2);
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
+ CHAR16 *loader_str = split_load_options(li->LoadOptions,
|
||||||
|
+ li->LoadOptionsSize,
|
||||||
|
+ &remaining,
|
||||||
|
+ &remaining_size);
|
||||||
|
+
|
||||||
|
+ if (loader_str && is_our_path(li, loader_str)) {
|
||||||
|
+ li->LoadOptions = remaining;
|
||||||
|
+ li->LoadOptionsSize = remaining_size;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- remaining_size -= i * 2 + 2;
|
||||||
|
- } else if (strings == 1 && is_our_path(li, start)) {
|
||||||
|
- /*
|
||||||
|
- * And then I found a version of BDS that gives us our own path
|
||||||
|
- * in LoadOptions:
|
||||||
|
-
|
||||||
|
-77162C58 5c 00 45 00 46 00 49 00 |\.E.F.I.|
|
||||||
|
-77162C60 5c 00 42 00 4f 00 4f 00 54 00 5c 00 42 00 4f 00 |\.B.O.O.T.\.B.O.|
|
||||||
|
-77162C70 4f 00 54 00 58 00 36 00 34 00 2e 00 45 00 46 00 |O.T.X.6.4...E.F.|
|
||||||
|
-77162C80 49 00 00 00 |I...|
|
||||||
|
-
|
||||||
|
- * which is just cruel... So yeah, just don't use it.
|
||||||
|
- */
|
||||||
|
- return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ loader_str = split_load_options(li->LoadOptions, li->LoadOptionsSize,
|
||||||
|
+ &remaining, &remaining_size);
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Set up the name of the alternative loader and the LoadOptions for
|
||||||
|
* the loader
|
||||||
|
*/
|
||||||
|
- if (loader_len > 0) {
|
||||||
|
- /* we might not always have a NULL at the end */
|
||||||
|
- loader_str = AllocatePool(loader_len + 2);
|
||||||
|
- if (!loader_str) {
|
||||||
|
- perror(L"Failed to allocate loader string\n");
|
||||||
|
- return EFI_OUT_OF_RESOURCES;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- for (i = 0; i < loader_len / 2; i++)
|
||||||
|
- loader_str[i] = start[i];
|
||||||
|
- loader_str[loader_len/2] = L'\0';
|
||||||
|
-
|
||||||
|
+ if (loader_str) {
|
||||||
|
second_stage = loader_str;
|
||||||
|
- load_options = remaining_size ? start + (loader_len/2) : NULL;
|
||||||
|
+ load_options = remaining;
|
||||||
|
load_options_size = remaining_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1777,12 +1763,6 @@ shim_fini(void)
|
||||||
|
|
||||||
|
unhook_exit();
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * Free the space allocated for the alternative 2nd stage loader
|
||||||
|
- */
|
||||||
|
- if (load_options_size > 0 && second_stage)
|
||||||
|
- FreePool(second_stage);
|
||||||
|
-
|
||||||
|
console_fini();
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
||||||
10
shim.spec
10
shim.spec
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
Name: shim
|
Name: shim
|
||||||
Version: 15.4
|
Version: 15.4
|
||||||
Release: 2
|
Release: 3
|
||||||
Summary: First-stage UEFI bootloader
|
Summary: First-stage UEFI bootloader
|
||||||
ExclusiveArch: x86_64 aarch64
|
ExclusiveArch: x86_64 aarch64
|
||||||
License: BSD
|
License: BSD
|
||||||
@ -31,6 +31,11 @@ Source0: https://github.com/rhboot/shim/releases/download/%{version}/shim-%{v
|
|||||||
Source1: BOOTAA64.CSV
|
Source1: BOOTAA64.CSV
|
||||||
Source2: BOOTX64.CSV
|
Source2: BOOTX64.CSV
|
||||||
|
|
||||||
|
Patch0: backport-shim-another-attempt-to-fix-load-options-handling.patch
|
||||||
|
Patch1: backport-arm-aa64-fix-the-size-of-.rela-sections.patch
|
||||||
|
Patch2: backport-mok-relax-the-maximum-variable-size-check.patch
|
||||||
|
Patch3: backport-mok-delete-the-existing-RT-variables-only-when-only_.patch
|
||||||
|
|
||||||
BuildRequires: elfutils-libelf-devel openssl-devel openssl git pesign gnu-efi gnu-efi-devel gcc
|
BuildRequires: elfutils-libelf-devel openssl-devel openssl git pesign gnu-efi gnu-efi-devel gcc
|
||||||
Requires: dbxtool efi-filesystem mokutil
|
Requires: dbxtool efi-filesystem mokutil
|
||||||
Provides: bundled(openssl) = 1.0.2j
|
Provides: bundled(openssl) = 1.0.2j
|
||||||
@ -136,6 +141,9 @@ cd ..
|
|||||||
/usr/src/debug/%{name}-%{version}-%{release}/*
|
/usr/src/debug/%{name}-%{version}-%{release}/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Jul 5 2022 Hugel <gengqihu1@h-partners.com> - 15.4-3
|
||||||
|
- fix shim occasionally crashes in _relocate() on AArch64
|
||||||
|
|
||||||
* Thu Mar 3 2022 panxiaohe <panxh.life@foxmail.com> - 15.4-2
|
* Thu Mar 3 2022 panxiaohe <panxh.life@foxmail.com> - 15.4-2
|
||||||
- list files into debuginfo subpackage
|
- list files into debuginfo subpackage
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user