blob: a2c0530f04cd44bfdcc1e4ee53e34245d76a3182 [file] [log] [blame]
Andrew Geissler517393d2023-01-13 08:55:19 -06001From 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