Merge branch 'c8' into a8

This commit is contained in:
eabdullin 2022-06-17 10:36:32 +03:00
commit 7c8932dcd0
53 changed files with 5457 additions and 9 deletions

View File

@ -0,0 +1,72 @@
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);

View File

@ -0,0 +1,335 @@
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;

View File

@ -0,0 +1,161 @@
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);

View File

@ -0,0 +1,150 @@
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;
};
-static struct grub_secureboot_chainloader_context *sb_context;
static grub_err_t
grub_start_image (grub_efi_handle_t handle)
@@ -97,11 +94,14 @@ grub_start_image (grub_efi_handle_t handle)
}
static grub_err_t
-grub_chainloader_unload (void)
+grub_chainloader_unload (void *context)
{
+ grub_efi_handle_t image_handle;
grub_efi_loaded_image_t *loaded_image;
grub_efi_boot_services_t *b;
+ image_handle = (grub_efi_handle_t) context;
+
loaded_image = grub_efi_get_loaded_image (image_handle);
if (loaded_image != NULL)
grub_free (loaded_image->load_options);
@@ -114,10 +114,12 @@ grub_chainloader_unload (void)
}
static grub_err_t
-grub_chainloader_boot (void)
+grub_chainloader_boot (void *context)
{
+ grub_efi_handle_t image_handle;
grub_err_t err;
+ image_handle = (grub_efi_handle_t) context;
err = grub_start_image (image_handle);
grub_loader_unset ();
@@ -833,15 +835,17 @@ error_exit:
}
static grub_err_t
-grub_secureboot_chainloader_unload (void)
+grub_secureboot_chainloader_unload (void *context)
{
+ struct grub_secureboot_chainloader_context *sb_context;
+
+ sb_context = (struct grub_secureboot_chainloader_context *) context;
+
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;
}
@@ -890,12 +894,15 @@ grub_load_image(grub_efi_device_path_t *file_path, void *boot_image,
}
static grub_err_t
-grub_secureboot_chainloader_boot (void)
+grub_secureboot_chainloader_boot (void *context)
{
+ struct grub_secureboot_chainloader_context *sb_context;
grub_efi_boot_services_t *b;
int rc;
grub_efi_handle_t handle = 0;
+ sb_context = (struct grub_secureboot_chainloader_context *) context;
+
rc = handle_image (sb_context);
if (rc == 0)
{
@@ -936,6 +943,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_efi_char16_t *cmdline = 0;
grub_ssize_t cmdline_len = 0;
grub_efi_handle_t dev_handle = 0;
+ grub_efi_handle_t image_handle = 0;
+ struct grub_secureboot_chainloader_context *sb_context = 0;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@@ -1108,8 +1117,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_file_close (file);
grub_device_close (dev);
- grub_loader_set (grub_secureboot_chainloader_boot,
- grub_secureboot_chainloader_unload, 0);
+ grub_loader_set_ex (grub_secureboot_chainloader_boot,
+ grub_secureboot_chainloader_unload, sb_context, 0);
return 0;
}
else if (rc == 0)
@@ -1123,7 +1132,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
efi_call_2 (b->free_pages, address, pages);
grub_free (file_path);
- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
+ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0);
return 0;
}
@@ -1145,10 +1154,7 @@ fail:
grub_free (cmdline);
if (image_handle != 0)
- {
- efi_call_1 (b->unload_image, image_handle);
- image_handle = 0;
- }
+ efi_call_1 (b->unload_image, image_handle);
grub_dl_unref (my_mod);

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Mon, 2 May 2022 14:39:31 +0200
Subject: [PATCH] loader/i386/efi/linux: Avoid a use-after-free in the linuxefi
loader
In some error paths in grub_cmd_linux, the pointer to lh may be
dereferenced after the buffer it points to has been freed. There aren't
any security implications from this because nothing else uses the
allocator after the buffer is freed and before the pointer is
dereferenced, but fix it anyway.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit 8224f5a71af94bec8697de17e7e579792db9f9e2)
(cherry picked from commit 4744b62e20d07674017213ac54d7442d679f9d1a)
(cherry picked from commit 329633cb060957c3d2aca677ac733f07b213a63f)
(cherry picked from commit 47b839b0a801ee4852447a85fb5de91dc7d2c856)
---
grub-core/loader/i386/efi/linux.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index a043df891f..c9a2b47370 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -482,9 +482,6 @@ fail:
if (file)
grub_file_close (file);
- if (kernel)
- grub_free (kernel);
-
if (grub_errno != GRUB_ERR_NONE)
{
grub_dl_unref (my_mod);
@@ -500,6 +497,8 @@ fail:
kernel_free (params, sizeof(*params));
}
+ grub_free (kernel);
+
return grub_errno;
}

View File

@ -0,0 +1,300 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Mon, 2 May 2022 17:04:23 +0200
Subject: [PATCH] loader/i386/efi/linux: Use grub_loader_set_ex
This ports the linuxefi loader to use grub_loader_set_ex in order to fix
a use-after-fre bug that occurs when grub_cmd_linux is executed more than
once before a boot attempt is performed.
This is more complicated than for the chainloader command, as the initrd
command needs access to the loader state. To solve this, the linuxefi
module registers a dummy initrd command at startup that returns an error.
The linuxefi command then registers a proper initrd command with a higher
priority that is passed the loader state.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit 7cf736436b4c934df5ddfa6f44b46a7e07d99fdc)
[rharwood/pjones: set kernel_size in context]
(cherry picked from commit 9c056391f7a36ea480de9a759c12e55a90f2040a)
[rharwood: verifying twice]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit df804892f1a754d88a9779320f9429bf40d2a1b3)
(cherry picked from commit d1b506f6c910b96ad47a20247b438c6402a74948)
---
grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++---------------
1 file changed, 87 insertions(+), 59 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index c9a2b47370..77a0734786 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -34,13 +34,19 @@
GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
-static int loaded;
-static void *kernel_mem;
-static grub_uint64_t kernel_size;
-static void *initrd_mem;
-static grub_uint32_t handover_offset;
-struct linux_kernel_params *params;
-static char *linux_cmdline;
+
+static grub_command_t cmd_linux, cmd_initrd;
+static grub_command_t cmd_linuxefi, cmd_initrdefi;
+
+struct grub_linuxefi_context {
+ void *kernel_mem;
+ grub_uint64_t kernel_size;
+ grub_uint32_t handover_offset;
+ struct linux_kernel_params *params;
+ char *cmdline;
+
+ void *initrd_mem;
+};
#define MIN(a, b) \
({ typeof (a) _a = (a); \
@@ -123,25 +129,32 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
}
static grub_err_t
-grub_linuxefi_boot (void)
+grub_linuxefi_boot (void *data)
{
+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data;
+
asm volatile ("cli");
- return grub_efi_linux_boot ((char *)kernel_mem,
- handover_offset,
- params);
+ return grub_efi_linux_boot ((char *)context->kernel_mem,
+ context->handover_offset,
+ context->params);
}
static grub_err_t
-grub_linuxefi_unload (void)
+grub_linuxefi_unload (void *data)
{
+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data;
+ struct linux_kernel_params *params = context->params;
+
grub_dl_unref (my_mod);
- loaded = 0;
- kernel_free(initrd_mem, params->ramdisk_size);
- kernel_free(linux_cmdline, params->cmdline_size + 1);
- kernel_free(kernel_mem, kernel_size);
- kernel_free(params, sizeof(*params));
+ kernel_free (context->initrd_mem, params->ramdisk_size);
+ kernel_free (context->cmdline, params->cmdline_size + 1);
+ kernel_free (context->kernel_mem, context->kernel_size);
+ kernel_free (params, sizeof(*params));
+ cmd_initrd->data = 0;
+ cmd_initrdefi->data = 0;
+ grub_free (context);
return GRUB_ERR_NONE;
}
@@ -188,13 +201,14 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull))
static grub_err_t
-grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *argv[])
+grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
{
grub_file_t *files = 0;
int i, nfiles = 0;
grub_size_t size = 0;
grub_uint8_t *ptr;
+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data;
+ struct linux_kernel_params *params;
if (argc == 0)
{
@@ -202,12 +216,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
- if (!loaded)
+ if (!context)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
goto fail;
}
+ params = context->params;
+
files = grub_calloc (argc, sizeof (files[0]));
if (!files)
goto fail;
@@ -226,19 +242,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
}
}
- initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
- if (initrd_mem == NULL)
+ context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
+ if (context->initrd_mem == NULL)
goto fail;
- grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
+ grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem);
params->ramdisk_size = LOW_U32(size);
- params->ramdisk_image = LOW_U32(initrd_mem);
+ params->ramdisk_image = LOW_U32(context->initrd_mem);
#if defined(__x86_64__)
params->ext_ramdisk_size = HIGH_U32(size);
- params->ext_ramdisk_image = HIGH_U32(initrd_mem);
+ params->ext_ramdisk_image = HIGH_U32(context->initrd_mem);
#endif
- ptr = initrd_mem;
+ ptr = context->initrd_mem;
for (i = 0; i < nfiles; i++)
{
@@ -264,8 +280,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
grub_file_close (files[i]);
grub_free (files);
- if (initrd_mem && grub_errno)
- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
+ if (context->initrd_mem && grub_errno)
+ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem,
BYTES_TO_PAGES(size));
return grub_errno;
@@ -281,6 +297,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
void *kernel = NULL;
int setup_header_end_offset;
int rc;
+ void *kernel_mem = 0;
+ grub_uint64_t kernel_size = 0;
+ grub_uint32_t handover_offset;
+ struct linux_kernel_params *params = 0;
+ char *cmdline = 0;
+ struct grub_linuxefi_context *context = 0;
grub_dl_ref (my_mod);
@@ -407,27 +429,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("linux", "new lh is at %p\n", lh);
grub_dprintf ("linux", "setting up cmdline\n");
- linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
- if (!linux_cmdline)
+ cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
+ if (!cmdline)
goto fail;
- grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline);
+ grub_dprintf ("linux", "cmdline = %p\n", cmdline);
- grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+ grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
grub_create_loader_cmdline (argc, argv,
- linux_cmdline + sizeof (LINUX_IMAGE) - 1,
+ cmdline + sizeof (LINUX_IMAGE) - 1,
lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1),
GRUB_VERIFY_KERNEL_CMDLINE);
- grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
+ grub_dprintf ("linux", "cmdline:%s\n", cmdline);
grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
- LOW_U32(linux_cmdline));
- lh->cmd_line_ptr = LOW_U32(linux_cmdline);
+ LOW_U32(cmdline));
+ lh->cmd_line_ptr = LOW_U32(cmdline);
#if defined(__x86_64__)
- if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull)
+ if ((grub_efi_uintn_t)cmdline > 0xffffffffull)
{
grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n",
- HIGH_U32(linux_cmdline));
- params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline);
+ HIGH_U32(cmdline));
+ params->ext_cmd_line_ptr = HIGH_U32(cmdline);
}
#endif
@@ -452,16 +474,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
- kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
+ kernel_size = lh->init_size;
+ kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel"));
restore_addresses();
if (!kernel_mem)
goto fail;
grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
- grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
-
- loaded = 1;
-
grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n",
LOW_U32(kernel_mem));
lh->code32_start = LOW_U32(kernel_mem);
@@ -478,33 +497,42 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
"setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n",
params->ext_loader_type, params->ext_loader_ver);
+ context = grub_zalloc (sizeof (*context));
+ if (!context)
+ goto fail;
+ context->kernel_mem = kernel_mem;
+ context->kernel_size = kernel_size;
+ context->handover_offset = handover_offset;
+ context->params = params;
+ context->cmdline = cmdline;
+
+ grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
+
+ cmd_initrd->data = context;
+ cmd_initrdefi->data = context;
+
+ grub_file_close (file);
+ grub_free (kernel);
+ return 0;
+
fail:
if (file)
grub_file_close (file);
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_dl_unref (my_mod);
- loaded = 0;
- }
+ grub_dl_unref (my_mod);
- if (!loaded)
- {
- if (lh)
- kernel_free (linux_cmdline, lh->cmdline_size + 1);
+ if (lh)
+ kernel_free (cmdline, lh->cmdline_size + 1);
- kernel_free (kernel_mem, kernel_size);
- kernel_free (params, sizeof(*params));
- }
+ kernel_free (kernel_mem, kernel_size);
+ kernel_free (params, sizeof(*params));
+ grub_free (context);
grub_free (kernel);
return grub_errno;
}
-static grub_command_t cmd_linux, cmd_initrd;
-static grub_command_t cmd_linuxefi, cmd_initrdefi;
-
GRUB_MOD_INIT(linux)
{
cmd_linux =

View File

@ -0,0 +1,78 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Tue, 3 May 2022 09:47:35 +0200
Subject: [PATCH] loader/i386/efi/linux: Fix a memory leak in the initrd
command
Subsequent invocations of the initrd command result in the previous
initrd being leaked, so fix that.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit d98af31ce1e31bb22163960d53f5eb28c66582a0)
(cherry picked from commit 62234d6a00e6d1dd8e017ff161d359feb5234082)
(cherry picked from commit bda5a10716dc9676400dce1374232452f46d0bc4)
(cherry picked from commit b862299a8502282a09af8e6c6189edd5b0a368b0)
---
grub-core/loader/i386/efi/linux.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 77a0734786..8337191921 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -209,6 +209,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
grub_uint8_t *ptr;
struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data;
struct linux_kernel_params *params;
+ void *initrd_mem = 0;
if (argc == 0)
{
@@ -242,19 +243,19 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
}
}
- context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
- if (context->initrd_mem == NULL)
+ initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
+ if (initrd_mem == NULL)
goto fail;
- grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem);
+ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
params->ramdisk_size = LOW_U32(size);
- params->ramdisk_image = LOW_U32(context->initrd_mem);
+ params->ramdisk_image = LOW_U32(initrd_mem);
#if defined(__x86_64__)
params->ext_ramdisk_size = HIGH_U32(size);
- params->ext_ramdisk_image = HIGH_U32(context->initrd_mem);
+ params->ext_ramdisk_image = HIGH_U32(initrd_mem);
#endif
- ptr = context->initrd_mem;
+ ptr = initrd_mem;
for (i = 0; i < nfiles; i++)
{
@@ -273,6 +274,9 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
+ kernel_free(context->initrd_mem, params->ramdisk_size);
+
+ context->initrd_mem = initrd_mem;
params->ramdisk_size = size;
fail:
@@ -280,9 +284,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
grub_file_close (files[i]);
grub_free (files);
- if (context->initrd_mem && grub_errno)
- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem,
- BYTES_TO_PAGES(size));
+ if (initrd_mem && grub_errno)
+ kernel_free (initrd_mem, size);
return grub_errno;
}

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Fri, 25 Jun 2021 02:19:05 +1000
Subject: [PATCH] kern/file: Do not leak device_name on error in
grub_file_open()
If we have an error in grub_file_open() before we free device_name, we
will leak it.
Free device_name in the error path and null out the pointer in the good
path once we free it there.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 1499a5068839fa37cb77ecef4b5bdacbd1ed12ea)
(cherry picked from commit 2ec50b289d8b24922433439533113087f111f110)
(cherry picked from commit 17c36ae88d7d6040cabc01cd4a21e71ff4731668)
(cherry picked from commit 723e7dbedb7669343e564d453d21b8ed2ab81216)
---
grub-core/kern/file.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 2efc31da94..f062fc21e7 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -81,6 +81,7 @@ grub_file_open (const char *name, enum grub_file_type type)
device = grub_device_open (device_name);
grub_free (device_name);
+ device_name = NULL;
if (! device)
goto fail;
@@ -135,6 +136,7 @@ grub_file_open (const char *name, enum grub_file_type type)
return file;
fail:
+ grub_free (device_name);
if (device)
grub_device_close (device);

View File

@ -0,0 +1,201 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 14:02:55 +1000
Subject: [PATCH] video/readers/png: Abort sooner if a read operation fails
Fuzzing revealed some inputs that were taking a long time, potentially
forever, because they did not bail quickly upon encountering an I/O error.
Try to catch I/O errors sooner and bail out.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 882be97d1df6449b9fd4d593f0cb70005fde3494)
(cherry picked from commit 3f6fc3ebfd58fcdb3fe6c2f7a5a4fa05772ae786)
(cherry picked from commit aac5b8257d4078c3f764216aeae3367bdc19043f)
(cherry picked from commit e9e58c9711de334fcf48a651ee20c21f2855a4bd)
---
grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 47 insertions(+), 8 deletions(-)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index 0157ff7420..e2a6b1cf3c 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -142,6 +142,7 @@ static grub_uint8_t
grub_png_get_byte (struct grub_png_data *data)
{
grub_uint8_t r;
+ grub_ssize_t bytes_read = 0;
if ((data->inside_idat) && (data->idat_remain == 0))
{
@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data)
}
r = 0;
- grub_file_read (data->file, &r, 1);
+ bytes_read = grub_file_read (data->file, &r, 1);
+
+ if (bytes_read != 1)
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: unexpected end of data");
+ return 0;
+ }
if (data->inside_idat)
data->idat_remain--;
@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data,
if (len == 0)
return GRUB_ERR_NONE;
- for (i = 0; 3 * i < len && i < 256; i++)
+ grub_errno = GRUB_ERR_NONE;
+ for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++)
for (j = 0; j < 3; j++)
data->palette[i][j] = grub_png_get_byte (data);
- for (i *= 3; i < len; i++)
+ for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++)
grub_png_get_byte (data);
grub_png_get_dword (data);
- return GRUB_ERR_NONE;
+ return grub_errno;
}
static grub_err_t
@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size");
color_bits = grub_png_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
data->is_16bit = (color_bits == 16);
color_type = grub_png_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
/* According to PNG spec, no other types are valid. */
if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR))
@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data)
if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: compression method not supported");
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: filter method not supported");
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (grub_png_get_byte (data) != PNG_INTERLACE_NONE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: interlace method not supported");
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
/* Skip crc checksum. */
grub_png_get_dword (data);
@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht)
int code, i;
code = 0;
- for (i = 0; i < ht->max_length; i++)
+ for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++)
{
code = (code << 1) + grub_png_get_bits (data, 1);
if (code < ht->maxval[i])
@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
grub_uint8_t lens[DEFLATE_HCLEN_MAX];
nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) ||
(nb > DEFLATE_HCLEN_MAX))
@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
data->dist_offset);
prev = 0;
- for (i = 0; i < nl + nd; i++)
+ for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++)
{
int n, code;
struct huff_table *ht;
@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
len = cplens[n];
if (cplext[n])
len += grub_png_get_bits (data, cplext[n]);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
n = grub_png_get_huff_code (data, &data->dist_table);
dist = cpdist[n];
if (cpdext[n])
dist += grub_png_get_bits (data, cpdext[n]);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
pos = data->wp - dist;
if (pos < 0)
pos += WSIZE;
- while (len > 0)
+ while (len > 0 && grub_errno == GRUB_ERR_NONE)
{
data->slide[data->wp] = data->slide[pos];
grub_png_output_byte (data, data->slide[data->wp]);
@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
int final;
cmf = grub_png_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
flg = grub_png_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if ((cmf & 0xF) != Z_DEFLATED)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
int block_type;
final = grub_png_get_bits (data, 1);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
block_type = grub_png_get_bits (data, 2);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
switch (block_type)
{
@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data)
grub_png_get_byte (data);
grub_png_get_byte (data);
- for (i = 0; i < len; i++)
+ for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++)
grub_png_output_byte (data, grub_png_get_byte (data));
break;
@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data)
len = grub_png_get_dword (data);
type = grub_png_get_dword (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ break;
data->next_offset = data->file->offset + len + 4;
switch (type)

View File

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 14:13:40 +1000
Subject: [PATCH] video/readers/png: Refuse to handle multiple image headers
This causes the bitmap to be leaked. Do not permit multiple image headers.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 8ce433557adeadbc46429aabb9f850b02ad2bdfb)
(cherry picked from commit 6e10bba6a4cbfd6c7bf116f41fd4e037465e19d8)
(cherry picked from commit 812272d919ecfd368c008f15b677d369616ada54)
(cherry picked from commit c04569b35600aa29d5b4cd8990a8ee1dd1162c72)
---
grub-core/video/readers/png.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index e2a6b1cf3c..8955b8ecfd 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data)
int color_bits;
enum grub_video_blit_format blt;
+ if (data->image_width || data->image_height)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found");
+
data->image_width = grub_png_get_dword (data);
data->image_height = grub_png_get_dword (data);

View File

@ -0,0 +1,173 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 18:51:35 +1000
Subject: [PATCH] video/readers/png: Drop greyscale support to fix heap
out-of-bounds write
A 16-bit greyscale PNG without alpha is processed in the following loop:
for (i = 0; i < (data->image_width * data->image_height);
i++, d1 += 4, d2 += 2)
{
d1[R3] = d2[1];
d1[G3] = d2[1];
d1[B3] = d2[1];
}
The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration,
but there are only 3 bytes allocated for storage. This means that image
data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes
out of every 4 following the end of the image.
This has existed since greyscale support was added in 2013 in commit
3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale).
Saving starfield.png as a 16-bit greyscale image without alpha in the gimp
and attempting to load it causes grub-emu to crash - I don't think this code
has ever worked.
Delete all PNG greyscale support.
Fixes: CVE-2021-3695
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 0e1d163382669bd734439d8864ee969616d971d9)
[rharwood: context conflict]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 4c631c8119206b3178912df2905434d967661c3d)
(cherry picked from commit 6d5d5f51266b8113c6ba560835500e3c135f3722)
(cherry picked from commit b20fc5589561a8c57a2071b2ae93fcdcf51a10d4)
---
grub-core/video/readers/png.c | 85 +++----------------------------------------
1 file changed, 6 insertions(+), 79 deletions(-)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index 8955b8ecfd..a3161e25b6 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -100,7 +100,7 @@ struct grub_png_data
unsigned image_width, image_height;
int bpp, is_16bit;
- int raw_bytes, is_gray, is_alpha, is_palette;
+ int raw_bytes, is_alpha, is_palette;
int row_bytes, color_bits;
grub_uint8_t *image_data;
@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
data->bpp = 3;
else
{
- data->is_gray = 1;
- data->bpp = 1;
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: color type not supported");
}
if ((color_bits != 8) && (color_bits != 16)
&& (color_bits != 4
- || !(data->is_gray || data->is_palette)))
+ || !data->is_palette))
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: bit depth must be 8 or 16");
@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data)
}
#ifndef GRUB_CPU_WORDS_BIGENDIAN
- if (data->is_16bit || data->is_gray || data->is_palette)
+ if (data->is_16bit || data->is_palette)
#endif
{
data->image_data = grub_calloc (data->image_height, data->row_bytes);
@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data)
int shift;
int mask = (1 << data->color_bits) - 1;
unsigned j;
- if (data->is_gray)
- {
- /* Generic formula is
- (0xff * i) / ((1U << data->color_bits) - 1)
- but for allowed bit depth of 1, 2 and for it's
- equivalent to
- (0xff / ((1U << data->color_bits) - 1)) * i
- Precompute the multipliers to avoid division.
- */
- const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 };
- for (i = 0; i < (1U << data->color_bits); i++)
- {
- grub_uint8_t col = multipliers[data->color_bits] * i;
- palette[i][0] = col;
- palette[i][1] = col;
- palette[i][2] = col;
- }
- }
- else
- grub_memcpy (palette, data->palette, 3 << data->color_bits);
+ grub_memcpy (palette, data->palette, 3 << data->color_bits);
d1c = d1;
d2c = d2;
for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3,
@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data)
}
return;
}
-
- if (data->is_gray)
- {
- switch (data->bpp)
- {
- case 4:
- /* 16-bit gray with alpha. */
- for (i = 0; i < (data->image_width * data->image_height);
- i++, d1 += 4, d2 += 4)
- {
- d1[R4] = d2[3];
- d1[G4] = d2[3];
- d1[B4] = d2[3];
- d1[A4] = d2[1];
- }
- break;
- case 2:
- if (data->is_16bit)
- /* 16-bit gray without alpha. */
- {
- for (i = 0; i < (data->image_width * data->image_height);
- i++, d1 += 4, d2 += 2)
- {
- d1[R3] = d2[1];
- d1[G3] = d2[1];
- d1[B3] = d2[1];
- }
- }
- else
- /* 8-bit gray with alpha. */
- {
- for (i = 0; i < (data->image_width * data->image_height);
- i++, d1 += 4, d2 += 2)
- {
- d1[R4] = d2[1];
- d1[G4] = d2[1];
- d1[B4] = d2[1];
- d1[A4] = d2[0];
- }
- }
- break;
- /* 8-bit gray without alpha. */
- case 1:
- for (i = 0; i < (data->image_width * data->image_height);
- i++, d1 += 3, d2++)
- {
- d1[R3] = d2[0];
- d1[G3] = d2[0];
- d1[B3] = d2[0];
- }
- break;
- }
- return;
- }
{
/* Only copy the upper 8 bit. */

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 23:25:07 +1000
Subject: [PATCH] video/readers/png: Avoid heap OOB R/W inserting huff table
items
In fuzzing we observed crashes where a code would attempt to be inserted
into a huffman table before the start, leading to a set of heap OOB reads
and writes as table entries with negative indices were shifted around and
the new code written in.
Catch the case where we would underflow the array and bail.
Fixes: CVE-2021-3696
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 1ae9a91d42cb40da8a6f11fac65541858e340afa)
(cherry picked from commit 132ccc681cf642ad748580f26b54c9259a7f43fd)
(cherry picked from commit 3a70e1f6e69af6e0d3c3cf526faa44dc0c80ac19)
(cherry picked from commit 809d25ffa6b89d390a66d2f3cf3090196f07e2aa)
---
grub-core/video/readers/png.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index a3161e25b6..d7ed5aa6cf 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len)
for (i = len; i < ht->max_length; i++)
n += ht->maxval[i];
+ if (n > ht->num_values)
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: out of range inserting huffman table item");
+ return;
+ }
+
for (i = 0; i < n; i++)
ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1];

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 19:19:11 +1000
Subject: [PATCH] video/readers/png: Sanity check some huffman codes
ASAN picked up two OOB global reads: we weren't checking if some code
values fit within the cplens or cpdext arrays. Check and throw an error
if not.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit c3a8ab0cbd24153ec7b1f84a96ddfdd72ef8d117)
(cherry picked from commit 5d09addf58086aa11d5f9a91af5632ff87c2d2ee)
(cherry picked from commit ff12584f9376a472f37d4ec14213fd29bf3b233a)
(cherry picked from commit ac8b5464a076d2e38ecf7f761be9cd1f5bbeb784)
---
grub-core/video/readers/png.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index d7ed5aa6cf..7f2ba7849b 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
int len, dist, pos;
n -= 257;
+ if (((unsigned int) n) >= ARRAY_SIZE (cplens))
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: invalid huff code");
len = cplens[n];
if (cplext[n])
len += grub_png_get_bits (data, cplext[n]);
@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
return grub_errno;
n = grub_png_get_huff_code (data, &data->dist_table);
+ if (((unsigned int) n) >= ARRAY_SIZE (cpdist))
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: invalid huff code");
dist = cpdist[n];
if (cpdext[n])
dist += grub_png_get_bits (data, cpdext[n]);

View File

@ -0,0 +1,258 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 28 Jun 2021 14:16:14 +1000
Subject: [PATCH] video/readers/jpeg: Abort sooner if a read operation fails
Fuzzing revealed some inputs that were taking a long time, potentially
forever, because they did not bail quickly upon encountering an I/O error.
Try to catch I/O errors sooner and bail out.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit ab2e5d2e4bff488bbb557ed435a61ae102ef9f0c)
(cherry picked from commit 1ff8df0d2dea8ec7c8575241d5e7d6622c204ec3)
(cherry picked from commit b07767383b74a0ce7135c09ba8701510d4ad32f0)
(cherry picked from commit 5f097165152d61d4aea02f26dc789d840147d50e)
---
grub-core/video/readers/jpeg.c | 86 ++++++++++++++++++++++++++++++++++--------
1 file changed, 70 insertions(+), 16 deletions(-)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index e31602f766..10225abd53 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -109,9 +109,17 @@ static grub_uint8_t
grub_jpeg_get_byte (struct grub_jpeg_data *data)
{
grub_uint8_t r;
+ grub_ssize_t bytes_read;
r = 0;
- grub_file_read (data->file, &r, 1);
+ bytes_read = grub_file_read (data->file, &r, 1);
+
+ if (bytes_read != 1)
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: unexpected end of data");
+ return 0;
+ }
return r;
}
@@ -120,9 +128,17 @@ static grub_uint16_t
grub_jpeg_get_word (struct grub_jpeg_data *data)
{
grub_uint16_t r;
+ grub_ssize_t bytes_read;
r = 0;
- grub_file_read (data->file, &r, sizeof (grub_uint16_t));
+ bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t));
+
+ if (bytes_read != sizeof (grub_uint16_t))
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: unexpected end of data");
+ return 0;
+ }
return grub_be_to_cpu16 (r);
}
@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
if (data->bit_mask == 0)
{
data->bit_save = grub_jpeg_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE) {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: file read error");
+ return 0;
+ }
if (data->bit_save == JPEG_ESC_CHAR)
{
if (grub_jpeg_get_byte (data) != 0)
@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
"jpeg: invalid 0xFF in data stream");
return 0;
}
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error");
+ return 0;
+ }
}
data->bit_mask = 0x80;
}
@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num)
return 0;
msb = value = grub_jpeg_get_bit (data);
- for (i = 1; i < num; i++)
+ for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++)
value = (value << 1) + (grub_jpeg_get_bit (data) != 0);
if (!msb)
value += 1 - (1 << num);
@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
while (data->file->offset + sizeof (count) + 1 <= next_marker)
{
id = grub_jpeg_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
ac = (id >> 4) & 1;
id &= 0xF;
if (id > 1)
@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
next_marker = data->file->offset;
next_marker += grub_jpeg_get_word (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (next_marker > data->file->size)
{
@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
<= next_marker)
{
id = grub_jpeg_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (id >= 0x10) /* Upper 4-bit is precision. */
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: only 8-bit precision is supported");
@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
next_marker = data->file->offset;
next_marker += grub_jpeg_get_word (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+
if (grub_jpeg_get_byte (data) != 8)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: only 8-bit precision is supported");
@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
ss = grub_jpeg_get_byte (data); /* Sampling factor. */
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (!id)
{
grub_uint8_t vs, hs;
@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du)
}
}
-static void
+static grub_err_t
grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
{
int h1, h2, qt;
@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
data->dc_value[id] +=
grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1));
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+
du[0] = data->dc_value[id] * (int) data->quan_table[qt][0];
pos = 1;
while (pos < ARRAY_SIZE (data->quan_table[qt]))
@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
num >>= 4;
pos += num;
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+
if (pos >= ARRAY_SIZE (jpeg_zigzag_order))
{
- grub_error (GRUB_ERR_BAD_FILE_TYPE,
- "jpeg: invalid position in zigzag order!?");
- return;
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: invalid position in zigzag order!?");
}
du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos];
@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
}
grub_jpeg_idct_transform (du);
+ return GRUB_ERR_NONE;
}
static void
@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
data_offset += grub_jpeg_get_word (data);
cc = grub_jpeg_get_byte (data);
-
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (cc != 3 && cc != 1)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: component count must be 1 or 3");
@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
id = grub_jpeg_get_byte (data) - 1;
if ((id < 0) || (id >= 3))
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
-
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
ht = grub_jpeg_get_byte (data);
data->comp_index[id][1] = (ht >> 4);
data->comp_index[id][2] = (ht & 0xF) + 2;
@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) ||
(data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3))
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index");
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
}
grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */
grub_jpeg_get_word (data);
-
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (data->file->offset != data_offset)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
{
unsigned c1, vb, hb, nr1, nc1;
int rst = data->dri;
+ grub_err_t err = GRUB_ERR_NONE;
vb = 8 << data->log_vs;
hb = 8 << data->log_hs;
@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
for (r2 = 0; r2 < (1U << data->log_vs); r2++)
for (c2 = 0; c2 < (1U << data->log_hs); c2++)
- grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
+ {
+ err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
if (data->color_components >= 3)
{
- grub_jpeg_decode_du (data, 1, data->cbdu);
- grub_jpeg_decode_du (data, 2, data->crdu);
+ err = grub_jpeg_decode_du (data, 1, data->cbdu);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ err = grub_jpeg_decode_du (data, 2, data->crdu);
+ if (err != GRUB_ERR_NONE)
+ return err;
}
- if (grub_errno)
- return grub_errno;
-
nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb;
nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb;

View File

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 28 Jun 2021 14:16:58 +1000
Subject: [PATCH] video/readers/jpeg: Do not reallocate a given huff table
Fix a memory leak where an invalid file could cause us to reallocate
memory for a huffman table we had already allocated memory for.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit bc06e12b4de55cc6f926af9f064170c82b1403e9)
(cherry picked from commit 5298bf758ea39a90537f9a1c76541ff2f21b970b)
(cherry picked from commit aae6bac7f26c6b848156ed7adcff83309b833664)
(cherry picked from commit bc58c0da3aed59486042759a03fe61a9782e36ce)
---
grub-core/video/readers/jpeg.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index 10225abd53..caa211f06d 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
n += count[i];
id += ac * 2;
+ if (data->huff_value[id] != NULL)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: attempt to reallocate huffman table");
data->huff_value[id] = grub_malloc (n);
if (grub_errno)
return grub_errno;

View File

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 28 Jun 2021 14:25:17 +1000
Subject: [PATCH] video/readers/jpeg: Refuse to handle multiple start of
streams
An invalid file could contain multiple start of stream blocks, which
would cause us to reallocate and leak our bitmap. Refuse to handle
multiple start of streams.
Additionally, fix a grub_error() call formatting.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit f3a854def3e281b7ad4bbea730cd3046de1da52f)
(cherry picked from commit db0154828989a0a52ee59a4dda8c3803752bc827)
(cherry picked from commit 75afb375ef46bc99a7faf5879d0283934e34db97)
(cherry picked from commit 82f8de94e19be775cdabd05528dc7acf0cb485a7)
---
grub-core/video/readers/jpeg.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index caa211f06d..1df1171d78 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
if (data->file->offset != data_offset)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
+ if (*data->bitmap)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks");
+
if (grub_video_bitmap_create (data->bitmap, data->image_width,
data->image_height,
GRUB_VIDEO_BLIT_FORMAT_RGB_888))
@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs);
if (data->bitmap_ptr == NULL)
- return grub_error(GRUB_ERR_BAD_FILE_TYPE,
- "jpeg: attempted to decode data before start of stream");
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: attempted to decode data before start of stream");
for (; data->r1 < nr1 && (!data->dri || rst);
data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)

View File

@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Wed, 7 Jul 2021 15:38:19 +1000
Subject: [PATCH] video/readers/jpeg: Block int underflow -> wild pointer write
Certain 1 px wide images caused a wild pointer write in
grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(),
we have the following loop:
for (; data->r1 < nr1 && (!data->dri || rst);
data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
We did not check if vb * width >= hb * nc1.
On a 64-bit platform, if that turns out to be negative, it will underflow,
be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so
we see data->bitmap_ptr jump, e.g.:
0x6180_0000_0480 to
0x6181_0000_0498
^
~--- carry has occurred and this pointer is now far away from
any object.
On a 32-bit platform, it will decrement the pointer, creating a pointer
that won't crash but will overwrite random data.
Catch the underflow and error out.
Fixes: CVE-2021-3697
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 41aeb2004db9924fecd9f2dd64bc2a5a5594a4b5)
(cherry picked from commit 5f9582490792108306d047379fed2371bee286f8)
(cherry picked from commit 7e4bf25d9bb5219fbf11c523296dc3bd78b80698)
(cherry picked from commit 397ecffe404b892470c41f4d24340526d3d33666)
---
grub-core/video/readers/jpeg.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index 1df1171d78..2da04094b3 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -705,6 +705,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: attempted to decode data before start of stream");
+ if (vb * data->image_width <= hb * nc1)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: cannot decode image with these dimensions");
+
for (; data->r1 < nr1 && (!data->dri || rst);
data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
for (c1 = 0; c1 < nc1 && (!data->dri || rst);

View File

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 13 Jul 2021 13:24:38 +1000
Subject: [PATCH] normal/charset: Fix array out-of-bounds formatting unicode
for display
In some cases attempting to display arbitrary binary strings leads
to ASAN splats reading the widthspec array out of bounds.
Check the index. If it would be out of bounds, return a width of 1.
I don't know if that's strictly correct, but we're not really expecting
great display of arbitrary binary data, and it's certainly not worse than
an OOB read.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit fdf32abc7a3928852422c0f291d8cd1dd6b34a8d)
(cherry picked from commit f2c10aaf335b88a69885375c4d68ffab2429df77)
(cherry picked from commit 4c942e1ba8d1f1199a58d2eb139022ae22f75cb2)
(cherry picked from commit 83efea59ad671d043b3a48fe0581f11beb63303c)
---
grub-core/normal/charset.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
index f902b13b44..7b2de12001 100644
--- a/grub-core/normal/charset.c
+++ b/grub-core/normal/charset.c
@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
{
if (grub_unicode_get_comb_type (c->base))
return 0;
+ if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec))
+ return 1;
if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
return 2;
else

View File

@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 8 Mar 2022 23:47:46 +1100
Subject: [PATCH] net/netbuff: Block overly large netbuff allocs
A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment
reassembly.
This helps avoid some bugs (and provides a spot to instrument to catch
them at their source).
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit ee9591103004cd13b4efadda671536090ca7fd57)
(cherry picked from commit acde668bb9d9fa862a1a63e3bbd5fa47fdfa9183)
(cherry picked from commit e47ad2eb4fe38ef2bdcab52245286f31170e73e3)
(cherry picked from commit 3517b6baf69ee77065f0216ff29190ad392a2c84)
---
grub-core/net/netbuff.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c
index dbeeefe478..d5e9e9a0d7 100644
--- a/grub-core/net/netbuff.c
+++ b/grub-core/net/netbuff.c
@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len)
COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0);
+ /*
+ * The largest size of a TCP packet is 64 KiB, and everything else
+ * should be a lot smaller - most MTUs are 1500 or less. Cap data
+ * size at 64 KiB + a buffer.
+ */
+ if (len > 0xffffUL + 0x1000UL)
+ {
+ grub_error (GRUB_ERR_BUG,
+ "attempted to allocate a packet that is too big");
+ return NULL;
+ }
+
if (len < NETBUFFMINLEN)
len = NETBUFFMINLEN;
len = ALIGN_UP (len, NETBUFF_ALIGN);
+
#ifdef GRUB_MACHINE_EMU
data = grub_malloc (len + sizeof (*nb));
#else

View File

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 20 Dec 2021 19:41:21 +1100
Subject: [PATCH] net/ip: Do IP fragment maths safely
This avoids an underflow and subsequent unpleasantness.
Fixes: CVE-2022-28733
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit eb74e5743ca7e18a5e75c392fe0b21d1549a1936)
(cherry picked from commit 552ad34583e788542e9ca08524a0d4bc8f98c297)
(cherry picked from commit 2c8cb7e3b8b48b136a950e5692fa6251b76df90e)
(cherry picked from commit 17bb2fe79e6b9688cf2008b840af9022804204ec)
---
grub-core/net/ip.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
index 9a4e589aa3..c766ac65f5 100644
--- a/grub-core/net/ip.c
+++ b/grub-core/net/ip.c
@@ -25,6 +25,7 @@
#include <grub/net/netbuff.h>
#include <grub/mm.h>
#include <grub/priority_queue.h>
+#include <grub/safemath.h>
#include <grub/time.h>
struct iphdr {
@@ -552,7 +553,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb,
{
rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
+ (nb->tail - nb->data));
- rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t));
+
+ if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t),
+ &rsm->total_len))
+ {
+ grub_dprintf ("net", "IP reassembly size underflow\n");
+ return GRUB_ERR_NONE;
+ }
+
rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len);
if (!rsm->asm_netbuff)
{

View File

@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Thu, 16 Sep 2021 01:29:54 +1000
Subject: [PATCH] net/dns: Fix double-free addresses on corrupt DNS response
grub_net_dns_lookup() takes as inputs a pointer to an array of addresses
("addresses") for the given name, and pointer to a number of addresses
("naddresses"). grub_net_dns_lookup() is responsible for allocating
"addresses", and the caller is responsible for freeing it if
"naddresses" > 0.
The DNS recv_hook will sometimes set and free the addresses array,
for example if the packet is too short:
if (ptr + 10 >= nb->tail)
{
if (!*data->naddresses)
grub_free (*data->addresses);
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
Later on the nslookup command code unconditionally frees the "addresses"
array. Normally this is fine: the array is either populated with valid
data or is NULL. But in these sorts of error cases it is neither NULL
nor valid and we get a double-free.
Only free "addresses" if "naddresses" > 0.
It looks like the other use of grub_net_dns_lookup() is not affected.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit eb2e69fcf51307757e43f55ee8c9354d1ee42dd1)
(cherry picked from commit d801a27e7acec6c1a83067fab0bb975877eaf704)
(cherry picked from commit 4d8b6e36ddfda4084e370b3b08c432e8a462e9be)
(cherry picked from commit ae133c18f304cb0a22c569c98abc62e15ccf56d0)
---
grub-core/net/dns.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
index 906ec7d678..135faac035 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
grub_net_addr_to_str (&addresses[i], buf);
grub_printf ("%s\n", buf);
}
- grub_free (addresses);
if (naddresses)
- return GRUB_ERR_NONE;
+ {
+ grub_free (addresses);
+ return GRUB_ERR_NONE;
+ }
return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
}

View File

@ -0,0 +1,74 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 20 Dec 2021 21:55:43 +1100
Subject: [PATCH] net/dns: Don't read past the end of the string we're checking
against
I don't really understand what's going on here but fuzzing found
a bug where we read past the end of check_with. That's a C string,
so use grub_strlen() to make sure we don't overread it.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 6a97b3f4b1d5173aa516edc6dedbc63de7306d21)
(cherry picked from commit e0589624e86bc96666cbdb62f6e55cafec2871b3)
(cherry picked from commit 95ecbc0b9aacfd43ba96cccc50daaf39eccd9f7f)
(cherry picked from commit 110eee925ecd9efeebb8d018b042fcf067a443c2)
---
grub-core/net/dns.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
index 135faac035..17961a9f18 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
int *length, char *set)
{
const char *readable_ptr = check_with;
+ int readable_len;
const grub_uint8_t *ptr;
char *optr = set;
int bytes_processed = 0;
if (length)
*length = 0;
+
+ if (readable_ptr != NULL)
+ readable_len = grub_strlen (readable_ptr);
+ else
+ readable_len = 0;
+
for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
{
/* End marker. */
@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
continue;
}
- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
+ if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0))
return 0;
if (grub_memchr (ptr + 1, 0, *ptr)
|| grub_memchr (ptr + 1, '.', *ptr))
return 0;
if (readable_ptr)
- readable_ptr += *ptr;
+ {
+ readable_ptr += *ptr;
+ readable_len -= *ptr;
+ }
if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
return 0;
bytes_processed += *ptr + 1;
@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
if (optr)
*optr++ = '.';
if (readable_ptr && *readable_ptr)
- readable_ptr++;
+ {
+ readable_ptr++;
+ readable_len--;
+ }
ptr += *ptr + 1;
}
return 0;

View File

@ -0,0 +1,115 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 20 Sep 2021 01:12:24 +1000
Subject: [PATCH] net/tftp: Prevent a UAF and double-free from a failed seek
A malicious tftp server can cause UAFs and a double free.
An attempt to read from a network file is handled by grub_net_fs_read(). If
the read is at an offset other than the current offset, grub_net_seek_real()
is invoked.
In grub_net_seek_real(), if a backwards seek cannot be satisfied from the
currently received packets, and the underlying transport does not provide
a seek method, then grub_net_seek_real() will close and reopen the network
protocol layer.
For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t
file->data. The file->data pointer is not nulled out after the free.
If the ->open() call fails, the file->data will not be reallocated and will
continue point to a freed memory block. This could happen from a server
refusing to send the requisite ack to the new tftp request, for example.
The seek and the read will then fail, but the grub_file continues to exist:
the failed seek does not necessarily cause the entire file to be thrown
away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc.,
a read failure is interpreted as a decompressor passing on the file, not as
an invalidation of the entire grub_file_t structure).
This means subsequent attempts to read or seek the file will use the old
file->data after free. Eventually, the file will be close()d again and
file->data will be freed again.
Mark a net_fs file that doesn't reopen as broken. Do not permit read() or
close() on a broken file (seek is not exposed directly to the file API -
it is only called as part of read, so this blocks seeks as well).
As an additional defence, null out the ->data pointer if tftp_open() fails.
That would have lead to a simple null pointer dereference rather than
a mess of UAFs.
This may affect other protocols, I haven't checked.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit dada1dda695439bb55b2848dddc2d89843552f81)
(cherry picked from commit 352c5ae8a9fc715712e6ecbd7ccb6218122c748f)
(cherry picked from commit 61a010085ab9f0ecf42677773a6fc212f1579b0a)
(cherry picked from commit 277d38531a47be78ac5062894e449726db2baf65)
---
grub-core/net/net.c | 11 +++++++++--
grub-core/net/tftp.c | 1 +
include/grub/net.h | 1 +
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index a27c53eee1..b9e2a4d100 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -1625,7 +1625,8 @@ grub_net_fs_close (grub_file_t file)
grub_netbuff_free (file->device->net->packs.first->nb);
grub_net_remove_packet (file->device->net->packs.first);
}
- file->device->net->protocol->close (file);
+ if (!file->device->net->broken)
+ file->device->net->protocol->close (file);
grub_free (file->device->net->name);
return GRUB_ERR_NONE;
}
@@ -1847,7 +1848,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
file->device->net->stall = 0;
err = file->device->net->protocol->open (file, file->device->net->name);
if (err)
- return err;
+ {
+ file->device->net->broken = 1;
+ return err;
+ }
grub_net_fs_read_real (file, NULL, offset);
return grub_errno;
}
@@ -1856,6 +1860,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
static grub_ssize_t
grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
{
+ if (file->device->net->broken)
+ return -1;
+
if (file->offset != file->device->net->offset)
{
grub_err_t err;
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
index aa0424dcee..85be965470 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -402,6 +402,7 @@ tftp_open (struct grub_file *file, const char *filename)
{
grub_net_udp_close (data->sock);
grub_free (data);
+ file->data = NULL;
return grub_errno;
}
diff --git a/include/grub/net.h b/include/grub/net.h
index 9cf6da6897..0d31f00664 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -280,6 +280,7 @@ typedef struct grub_net
grub_fs_t fs;
int eof;
int stall;
+ int broken;
} *grub_net_t;
extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);

View File

@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 4 Mar 2021 18:22:32 -0600
Subject: [PATCH] misc: Format string for grub_error() should be a literal
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry-picked from commit 60875f4e15d704b875969b415501802b531c4db3)
(cherry-picked from commit 6353cbd63cb3615a2b7aece183e3b177250d9415)
---
grub-core/loader/efi/chainloader.c | 2 +-
grub-core/net/tftp.c | 2 +-
grub-core/script/lexer.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 720f6181e5..8e658f713e 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -79,7 +79,7 @@ grub_start_image (grub_efi_handle_t handle)
*grub_utf16_to_utf8 ((grub_uint8_t *) buf,
exit_data, exit_data_size) = 0;
- grub_error (GRUB_ERR_BAD_OS, buf);
+ grub_error (GRUB_ERR_BAD_OS, "%s", buf);
grub_free (buf);
}
}
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
index 85be965470..69a9ba6979 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -253,7 +253,7 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
case TFTP_ERROR:
data->have_oack = 1;
grub_netbuff_free (nb);
- grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg);
+ grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg);
grub_error_save (&data->save_err);
return GRUB_ERR_NONE;
default:
diff --git a/grub-core/script/lexer.c b/grub-core/script/lexer.c
index 5fb0cbd0bc..27daad791c 100644
--- a/grub-core/script/lexer.c
+++ b/grub-core/script/lexer.c
@@ -349,7 +349,7 @@ void
grub_script_yyerror (struct grub_parser_param *state, char const *err)
{
if (err)
- grub_error (GRUB_ERR_INVALID_COMMAND, err);
+ grub_error (GRUB_ERR_INVALID_COMMAND, "%s", err);
grub_print_error ();
state->err++;

View File

@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 18 Jan 2022 14:29:20 +1100
Subject: [PATCH] net/tftp: Avoid a trivial UAF
Under tftp errors, we print a tftp error message from the tftp header.
However, the tftph pointer is a pointer inside nb, the netbuff. Previously,
we were freeing the nb and then dereferencing it. Don't do that, use it
and then free it later.
This isn't really _bad_ per se, especially as we're single-threaded, but
it trips up fuzzers.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 956f4329cec23e4375182030ca9b2be631a61ba5)
(cherry picked from commit dbe9abcdee6ce796811111b67e3f24eefe2135d1)
(cherry picked from commit 72ae9c5d389d2c0337c44edead6e00db0bb84039)
(cherry picked from commit 6a367d5b45cee3b452319cbaba1052f045c68081)
---
grub-core/net/tftp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
index 69a9ba6979..09e1511ccf 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -252,9 +252,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
return GRUB_ERR_NONE;
case TFTP_ERROR:
data->have_oack = 1;
- grub_netbuff_free (nb);
grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg);
grub_error_save (&data->save_err);
+ grub_netbuff_free (nb);
return GRUB_ERR_NONE;
default:
grub_netbuff_free (nb);

View File

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 1 Mar 2022 23:14:15 +1100
Subject: [PATCH] net/http: Do not tear down socket if it's already been torn
down
It's possible for data->sock to get torn down in tcp error handling.
If we unconditionally tear it down again we will end up doing writes
to an offset of the NULL pointer when we go to tear it down again.
Detect if it has been torn down and don't do it again.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit ec233d3ecf995293304de443579aab5c46c49e85)
(cherry picked from commit d39cf87ed701b9f0900daed7f672e07994d37ce8)
(cherry picked from commit e0aa5c3acec70eac3489d6df1893a93726cbce3a)
(cherry picked from commit d29000397693cae279291b75ff89e5b9a5e2ed97)
---
grub-core/net/http.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
index b52b558d63..5223ca57a4 100644
--- a/grub-core/net/http.c
+++ b/grub-core/net/http.c
@@ -427,7 +427,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
return err;
}
- for (i = 0; !data->headers_recv && i < 100; i++)
+ for (i = 0; data->sock && !data->headers_recv && i < 100; i++)
{
grub_net_tcp_retransmit ();
grub_net_poll_cards (300, &data->headers_recv);
@@ -435,7 +435,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
if (!data->headers_recv)
{
- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
+ if (data->sock)
+ grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
if (data->err)
{
char *str = data->errmsg;

View File

@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 8 Mar 2022 18:17:03 +1100
Subject: [PATCH] net/http: Fix OOB write for split http headers
GRUB has special code for handling an http header that is split
across two packets.
The code tracks the end of line by looking for a "\n" byte. The
code for split headers has always advanced the pointer just past the
end of the line, whereas the code that handles unsplit headers does
not advance the pointer. This extra advance causes the length to be
one greater, which breaks an assumption in parse_line(), leading to
it writing a NUL byte one byte past the end of the buffer where we
reconstruct the line from the two packets.
It's conceivable that an attacker controlled set of packets could
cause this to zero out the first byte of the "next" pointer of the
grub_mm_region structure following the current_line buffer.
Do not advance the pointer in the split header case.
Fixes: CVE-2022-28734
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit e9fb459638811c12b0989dbf64e3e124974ef617)
(cherry picked from commit b604916beb6c39e8ed27f72851eb16f3eaa293c5)
(cherry picked from commit c3c6b1167a43275991efd6847160a46ce3839fae)
(cherry picked from commit 9b4ef71ed4f6fce00e868e3223cdbfb734e840d6)
---
grub-core/net/http.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
index 5223ca57a4..7fa2dcaea7 100644
--- a/grub-core/net/http.c
+++ b/grub-core/net/http.c
@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
int have_line = 1;
char *t;
ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data);
- if (ptr)
- ptr++;
- else
+ if (ptr == NULL)
{
have_line = 0;
ptr = (char *) nb->tail;

View File

@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 8 Mar 2022 19:04:40 +1100
Subject: [PATCH] net/http: Error out on headers with LF without CR
In a similar vein to the previous patch, parse_line() would write
a NUL byte past the end of the buffer if there was an HTTP header
with a LF rather than a CRLF.
RFC-2616 says:
Many HTTP/1.1 header field values consist of words separated by LWS
or special characters. These special characters MUST be in a quoted
string to be used within a parameter value (as defined in section 3.6).
We don't support quoted sections or continuation lines, etc.
If we see an LF that's not part of a CRLF, bail out.
Fixes: CVE-2022-28734
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit d232ad41ac4979a9de4d746e5fdff9caf0e303de)
(cherry picked from commit 8960e6d6137090a7e8c6592077da6e387a4ef972)
(cherry picked from commit 9b6b9398c90dd76ce0b935d21c4ecb8954c4b2b7)
(cherry picked from commit 3eef2cc845f7ed34a89d8d0a7042d7768e43eaad)
---
grub-core/net/http.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
index 7fa2dcaea7..745f429b51 100644
--- a/grub-core/net/http.c
+++ b/grub-core/net/http.c
@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
char *end = ptr + len;
while (end > ptr && *(end - 1) == '\r')
end--;
+
+ /* LF without CR. */
+ if (end == ptr + len)
+ {
+ data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR"));
+ return GRUB_ERR_NONE;
+ }
*end = 0;
+
/* Trailing CRLF. */
if (data->in_chunk_len == 1)
{

View File

@ -0,0 +1,75 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 6 Apr 2022 18:03:37 +0530
Subject: [PATCH] fs/f2fs: Do not read past the end of nat journal entries
A corrupt f2fs file system could specify a nat journal entry count
that is beyond the maximum NAT_JOURNAL_ENTRIES.
Check if the specified nat journal entry count before accessing the
array, and throw an error if it is too large.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit a3988cb3f0a108dd67ac127a79a4c8479d23334e)
(cherry picked from commit 7125978aa7d6068812ef6da0ab38ce521ae7eba1)
(cherry picked from commit e488538cbf9fc63796c7047550b0598e1ef95c03)
(cherry picked from commit a2e520d7ced2ded854fb24f3718530e1e6d7dd5e)
---
grub-core/fs/f2fs.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index 1cad2615f3..09dc932420 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data)
return err;
}
-static grub_uint32_t
-get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid)
+static grub_err_t
+get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid,
+ grub_uint32_t *blkaddr)
{
grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats);
- grub_uint32_t blkaddr = 0;
grub_uint16_t i;
+ if (n >= NAT_JOURNAL_ENTRIES)
+ return grub_error (GRUB_ERR_BAD_FS,
+ "invalid number of nat journal entries");
+
for (i = 0; i < n; i++)
{
if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid)
{
- blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
+ *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
break;
}
}
- return blkaddr;
+ return GRUB_ERR_NONE;
}
static grub_uint32_t
@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
{
struct grub_f2fs_nat_block *nat_block;
grub_uint32_t seg_off, block_off, entry_off, block_addr;
- grub_uint32_t blkaddr;
+ grub_uint32_t blkaddr = 0;
grub_err_t err;
- blkaddr = get_blkaddr_from_nat_journal (data, nid);
+ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
+ if (err != GRUB_ERR_NONE)
+ return 0;
+
if (blkaddr)
return blkaddr;

View File

@ -0,0 +1,135 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 6 Apr 2022 18:49:09 +0530
Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap
A corrupt f2fs filesystem could have a block offset or a bitmap
offset that would cause us to read beyond the bounds of the nat
bitmap.
Introduce the nat_bitmap_size member in grub_f2fs_data which holds
the size of nat bitmap.
Set the size when loading the nat bitmap in nat_bitmap_ptr(), and
catch when an invalid offset would create a pointer past the end of
the allocated space.
Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid
reading past the end of the nat bitmap.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e)
(cherry picked from commit 92219e6d379b5b4d30b05361830b72ab1d95d281)
(cherry picked from commit c23d97e3b56594bf0f802d94062e14b221143115)
(cherry picked from commit e9536dd7fbdc632efbe3506386dbfb3bfc0465c8)
---
grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index 09dc932420..33e565b180 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */
#define MAX_VOLUME_NAME 512
+#define MAX_NAT_BITMAP_SIZE 3900
enum FILE_TYPE
{
@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint
grub_uint32_t checksum_offset;
grub_uint64_t elapsed_time;
grub_uint8_t alloc_type[MAX_ACTIVE_LOGS];
- grub_uint8_t sit_nat_version_bitmap[3900];
+ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE];
grub_uint32_t checksum;
} GRUB_PACKED;
@@ -302,6 +303,7 @@ struct grub_f2fs_data
struct grub_f2fs_nat_journal nat_j;
char *nat_bitmap;
+ grub_uint32_t nat_bitmap_size;
grub_disk_t disk;
struct grub_f2fs_node *inode;
@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
}
static void *
-nat_bitmap_ptr (struct grub_f2fs_data *data)
+nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size)
{
struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
grub_uint32_t offset;
+ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE;
if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
return ckpt->sit_nat_version_bitmap;
offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
+ if (offset >= MAX_NAT_BITMAP_SIZE)
+ return NULL;
+
+ *nat_bitmap_size = *nat_bitmap_size - offset;
return ckpt->sit_nat_version_bitmap + offset;
}
@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
}
static int
-grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
+grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len)
{
int mask;
+ grub_uint32_t shifted_nr = (nr >> 3);
- p += (nr >> 3);
+ if (shifted_nr >= len)
+ return -1;
+
+ p += shifted_nr;
mask = 1 << (7 - (nr & 0x07));
return mask & *p;
@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
grub_uint32_t seg_off, block_off, entry_off, block_addr;
grub_uint32_t blkaddr = 0;
grub_err_t err;
+ int result_bit;
err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
if (err != GRUB_ERR_NONE)
@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
((seg_off * data->blocks_per_seg) << 1) +
(block_off & (data->blocks_per_seg - 1));
- if (grub_f2fs_test_bit (block_off, data->nat_bitmap))
+ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap,
+ data->nat_bitmap_size);
+ if (result_bit > 0)
block_addr += data->blocks_per_seg;
+ else if (result_bit == -1)
+ {
+ grub_free (nat_block);
+ return 0;
+ }
err = grub_f2fs_block_read (data, block_addr, nat_block);
if (err)
@@ -832,7 +851,9 @@ grub_f2fs_mount (grub_disk_t disk)
if (err)
goto fail;
- data->nat_bitmap = nat_bitmap_ptr (data);
+ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size);
+ if (data->nat_bitmap == NULL)
+ goto fail;
err = get_nat_journal (data);
if (err)

View File

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 6 Apr 2022 18:17:43 +0530
Subject: [PATCH] fs/f2fs: Do not copy file names that are too long
A corrupt f2fs file system might specify a name length which is greater
than the maximum name length supported by the GRUB f2fs driver.
We will allocate enough memory to store the overly long name, but there
are only F2FS_NAME_LEN bytes in the source, so we would read past the end
of the source.
While checking directory entries, do not copy a file name with an invalid
length.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 9a891f638509e031d322c94e3cbcf38d36f3993a)
(cherry picked from commit 13f9160ae0d2806baed459884999356817096cd7)
(cherry picked from commit a48ba4d48b3c66431e6bbeb386078efc6602110c)
(cherry picked from commit f0440b61cebbab807638b90eb2ae86265d6cf49f)
---
grub-core/fs/f2fs.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index 33e565b180..07ea34196c 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -998,6 +998,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
ftype = ctx->dentry[i].file_type;
name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len);
+
+ if (name_len >= F2FS_NAME_LEN)
+ return 0;
+
filename = grub_malloc (name_len + 1);
if (!filename)
return 0;

View File

@ -0,0 +1,82 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Darren Kenny <darren.kenny@oracle.com>
Date: Tue, 29 Mar 2022 10:49:56 +0000
Subject: [PATCH] fs/btrfs: Fix several fuzz issues with invalid dir item
sizing
According to the btrfs code in Linux, the structure of a directory item
leaf should be of the form:
|struct btrfs_dir_item|name|data|
in GRUB the name len and data len are in the grub_btrfs_dir_item
structure's n and m fields respectively.
The combined size of the structure, name and data should be less than
the allocated memory, a difference to the Linux kernel's struct
btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for
where the name is stored, so we adjust for that too.
Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 6d3f06c0b6a8992b9b1bb0e62af93ac5ff2781f0)
[rharwood: we've an extra variable here]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit e3e21b9a81aea09dd43368cf097c1029a8380d82)
(cherry picked from commit ab14a39777edb60c99751d4fdf1cc254a4faebf5)
(cherry picked from commit 90a9fbd5969325993e069ee5a04a802b59657920)
---
grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 3faf9056c7..9da2952f70 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -1834,6 +1834,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
grub_uint64_t tree;
grub_uint8_t type;
char *new_path = NULL;
+ grub_size_t est_size = 0;
if (!data)
return grub_errno;
@@ -1900,6 +1901,18 @@ grub_btrfs_dir (grub_device_t device, const char *path,
break;
}
+ if (direl == NULL ||
+ grub_add (grub_le_to_cpu16 (direl->n),
+ grub_le_to_cpu16 (direl->m), &est_size) ||
+ grub_add (est_size, sizeof (*direl), &est_size) ||
+ grub_sub (est_size, sizeof (direl->name), &est_size) ||
+ est_size > allocated)
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ r = -grub_errno;
+ goto out;
+ }
+
for (cdirel = direl;
(grub_uint8_t *) cdirel - (grub_uint8_t *) direl
< (grub_ssize_t) elemsize;
@@ -1910,6 +1923,19 @@ grub_btrfs_dir (grub_device_t device, const char *path,
char c;
struct grub_btrfs_inode inode;
struct grub_dirhook_info info;
+
+ if (cdirel == NULL ||
+ grub_add (grub_le_to_cpu16 (cdirel->n),
+ grub_le_to_cpu16 (cdirel->m), &est_size) ||
+ grub_add (est_size, sizeof (*cdirel), &est_size) ||
+ grub_sub (est_size, sizeof (cdirel->name), &est_size) ||
+ est_size > allocated)
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ r = -grub_errno;
+ goto out;
+ }
+
err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id,
tree);
grub_memset (&info, 0, sizeof (info));

View File

@ -0,0 +1,144 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Kiper <daniel.kiper@oracle.com>
Date: Thu, 3 Dec 2020 16:01:46 +0100
Subject: [PATCH] efi: Return grub_efi_status_t from grub_efi_get_variable()
This is needed to properly detect and report UEFI Secure Boot status
to the x86 Linux kernel. The functionality will be added by subsequent
patches.
Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
Signed-off-by: Marco A Benatto <mbenatto@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 04ae030d0eea8668d4417702d88bf2cf04713d80)
(cherry picked from commit ed33b47f00bc0d728197357b8ae632028f91599b)
---
grub-core/commands/efi/efifwsetup.c | 8 ++++----
grub-core/kern/efi/efi.c | 16 +++++++++-------
grub-core/video/efi_gop.c | 2 +-
include/grub/efi/efi.h | 7 ++++---
4 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c
index 7a137a72a2..eaca032838 100644
--- a/grub-core/commands/efi/efifwsetup.c
+++ b/grub-core/commands/efi/efifwsetup.c
@@ -38,8 +38,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
grub_size_t oi_size;
grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
- old_os_indications = grub_efi_get_variable ("OsIndications", &global,
- &oi_size);
+ grub_efi_get_variable ("OsIndications", &global, &oi_size,
+ (void **) &old_os_indications);
if (old_os_indications != NULL && oi_size == sizeof (os_indications))
os_indications |= *old_os_indications;
@@ -63,8 +63,8 @@ efifwsetup_is_supported (void)
grub_size_t oi_size = 0;
grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
- os_indications_supported = grub_efi_get_variable ("OsIndicationsSupported",
- &global, &oi_size);
+ grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size,
+ (void **) &os_indications_supported);
if (!os_indications_supported)
return 0;
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 2863956458..335033975d 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -241,9 +241,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var);
}
-void *
+grub_efi_status_t
grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
- grub_size_t *datasize_out)
+ grub_size_t *datasize_out, void **data_out)
{
grub_efi_status_t status;
grub_efi_uintn_t datasize = 0;
@@ -252,13 +252,14 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
void *data;
grub_size_t len, len16;
+ *data_out = NULL;
*datasize_out = 0;
len = grub_strlen (var);
len16 = len * GRUB_MAX_UTF16_PER_UTF8;
var16 = grub_calloc (len16 + 1, sizeof (var16[0]));
if (!var16)
- return NULL;
+ return GRUB_EFI_OUT_OF_RESOURCES;
len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL);
var16[len16] = 0;
@@ -269,14 +270,14 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
if (status != GRUB_EFI_BUFFER_TOO_SMALL || !datasize)
{
grub_free (var16);
- return NULL;
+ return status;
}
data = grub_malloc (datasize);
if (!data)
{
grub_free (var16);
- return NULL;
+ return GRUB_EFI_OUT_OF_RESOURCES;
}
status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data);
@@ -284,12 +285,13 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
if (status == GRUB_EFI_SUCCESS)
{
+ *data_out = data;
*datasize_out = datasize;
- return data;
+ return status;
}
grub_free (data);
- return NULL;
+ return status;
}
#pragma GCC diagnostic ignored "-Wcast-align"
diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c
index 9fcc41ac03..ec217db70f 100644
--- a/grub-core/video/efi_gop.c
+++ b/grub-core/video/efi_gop.c
@@ -302,7 +302,7 @@ grub_video_gop_get_edid (struct grub_video_edid_info *edid_info)
char edidname[] = "agp-internal-edid";
grub_size_t datasize;
grub_uint8_t *data;
- data = grub_efi_get_variable (edidname, &efi_var_guid, &datasize);
+ grub_efi_get_variable (edidname, &efi_var_guid, &datasize, (void **) &data);
if (data && datasize > 16)
{
copy_size = datasize - 16;
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 4411ffa16b..90a85d7d9a 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -113,9 +113,10 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo
grub_efi_uintn_t descriptor_size,
grub_efi_uint32_t descriptor_version,
grub_efi_memory_descriptor_t *virtual_map);
-void *EXPORT_FUNC (grub_efi_get_variable) (const char *variable,
- const grub_efi_guid_t *guid,
- grub_size_t *datasize_out);
+grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable) (const char *variable,
+ const grub_efi_guid_t *guid,
+ grub_size_t *datasize_out,
+ void **data_out);
grub_err_t
EXPORT_FUNC (grub_efi_set_variable) (const char *var,
const grub_efi_guid_t *guid,

View File

@ -0,0 +1,77 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Kiper <daniel.kiper@oracle.com>
Date: Thu, 3 Dec 2020 16:01:47 +0100
Subject: [PATCH] efi: Add a function to read EFI variables with attributes
It will be used to properly detect and report UEFI Secure Boot status to
the x86 Linux kernel. The functionality will be added by subsequent patches.
Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
Signed-off-by: Marco A Benatto <mbenatto@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit ac5c9367548750e75ed1e7fc4354a3d20186d733)
(cherry picked from commit 51b11f8b3ab96c38efb1636d9c53b5a86503f1f2)
---
grub-core/kern/efi/efi.c | 16 +++++++++++++---
include/grub/efi/efi.h | 5 +++++
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 335033975d..fccea20a01 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -242,8 +242,11 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
}
grub_efi_status_t
-grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
- grub_size_t *datasize_out, void **data_out)
+grub_efi_get_variable_with_attributes (const char *var,
+ const grub_efi_guid_t *guid,
+ grub_size_t *datasize_out,
+ void **data_out,
+ grub_efi_uint32_t *attributes)
{
grub_efi_status_t status;
grub_efi_uintn_t datasize = 0;
@@ -280,7 +283,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
return GRUB_EFI_OUT_OF_RESOURCES;
}
- status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data);
+ status = efi_call_5 (r->get_variable, var16, guid, attributes, &datasize, data);
grub_free (var16);
if (status == GRUB_EFI_SUCCESS)
@@ -294,6 +297,13 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
return status;
}
+grub_efi_status_t
+grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
+ grub_size_t *datasize_out, void **data_out)
+{
+ return grub_efi_get_variable_with_attributes (var, guid, datasize_out, data_out, NULL);
+}
+
#pragma GCC diagnostic ignored "-Wcast-align"
/* Search the mods section from the PE32/PE32+ image. This code uses
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 90a85d7d9a..7af979b184 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -113,6 +113,11 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo
grub_efi_uintn_t descriptor_size,
grub_efi_uint32_t descriptor_version,
grub_efi_memory_descriptor_t *virtual_map);
+grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable_with_attributes) (const char *variable,
+ const grub_efi_guid_t *guid,
+ grub_size_t *datasize_out,
+ void **data_out,
+ grub_efi_uint32_t *attributes);
grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable) (const char *variable,
const grub_efi_guid_t *guid,
grub_size_t *datasize_out,

View File

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 11 May 2022 16:20:52 -0400
Subject: [PATCH] Define GRUB_EFI_SHIM_LOCK_GUID
Added in f76a27996c34900f2c369a8a0d6ac72ae2faa988 ("efi: Make shim_lock
GUID and protocol type public"), but that commit also manipulates the
lock protocol definition and some other guids we don't care about right
now.
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit e44d6f8e801fae4716dd2528d7194f759c52aa12)
---
include/grub/efi/api.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 37e7b16287..2a243fd290 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -349,6 +349,11 @@
{ 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \
}
+#define GRUB_EFI_SHIM_LOCK_GUID \
+ { 0x605dab50, 0xe046, 0x4300, \
+ { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \
+ }
+
struct grub_efi_sal_system_table
{
grub_uint32_t signature;

View File

@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 21 Mar 2022 16:06:10 -0400
Subject: [PATCH] misc: Make grub_min() and grub_max() more resilient.
grub_min(a,b) and grub_max(a,b) use a relatively naive implementation
which leads to several problems:
- they evaluate their parameters more than once
- the naive way to address this, to declare temporary variables in a
statement-expression, isn't resilient against nested uses, because
MIN(a,MIN(b,c)) results in the temporary variables being declared in
two nested scopes, which may result in a build warning depending on
your build options.
This patch changes our implementation to use a statement-expression
inside a helper macro, and creates the symbols for the temporary
variables with __COUNTER__ (A GNU C cpp extension) and token pasting to
create uniquely named internal variables.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 2d6800450fa731d7b3ef9893986806e88e819eb6)
(cherry picked from commit adaf6a5ae66fb8a23274e3030e9df2714d0fc396)
(cherry picked from commit 5282d19d1942d9c3470337a84aa4a92562ba1575)
---
grub-core/loader/multiboot_elfxx.c | 4 +---
include/grub/misc.h | 25 +++++++++++++++++++++++--
2 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c
index f2318e0d16..87f6e31aa6 100644
--- a/grub-core/loader/multiboot_elfxx.c
+++ b/grub-core/loader/multiboot_elfxx.c
@@ -35,9 +35,7 @@
#endif
#include <grub/i386/relocator.h>
-
-#define CONCAT(a,b) CONCAT_(a, b)
-#define CONCAT_(a,b) a ## b
+#include <grub/misc.h>
#pragma GCC diagnostic ignored "-Wcast-align"
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 6be6a88f65..7ef1a1a87e 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -35,6 +35,14 @@
#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
#define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
+#ifndef CONCAT_
+#define CONCAT_(a, b) a ## b
+#endif
+
+#ifndef CONCAT
+#define CONCAT(a, b) CONCAT_(a, b)
+#endif
+
#define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__)
void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n);
@@ -524,7 +532,20 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
#define grub_boot_time(...)
#endif
-#define grub_max(a, b) (((a) > (b)) ? (a) : (b))
-#define grub_min(a, b) (((a) < (b)) ? (a) : (b))
+#define _grub_min(a, b, _a, _b) \
+ ({ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ _a < _b ? _a : _b; })
+#define grub_min(a, b) _grub_min(a, b, \
+ CONCAT(_a_,__COUNTER__), \
+ CONCAT(_b_,__COUNTER__))
+
+#define _grub_max(a, b, _a, _b) \
+ ({ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ _a > _b ? _a : _b; })
+#define grub_max(a, b) _grub_max(a, b, \
+ CONCAT(_a_,__COUNTER__), \
+ CONCAT(_b_,__COUNTER__))
#endif /* ! GRUB_MISC_HEADER */

View File

@ -0,0 +1,95 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 21 Apr 2022 16:31:17 -0400
Subject: [PATCH] ReiserFS: switch to using grub_min()/grub_max()
This is a minor cleanup patch to remove the bespoke MIN() and MAX()
definitions from the reiserfs driver, and uses grub_min() / grub_max()
instead.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 5fc601574fce99b32fe4dfb55bd8f3ab0175fd6a)
(cherry picked from commit 31e581893c564582c729fd0c033d3ce021854be8)
(cherry picked from commit 2c46aae48eabcf91d7ed34a7bed2b59aa80c2c03)
---
grub-core/fs/reiserfs.c | 28 +++++++++-------------------
1 file changed, 9 insertions(+), 19 deletions(-)
diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c
index 39736f63c6..9556c15ff0 100644
--- a/grub-core/fs/reiserfs.c
+++ b/grub-core/fs/reiserfs.c
@@ -42,16 +42,6 @@
GRUB_MOD_LICENSE ("GPLv3+");
-#define MIN(a, b) \
- ({ typeof (a) _a = (a); \
- typeof (b) _b = (b); \
- _a < _b ? _a : _b; })
-
-#define MAX(a, b) \
- ({ typeof (a) _a = (a); \
- typeof (b) _b = (b); \
- _a > _b ? _a : _b; })
-
#define REISERFS_SUPER_BLOCK_OFFSET 0x10000
#define REISERFS_MAGIC_LEN 12
#define REISERFS_MAGIC_STRING "ReIsEr"
@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2);
initial_position = off;
current_position = 0;
- final_position = MIN (len + initial_position, node->size);
+ final_position = grub_min (len + initial_position, node->size);
grub_dprintf ("reiserfs",
"Reading from %lld to %lld (%lld instead of requested %ld)\n",
(unsigned long long) initial_position,
@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
if (initial_position < current_position + item_size)
{
- offset = MAX ((signed) (initial_position - current_position), 0);
- length = (MIN (item_size, final_position - current_position)
+ offset = grub_max ((signed) (initial_position - current_position), 0);
+ length = (grub_min (item_size, final_position - current_position)
- offset);
grub_dprintf ("reiserfs",
"Reading direct block %u from %u to %u...\n",
@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
if (current_position + block_size >= initial_position)
{
- offset = MAX ((signed) (initial_position - current_position),
- 0);
- length = (MIN (block_size, final_position - current_position)
+ offset = grub_max ((signed) (initial_position - current_position),
+ 0);
+ length = (grub_min (block_size, final_position - current_position)
- offset);
grub_dprintf ("reiserfs",
"Reading indirect block %u from %u to %u...\n",
@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
switch (found.type)
{
case GRUB_REISERFS_DIRECT:
- read_length = MIN (len, item_size - file->offset);
+ read_length = grub_min (len, item_size - file->offset);
grub_disk_read (found.data->disk,
(found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
grub_le_to_cpu16 (found.header.item_location) + file->offset,
@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
item_size, (char *) indirect_block_ptr);
if (grub_errno)
goto fail;
- len = MIN (len, file->size - file->offset);
+ len = grub_min (len, file->size - file->offset);
for (indirect_block = file->offset / block_size;
indirect_block < indirect_block_count && read_length < len;
indirect_block++)
{
- read = MIN (block_size, len - read_length);
+ read = grub_min (block_size, len - read_length);
grub_disk_read (found.data->disk,
(grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
file->offset % block_size, read,

View File

@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 24 Mar 2022 14:40:01 -0400
Subject: [PATCH] misc: make grub_boot_time() also call
grub_dprintf("boot",...)
Currently grub_boot_time() includes valuable debugging messages, but if
you build without BOOT_TIME_STATS enabled, they are silently and
confusingly compiled away.
This patch changes grub_boot_time() to also log when "boot" is enabled
in DEBUG, regardless of BOOT_TIME_STATS.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 4fd282de00df05ce289467861deb7a0e186cfbd7)
(cherry picked from commit cc7e60a9f3ad1fa74b9cd48a7e66b1976f9a554a)
(cherry picked from commit 9e78e5749d5c99a01c96c9c0d9ec3e98633a4cbd)
---
grub-core/kern/misc.c | 3 ++-
include/grub/misc.h | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index 859d71659a..b375e486a4 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -1336,7 +1336,8 @@ grub_real_boot_time (const char *file,
n->next = 0;
va_start (args, fmt);
- n->msg = grub_xvasprintf (fmt, args);
+ n->msg = grub_xvasprintf (fmt, args);
+ grub_dprintf ("boot", "%s\n", n->msg);
va_end (args);
*boot_time_last = n;
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 7ef1a1a87e..1b722c8185 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -529,7 +529,7 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4)));
#define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__)
#else
-#define grub_boot_time(...)
+#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__)
#endif
#define _grub_min(a, b, _a, _b) \

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 24 Feb 2022 16:32:51 -0500
Subject: [PATCH] modules: make .module_license read-only
Currently .module_license is set writable (that is, the section has the
SHF_WRITE flag set) in the module's ELF headers. This probably never
actually matters, but it can't possibly be correct.
This patch sets that data as "const", which causes that flag not to be
set.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 2eff3e2c9d9e6b75daa81b840c96f112ef7d5de6)
(cherry picked from commit 3c3c1858d1c056eee660d67888be80e7eae498ca)
(cherry picked from commit ebcce09e35ef6916a2d1ddbf0906e9f3f5c539ad)
---
include/grub/dl.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 6a3e251b45..9ec6caf3f9 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -121,7 +121,7 @@ grub_mod_fini (void)
#define ATTRIBUTE_USED __unused__
#endif
#define GRUB_MOD_LICENSE(license) \
- static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license;
+ static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license;
#define GRUB_MOD_DEP(name) \
static const char grub_module_depend_##name[] \
__attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 24 Feb 2022 16:40:11 -0500
Subject: [PATCH] modules: strip .llvm_addrsig sections and similar.
Currently grub modules built with clang or gcc have several sections
which we don't actually need or support.
We already have a list of section to skip in genmod.sh, and this patch
adds the following sections to that list (as well as a few newlines):
.note.gnu.property
.llvm*
Note that the glob there won't work without a new enough linker, but the
failure is just reversion to the status quo, so that's not a big problem.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit e85d1c4d795f8135ad0acfa36d64760d12d6fed1)
(cherry picked from commit d3024204b2e2c69ecb91392eeb87c1e6835c3743)
(cherry picked from commit f729241a34394b1019d83d75ffe6bfe0986ab274)
---
grub-core/genmod.sh.in | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in
index 1250589b3f..c2c5280d75 100644
--- a/grub-core/genmod.sh.in
+++ b/grub-core/genmod.sh.in
@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then
@TARGET_STRIP@ --strip-unneeded \
-K grub_mod_init -K grub_mod_fini \
-K _grub_mod_init -K _grub_mod_fini \
- -R .note.gnu.gold-version -R .note.GNU-stack \
+ -R .note.GNU-stack \
+ -R .note.gnu.gold-version \
+ -R .note.gnu.property \
-R .gnu.build.attributes \
+ -R '.llvm*' \
-R .rel.gnu.build.attributes \
-R .rela.gnu.build.attributes \
-R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \

View File

@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 21 Mar 2022 16:56:10 -0400
Subject: [PATCH] modules: Don't allocate space for non-allocable sections.
Currently when loading grub modules, we allocate space for all sections,
including those without SHF_ALLOC set. We then copy the sections that
/do/ have SHF_ALLOC set into the allocated memory, leaving some of our
allocation untouched forever. Additionally, on platforms with GOT
fixups and trampolines, we currently compute alignment round-ups for the
sections and sections with sh_size = 0.
This patch removes the extra space from the allocation computation, and
makes the allocation computation loop skip empty sections as the loading
loop does.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 03215e342f552396ab08125ea769b1e166417ec1)
(cherry picked from commit 91518751b9bcba078e3f4385f4b2f6c39cab49cd)
(cherry picked from commit ee945970425488bd5b72d837706764a6a0fde46c)
---
grub-core/kern/dl.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 520126beab..ba1b33c20b 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -290,6 +290,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
i < e->e_shnum;
i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
{
+ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
+ continue;
+
tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
if (talign < s->sh_addralign)
talign = s->sh_addralign;

View File

@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Fri, 25 Mar 2022 15:40:12 -0400
Subject: [PATCH] pe: add the DOS header struct and fix some bad naming.
In order to properly validate a loaded kernel's support for being loaded
without a writable stack or executable, we need to be able to properly
parse arbitrary PE headers.
Currently, pe32.h is written in such a way that the MS-DOS header that
tells us where to find the PE header in the binary can't be accessed.
Further, for some reason it calls the DOS MZ magic "GRUB_PE32_MAGIC".
This patch adds the structure for the DOS header, renames the DOS magic
define, and adds defines for the actual PE magic.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 955f47aa8300387eecf18b0866d21dde7720593d)
(cherry picked from commit 662744c2e986cb770fe49e71e019aaf33a66272d)
(cherry picked from commit 4b541b7e76b77d131ff534e537a622551e774a2b)
---
grub-core/loader/arm64/linux.c | 2 +-
include/grub/efi/pe32.h | 28 ++++++++++++++++++++++++++--
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
index e1923cf725..24ab0f0074 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -57,7 +57,7 @@ grub_armxx_efi_linux_check_image (struct linux_armxx_kernel_header * lh)
if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE)
return grub_error(GRUB_ERR_BAD_OS, "invalid magic number");
- if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC)
+ if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled"));
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index c03cc599f6..2241f6317b 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -45,7 +45,30 @@
#define GRUB_PE32_MSDOS_STUB_SIZE 0x80
-#define GRUB_PE32_MAGIC 0x5a4d
+#define GRUB_DOS_MAGIC 0x5a4d
+
+struct grub_dos_header
+{
+ grub_uint16_t magic;
+ grub_uint16_t cblp;
+ grub_uint16_t cp;
+ grub_uint16_t crlc;
+ grub_uint16_t cparhdr;
+ grub_uint16_t minalloc;
+ grub_uint16_t maxalloc;
+ grub_uint16_t ss;
+ grub_uint16_t sp;
+ grub_uint16_t csum;
+ grub_uint16_t ip;
+ grub_uint16_t cs;
+ grub_uint16_t lfarlc;
+ grub_uint16_t ovno;
+ grub_uint16_t res0[4];
+ grub_uint16_t oemid;
+ grub_uint16_t oeminfo;
+ grub_uint16_t res1[10];
+ grub_uint32_t lfanew;
+};
/* According to the spec, the minimal alignment is 512 bytes...
But some examples (such as EFI drivers in the Intel
@@ -271,7 +294,8 @@ struct grub_pe32_section_table
-#define GRUB_PE32_SIGNATURE_SIZE 4
+#define GRUB_PE32_SIGNATURE_SIZE 4
+#define GRUB_PE32_SIGNATURE "PE\0\0"
struct grub_pe32_header
{

View File

@ -0,0 +1,88 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Wed, 9 Feb 2022 16:08:20 -0500
Subject: [PATCH] EFI: allocate kernel in EFI_RUNTIME_SERVICES_CODE instead of
EFI_LOADER_DATA.
On some of the firmwares with more security mitigations, EFI_LOADER_DATA
doesn't get you executable memory, and we take a fault and reboot when
we enter kernel.
This patch correctly allocates the kernel code as EFI_RUNTIME_SERVICES_CODE
rather than EFI_LOADER_DATA.
Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: use kernel_size]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 8b31058a12d3e85f0f0180ac90b98d6465fccbb7)
(cherry picked from commit 460df66aab9b3a57fc0d14a21a595cd467c4b13e)
(cherry picked from commit 2380ad45c78ed12710f1186eda9f2ba38c20f6ba)
---
grub-core/loader/i386/efi/linux.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 8337191921..3d4069e4c6 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -86,7 +86,9 @@ kernel_free(void *addr, grub_efi_uintn_t size)
}
static void *
-kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
+kernel_alloc(grub_efi_uintn_t size,
+ grub_efi_memory_type_t memtype,
+ const char * const errmsg)
{
void *addr = 0;
unsigned int i;
@@ -112,7 +114,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
prev_max = max;
addr = grub_efi_allocate_pages_real (max, pages,
max_addresses[i].alloc_type,
- GRUB_EFI_LOADER_DATA);
+ memtype);
if (addr)
grub_dprintf ("linux", "Allocated at %p\n", addr);
}
@@ -243,7 +245,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
}
}
- initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
+ initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA,
+ N_("can't allocate initrd"));
if (initrd_mem == NULL)
goto fail;
grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
@@ -411,7 +414,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
#endif
- params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
+ params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA,
+ "cannot allocate kernel parameters");
if (!params)
goto fail;
grub_dprintf ("linux", "params = %p\n", params);
@@ -432,7 +436,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("linux", "new lh is at %p\n", lh);
grub_dprintf ("linux", "setting up cmdline\n");
- cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
+ cmdline = kernel_alloc (lh->cmdline_size + 1,
+ GRUB_EFI_RUNTIME_SERVICES_DATA,
+ N_("can't allocate cmdline"));
if (!cmdline)
goto fail;
grub_dprintf ("linux", "cmdline = %p\n", cmdline);
@@ -478,7 +484,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
kernel_size = lh->init_size;
- kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel"));
+ kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE,
+ N_("can't allocate kernel"));
restore_addresses();
if (!kernel_mem)
goto fail;

View File

@ -0,0 +1,361 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 21 Mar 2022 17:45:40 -0400
Subject: [PATCH] modules: load module sections at page-aligned addresses
Currently we load module sections at whatever alignment gcc+ld happened
to dump into the ELF section header, which is often pretty useless. For
example, by default time.mod has these sections on a current x86_64
build:
$ eu-readelf -a grub-core/time.mod |& grep ^Section -A13
Section Headers:
[Nr] Name Type Addr Off Size ES Flags Lk Inf Al
[ 0] NULL 0 00000000 00000000 0 0 0 0
[ 1] .text PROGBITS 0 00000040 0000015e 0 AX 0 0 1
[ 2] .rela.text RELA 0 00000458 000001e0 24 I 8 1 8
[ 3] .rodata.str1.1 PROGBITS 0 0000019e 000000a1 1 AMS 0 0 1
[ 4] .module_license PROGBITS 0 00000240 0000000f 0 A 0 0 8
[ 5] .data PROGBITS 0 0000024f 00000000 0 WA 0 0 1
[ 6] .bss NOBITS 0 00000250 00000008 0 WA 0 0 8
[ 7] .modname PROGBITS 0 00000250 00000005 0 0 0 1
[ 8] .symtab SYMTAB 0 00000258 00000150 24 9 6 8
[ 9] .strtab STRTAB 0 000003a8 000000ab 0 0 0 1
[10] .shstrtab STRTAB 0 00000638 00000059 0 0 0 1
With NX protections being page based, loading sections with either a 1
or 8 *byte* alignment does absolutely nothing to help us out.
This patch switches most EFI platforms to load module sections at 4kB
page-aligned addresses. To do so, it adds an new per-arch function,
grub_arch_dl_min_alignment(), which returns the alignment needed for
dynamically loaded sections (in bytes). Currently it sets it to 4096
when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and
1-byte alignment on everything else.
It then changes the allocation size computation and the loader code in
grub_dl_load_segments() to align the locations and sizes up to these
boundaries, and fills any added padding with zeros.
All of this happens before relocations are applied, so the relocations
factor that in with no change.
As an aside, initially Daniel Kiper and I thought that it might be a
better idea to split the modules up into top-level sections as
.text.modules, .rodata.modules, .data.modules, etc., so that their page
permissions would get set by the loader that's loading grub itself.
This turns out to have two significant downsides: 1) either in mkimage
or in grub_dl_relocate_symbols(), you wind up having to dynamically
process the relocations to accommodate the moved module sections, and 2)
you then need to change the permissions on the modules and change them
back while relocating them in grub_dl_relocate_symbols(), which means
that any loader that /does/ honor the section flags but does /not/
generally support NX with the memory attributes API will cause grub to
fail.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 31d52500b281619d92b03b2c2d30fe15aedaf326)
(cherry picked from commit 04f1df6b665493e38de66018aebe377fdac4ceec)
[rharwood: not risc-v yet]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 62c48da3ef51fc4f98746fbc35791ec2beab0426)
---
grub-core/kern/arm/dl.c | 13 +++++++++++++
grub-core/kern/arm64/dl.c | 13 +++++++++++++
grub-core/kern/dl.c | 29 +++++++++++++++++++++--------
grub-core/kern/emu/full.c | 13 +++++++++++++
grub-core/kern/i386/dl.c | 13 +++++++++++++
grub-core/kern/ia64/dl.c | 9 +++++++++
grub-core/kern/mips/dl.c | 8 ++++++++
grub-core/kern/powerpc/dl.c | 9 +++++++++
grub-core/kern/sparc64/dl.c | 9 +++++++++
grub-core/kern/x86_64/dl.c | 13 +++++++++++++
include/grub/dl.h | 2 ++
docs/grub-dev.texi | 6 +++---
12 files changed, 126 insertions(+), 11 deletions(-)
diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c
index eab9d17ff2..9260737936 100644
--- a/grub-core/kern/arm/dl.c
+++ b/grub-core/kern/arm/dl.c
@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr)
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c
index fb03373190..826f8e721e 100644
--- a/grub-core/kern/arm64/dl.c
+++ b/grub-core/kern/arm64/dl.c
@@ -191,3 +191,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index ba1b33c20b..5c2153acf9 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -278,7 +278,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{
unsigned i;
const Elf_Shdr *s;
- grub_size_t tsize = 0, talign = 1;
+ grub_size_t tsize = 0, talign = 1, arch_addralign = 1;
#if !defined (__i386__) && !defined (__x86_64__)
grub_size_t tramp;
grub_size_t got;
@@ -286,16 +286,24 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
#endif
char *ptr;
+ arch_addralign = grub_arch_dl_min_alignment ();
+
for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
{
+ grub_size_t sh_addralign;
+ grub_size_t sh_size;
+
if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
continue;
- tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
- if (talign < s->sh_addralign)
- talign = s->sh_addralign;
+ sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
+ sh_size = ALIGN_UP(s->sh_size, sh_addralign);
+
+ tsize = ALIGN_UP (tsize, sh_addralign) + sh_size;
+ if (talign < sh_addralign)
+ talign = sh_addralign;
}
#if !defined (__i386__) && !defined (__x86_64__)
@@ -324,6 +332,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
i < e->e_shnum;
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
{
+ grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
+ grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign);
+
if (s->sh_flags & SHF_ALLOC)
{
grub_dl_segment_t seg;
@@ -336,17 +347,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{
void *addr;
- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
+ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign);
addr = ptr;
- ptr += s->sh_size;
+ ptr += sh_size;
switch (s->sh_type)
{
case SHT_PROGBITS:
grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
+ grub_memset ((char *)addr + s->sh_size, 0,
+ sh_size - s->sh_size);
break;
case SHT_NOBITS:
- grub_memset (addr, 0, s->sh_size);
+ grub_memset (addr, 0, sh_size);
break;
}
@@ -355,7 +368,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
else
seg->addr = 0;
- seg->size = s->sh_size;
+ seg->size = sh_size;
seg->section = i;
seg->next = mod->segment;
mod->segment = seg;
diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c
index e8d63b1f5f..1de1c28eb0 100644
--- a/grub-core/kern/emu/full.c
+++ b/grub-core/kern/emu/full.c
@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void)
}
#endif
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c
index 1346da5cc9..d6b4681fc9 100644
--- a/grub-core/kern/i386/dl.c
+++ b/grub-core/kern/i386/dl.c
@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c
index ebcf316298..3bb753a89b 100644
--- a/grub-core/kern/ia64/dl.c
+++ b/grub-core/kern/ia64/dl.c
@@ -143,3 +143,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
}
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ return 1;
+}
diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c
index 5d7d299c74..6d83bd71e9 100644
--- a/grub-core/kern/mips/dl.c
+++ b/grub-core/kern/mips/dl.c
@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void)
grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0);
}
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ return 1;
+}
diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c
index 3a7fa3ed3d..577e27d871 100644
--- a/grub-core/kern/powerpc/dl.c
+++ b/grub-core/kern/powerpc/dl.c
@@ -165,3 +165,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ return 1;
+}
diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c
index 739be47174..c741c1782e 100644
--- a/grub-core/kern/sparc64/dl.c
+++ b/grub-core/kern/sparc64/dl.c
@@ -184,3 +184,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ return 1;
+}
diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c
index 3a73e6e6ce..6c20b7c367 100644
--- a/grub-core/kern/x86_64/dl.c
+++ b/grub-core/kern/x86_64/dl.c
@@ -114,3 +114,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 9ec6caf3f9..dd4c3e7ff4 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -280,6 +280,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr);
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
Elf_Shdr *s, grub_dl_segment_t seg);
+grub_size_t
+grub_arch_dl_min_alignment (void);
#endif
#if defined (_mips)
diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index 03d53498c5..dbfb94bc06 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -638,9 +638,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files
(e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c).
At this stage you will also need to add dummy dl.c and cache.S with functions
grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t
-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and
-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They
-won't be used for now.
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t
+grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void
+*address, grub_size_t len) (cache.S). They won't be used for now.
You will need to create directory include/$cpu/$platform and a file
include/$cpu/types.h. The later folowing this template:

View File

@ -0,0 +1,321 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Tue, 22 Mar 2022 10:56:21 -0400
Subject: [PATCH] nx: add memory attribute get/set API
For NX, we need to set the page access permission attributes for write
and execute permissions.
This patch adds two new primitives, grub_set_mem_attrs() and
grub_clear_mem_attrs(), and associated constant definitions, to be used
for that purpose.
For most platforms, it adds a dummy implementation that returns
GRUB_ERR_NONE. On EFI platforms, it adds a common helper function,
grub_efi_status_to_err(), which translates EFI error codes to grub error
codes, adds headers for the EFI Memory Attribute Protocol (still pending
standardization), and an implementation of the grub nx primitives using
it.
Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: add pjones's none/nyi fixup]
(cherry picked from commit 35de78a8d32b9fad5291ec96fd3cbb9cf2f4a80b)
(cherry picked from commit 46cb4f9557bdba1db0a17d012df705d94d81a9f6)
[rharwood: context fuzz, guids]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 7d8eea48e82c4ef572cc0f9d3252487c1d7e5729)
---
grub-core/kern/efi/efi.c | 36 +++++++++++++
grub-core/kern/efi/mm.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++
include/grub/efi/api.h | 25 +++++++++
include/grub/efi/efi.h | 2 +
include/grub/mm.h | 32 ++++++++++++
5 files changed, 226 insertions(+)
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index fccea20a01..09468dc5d5 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -1093,3 +1093,39 @@ grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1,
return 0;
}
+
+grub_err_t
+grub_efi_status_to_err (grub_efi_status_t status)
+{
+ grub_err_t err;
+ switch (status)
+ {
+ case GRUB_EFI_SUCCESS:
+ err = GRUB_ERR_NONE;
+ break;
+ case GRUB_EFI_INVALID_PARAMETER:
+ default:
+ err = GRUB_ERR_BAD_ARGUMENT;
+ break;
+ case GRUB_EFI_OUT_OF_RESOURCES:
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ break;
+ case GRUB_EFI_DEVICE_ERROR:
+ err = GRUB_ERR_IO;
+ break;
+ case GRUB_EFI_WRITE_PROTECTED:
+ err = GRUB_ERR_WRITE_ERROR;
+ break;
+ case GRUB_EFI_SECURITY_VIOLATION:
+ err = GRUB_ERR_ACCESS_DENIED;
+ break;
+ case GRUB_EFI_NOT_FOUND:
+ err = GRUB_ERR_FILE_NOT_FOUND;
+ break;
+ case GRUB_EFI_ABORTED:
+ err = GRUB_ERR_WAIT;
+ break;
+ }
+
+ return err;
+}
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 9e76f23e5f..2cf4a4883a 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -730,3 +730,134 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
return GRUB_ERR_NONE;
}
#endif
+
+static inline grub_uint64_t
+grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs)
+{
+ grub_uint64_t ret = GRUB_EFI_MEMORY_RP |
+ GRUB_EFI_MEMORY_RO |
+ GRUB_EFI_MEMORY_XP;
+
+ if (attrs & GRUB_MEM_ATTR_R)
+ ret &= ~GRUB_EFI_MEMORY_RP;
+
+ if (attrs & GRUB_MEM_ATTR_W)
+ ret &= ~GRUB_EFI_MEMORY_RO;
+
+ if (attrs & GRUB_MEM_ATTR_X)
+ ret &= ~GRUB_EFI_MEMORY_XP;
+
+ return ret;
+}
+
+static inline grub_uint64_t
+uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs)
+{
+ grub_uint64_t ret = GRUB_MEM_ATTR_R |
+ GRUB_MEM_ATTR_W |
+ GRUB_MEM_ATTR_X;
+
+ if (attrs & GRUB_EFI_MEMORY_RP)
+ ret &= ~GRUB_MEM_ATTR_R;
+
+ if (attrs & GRUB_EFI_MEMORY_RO)
+ ret &= ~GRUB_MEM_ATTR_W;
+
+ if (attrs & GRUB_EFI_MEMORY_XP)
+ ret &= ~GRUB_MEM_ATTR_X;
+
+ return ret;
+}
+
+grub_err_t
+grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs)
+{
+ grub_efi_memory_attribute_protocol_t *proto;
+ grub_efi_physical_address_t physaddr = addr;
+ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+ grub_efi_status_t efi_status;
+
+ proto = grub_efi_locate_protocol (&protocol_guid, 0);
+ if (!proto)
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+
+ if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL)
+ {
+ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n",
+ __func__, physaddr, physaddr+size-1, attrs);
+ return 0;
+ }
+
+ efi_status = efi_call_4(proto->get_memory_attributes,
+ proto, physaddr, size, attrs);
+ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs);
+
+ return grub_efi_status_to_err (efi_status);
+}
+
+grub_err_t
+grub_update_mem_attrs (grub_addr_t addr, grub_size_t size,
+ grub_uint64_t set_attrs, grub_uint64_t clear_attrs)
+{
+ grub_efi_memory_attribute_protocol_t *proto;
+ grub_efi_physical_address_t physaddr = addr;
+ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS;
+ grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs;
+ grub_err_t err;
+
+ proto = grub_efi_locate_protocol (&protocol_guid, 0);
+ if (!proto)
+ return GRUB_ERR_NONE;
+
+ err = grub_get_mem_attrs (addr, size, &before);
+ if (err)
+ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n",
+ addr, size, &before, err);
+
+ if (physaddr & 0xfff || size & 0xfff || size == 0)
+ {
+ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n",
+ __func__, physaddr, physaddr + size - 1,
+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
+ return 0;
+ }
+
+ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs);
+ grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs);
+ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs);
+ grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs);
+ if (uefi_set_attrs)
+ efi_status = efi_call_4(proto->set_memory_attributes,
+ proto, physaddr, size, uefi_set_attrs);
+ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs)
+ efi_status = efi_call_4(proto->clear_memory_attributes,
+ proto, physaddr, size, uefi_clear_attrs);
+
+ err = grub_get_mem_attrs (addr, size, &after);
+ if (err)
+ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n",
+ addr, size, &after, err);
+
+ grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n",
+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+ addr, addr + size - 1,
+ (before & GRUB_MEM_ATTR_R) ? 'r' : '-',
+ (before & GRUB_MEM_ATTR_W) ? 'w' : '-',
+ (before & GRUB_MEM_ATTR_X) ? 'x' : '-',
+ (after & GRUB_MEM_ATTR_R) ? 'r' : '-',
+ (after & GRUB_MEM_ATTR_W) ? 'w' : '-',
+ (after & GRUB_MEM_ATTR_X) ? 'x' : '-');
+
+ return grub_efi_status_to_err (efi_status);
+}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 2a243fd290..510a4030f5 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -354,6 +354,11 @@
{ 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \
}
+#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \
+ { 0xf4560cf6, 0x40ec, 0x4b4a, \
+ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \
+ }
+
struct grub_efi_sal_system_table
{
grub_uint32_t signature;
@@ -2091,6 +2096,26 @@ struct grub_efi_rng_protocol
};
typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t;
+struct grub_efi_memory_attribute_protocol
+{
+ grub_efi_status_t (*get_memory_attributes) (
+ struct grub_efi_memory_attribute_protocol *this,
+ grub_efi_physical_address_t base_address,
+ grub_efi_uint64_t length,
+ grub_efi_uint64_t *attributes);
+ grub_efi_status_t (*set_memory_attributes) (
+ struct grub_efi_memory_attribute_protocol *this,
+ grub_efi_physical_address_t base_address,
+ grub_efi_uint64_t length,
+ grub_efi_uint64_t attributes);
+ grub_efi_status_t (*clear_memory_attributes) (
+ struct grub_efi_memory_attribute_protocol *this,
+ grub_efi_physical_address_t base_address,
+ grub_efi_uint64_t length,
+ grub_efi_uint64_t attributes);
+};
+typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t;
+
#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
|| defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__)
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 7af979b184..a635bcb0a9 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -159,4 +159,6 @@ struct grub_net_card;
grub_efi_handle_t
grub_efinet_get_device_handle (struct grub_net_card *card);
+grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status);
+
#endif /* ! GRUB_EFI_EFI_HEADER */
diff --git a/include/grub/mm.h b/include/grub/mm.h
index 9c38dd3ca5..d81623d226 100644
--- a/include/grub/mm.h
+++ b/include/grub/mm.h
@@ -22,6 +22,7 @@
#include <grub/types.h>
#include <grub/symbol.h>
+#include <grub/err.h>
#include <config.h>
#ifndef NULL
@@ -38,6 +39,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size);
void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size);
#endif
+#define GRUB_MEM_ATTR_R 0x0000000000000004LLU
+#define GRUB_MEM_ATTR_W 0x0000000000000002LLU
+#define GRUB_MEM_ATTR_X 0x0000000000000001LLU
+
+#ifdef GRUB_MACHINE_EFI
+grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr,
+ grub_size_t size,
+ grub_uint64_t *attrs);
+grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr,
+ grub_size_t size,
+ grub_uint64_t set_attrs,
+ grub_uint64_t clear_attrs);
+#else /* !GRUB_MACHINE_EFI */
+static inline grub_err_t
+grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
+ grub_size_t size __attribute__((__unused__)),
+ grub_uint64_t *attrs __attribute__((__unused__)))
+{
+ return GRUB_ERR_NONE;
+}
+
+static inline grub_err_t
+grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
+ grub_size_t size __attribute__((__unused__)),
+ grub_uint64_t set_attrs __attribute__((__unused__)),
+ grub_uint64_t clear_attrs __attribute__((__unused__)))
+{
+ return GRUB_ERR_NONE;
+}
+#endif /* GRUB_MACHINE_EFI */
+
void grub_mm_check_real (const char *file, int line);
#define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__);

View File

@ -0,0 +1,266 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 21 Mar 2022 17:46:35 -0400
Subject: [PATCH] nx: set page permissions for loaded modules.
For NX, we need to set write and executable permissions on the sections
of grub modules when we load them.
On sections with SHF_ALLOC set, which is typically everything except
.modname and the symbol and string tables, this patch clears the Read
Only flag on sections that have the ELF flag SHF_WRITE set, and clears
the No eXecute flag on sections with SHF_EXECINSTR set. In all other
cases it sets both flags.
Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: arm tgptr -> tgaddr]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry-picked from commit ca74904ede0406b594cbedc52ce8e38a6633d2ae)
(cherry picked from commit 2e2e72026f41cf7cffeb46a6a47f3c67d0b3be45)
(cherry picked from commit 736e5ccd9175d31ebea848f3b627f3e99988bb0a)
---
grub-core/kern/dl.c | 120 +++++++++++++++++++++++++++++++++++++++-------------
include/grub/dl.h | 44 +++++++++++++++++++
2 files changed, 134 insertions(+), 30 deletions(-)
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 5c2153acf9..68d3177f5e 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -286,6 +286,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
#endif
char *ptr;
+ grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name);
+
arch_addralign = grub_arch_dl_min_alignment ();
for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
@@ -385,6 +387,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
ptr += got;
#endif
+ grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name);
return GRUB_ERR_NONE;
}
@@ -518,23 +521,6 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name)
return s;
return NULL;
}
-static long
-grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
-{
- Elf_Shdr *s;
- const char *str;
- unsigned i;
-
- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
- str = (char *) e + s->sh_offset;
-
- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
- i < e->e_shnum;
- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
- if (grub_strcmp (str + s->sh_name, name) == 0)
- return (long)i;
- return -1;
-}
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
GNU module policy. Note that this license check is informative only.
@@ -661,6 +647,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
Elf_Shdr *s;
unsigned i;
+ grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name);
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
@@ -669,24 +656,95 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
grub_dl_segment_t seg;
grub_err_t err;
- /* Find the target segment. */
- for (seg = mod->segment; seg; seg = seg->next)
- if (seg->section == s->sh_info)
- break;
+ seg = grub_dl_find_segment(mod, s->sh_info);
+ if (!seg)
+ continue;
- if (seg)
- {
- if (!mod->symtab)
- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
+ if (!mod->symtab)
+ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
- if (err)
- return err;
- }
+ err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
+ if (err)
+ return err;
}
+ grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name);
return GRUB_ERR_NONE;
}
+
+static grub_err_t
+grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
+{
+ unsigned i;
+ const Elf_Shdr *s;
+ const Elf_Ehdr *e = ehdr;
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+ grub_size_t arch_addralign = grub_arch_dl_min_alignment ();
+ grub_addr_t tgaddr;
+ grub_uint64_t tgsz;
+#endif
+
+ grub_dprintf ("modules", "updating memory attributes for \"%s\"\n",
+ mod->name);
+ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
+ i < e->e_shnum;
+ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
+ {
+ grub_dl_segment_t seg;
+ grub_uint64_t set_attrs = GRUB_MEM_ATTR_R;
+ grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X;
+
+ seg = grub_dl_find_segment(mod, i);
+ if (!seg)
+ continue;
+
+ if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC))
+ continue;
+
+ if (s->sh_flags & SHF_WRITE)
+ {
+ set_attrs |= GRUB_MEM_ATTR_W;
+ clear_attrs &= ~GRUB_MEM_ATTR_W;
+ }
+
+ if (s->sh_flags & SHF_EXECINSTR)
+ {
+ set_attrs |= GRUB_MEM_ATTR_X;
+ clear_attrs &= ~GRUB_MEM_ATTR_X;
+ }
+
+ grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n",
+ grub_dl_get_section_name(e, s),
+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
+ grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs);
+ }
+
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+ tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got);
+ tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr;
+
+ if (tgsz)
+ {
+ tgsz = ALIGN_UP(tgsz, arch_addralign);
+
+ grub_dprintf ("modules", "updating attributes for GOT and trampolines\n",
+ mod->name);
+ grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X,
+ GRUB_MEM_ATTR_W);
+ }
+#endif
+
+ grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n",
+ mod->name);
+
+ return GRUB_ERR_NONE;
+}
+
static void
grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e)
{
@@ -752,6 +810,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
mod->ref_count = 1;
grub_dprintf ("modules", "relocating to %p\n", mod);
+
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
GNU module policy. Note that this license check is informative only.
Modules have to be licensed under GPLv3 or GPLv3+ (optionally
@@ -765,7 +824,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
|| grub_dl_resolve_dependencies (mod, e)
|| grub_dl_load_segments (mod, e)
|| grub_dl_resolve_symbols (mod, e)
- || grub_dl_relocate_symbols (mod, e))
+ || grub_dl_relocate_symbols (mod, e)
+ || grub_dl_set_mem_attrs (mod, e))
{
mod->fini = 0;
grub_dl_unload (mod);
diff --git a/include/grub/dl.h b/include/grub/dl.h
index dd4c3e7ff4..6f46b7e86f 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -27,6 +27,7 @@
#include <grub/elf.h>
#include <grub/list.h>
#include <grub/misc.h>
+#include <grub/mm.h>
#endif
/*
@@ -268,6 +269,49 @@ grub_dl_is_persistent (grub_dl_t mod)
return mod->persistent;
}
+static inline const char *
+grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s)
+{
+ Elf_Shdr *str_s;
+ const char *str;
+
+ str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
+ str = (char *) e + str_s->sh_offset;
+
+ return str + s->sh_name;
+}
+
+static inline long
+grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
+{
+ Elf_Shdr *s;
+ const char *str;
+ unsigned i;
+
+ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
+ str = (char *) e + s->sh_offset;
+
+ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+ i < e->e_shnum;
+ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+ if (grub_strcmp (str + s->sh_name, name) == 0)
+ return (long)i;
+ return -1;
+}
+
+/* Return the segment for a section of index N */
+static inline grub_dl_segment_t
+grub_dl_find_segment (grub_dl_t mod, unsigned n)
+{
+ grub_dl_segment_t seg;
+
+ for (seg = mod->segment; seg; seg = seg->next)
+ if (seg->section == n)
+ return seg;
+
+ return NULL;
+}
+
#endif
void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);

View File

@ -0,0 +1,572 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Tue, 22 Mar 2022 10:57:07 -0400
Subject: [PATCH] nx: set attrs in our kernel loaders
For NX, our kernel loaders need to set write and execute page
permissions on allocated pages and the stack.
This patch adds those calls.
Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: fix aarch64 callsites]
(cherry-picked from commit a9f79a997f01a83b36cdfa89ef2e72ac2a17c06c)
[rharwood: double verification]
(cherry picked from commit daba852bd3e4d7b7784b19cf7acf107dc3c0dce4)
[rharwood: stack_attrs initialization, no risc-v, arm renames, arm age]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 3a402a2e54b3468b20eae182d98913600a6b68dd)
---
grub-core/kern/efi/mm.c | 78 ++++++++++++++++++
grub-core/loader/arm64/linux.c | 16 +++-
grub-core/loader/arm64/xen_boot.c | 4 +-
grub-core/loader/efi/chainloader.c | 11 +++
grub-core/loader/efi/linux.c | 162 ++++++++++++++++++++++++++++++++++++-
grub-core/loader/i386/efi/linux.c | 26 +++++-
grub-core/loader/i386/linux.c | 5 ++
include/grub/efi/efi.h | 6 +-
include/grub/efi/linux.h | 17 +++-
include/grub/efi/pe32.h | 2 +
10 files changed, 312 insertions(+), 15 deletions(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 2cf4a4883a..8a896144df 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -602,6 +602,82 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
}
#endif
+grub_addr_t grub_stack_addr = (grub_addr_t)-1ll;
+grub_size_t grub_stack_size = 0;
+
+static void
+grub_nx_init (void)
+{
+ grub_uint64_t attrs, stack_attrs;
+ grub_err_t err;
+ grub_addr_t stack_current, stack_end;
+ const grub_uint64_t page_size = 4096;
+ const grub_uint64_t page_mask = ~(page_size - 1);
+
+ /*
+ * These are to confirm that the flags are working as expected when
+ * debugging.
+ */
+ attrs = 0;
+ stack_current = (grub_addr_t)grub_nx_init & page_mask;
+ err = grub_get_mem_attrs (stack_current, page_size, &attrs);
+ if (err)
+ {
+ grub_dprintf ("nx",
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
+ stack_current, err);
+ grub_error_pop ();
+ }
+ else
+ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n",
+ grub_dl_load_core,
+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
+
+ stack_current = (grub_addr_t)&stack_current & page_mask;
+ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs);
+ if (err)
+ {
+ grub_dprintf ("nx",
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
+ stack_current, err);
+ grub_error_pop ();
+ }
+ else
+ {
+ attrs = stack_attrs;
+ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n",
+ &attrs,
+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
+ }
+
+ for (stack_end = stack_current + page_size ;
+ !(attrs & GRUB_MEM_ATTR_R);
+ stack_end += page_size)
+ {
+ err = grub_get_mem_attrs (stack_current, page_size, &attrs);
+ if (err)
+ {
+ grub_dprintf ("nx",
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
+ stack_current, err);
+ grub_error_pop ();
+ break;
+ }
+ }
+ if (stack_end > stack_current)
+ {
+ grub_stack_addr = stack_current;
+ grub_stack_size = stack_end - stack_current;
+ grub_dprintf ("nx",
+ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n",
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1);
+ }
+}
+
void
grub_efi_mm_init (void)
{
@@ -615,6 +691,8 @@ grub_efi_mm_init (void)
grub_efi_uint64_t required_pages;
int mm_status;
+ grub_nx_init ();
+
/* Prepare a memory region to store two memory maps. */
memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
if (! memory_map)
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
index 24ab0f0074..37f5d0c7eb 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -191,7 +191,8 @@ free_params (void)
}
grub_err_t
-grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
+grub_armxx_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args,
+ int nx_supported)
{
grub_err_t retval;
@@ -201,7 +202,8 @@ grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
grub_dprintf ("linux", "linux command line: '%s'\n", args);
- retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr);
+ retval = grub_efi_linux_boot (addr, size, handover_offset,
+ (void *)addr, nx_supported);
/* Never reached... */
free_params();
@@ -211,7 +213,10 @@ grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
static grub_err_t
grub_linux_boot (void)
{
- return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args);
+ return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr,
+ (grub_size_t)kernel_size,
+ linux_args,
+ 0);
}
static grub_err_t
@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
struct grub_armxx_linux_pe_header *pe;
int rc;
grub_err_t err;
+ int nx_supported = 1;
grub_dl_ref (my_mod);
@@ -395,6 +401,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
}
+ err = grub_efi_check_nx_image_support((grub_addr_t) kernel_addr, kernel_size, &nx_supported);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
handover_offset = pe->opt.entry_addr;
diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
index 1a337866f0..1fd1bbb4bd 100644
--- a/grub-core/loader/arm64/xen_boot.c
+++ b/grub-core/loader/arm64/xen_boot.c
@@ -266,7 +266,9 @@ xen_boot (void)
return err;
return grub_armxx_efi_linux_boot_image (xen_hypervisor->start,
- xen_hypervisor->cmdline);
+ xen_hypervisor->size,
+ xen_hypervisor->cmdline,
+ 0);
}
static void
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 8e658f713e..b72e6bd5e3 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -1055,6 +1055,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
+ /*
+ * The OS kernel is going to set its own permissions when it takes over
+ * paging a few million instructions from now, and load_image() will set up
+ * anything that's needed based on the section headers, so there's no point
+ * in doing anything but clearing the protection bits here.
+ */
+ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n",
+ (void *)(grub_addr_t)address, fsize, 0llu);
+ grub_update_mem_attrs (address, fsize,
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0);
+
#if defined (__i386__) || defined (__x86_64__)
if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
{
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index 927d89a90d..421502bd25 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -66,16 +66,125 @@ grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
+#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
+
+grub_err_t
+grub_efi_check_nx_image_support (grub_addr_t kernel_addr,
+ grub_size_t kernel_size,
+ int *nx_supported)
+{
+ struct grub_dos_header *doshdr;
+ grub_size_t sz = sizeof (*doshdr);
+
+ struct grub_pe32_header_32 *pe32;
+ struct grub_pe32_header_64 *pe64;
+
+ int image_is_compatible = 0;
+ int is_64_bit;
+
+ if (kernel_size < sz)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
+
+ doshdr = (void *)kernel_addr;
+
+ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid"));
+
+ sz = doshdr->lfanew + sizeof (*pe32);
+ if (kernel_size < sz)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
+
+ pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew);
+ pe64 = (struct grub_pe32_header_64 *)pe32;
+
+ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE,
+ GRUB_PE32_SIGNATURE_SIZE) != 0)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid"));
+
+ switch (pe32->coff_header.machine)
+ {
+ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED:
+ case GRUB_PE32_MACHINE_I386:
+ is_64_bit = 0;
+ break;
+ case GRUB_PE32_MACHINE_ARM64:
+ case GRUB_PE32_MACHINE_IA64:
+ case GRUB_PE32_MACHINE_X86_64:
+ is_64_bit = 1;
+ break;
+ default:
+ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"),
+ pe32->coff_header.machine);
+ }
+
+ if (is_64_bit)
+ {
+ sz = doshdr->lfanew + sizeof (*pe64);
+ if (kernel_size < sz)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
+
+ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
+ image_is_compatible = 1;
+ }
+ else
+ {
+ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
+ image_is_compatible = 1;
+ }
+
+ *nx_supported = image_is_compatible;
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_efi_check_nx_required (int *nx_required)
+{
+ grub_efi_status_t status;
+ grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID;
+ grub_size_t mok_policy_sz = 0;
+ char *mok_policy = NULL;
+ grub_uint32_t mok_policy_attrs = 0;
+
+ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid,
+ &mok_policy_sz,
+ (void **)&mok_policy,
+ &mok_policy_attrs);
+ if (status == GRUB_EFI_NOT_FOUND ||
+ mok_policy_sz == 0 ||
+ mok_policy == NULL)
+ {
+ *nx_required = 0;
+ return GRUB_ERR_NONE;
+ }
+
+ *nx_required = 0;
+ if (mok_policy_sz < 1 ||
+ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) ||
+ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED))
+ *nx_required = 1;
+
+ return GRUB_ERR_NONE;
+}
typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
grub_err_t
-grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
- void *kernel_params)
+grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
+ grub_off_t handover_offset, void *kernel_params,
+ int nx_supported)
{
grub_efi_loaded_image_t *loaded_image = NULL;
handover_func hf;
int offset = 0;
+ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R |
+ GRUB_MEM_ATTR_W |
+ GRUB_MEM_ATTR_X;
+ grub_uint64_t stack_clear_attrs = 0;
+ grub_uint64_t kernel_set_attrs = stack_set_attrs;
+ grub_uint64_t kernel_clear_attrs = stack_clear_attrs;
+ grub_uint64_t attrs;
+ int nx_required = 0;
#ifdef __x86_64__
offset = 512;
@@ -88,12 +197,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
*/
loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (loaded_image)
- loaded_image->image_base = kernel_addr;
+ loaded_image->image_base = (void *)kernel_addr;
else
grub_dprintf ("linux", "Loaded Image base address could not be set\n");
grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n",
- kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params);
+ (void *)kernel_addr, (void *)handover_offset, kernel_params);
+
+
+ if (nx_required && !nx_supported)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy"));
+
+ if (nx_supported)
+ {
+ kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
+ kernel_clear_attrs |= GRUB_MEM_ATTR_W;
+ stack_set_attrs &= ~GRUB_MEM_ATTR_X;
+ stack_clear_attrs |= GRUB_MEM_ATTR_X;
+ }
+
+ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n",
+ kernel_addr, kernel_addr + kernel_size - 1,
+ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-');
+ grub_update_mem_attrs (kernel_addr, kernel_size,
+ kernel_set_attrs, kernel_clear_attrs);
+
+ grub_get_mem_attrs (kernel_addr, 4096, &attrs);
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
+ (grub_addr_t)kernel_addr,
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
+ if (grub_stack_addr != (grub_addr_t)-1ll)
+ {
+ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n",
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1,
+ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
+ grub_update_mem_attrs (grub_stack_addr, grub_stack_size,
+ stack_set_attrs, stack_clear_attrs);
+
+ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs);
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
+ grub_stack_addr,
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
+ }
+
+#if defined(__i386__) || defined(__x86_64__)
+ asm volatile ("cli");
+#endif
+
hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
grub_dprintf ("linux", "handover_func() = %p\n", hf);
hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 3d4069e4c6..d80d6ec312 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -44,7 +44,7 @@ struct grub_linuxefi_context {
grub_uint32_t handover_offset;
struct linux_kernel_params *params;
char *cmdline;
-
+ int nx_supported;
void *initrd_mem;
};
@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size,
pages = BYTES_TO_PAGES(size);
grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
pages, (void *)max);
+ size = pages * GRUB_EFI_PAGE_SIZE;
prev_max = max;
addr = grub_efi_allocate_pages_real (max, pages,
max_addresses[i].alloc_type,
memtype);
if (addr)
- grub_dprintf ("linux", "Allocated at %p\n", addr);
+ {
+ grub_dprintf ("linux", "Allocated at %p\n", addr);
+ grub_update_mem_attrs ((grub_addr_t)addr, size,
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W,
+ GRUB_MEM_ATTR_X);
+ }
}
while (grub_error_pop ())
@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data)
asm volatile ("cli");
- return grub_efi_linux_boot ((char *)context->kernel_mem,
+ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem,
+ context->kernel_size,
context->handover_offset,
- context->params);
+ context->params,
+ context->nx_supported);
}
static grub_err_t
@@ -308,7 +316,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_uint32_t handover_offset;
struct linux_kernel_params *params = 0;
char *cmdline = 0;
+ int nx_supported = 1;
struct grub_linuxefi_context *context = 0;
+ grub_err_t err;
grub_dl_ref (my_mod);
@@ -352,6 +362,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
}
+ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen,
+ &nx_supported);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ grub_dprintf ("linux", "nx is%s supported by this kernel\n",
+ nx_supported ? "" : " not");
+
lh = (struct linux_i386_kernel_header *)kernel;
grub_dprintf ("linux", "original lh is at %p\n", kernel);
@@ -515,6 +532,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
context->handover_offset = handover_offset;
context->params = params;
context->cmdline = cmdline;
+ context->nx_supported = nx_supported;
grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index ef8fcb9e1b..c160ddb0ea 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -831,6 +831,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_memset (&linux_params, 0, sizeof (linux_params));
grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
+ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n",
+ &linux_params, sizeof (lh) + len);
+ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len,
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X);
+
linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
linux_params.kernel_alignment = (1 << align);
linux_params.ps_mouse = linux_params.padding10 = 0;
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index a635bcb0a9..8ca8c38f9a 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -135,12 +135,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
char **device,
char **path);
+extern grub_addr_t EXPORT_VAR(grub_stack_addr);
+extern grub_size_t EXPORT_VAR(grub_stack_size);
+
#if defined(__arm__) || defined(__aarch64__)
void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
#include <grub/cpu/linux.h>
grub_err_t grub_armxx_efi_linux_check_image(struct linux_armxx_kernel_header *lh);
-grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, char *args);
+grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
+ char *args, int nx_enabled);
#endif
grub_addr_t grub_efi_section_addr (const char *section);
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
index 0033d9305a..8130b19590 100644
--- a/include/grub/efi/linux.h
+++ b/include/grub/efi/linux.h
@@ -22,10 +22,23 @@
#include <grub/err.h>
#include <grub/symbol.h>
+#define GRUB_MOK_POLICY_NX_REQUIRED 0x1
+
int
EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
+
grub_err_t
-EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
- void *kernel_param);
+EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address,
+ grub_size_t kernel_size,
+ grub_off_t handover_offset,
+ void *kernel_param, int nx_enabled);
+
+grub_err_t
+EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr,
+ grub_size_t kernel_size,
+ int *nx_supported);
+
+grub_err_t
+EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required);
#endif /* ! GRUB_EFI_LINUX_HEADER */
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index 2241f6317b..45c9f8b756 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -172,6 +172,8 @@ struct grub_pe32_optional_header
struct grub_pe32_data_directory reserved_entry;
};
+#define GRUB_PE32_NX_COMPAT 0x0100
+
struct grub_pe64_optional_header
{
grub_uint16_t magic;

View File

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Tue, 22 Mar 2022 10:57:20 -0400
Subject: [PATCH] nx: set the nx compatible flag in EFI grub images
For NX, we need the grub binary to announce that it is compatible with
the NX feature. This implies that when loading the executable grub
image, several attributes are true:
- the binary doesn't need an executable stack
- the binary doesn't need sections to be both executable and writable
- the binary knows how to use the EFI Memory Attributes protocol on code
it is loading.
This patch adds a definition for the PE DLL Characteristics flag
GRUB_PE32_NX_COMPAT, and changes grub-mkimage to set that flag.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 0c7f1aed5a87f75051b421903a900ccb4bbd795a)
(cherry picked from commit 2f9446d488da96de963f4ffe03b0a1c60a4664f5)
(cherry picked from commit f56671343622b0e0216340cd07e77dfc4e88a97a)
---
util/mkimage.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/util/mkimage.c b/util/mkimage.c
index 16418e245d..c77025904c 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -1358,6 +1358,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
section = (struct grub_pe32_section_table *)(o64 + 1);
}
+ PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT);
PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size);
PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address);
PE_OHDR (o32, o64, image_base) = 0;

View File

@ -0,0 +1,52 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 11 May 2022 16:37:14 -0400
Subject: [PATCH] Fixup grub_efi_get_variable() type in our loaders
Has a new type now that we have 04ae030d0eea8668d4417702d88bf2cf04713d80
("efi: Return grub_efi_status_t from grub_efi_get_variable()").
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit d27cee05d31a9612f0b877d2de727b22cc3ec51a)
---
grub-core/kern/efi/init.c | 4 ++--
grub-core/kern/efi/sb.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
index 501608f743..565ce541f5 100644
--- a/grub-core/kern/efi/init.c
+++ b/grub-core/kern/efi/init.c
@@ -104,8 +104,8 @@ grub_efi_env_init (void)
struct grub_envblk envblk_s = { NULL, 0 };
grub_envblk_t envblk = &envblk_s;
- envblk_s.buf = grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid,
- &envblk_s.size);
+ grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid, &envblk_s.size,
+ &envblk_s.buf);
if (!envblk_s.buf || envblk_s.size < 1)
return;
diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
index d74778b0ca..f84d7d3080 100644
--- a/grub-core/kern/efi/sb.c
+++ b/grub-core/kern/efi/sb.c
@@ -35,7 +35,7 @@ grub_efi_secure_boot (void)
char *setup_mode = NULL;
grub_efi_boolean_t ret = 0;
- secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
+ grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize, &secure_boot);
if (datasize != 1 || !secure_boot)
{
grub_dprintf ("secureboot", "No SecureBoot variable\n");
@@ -43,7 +43,7 @@ grub_efi_secure_boot (void)
}
grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot);
- setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
+ grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize, &setup_mode);
if (datasize != 1 || !setup_mode)
{
grub_dprintf ("secureboot", "No SetupMode variable\n");

View File

@ -380,11 +380,11 @@ for x in grub-mkimage ; do \\\
done \
%{nil}
%global grub_modules " all_video boot blscfg btrfs \\\
%global grub_modules " all_video boot blscfg \\\
cat configfile cryptodisk echo ext2 \\\
fat font gcry_rijndael gcry_rsa gcry_serpent \\\
gcry_sha256 gcry_twofish gcry_whirlpool \\\
gfxmenu gfxterm gzio halt hfsplus http \\\
gfxmenu gfxterm gzio halt http \\\
increment iso9660 jpeg loadenv loopback linux \\\
lvm luks mdraid09 mdraid1x minicmd net \\\
normal part_apple part_msdos part_gpt \\\

View File

@ -498,3 +498,52 @@ Patch0497: 0497-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch
Patch0498: 0498-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch
Patch0499: 0499-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
Patch0500: 0500-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch
Patch0501: 0501-loader-efi-chainloader-grub_load_and_start_image-doe.patch
Patch0502: 0502-loader-efi-chainloader-simplify-the-loader-state.patch
Patch0503: 0503-commands-boot-Add-API-to-pass-context-to-loader.patch
Patch0504: 0504-loader-efi-chainloader-Use-grub_loader_set_ex.patch
Patch0505: 0505-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch
Patch0506: 0506-loader-i386-efi-linux-Use-grub_loader_set_ex.patch
Patch0507: 0507-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch
Patch0508: 0508-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
Patch0509: 0509-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
Patch0510: 0510-video-readers-png-Refuse-to-handle-multiple-image-he.patch
Patch0511: 0511-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
Patch0512: 0512-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
Patch0513: 0513-video-readers-png-Sanity-check-some-huffman-codes.patch
Patch0514: 0514-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
Patch0515: 0515-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
Patch0516: 0516-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
Patch0517: 0517-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
Patch0518: 0518-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
Patch0519: 0519-net-netbuff-Block-overly-large-netbuff-allocs.patch
Patch0520: 0520-net-ip-Do-IP-fragment-maths-safely.patch
Patch0521: 0521-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
Patch0522: 0522-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
Patch0523: 0523-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
Patch0524: 0524-misc-Format-string-for-grub_error-should-be-a-litera.patch
Patch0525: 0525-net-tftp-Avoid-a-trivial-UAF.patch
Patch0526: 0526-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
Patch0527: 0527-net-http-Fix-OOB-write-for-split-http-headers.patch
Patch0528: 0528-net-http-Error-out-on-headers-with-LF-without-CR.patch
Patch0529: 0529-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
Patch0530: 0530-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
Patch0531: 0531-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
Patch0532: 0532-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
Patch0533: 0533-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch
Patch0534: 0534-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch
Patch0535: 0535-Define-GRUB_EFI_SHIM_LOCK_GUID.patch
Patch0536: 0536-misc-Make-grub_min-and-grub_max-more-resilient.patch
Patch0537: 0537-ReiserFS-switch-to-using-grub_min-grub_max.patch
Patch0538: 0538-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch
Patch0539: 0539-modules-make-.module_license-read-only.patch
Patch0540: 0540-modules-strip-.llvm_addrsig-sections-and-similar.patch
Patch0541: 0541-modules-Don-t-allocate-space-for-non-allocable-secti.patch
Patch0542: 0542-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch
Patch0543: 0543-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch
Patch0544: 0544-modules-load-module-sections-at-page-aligned-address.patch
Patch0545: 0545-nx-add-memory-attribute-get-set-API.patch
Patch0546: 0546-nx-set-page-permissions-for-loaded-modules.patch
Patch0547: 0547-nx-set-attrs-in-our-kernel-loaders.patch
Patch0548: 0548-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
Patch0549: 0549-Fixup-grub_efi_get_variable-type-in-our-loaders.patch

View File

@ -1,4 +1,4 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
grub,1,Free Software Foundation,grub,2.02,https://www.gnu.org/software/grub/
grub.rhel8,1,Red Hat Enterprise Linux 8,grub2,@@RHEL_VERSION@@,mail:secalert@redhat.com
grub.almalinux8,1,AlmaLinux 8,grub2,@@VERSION@@,mail:security@almalinux.org
grub,2,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/
grub.rh,2,Red Hat,grub2,@@VERSION_RELEASE@@,mailto:secalert@redhat.com
grub.almalinux8,2,AlmaLinux 8,grub2,@@VERSION_RELEASE@@,mail:security@almalinux.org

View File

@ -11,7 +11,7 @@
Name: grub2
Epoch: 1
Version: 2.02
Release: 123%{?dist}.alma
Release: 123%{?dist}.8.alma
Summary: Bootloader with support for Linux, Multiboot and more
Group: System Environment/Base
License: GPLv3+
@ -168,8 +168,8 @@ This subpackage provides tools for support of all platforms.
mkdir grub-%{grubefiarch}-%{tarversion}
grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grubefiarch}-%{tarversion}/.gitignore
cp %{SOURCE4} grub-%{grubefiarch}-%{tarversion}/unifont.pcf.gz
sed -e "s,@@VERSION@@,%{evr},g" -e "s,@@RHEL_VERSION@@,%{rhel_evr},g" %{SOURCE19} \
> grub-%{grubefiarch}-%{tarversion}/sbat.csv
sed -e "s,@@VERSION@@,%{version},g" -e "s,@@VERSION_RELEASE@@,%{version}-%{release},g" \
%{SOURCE19} > grub-%{grubefiarch}-%{tarversion}/sbat.csv
git add grub-%{grubefiarch}-%{tarversion}
%endif
%if 0%{with_alt_efi_arch}
@ -526,9 +526,15 @@ fi
%endif
%changelog
* Tue May 10 2022 Andrew Lukoshko <alukoshko@almalinux.org> - 2.06-123.alma
* Fri Jun 17 2022 Andrew Lukoshko <alukoshko@almalinux.org> - 2.06-123.el8_6.8.alma
- Debrand for AlmaLinux
* Fri Jun 03 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-123.el8_6.8
- CVE fixes for 2022-06-07
- CVE-2022-28736 CVE-2022-28735 CVE-2022-28734 CVE-2022-28733
- CVE-2021-3697 CVE-2021-3696 CVE-2021-3695
- Resolves: #2031899
* Mon Mar 28 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-123
- Bump for signing
- Resolves: #2061252