nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

Blame SOURCES/0214-commands-boot-Add-API-to-pass-context-to-loader.patch

b35c50
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
b35c50
From: Chris Coulson <chris.coulson@canonical.com>
b35c50
Date: Fri, 29 Apr 2022 21:16:02 +0100
b35c50
Subject: [PATCH] commands/boot: Add API to pass context to loader
b35c50
b35c50
Loaders rely on global variables for saving context which is consumed
b35c50
in the boot hook and freed in the unload hook. In the case where a loader
b35c50
command is executed twice, calling grub_loader_set a second time executes
b35c50
the unload hook, but in some cases this runs when the loader's global
b35c50
context has already been updated, resulting in the updated context being
b35c50
freed and potential use-after-free bugs when the boot hook is subsequently
b35c50
called.
b35c50
b35c50
This adds a new API (grub_loader_set_ex) which allows a loader to specify
b35c50
context that is passed to its boot and unload hooks. This is an alternative
b35c50
to requiring that loaders call grub_loader_unset before mutating their
b35c50
global context.
b35c50
b35c50
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
b35c50
(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3)
b35c50
---
b35c50
 grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------
b35c50
 include/grub/loader.h     |  5 ++++
b35c50
 2 files changed, 63 insertions(+), 8 deletions(-)
b35c50
b35c50
diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
b35c50
index bbca81e947..53691a62d9 100644
b35c50
--- a/grub-core/commands/boot.c
b35c50
+++ b/grub-core/commands/boot.c
b35c50
@@ -27,10 +27,20 @@
b35c50
 
b35c50
 GRUB_MOD_LICENSE ("GPLv3+");
b35c50
 
b35c50
-static grub_err_t (*grub_loader_boot_func) (void);
b35c50
-static grub_err_t (*grub_loader_unload_func) (void);
b35c50
+static grub_err_t (*grub_loader_boot_func) (void *);
b35c50
+static grub_err_t (*grub_loader_unload_func) (void *);
b35c50
+static void *grub_loader_context;
b35c50
 static int grub_loader_flags;
b35c50
 
b35c50
+struct grub_simple_loader_hooks
b35c50
+{
b35c50
+  grub_err_t (*boot) (void);
b35c50
+  grub_err_t (*unload) (void);
b35c50
+};
b35c50
+
b35c50
+/* Don't heap allocate this to avoid making grub_loader_set fallible. */
b35c50
+static struct grub_simple_loader_hooks simple_loader_hooks;
b35c50
+
b35c50
 struct grub_preboot
b35c50
 {
b35c50
   grub_err_t (*preboot_func) (int);
b35c50
@@ -44,6 +54,29 @@ static int grub_loader_loaded;
b35c50
 static struct grub_preboot *preboots_head = 0,
b35c50
   *preboots_tail = 0;
b35c50
 
b35c50
+static grub_err_t
b35c50
+grub_simple_boot_hook (void *context)
b35c50
+{
b35c50
+  struct grub_simple_loader_hooks *hooks;
b35c50
+
b35c50
+  hooks = (struct grub_simple_loader_hooks *) context;
b35c50
+  return hooks->boot ();
b35c50
+}
b35c50
+
b35c50
+static grub_err_t
b35c50
+grub_simple_unload_hook (void *context)
b35c50
+{
b35c50
+  struct grub_simple_loader_hooks *hooks;
b35c50
+  grub_err_t ret;
b35c50
+
b35c50
+  hooks = (struct grub_simple_loader_hooks *) context;
b35c50
+
b35c50
+  ret = hooks->unload ();
b35c50
+  grub_memset (hooks, 0, sizeof (*hooks));
b35c50
+
b35c50
+  return ret;
b35c50
+}
b35c50
+
b35c50
 int
b35c50
 grub_loader_is_loaded (void)
b35c50
 {
b35c50
@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
b35c50
 }
b35c50
 
b35c50
 void
b35c50
-grub_loader_set (grub_err_t (*boot) (void),
b35c50
-		 grub_err_t (*unload) (void),
b35c50
-		 int flags)
b35c50
+grub_loader_set_ex (grub_err_t (*boot) (void *),
b35c50
+		    grub_err_t (*unload) (void *),
b35c50
+		    void *context,
b35c50
+		    int flags)
b35c50
 {
b35c50
   if (grub_loader_loaded && grub_loader_unload_func)
b35c50
-    grub_loader_unload_func ();
b35c50
+    grub_loader_unload_func (grub_loader_context);
b35c50
 
b35c50
   grub_loader_boot_func = boot;
b35c50
   grub_loader_unload_func = unload;
b35c50
+  grub_loader_context = context;
b35c50
   grub_loader_flags = flags;
b35c50
 
b35c50
   grub_loader_loaded = 1;
b35c50
 }
b35c50
 
b35c50
+void
b35c50
+grub_loader_set (grub_err_t (*boot) (void),
b35c50
+		 grub_err_t (*unload) (void),
b35c50
+		 int flags)
b35c50
+{
b35c50
+  grub_loader_set_ex (grub_simple_boot_hook,
b35c50
+		      grub_simple_unload_hook,
b35c50
+		      &simple_loader_hooks,
b35c50
+		      flags);
b35c50
+
b35c50
+  simple_loader_hooks.boot = boot;
b35c50
+  simple_loader_hooks.unload = unload;
b35c50
+}
b35c50
+
b35c50
 void
b35c50
 grub_loader_unset(void)
b35c50
 {
b35c50
   if (grub_loader_loaded && grub_loader_unload_func)
b35c50
-    grub_loader_unload_func ();
b35c50
+    grub_loader_unload_func (grub_loader_context);
b35c50
 
b35c50
   grub_loader_boot_func = 0;
b35c50
   grub_loader_unload_func = 0;
b35c50
+  grub_loader_context = 0;
b35c50
 
b35c50
   grub_loader_loaded = 0;
b35c50
 }
b35c50
@@ -158,7 +208,7 @@ grub_loader_boot (void)
b35c50
 	  return err;
b35c50
 	}
b35c50
     }
b35c50
-  err = (grub_loader_boot_func) ();
b35c50
+  err = (grub_loader_boot_func) (grub_loader_context);
b35c50
 
b35c50
   for (cur = preboots_tail; cur; cur = cur->prev)
b35c50
     if (! err)
b35c50
diff --git a/include/grub/loader.h b/include/grub/loader.h
b35c50
index b208642821..1846fa6c5f 100644
b35c50
--- a/include/grub/loader.h
b35c50
+++ b/include/grub/loader.h
b35c50
@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),
b35c50
 				    grub_err_t (*unload) (void),
b35c50
 				    int flags);
b35c50
 
b35c50
+void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *),
b35c50
+				       grub_err_t (*unload) (void *),
b35c50
+				       void *context,
b35c50
+				       int flags);
b35c50
+
b35c50
 /* Unset current loader, if any.  */
b35c50
 void EXPORT_FUNC (grub_loader_unset) (void);
b35c50