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

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