Commit 56ffb098 authored by Rocky Automation's avatar Rocky Automation 📺
Browse files

import grub2-2.02-123.el8_6.8

parent 66ab366d
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Thu, 28 Apr 2022 21:53:36 +0100
Subject: [PATCH] loader/efi/chainloader: grub_load_and_start_image doesn't
load and start
grub_load_and_start_image only loads an image - it still requires the
caller to start it. This renames it to grub_load_image.
It's called from 2 places:
- grub_cmd_chainloader when not using the shim protocol.
- grub_secureboot_chainloader_boot if handle_image returns an error.
In this case, the image is loaded and then nothing else happens which
seems strange. I assume the intention is that it falls back to LoadImage
and StartImage if handle_image fails, so I've made it do that.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit b4d70820a65c00561045856b7b8355461a9545f6)
(cherry picked from commit 05b16a6be50b1910609740a66b561276fa490538)
(cherry picked from commit 16486a34f3aa41a94e334e86db1a1e21e9b0a45f)
(cherry picked from commit 4a23f40cb6400d94621de688a7e79dfe124f5a63)
---
grub-core/loader/efi/chainloader.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 29663f7180..d75d345003 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -835,7 +835,7 @@ grub_secureboot_chainloader_unload (void)
}
static grub_err_t
-grub_load_and_start_image(void *boot_image)
+grub_load_image(void *boot_image)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
@@ -877,13 +877,23 @@ grub_load_and_start_image(void *boot_image)
static grub_err_t
grub_secureboot_chainloader_boot (void)
{
+ grub_efi_boot_services_t *b;
int rc;
+
rc = handle_image ((void *)(unsigned long)address, fsize);
if (rc == 0)
{
- grub_load_and_start_image((void *)(unsigned long)address);
+ /* We weren't able to attempt to execute the image, so fall back
+ * to LoadImage / StartImage.
+ */
+ rc = grub_load_image((void *)(unsigned long)address);
+ if (rc == 0)
+ grub_chainloader_boot ();
}
+ b = grub_efi_system_table->boot_services;
+ efi_call_1 (b->unload_image, image_handle);
+
grub_loader_unset ();
return grub_errno;
}
@@ -1072,7 +1082,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
}
else if (rc == 0)
{
- grub_load_and_start_image(boot_image);
+ grub_load_image(boot_image);
grub_file_close (file);
grub_device_close (dev);
grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Fri, 29 Apr 2022 21:13:08 +0100
Subject: [PATCH] loader/efi/chainloader: simplify the loader state
When not using the shim lock protocol, the chainloader command retains
the source buffer and device path passed to LoadImage, requiring the
unload hook passed to grub_loader_set to free them. It isn't required
to retain this state though - they aren't required by StartImage or
anything else in the boot hook, so clean them up before
grub_cmd_chainloader finishes.
This also wraps the loader state when using the shim lock protocol
inside a struct.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit fa39862933b3be1553a580a3a5c28073257d8046)
(cherry picked from commit 0333343ee99c4e88f062789263c94291c057251b)
[rharwood: verifying twice]
(cherry picked from commit 6080ad5d91d6a80d5f67c592dd33b6dd413e9453)
[rharwood: double frees and unintialized, context fuzz - orig_dp]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit b44b88ae45008611ec0469fb47139f4c0d1ee233)
---
grub-core/loader/efi/chainloader.c | 160 +++++++++++++++++++++++--------------
1 file changed, 102 insertions(+), 58 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index d75d345003..afeb1fc97e 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -47,38 +47,21 @@ GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
-static grub_efi_physical_address_t address;
-static grub_efi_uintn_t pages;
-static grub_ssize_t fsize;
-static grub_efi_device_path_t *file_path;
static grub_efi_handle_t image_handle;
-static grub_efi_char16_t *cmdline;
-static grub_ssize_t cmdline_len;
-static grub_efi_handle_t dev_handle;
-static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
+struct grub_secureboot_chainloader_context {
+ grub_efi_physical_address_t address;
+ grub_efi_uintn_t pages;
+ grub_ssize_t fsize;
+ grub_efi_device_path_t *file_path;
+ grub_efi_char16_t *cmdline;
+ grub_ssize_t cmdline_len;
+ grub_efi_handle_t dev_handle;
+};
+static struct grub_secureboot_chainloader_context *sb_context;
static grub_err_t
-grub_chainloader_unload (void)
-{
- grub_efi_boot_services_t *b;
-
- b = grub_efi_system_table->boot_services;
- efi_call_1 (b->unload_image, image_handle);
- grub_efi_free_pages (address, pages);
-
- grub_free (file_path);
- grub_free (cmdline);
- cmdline = 0;
- file_path = 0;
- dev_handle = 0;
-
- grub_dl_unref (my_mod);
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_chainloader_boot (void)
+grub_start_image (grub_efi_handle_t handle)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
@@ -86,7 +69,7 @@ grub_chainloader_boot (void)
grub_efi_char16_t *exit_data = NULL;
b = grub_efi_system_table->boot_services;
- status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
+ status = efi_call_3 (b->start_image, handle, &exit_data_size, &exit_data);
if (status != GRUB_EFI_SUCCESS)
{
if (exit_data)
@@ -110,11 +93,37 @@ grub_chainloader_boot (void)
if (exit_data)
grub_efi_free_pool (exit_data);
- grub_loader_unset ();
-
return grub_errno;
}
+static grub_err_t
+grub_chainloader_unload (void)
+{
+ grub_efi_loaded_image_t *loaded_image;
+ grub_efi_boot_services_t *b;
+
+ loaded_image = grub_efi_get_loaded_image (image_handle);
+ if (loaded_image != NULL)
+ grub_free (loaded_image->load_options);
+
+ b = grub_efi_system_table->boot_services;
+ efi_call_1 (b->unload_image, image_handle);
+
+ grub_dl_unref (my_mod);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_chainloader_boot (void)
+{
+ grub_err_t err;
+
+ err = grub_start_image (image_handle);
+
+ grub_loader_unset ();
+ return err;
+}
+
static grub_err_t
copy_file_path (grub_efi_file_path_device_path_t *fp,
const char *str, grub_efi_uint16_t len)
@@ -149,7 +158,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
char *dir_start;
char *dir_end;
grub_size_t size;
- grub_efi_device_path_t *d;
+ grub_efi_device_path_t *d, *file_path;
dir_start = grub_strchr (filename, ')');
if (! dir_start)
@@ -520,10 +529,12 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
}
static grub_efi_boolean_t
-handle_image (void *data, grub_efi_uint32_t datasize)
+handle_image (struct grub_secureboot_chainloader_context *load_context)
{
grub_efi_loaded_image_t *li, li_bak;
grub_efi_status_t efi_status;
+ void *data = (void *)(unsigned long)load_context->address;
+ grub_efi_uint32_t datasize = load_context->fsize;
void *buffer = NULL;
char *buffer_aligned = NULL;
grub_efi_uint32_t i;
@@ -534,6 +545,7 @@ handle_image (void *data, grub_efi_uint32_t datasize)
grub_uint32_t buffer_size;
int found_entry_point = 0;
int rc;
+ grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
rc = read_header (data, datasize, &context);
if (rc < 0)
@@ -791,10 +803,10 @@ handle_image (void *data, grub_efi_uint32_t datasize)
grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t));
li->image_base = buffer_aligned;
li->image_size = context.image_size;
- li->load_options = cmdline;
- li->load_options_size = cmdline_len;
- li->file_path = grub_efi_get_media_file_path (file_path);
- li->device_handle = dev_handle;
+ li->load_options = load_context->cmdline;
+ li->load_options_size = load_context->cmdline_len;
+ li->file_path = grub_efi_get_media_file_path (load_context->file_path);
+ li->device_handle = load_context->dev_handle;
if (!li->file_path)
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found");
@@ -823,19 +835,22 @@ error_exit:
static grub_err_t
grub_secureboot_chainloader_unload (void)
{
- grub_efi_free_pages (address, pages);
- grub_free (file_path);
- grub_free (cmdline);
- cmdline = 0;
- file_path = 0;
- dev_handle = 0;
+ grub_efi_free_pages (sb_context->address, sb_context->pages);
+ grub_free (sb_context->file_path);
+ grub_free (sb_context->cmdline);
+ grub_free (sb_context);
+
+ sb_context = 0;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
static grub_err_t
-grub_load_image(void *boot_image)
+grub_load_image(grub_efi_device_path_t *file_path, void *boot_image,
+ grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle,
+ grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len,
+ grub_efi_handle_t *image_handle_out)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
@@ -844,7 +859,7 @@ grub_load_image(void *boot_image)
b = grub_efi_system_table->boot_services;
status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
- boot_image, fsize, &image_handle);
+ boot_image, image_size, image_handle_out);
if (status != GRUB_EFI_SUCCESS)
{
if (status == GRUB_EFI_OUT_OF_RESOURCES)
@@ -857,7 +872,7 @@ grub_load_image(void *boot_image)
/* LoadImage does not set a device handler when the image is
loaded from memory, so it is necessary to set it explicitly here.
This is a mess. */
- loaded_image = grub_efi_get_loaded_image (image_handle);
+ loaded_image = grub_efi_get_loaded_image (*image_handle_out);
if (! loaded_image)
{
grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
@@ -879,20 +894,25 @@ grub_secureboot_chainloader_boot (void)
{
grub_efi_boot_services_t *b;
int rc;
+ grub_efi_handle_t handle = 0;
- rc = handle_image ((void *)(unsigned long)address, fsize);
+ rc = handle_image (sb_context);
if (rc == 0)
{
/* We weren't able to attempt to execute the image, so fall back
* to LoadImage / StartImage.
*/
- rc = grub_load_image((void *)(unsigned long)address);
+ rc = grub_load_image(sb_context->file_path,
+ (void *)(unsigned long)sb_context->address,
+ sb_context->fsize, sb_context->dev_handle,
+ sb_context->cmdline, sb_context->cmdline_len,
+ &handle);
if (rc == 0)
- grub_chainloader_boot ();
+ grub_start_image (handle);
}
b = grub_efi_system_table->boot_services;
- efi_call_1 (b->unload_image, image_handle);
+ efi_call_1 (b->unload_image, handle);
grub_loader_unset ();
return grub_errno;
@@ -906,10 +926,16 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_efi_status_t status;
grub_efi_boot_services_t *b;
grub_device_t dev = 0;
- grub_efi_device_path_t *dp = 0;
+ grub_efi_device_path_t *dp = 0, *file_path = 0;
char *filename;
void *boot_image = 0;
int rc;
+ grub_efi_physical_address_t address = 0;
+ grub_ssize_t fsize;
+ grub_efi_uintn_t pages = 0;
+ grub_efi_char16_t *cmdline = 0;
+ grub_ssize_t cmdline_len = 0;
+ grub_efi_handle_t dev_handle = 0;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@@ -917,12 +943,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_dl_ref (my_mod);
- /* Initialize some global variables. */
- address = 0;
- image_handle = 0;
- file_path = 0;
- dev_handle = 0;
-
b = grub_efi_system_table->boot_services;
if (argc > 1)
@@ -1074,17 +1094,35 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
if (rc > 0)
{
+ sb_context = grub_malloc (sizeof (*sb_context));
+ if (sb_context == NULL)
+ goto fail;
+ sb_context->address = address;
+ sb_context->fsize = fsize;
+ sb_context->pages = pages;
+ sb_context->file_path = file_path;
+ sb_context->cmdline = cmdline;
+ sb_context->cmdline_len = cmdline_len;
+ sb_context->dev_handle = dev_handle;
+
grub_file_close (file);
grub_device_close (dev);
+
grub_loader_set (grub_secureboot_chainloader_boot,
grub_secureboot_chainloader_unload, 0);
return 0;
}
else if (rc == 0)
{
- grub_load_image(boot_image);
+ grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline,
+ cmdline_len, &image_handle);
grub_file_close (file);
grub_device_close (dev);
+
+ /* We're finished with the source image buffer and file path now */
+ efi_call_2 (b->free_pages, address, pages);
+ grub_free (file_path);
+
grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
return 0;
@@ -1106,6 +1144,12 @@ fail:
if (cmdline)
grub_free (cmdline);
+ if (image_handle != 0)
+ {
+ efi_call_1 (b->unload_image, image_handle);
+ image_handle = 0;
+ }
+
grub_dl_unref (my_mod);
return grub_errno;
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Fri, 29 Apr 2022 21:16:02 +0100
Subject: [PATCH] commands/boot: Add API to pass context to loader
Loaders rely on global variables for saving context which is consumed
in the boot hook and freed in the unload hook. In the case where a loader
command is executed twice, calling grub_loader_set a second time executes
the unload hook, but in some cases this runs when the loader's global
context has already been updated, resulting in the updated context being
freed and potential use-after-free bugs when the boot hook is subsequently
called.
This adds a new API (grub_loader_set_ex) which allows a loader to specify
context that is passed to its boot and unload hooks. This is an alternative
to requiring that loaders call grub_loader_unset before mutating their
global context.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3)
(cherry picked from commit 937ad0e2159b6b8cb0d2ce3515da3a8b797c7927)
(cherry picked from commit 873038ae7048f6cae8a3ebb2f97a8d361a080e13)
(cherry picked from commit 7eefe9ba7e8f1557705f0f854ab7a3014d6cb5e2)
---
grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------
include/grub/loader.h | 5 ++++
2 files changed, 63 insertions(+), 8 deletions(-)
diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
index bbca81e947..53691a62d9 100644
--- a/grub-core/commands/boot.c
+++ b/grub-core/commands/boot.c
@@ -27,10 +27,20 @@
GRUB_MOD_LICENSE ("GPLv3+");
-static grub_err_t (*grub_loader_boot_func) (void);
-static grub_err_t (*grub_loader_unload_func) (void);
+static grub_err_t (*grub_loader_boot_func) (void *);
+static grub_err_t (*grub_loader_unload_func) (void *);
+static void *grub_loader_context;
static int grub_loader_flags;
+struct grub_simple_loader_hooks
+{
+ grub_err_t (*boot) (void);
+ grub_err_t (*unload) (void);
+};
+
+/* Don't heap allocate this to avoid making grub_loader_set fallible. */
+static struct grub_simple_loader_hooks simple_loader_hooks;
+
struct grub_preboot
{
grub_err_t (*preboot_func) (int);
@@ -44,6 +54,29 @@ static int grub_loader_loaded;
static struct grub_preboot *preboots_head = 0,
*preboots_tail = 0;
+static grub_err_t
+grub_simple_boot_hook (void *context)
+{
+ struct grub_simple_loader_hooks *hooks;
+
+ hooks = (struct grub_simple_loader_hooks *) context;
+ return hooks->boot ();
+}
+
+static grub_err_t
+grub_simple_unload_hook (void *context)
+{
+ struct grub_simple_loader_hooks *hooks;
+ grub_err_t ret;
+
+ hooks = (struct grub_simple_loader_hooks *) context;
+
+ ret = hooks->unload ();
+ grub_memset (hooks, 0, sizeof (*hooks));
+
+ return ret;
+}
+
int
grub_loader_is_loaded (void)
{
@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
}
void
-grub_loader_set (grub_err_t (*boot) (void),
- grub_err_t (*unload) (void),
- int flags)
+grub_loader_set_ex (grub_err_t (*boot) (void *),
+ grub_err_t (*unload) (void *),
+ void *context,
+ int flags)
{
if (grub_loader_loaded && grub_loader_unload_func)
- grub_loader_unload_func ();
+ grub_loader_unload_func (grub_loader_context);
grub_loader_boot_func = boot;
grub_loader_unload_func = unload;
+ grub_loader_context = context;
grub_loader_flags = flags;
grub_loader_loaded = 1;
}
+void
+grub_loader_set (grub_err_t (*boot) (void),
+ grub_err_t (*unload) (void),
+ int flags)
+{
+ grub_loader_set_ex (grub_simple_boot_hook,
+ grub_simple_unload_hook,
+ &simple_loader_hooks,
+ flags);
+
+ simple_loader_hooks.boot = boot;
+ simple_loader_hooks.unload = unload;
+}
+
void
grub_loader_unset(void)
{
if (grub_loader_loaded && grub_loader_unload_func)
- grub_loader_unload_func ();
+ grub_loader_unload_func (grub_loader_context);
grub_loader_boot_func = 0;
grub_loader_unload_func = 0;
+ grub_loader_context = 0;
grub_loader_loaded = 0;
}
@@ -158,7 +208,7 @@ grub_loader_boot (void)
return err;
}
}
- err = (grub_loader_boot_func) ();
+ err = (grub_loader_boot_func) (grub_loader_context);
for (cur = preboots_tail; cur; cur = cur->prev)
if (! err)
diff --git a/include/grub/loader.h b/include/grub/loader.h
index b208642821..1846fa6c5f 100644
--- a/include/grub/loader.h
+++ b/include/grub/loader.h
@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),
grub_err_t (*unload) (void),
int flags);
+void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *),
+ grub_err_t (*unload) (void *),
+ void *context,
+ int flags);
+
/* Unset current loader, if any. */
void EXPORT_FUNC (grub_loader_unset) (void);
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Fri, 29 Apr 2022 21:30:56 +0100
Subject: [PATCH] loader/efi/chainloader: Use grub_loader_set_ex
This ports the EFI chainloader to use grub_loader_set_ex in order to fix
a use-after-free bug that occurs when grub_cmd_chainloader is executed
more than once before a boot attempt is performed.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit 4b7f0402b7cb0f67a93be736f2b75b818d7f44c9)
(cherry picked from commit fc1a79bf0e0bc019362ace46d908a92b48dcd55b)
(cherry picked from commit f5b653dfe00271384ff7fbd82db926ab95dbd80e)
(cherry picked from commit 535a9d787f71ed6eb43e7c3a136a149684ec62ea)
[rharwood: context sludge from previous commit]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/loader/efi/chainloader.c | 38 ++++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 16 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index afeb1fc97e..720f6181e5 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -47,8 +47,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
-static grub_efi_handle_t image_handle;
-
struct grub_secureboot_chainloader_context {
grub_efi_physical_address_t address;
grub_efi_uintn_t pages;
@@ -58,7 +56,6 @@ struct grub_secureboot_chainloader_context {
grub_ssize_t cmdline_len;
grub_efi_handle_t dev_handle;
};