nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

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

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