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

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