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

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