]> git.proxmox.com Git - grub2.git/blob - util/resolve.c
fs/ntfs: Fix various OOB reads and writes (CVE-2023-4692, CVE-2023-4693)
[grub2.git] / util / resolve.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2002,2007 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <errno.h>
26
27 #include <grub/emu/misc.h>
28 #include <grub/misc.h>
29 #include <grub/util/misc.h>
30 #include <grub/util/resolve.h>
31 #include <grub/i18n.h>
32
33 /* Module. */
34 struct mod_list
35 {
36 const char *name;
37 struct mod_list *next;
38 };
39
40 /* Dependency. */
41 struct dep_list
42 {
43 const char *name;
44 struct mod_list *list;
45 struct dep_list *next;
46 };
47
48 static char buf[1024];
49
50 static void
51 free_mod_list (struct mod_list *head)
52 {
53 while (head)
54 {
55 struct mod_list *next;
56
57 next = head->next;
58 free ((void *) head->name);
59 free (head);
60 head = next;
61 }
62 }
63
64 static void
65 free_dep_list (struct dep_list *head)
66 {
67 while (head)
68 {
69 struct dep_list *next;
70
71 next = head->next;
72 free ((void *) head->name);
73 free_mod_list (head->list);
74 free (head);
75 head = next;
76 }
77 }
78
79 /* Read the list of dependencies. */
80 static struct dep_list *
81 read_dep_list (FILE *fp)
82 {
83 struct dep_list *dep_list = 0;
84
85 while (fgets (buf, sizeof (buf), fp))
86 {
87 char *p;
88 struct dep_list *dep;
89
90 /* Get the target name. */
91 p = strchr (buf, ':');
92 if (! p)
93 grub_util_error (_("invalid line format: %s"), buf);
94
95 *p++ = '\0';
96
97 dep = xmalloc (sizeof (*dep));
98 dep->name = xstrdup (buf);
99 dep->list = 0;
100
101 dep->next = dep_list;
102 dep_list = dep;
103
104 /* Add dependencies. */
105 while (*p)
106 {
107 struct mod_list *mod;
108 char *name;
109
110 /* Skip whitespace. */
111 while (*p && grub_isspace (*p))
112 p++;
113
114 if (! *p)
115 break;
116
117 name = p;
118
119 /* Skip non-whitespace. */
120 while (*p && ! grub_isspace (*p))
121 p++;
122
123 *p++ = '\0';
124
125 mod = (struct mod_list *) xmalloc (sizeof (*mod));
126 mod->name = xstrdup (name);
127 mod->next = dep->list;
128 dep->list = mod;
129 }
130 }
131
132 return dep_list;
133 }
134
135 static char *
136 get_module_name (const char *str)
137 {
138 char *base;
139 char *ext;
140
141 base = strrchr (str, '/');
142 if (! base)
143 base = (char *) str;
144 else
145 base++;
146
147 ext = strrchr (base, '.');
148 if (ext && strcmp (ext, ".mod") == 0)
149 {
150 char *name;
151
152 name = xmalloc (ext - base + 1);
153 memcpy (name, base, ext - base);
154 name[ext - base] = '\0';
155 return name;
156 }
157
158 return xstrdup (base);
159 }
160
161 static char *
162 get_module_path (const char *prefix, const char *str)
163 {
164 char *dir;
165 char *base;
166 char *ext;
167 char *ret;
168
169 ext = strrchr (str, '.');
170 if (ext && strcmp (ext, ".mod") == 0)
171 base = xstrdup (str);
172 else
173 {
174 base = xmalloc (strlen (str) + 4 + 1);
175 sprintf (base, "%s.mod", str);
176 }
177
178 dir = strchr (str, '/');
179 if (dir)
180 return base;
181
182 ret = grub_util_get_path (prefix, base);
183 free (base);
184 return ret;
185 }
186
187 static void
188 add_module (const char *dir,
189 struct dep_list *dep_list,
190 struct mod_list **mod_head,
191 struct grub_util_path_list **path_head,
192 const char *name)
193 {
194 char *mod_name;
195 struct grub_util_path_list *path;
196 struct mod_list *mod;
197 struct dep_list *dep;
198
199 mod_name = get_module_name (name);
200
201 /* Check if the module has already been added. */
202 for (mod = *mod_head; mod; mod = mod->next)
203 if (strcmp (mod->name, mod_name) == 0)
204 {
205 free (mod_name);
206 return;
207 }
208
209 /* Resolve dependencies. */
210 for (dep = dep_list; dep; dep = dep->next)
211 if (strcmp (dep->name, mod_name) == 0)
212 {
213 for (mod = dep->list; mod; mod = mod->next)
214 add_module (dir, dep_list, mod_head, path_head, mod->name);
215
216 break;
217 }
218
219 /* Add this module. */
220 mod = (struct mod_list *) xmalloc (sizeof (*mod));
221 mod->name = mod_name;
222 mod->next = *mod_head;
223 *mod_head = mod;
224
225 /* Add this path. */
226 path = (struct grub_util_path_list *) xmalloc (sizeof (*path));
227 path->name = get_module_path (dir, name);
228 path->next = *path_head;
229 *path_head = path;
230 }
231
232 struct grub_util_path_list *
233 grub_util_resolve_dependencies (const char *prefix,
234 const char *dep_list_file,
235 char *modules[])
236 {
237 char *path;
238 FILE *fp;
239 struct dep_list *dep_list;
240 struct mod_list *mod_list = 0;
241 struct grub_util_path_list *path_list = 0;
242
243 path = grub_util_get_path (prefix, dep_list_file);
244 fp = grub_util_fopen (path, "r");
245 if (! fp)
246 grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
247
248 free (path);
249 dep_list = read_dep_list (fp);
250 fclose (fp);
251
252 while (*modules)
253 {
254 add_module (prefix, dep_list, &mod_list, &path_list, *modules);
255 modules++;
256 }
257
258 free_dep_list (dep_list);
259 free_mod_list (mod_list);
260
261 { /* Reverse the path_list */
262 struct grub_util_path_list *p, *prev, *next;
263
264 for (p = path_list, prev = NULL; p; p = next)
265 {
266 next = p->next;
267 p->next = prev;
268 prev = p;
269 }
270
271 return prev;
272 }
273 }
274
275 void
276 grub_util_free_path_list (struct grub_util_path_list *path_list)
277 {
278 struct grub_util_path_list *next;
279
280 while (path_list)
281 {
282 next = path_list->next;
283 free ((void *) path_list->name);
284 free (path_list);
285 path_list = next;
286 }
287 }