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