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

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