1From 14ceb3b3ff6db664649138442b6562c114dcf56e Mon Sep 17 00:00:00 2001 2From: Chris Coulson <chris.coulson@canonical.com> 3Date: Tue, 5 Apr 2022 10:58:28 +0100 4Subject: [PATCH] commands/boot: Add API to pass context to loader 5 6Loaders rely on global variables for saving context which is consumed 7in the boot hook and freed in the unload hook. In the case where a loader 8command is executed twice, calling grub_loader_set() a second time executes 9the unload hook, but in some cases this runs when the loader's global 10context has already been updated, resulting in the updated context being 11freed and potential use-after-free bugs when the boot hook is subsequently 12called. 13 14This adds a new API, grub_loader_set_ex(), which allows a loader to specify 15context that is passed to its boot and unload hooks. This is an alternative 16to requiring that loaders call grub_loader_unset() before mutating their 17global context. 18 19Signed-off-by: Chris Coulson <chris.coulson@canonical.com> 20Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> 21 22Upstream-Status: Backport 23 24Reference to upstream patch: 25https://git.savannah.gnu.org/cgit/grub.git/commit/?id=14ceb3b3ff6db664649138442b6562c114dcf56e 26 27Signed-off-by: Xiangyu Chen <xiangyu.chen@windriver.com> 28--- 29 grub-core/commands/boot.c | 66 ++++++++++++++++++++++++++++++++++----- 30 include/grub/loader.h | 5 +++ 31 2 files changed, 63 insertions(+), 8 deletions(-) 32 33diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c 34index bbca81e94..61514788e 100644 35--- a/grub-core/commands/boot.c 36+++ b/grub-core/commands/boot.c 37@@ -27,10 +27,20 @@ 38 39 GRUB_MOD_LICENSE ("GPLv3+"); 40 41-static grub_err_t (*grub_loader_boot_func) (void); 42-static grub_err_t (*grub_loader_unload_func) (void); 43+static grub_err_t (*grub_loader_boot_func) (void *context); 44+static grub_err_t (*grub_loader_unload_func) (void *context); 45+static void *grub_loader_context; 46 static int grub_loader_flags; 47 48+struct grub_simple_loader_hooks 49+{ 50+ grub_err_t (*boot) (void); 51+ grub_err_t (*unload) (void); 52+}; 53+ 54+/* Don't heap allocate this to avoid making grub_loader_set() fallible. */ 55+static struct grub_simple_loader_hooks simple_loader_hooks; 56+ 57 struct grub_preboot 58 { 59 grub_err_t (*preboot_func) (int); 60@@ -44,6 +54,29 @@ static int grub_loader_loaded; 61 static struct grub_preboot *preboots_head = 0, 62 *preboots_tail = 0; 63 64+static grub_err_t 65+grub_simple_boot_hook (void *context) 66+{ 67+ struct grub_simple_loader_hooks *hooks; 68+ 69+ hooks = (struct grub_simple_loader_hooks *) context; 70+ return hooks->boot (); 71+} 72+ 73+static grub_err_t 74+grub_simple_unload_hook (void *context) 75+{ 76+ struct grub_simple_loader_hooks *hooks; 77+ grub_err_t ret; 78+ 79+ hooks = (struct grub_simple_loader_hooks *) context; 80+ 81+ ret = hooks->unload (); 82+ grub_memset (hooks, 0, sizeof (*hooks)); 83+ 84+ return ret; 85+} 86+ 87 int 88 grub_loader_is_loaded (void) 89 { 90@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd) 91 } 92 93 void 94-grub_loader_set (grub_err_t (*boot) (void), 95- grub_err_t (*unload) (void), 96- int flags) 97+grub_loader_set_ex (grub_err_t (*boot) (void *context), 98+ grub_err_t (*unload) (void *context), 99+ void *context, 100+ int flags) 101 { 102 if (grub_loader_loaded && grub_loader_unload_func) 103- grub_loader_unload_func (); 104+ grub_loader_unload_func (grub_loader_context); 105 106 grub_loader_boot_func = boot; 107 grub_loader_unload_func = unload; 108+ grub_loader_context = context; 109 grub_loader_flags = flags; 110 111 grub_loader_loaded = 1; 112 } 113 114+void 115+grub_loader_set (grub_err_t (*boot) (void), 116+ grub_err_t (*unload) (void), 117+ int flags) 118+{ 119+ grub_loader_set_ex (grub_simple_boot_hook, 120+ grub_simple_unload_hook, 121+ &simple_loader_hooks, 122+ flags); 123+ 124+ simple_loader_hooks.boot = boot; 125+ simple_loader_hooks.unload = unload; 126+} 127+ 128 void 129 grub_loader_unset(void) 130 { 131 if (grub_loader_loaded && grub_loader_unload_func) 132- grub_loader_unload_func (); 133+ grub_loader_unload_func (grub_loader_context); 134 135 grub_loader_boot_func = 0; 136 grub_loader_unload_func = 0; 137+ grub_loader_context = 0; 138 139 grub_loader_loaded = 0; 140 } 141@@ -158,7 +208,7 @@ grub_loader_boot (void) 142 return err; 143 } 144 } 145- err = (grub_loader_boot_func) (); 146+ err = (grub_loader_boot_func) (grub_loader_context); 147 148 for (cur = preboots_tail; cur; cur = cur->prev) 149 if (! err) 150diff --git a/include/grub/loader.h b/include/grub/loader.h 151index b20864282..97f231054 100644 152--- a/include/grub/loader.h 153+++ b/include/grub/loader.h 154@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), 155 grub_err_t (*unload) (void), 156 int flags); 157 158+void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *context), 159+ grub_err_t (*unload) (void *context), 160+ void *context, 161+ int flags); 162+ 163 /* Unset current loader, if any. */ 164 void EXPORT_FUNC (grub_loader_unset) (void); 165 166-- 1672.34.1 168 169