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