]> git.proxmox.com Git - grub2.git/blame - grub-core/kern/dl.c
verifiers: File type for fine-grained signature-verification controlling
[grub2.git] / grub-core / kern / dl.c
CommitLineData
6a161fa9 1/* dl.c - loadable module support */
2/*
4b13b216 3 * GRUB -- GRand Unified Bootloader
8231fb77 4 * Copyright (C) 2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
6a161fa9 5 *
5a79f472 6 * GRUB is free software: you can redistribute it and/or modify
6a161fa9 7 * it under the terms of the GNU General Public License as published by
5a79f472 8 * the Free Software Foundation, either version 3 of the License, or
6a161fa9 9 * (at your option) any later version.
10 *
5a79f472 11 * GRUB is distributed in the hope that it will be useful,
6a161fa9 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
5a79f472 17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
6a161fa9 18 */
19
17dc3751 20/* Force native word size */
21#define GRUB_TARGET_WORDSIZE (8 * GRUB_CPU_SIZEOF_VOID_P)
22
6a161fa9 23#include <config.h>
4b13b216 24#include <grub/elf.h>
25#include <grub/dl.h>
26#include <grub/misc.h>
27#include <grub/mm.h>
28#include <grub/err.h>
29#include <grub/types.h>
30#include <grub/symbol.h>
31#include <grub/file.h>
32#include <grub/env.h>
924b6140 33#include <grub/cache.h>
9c4b5c13 34#include <grub/i18n.h>
8231fb77 35
36/* Platforms where modules are in a readonly area of memory. */
37#if defined(GRUB_MACHINE_QEMU)
38#define GRUB_MODULES_MACHINE_READONLY
39#endif
4b13b216 40
6a161fa9 41\f
42
ebcecdf1
VS
43#pragma GCC diagnostic ignored "-Wcast-align"
44
fcaae9ec 45grub_dl_t grub_dl_head = 0;
6a161fa9 46
ba287dd8
VS
47grub_err_t
48grub_dl_add (grub_dl_t mod);
49
7cd0df84 50/* Keep global so that GDB scripts work. */
ba287dd8 51grub_err_t
4b13b216 52grub_dl_add (grub_dl_t mod)
6a161fa9 53{
4b13b216 54 if (grub_dl_get (mod->name))
55 return grub_error (GRUB_ERR_BAD_MODULE,
6a161fa9 56 "`%s' is already loaded", mod->name);
b39f9d20 57
4b13b216 58 return GRUB_ERR_NONE;
6a161fa9 59}
60
61static void
4b13b216 62grub_dl_remove (grub_dl_t mod)
6a161fa9 63{
fcaae9ec 64 grub_dl_t *p, q;
6a161fa9 65
4b13b216 66 for (p = &grub_dl_head, q = *p; q; p = &q->next, q = *p)
fcaae9ec 67 if (q == mod)
6a161fa9 68 {
69 *p = q->next;
6a161fa9 70 return;
71 }
72}
73
6a161fa9 74\f
75
4b13b216 76struct grub_symbol
6a161fa9 77{
4b13b216 78 struct grub_symbol *next;
6a161fa9 79 const char *name;
80 void *addr;
7b58e65f 81 int isfunc;
4b13b216 82 grub_dl_t mod; /* The module to which this symbol belongs. */
6a161fa9 83};
4b13b216 84typedef struct grub_symbol *grub_symbol_t;
6a161fa9 85
86/* The size of the symbol table. */
4b13b216 87#define GRUB_SYMTAB_SIZE 509
6a161fa9 88
89/* The symbol table (using an open-hash). */
4b13b216 90static struct grub_symbol *grub_symtab[GRUB_SYMTAB_SIZE];
6a161fa9 91
92/* Simple hash function. */
93static unsigned
4b13b216 94grub_symbol_hash (const char *s)
6a161fa9 95{
96 unsigned key = 0;
97
98 while (*s)
99 key = key * 65599 + *s++;
100
4b13b216 101 return (key + (key >> 5)) % GRUB_SYMTAB_SIZE;
6a161fa9 102}
103
104/* Resolve the symbol name NAME and return the address.
105 Return NULL, if not found. */
7b58e65f 106static grub_symbol_t
4b13b216 107grub_dl_resolve_symbol (const char *name)
6a161fa9 108{
4b13b216 109 grub_symbol_t sym;
6a161fa9 110
4b13b216 111 for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next)
112 if (grub_strcmp (sym->name, name) == 0)
7b58e65f 113 return sym;
6a161fa9 114
115 return 0;
116}
117
118/* Register a symbol with the name NAME and the address ADDR. */
4b13b216 119grub_err_t
7b58e65f
VS
120grub_dl_register_symbol (const char *name, void *addr, int isfunc,
121 grub_dl_t mod)
6a161fa9 122{
4b13b216 123 grub_symbol_t sym;
6a161fa9 124 unsigned k;
b39f9d20 125
4b13b216 126 sym = (grub_symbol_t) grub_malloc (sizeof (*sym));
6a161fa9 127 if (! sym)
4b13b216 128 return grub_errno;
6a161fa9 129
130 if (mod)
131 {
4b13b216 132 sym->name = grub_strdup (name);
6a161fa9 133 if (! sym->name)
134 {
4b13b216 135 grub_free (sym);
136 return grub_errno;
6a161fa9 137 }
138 }
139 else
140 sym->name = name;
b39f9d20 141
6a161fa9 142 sym->addr = addr;
143 sym->mod = mod;
7b58e65f 144 sym->isfunc = isfunc;
b39f9d20 145
4b13b216 146 k = grub_symbol_hash (name);
147 sym->next = grub_symtab[k];
148 grub_symtab[k] = sym;
6a161fa9 149
4b13b216 150 return GRUB_ERR_NONE;
6a161fa9 151}
152
153/* Unregister all the symbols defined in the module MOD. */
154static void
4b13b216 155grub_dl_unregister_symbols (grub_dl_t mod)
6a161fa9 156{
157 unsigned i;
158
159 if (! mod)
4b13b216 160 grub_fatal ("core symbols cannot be unregistered");
b39f9d20 161
4b13b216 162 for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
6a161fa9 163 {
4b13b216 164 grub_symbol_t sym, *p, q;
6a161fa9 165
4b13b216 166 for (p = &grub_symtab[i], sym = *p; sym; sym = q)
6a161fa9 167 {
168 q = sym->next;
169 if (sym->mod == mod)
170 {
171 *p = q;
4b13b216 172 grub_free ((void *) sym->name);
173 grub_free (sym);
6a161fa9 174 }
175 else
176 p = &sym->next;
177 }
178 }
179}
180
181/* Return the address of a section whose index is N. */
182static void *
4b13b216 183grub_dl_get_section_addr (grub_dl_t mod, unsigned n)
6a161fa9 184{
4b13b216 185 grub_dl_segment_t seg;
6a161fa9 186
187 for (seg = mod->segment; seg; seg = seg->next)
188 if (seg->section == n)
189 return seg->addr;
190
191 return 0;
192}
193
c642636f 194/* Check if EHDR is a valid ELF header. */
f76ce889 195static grub_err_t
c642636f 196grub_dl_check_header (void *ehdr, grub_size_t size)
197{
198 Elf_Ehdr *e = ehdr;
9c4b5c13 199 grub_err_t err;
c642636f 200
201 /* Check the header size. */
202 if (size < sizeof (Elf_Ehdr))
203 return grub_error (GRUB_ERR_BAD_OS, "ELF header smaller than expected");
204
205 /* Check the magic numbers. */
9c4b5c13 206 if (e->e_ident[EI_MAG0] != ELFMAG0
c642636f 207 || e->e_ident[EI_MAG1] != ELFMAG1
208 || e->e_ident[EI_MAG2] != ELFMAG2
209 || e->e_ident[EI_MAG3] != ELFMAG3
210 || e->e_ident[EI_VERSION] != EV_CURRENT
211 || e->e_version != EV_CURRENT)
67093bc0 212 return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
9c4b5c13
VS
213
214 err = grub_arch_dl_check_header (ehdr);
215 if (err)
216 return err;
c642636f 217
218 return GRUB_ERR_NONE;
219}
220
6a161fa9 221/* Load all segments from memory specified by E. */
4b13b216 222static grub_err_t
223grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
6a161fa9 224{
225 unsigned i;
05126706 226 const Elf_Shdr *s;
f49157df 227 grub_size_t tsize = 0, talign = 1;
7a148da6 228#if !defined (__i386__) && !defined (__x86_64__)
f49157df 229 grub_size_t tramp;
230 grub_size_t got;
49060520 231 grub_err_t err;
f49157df 232#endif
233 char *ptr;
234
05126706 235 for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
f49157df 236 i < e->e_shnum;
05126706 237 i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
f49157df 238 {
10b64f1c 239 tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
f49157df 240 if (talign < s->sh_addralign)
241 talign = s->sh_addralign;
242 }
243
7a148da6 244#if !defined (__i386__) && !defined (__x86_64__)
49060520
VS
245 err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
246 if (err)
247 return err;
f49157df 248 tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
249 if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
250 talign = GRUB_ARCH_DL_TRAMP_ALIGN;
251 tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
252 if (talign < GRUB_ARCH_DL_GOT_ALIGN)
253 talign = GRUB_ARCH_DL_GOT_ALIGN;
254#endif
255
256#ifdef GRUB_MACHINE_EMU
a19293cb
VS
257 mod->base = grub_osdep_dl_memalign (talign, tsize);
258#else
f49157df 259 mod->base = grub_memalign (talign, tsize);
a19293cb 260#endif
f49157df 261 if (!mod->base)
262 return grub_errno;
ed64e9e2 263 mod->sz = tsize;
f49157df 264 ptr = mod->base;
265
6a161fa9 266 for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
267 i < e->e_shnum;
268 i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
269 {
270 if (s->sh_flags & SHF_ALLOC)
271 {
4b13b216 272 grub_dl_segment_t seg;
6a161fa9 273
4b13b216 274 seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
6a161fa9 275 if (! seg)
4b13b216 276 return grub_errno;
b39f9d20 277
6a161fa9 278 if (s->sh_size)
279 {
280 void *addr;
281
f49157df 282 ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
283 addr = ptr;
284 ptr += s->sh_size;
6a161fa9 285
286 switch (s->sh_type)
287 {
288 case SHT_PROGBITS:
4b13b216 289 grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
6a161fa9 290 break;
291 case SHT_NOBITS:
4b13b216 292 grub_memset (addr, 0, s->sh_size);
6a161fa9 293 break;
294 }
295
296 seg->addr = addr;
297 }
298 else
299 seg->addr = 0;
300
301 seg->size = s->sh_size;
302 seg->section = i;
303 seg->next = mod->segment;
304 mod->segment = seg;
305 }
306 }
7a148da6 307#if !defined (__i386__) && !defined (__x86_64__)
f49157df 308 ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
309 mod->tramp = ptr;
8c534b85 310 mod->trampptr = ptr;
f49157df 311 ptr += tramp;
312 ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
313 mod->got = ptr;
8c534b85 314 mod->gotptr = ptr;
f49157df 315 ptr += got;
316#endif
6a161fa9 317
4b13b216 318 return GRUB_ERR_NONE;
6a161fa9 319}
320
4b13b216 321static grub_err_t
322grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
6a161fa9 323{
324 unsigned i;
325 Elf_Shdr *s;
326 Elf_Sym *sym;
327 const char *str;
328 Elf_Word size, entsize;
b39f9d20 329
6a161fa9 330 for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
331 i < e->e_shnum;
332 i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
333 if (s->sh_type == SHT_SYMTAB)
334 break;
335
67dba97e
AB
336 /* Module without symbol table may still be used to pull in dependencies.
337 We verify at build time that such modules do not contain any relocations
338 that may reference symbol table. */
6a161fa9 339 if (i == e->e_shnum)
67dba97e 340 return GRUB_ERR_NONE;
6a161fa9 341
8231fb77 342#ifdef GRUB_MODULES_MACHINE_READONLY
343 mod->symtab = grub_malloc (s->sh_size);
cdeb8324
VS
344 if (!mod->symtab)
345 return grub_errno;
7ea452a1 346 grub_memcpy (mod->symtab, (char *) e + s->sh_offset, s->sh_size);
8231fb77 347#else
348 mod->symtab = (Elf_Sym *) ((char *) e + s->sh_offset);
349#endif
8c534b85 350 mod->symsize = s->sh_entsize;
8231fb77 351 sym = mod->symtab;
6a161fa9 352 size = s->sh_size;
353 entsize = s->sh_entsize;
b39f9d20 354
6a161fa9 355 s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
356 str = (char *) e + s->sh_offset;
357
358 for (i = 0;
359 i < size / entsize;
360 i++, sym = (Elf_Sym *) ((char *) sym + entsize))
361 {
362 unsigned char type = ELF_ST_TYPE (sym->st_info);
363 unsigned char bind = ELF_ST_BIND (sym->st_info);
364 const char *name = str + sym->st_name;
b39f9d20 365
6a161fa9 366 switch (type)
367 {
368 case STT_NOTYPE:
50739170 369 case STT_OBJECT:
6a161fa9 370 /* Resolve a global symbol. */
371 if (sym->st_name != 0 && sym->st_shndx == 0)
372 {
7b58e65f
VS
373 grub_symbol_t nsym = grub_dl_resolve_symbol (name);
374 if (! nsym)
4b13b216 375 return grub_error (GRUB_ERR_BAD_MODULE,
9c4b5c13 376 N_("symbol `%s' not found"), name);
7b58e65f
VS
377 sym->st_value = (Elf_Addr) nsym->addr;
378 if (nsym->isfunc)
379 sym->st_info = ELF_ST_INFO (bind, STT_FUNC);
6a161fa9 380 }
381 else
50739170 382 {
383 sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
384 sym->st_shndx);
385 if (bind != STB_LOCAL)
7b58e65f 386 if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod))
50739170 387 return grub_errno;
388 }
6a161fa9 389 break;
390
391 case STT_FUNC:
4b13b216 392 sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
6a161fa9 393 sym->st_shndx);
73911575 394#ifdef __ia64__
bbbf8435 395 {
73911575 396 /* FIXME: free descriptor once it's not used anymore. */
397 char **desc;
398 desc = grub_malloc (2 * sizeof (char *));
399 if (!desc)
400 return grub_errno;
401 desc[0] = (void *) sym->st_value;
f49157df 402 desc[1] = mod->base;
bbbf8435 403 sym->st_value = (grub_addr_t) desc;
404 }
405#endif
6a161fa9 406 if (bind != STB_LOCAL)
7b58e65f 407 if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod))
4b13b216 408 return grub_errno;
4b13b216 409 if (grub_strcmp (name, "grub_mod_init") == 0)
410 mod->init = (void (*) (grub_dl_t)) sym->st_value;
411 else if (grub_strcmp (name, "grub_mod_fini") == 0)
a5ffe966 412 mod->fini = (void (*) (void)) sym->st_value;
6a161fa9 413 break;
414
415 case STT_SECTION:
4b13b216 416 sym->st_value = (Elf_Addr) grub_dl_get_section_addr (mod,
6a161fa9 417 sym->st_shndx);
418 break;
419
420 case STT_FILE:
421 sym->st_value = 0;
422 break;
423
424 default:
4b13b216 425 return grub_error (GRUB_ERR_BAD_MODULE,
6a161fa9 426 "unknown symbol type `%d'", (int) type);
427 }
428 }
429
4b13b216 430 return GRUB_ERR_NONE;
6a161fa9 431}
432
80e8b13a
VS
433static Elf_Shdr *
434grub_dl_find_section (Elf_Ehdr *e, const char *name)
e745cf0c
VS
435{
436 Elf_Shdr *s;
437 const char *str;
438 unsigned i;
439
440 s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
441 str = (char *) e + s->sh_offset;
442
443 for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
444 i < e->e_shnum;
445 i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
80e8b13a
VS
446 if (grub_strcmp (str + s->sh_name, name) == 0)
447 return s;
448 return NULL;
449}
e745cf0c 450
80e8b13a
VS
451/* Me, Vladimir Serbinenko, hereby I add this module check as per new
452 GNU module policy. Note that this license check is informative only.
453 Modules have to be licensed under GPLv3 or GPLv3+ (optionally
454 multi-licensed under other licences as well) independently of the
455 presence of this check and solely by linking (module loading in GRUB
456 constitutes linking) and GRUB core being licensed under GPLv3+.
457 Be sure to understand your license obligations.
458*/
459static grub_err_t
460grub_dl_check_license (Elf_Ehdr *e)
461{
462 Elf_Shdr *s = grub_dl_find_section (e, ".module_license");
463 if (s && (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0
464 || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0
465 || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0))
466 return GRUB_ERR_NONE;
e745cf0c
VS
467 return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license");
468}
469
4b13b216 470static grub_err_t
471grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
6a161fa9 472{
473 Elf_Shdr *s;
6a161fa9 474
80e8b13a
VS
475 s = grub_dl_find_section (e, ".modname");
476 if (!s)
4b13b216 477 return grub_error (GRUB_ERR_BAD_MODULE, "no module name found");
80e8b13a
VS
478
479 mod->name = grub_strdup ((char *) e + s->sh_offset);
480 if (! mod->name)
481 return grub_errno;
6a161fa9 482
4b13b216 483 return GRUB_ERR_NONE;
6a161fa9 484}
485
4b13b216 486static grub_err_t
487grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
6a161fa9 488{
489 Elf_Shdr *s;
6a161fa9 490
80e8b13a 491 s = grub_dl_find_section (e, ".moddeps");
b39f9d20 492
80e8b13a
VS
493 if (!s)
494 return GRUB_ERR_NONE;
6a161fa9 495
80e8b13a
VS
496 const char *name = (char *) e + s->sh_offset;
497 const char *max = name + s->sh_size;
b39f9d20 498
80e8b13a
VS
499 while ((name < max) && (*name))
500 {
501 grub_dl_t m;
502 grub_dl_dep_t dep;
a5ffe966 503
80e8b13a
VS
504 m = grub_dl_load (name);
505 if (! m)
506 return grub_errno;
b39f9d20 507
80e8b13a 508 grub_dl_ref (m);
b39f9d20 509
80e8b13a
VS
510 dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep));
511 if (! dep)
512 return grub_errno;
b39f9d20 513
80e8b13a
VS
514 dep->mod = m;
515 dep->next = mod->dep;
516 mod->dep = dep;
517
518 name += grub_strlen (name) + 1;
519 }
6a161fa9 520
4b13b216 521 return GRUB_ERR_NONE;
6a161fa9 522}
523
a5ffe966 524int
4b13b216 525grub_dl_ref (grub_dl_t mod)
a5ffe966 526{
4b13b216 527 grub_dl_dep_t dep;
ce5bf700 528
4c7085f8
BC
529 if (!mod)
530 return 0;
531
ce5bf700 532 for (dep = mod->dep; dep; dep = dep->next)
4b13b216 533 grub_dl_ref (dep->mod);
b39f9d20 534
a5ffe966 535 return ++mod->ref_count;
536}
537
538int
4b13b216 539grub_dl_unref (grub_dl_t mod)
a5ffe966 540{
4b13b216 541 grub_dl_dep_t dep;
a5ffe966 542
4c7085f8
BC
543 if (!mod)
544 return 0;
545
ce5bf700 546 for (dep = mod->dep; dep; dep = dep->next)
4b13b216 547 grub_dl_unref (dep->mod);
b39f9d20 548
ce5bf700 549 return --mod->ref_count;
a5ffe966 550}
551
924b6140 552static void
553grub_dl_flush_cache (grub_dl_t mod)
554{
ed64e9e2
VS
555 grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
556 (unsigned long) mod->sz, mod->base);
557 grub_arch_sync_caches (mod->base, mod->sz);
924b6140 558}
559
8c534b85
VS
560static grub_err_t
561grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
562{
563 Elf_Ehdr *e = ehdr;
564 Elf_Shdr *s;
565 unsigned i;
566
567 for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
568 i < e->e_shnum;
569 i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
570 if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA)
571 {
572 grub_dl_segment_t seg;
573 grub_err_t err;
574
575 /* Find the target segment. */
576 for (seg = mod->segment; seg; seg = seg->next)
577 if (seg->section == s->sh_info)
578 break;
579
580 if (seg)
581 {
67dba97e
AB
582 if (!mod->symtab)
583 return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
584
8c534b85
VS
585 err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
586 if (err)
587 return err;
588 }
589 }
590
591 return GRUB_ERR_NONE;
592}
593
6a161fa9 594/* Load a module from core memory. */
4b13b216 595grub_dl_t
7cd0df84 596grub_dl_load_core_noinit (void *addr, grub_size_t size)
6a161fa9 597{
598 Elf_Ehdr *e;
4b13b216 599 grub_dl_t mod;
be973c1b 600
e4e8eaa5 601 grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr,
602 (unsigned long) size);
6a161fa9 603 e = addr;
c642636f 604 if (grub_dl_check_header (e, size))
605 return 0;
be973c1b 606
c642636f 607 if (e->e_type != ET_REL)
6a161fa9 608 {
9c4b5c13 609 grub_error (GRUB_ERR_BAD_MODULE, N_("this ELF file is not of the right type"));
6a161fa9 610 return 0;
611 }
c642636f 612
613 /* Make sure that every section is within the core. */
4f8fe948 614 if (size < e->e_shoff + (grub_uint32_t) e->e_shentsize * e->e_shnum)
c642636f 615 {
616 grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core");
617 return 0;
618 }
619
eab58da2 620 mod = (grub_dl_t) grub_zalloc (sizeof (*mod));
6a161fa9 621 if (! mod)
622 return 0;
623
6a161fa9 624 mod->ref_count = 1;
6a161fa9 625
be973c1b 626 grub_dprintf ("modules", "relocating to %p\n", mod);
e745cf0c
VS
627 /* Me, Vladimir Serbinenko, hereby I add this module check as per new
628 GNU module policy. Note that this license check is informative only.
629 Modules have to be licensed under GPLv3 or GPLv3+ (optionally
630 multi-licensed under other licences as well) independently of the
631 presence of this check and solely by linking (module loading in GRUB
632 constitutes linking) and GRUB core being licensed under GPLv3+.
633 Be sure to understand your license obligations.
634 */
635 if (grub_dl_check_license (e)
636 || grub_dl_resolve_name (mod, e)
4b13b216 637 || grub_dl_resolve_dependencies (mod, e)
638 || grub_dl_load_segments (mod, e)
639 || grub_dl_resolve_symbols (mod, e)
8c534b85 640 || grub_dl_relocate_symbols (mod, e))
6a161fa9 641 {
642 mod->fini = 0;
4b13b216 643 grub_dl_unload (mod);
6a161fa9 644 return 0;
645 }
646
924b6140 647 grub_dl_flush_cache (mod);
be973c1b 648
649 grub_dprintf ("modules", "module name: %s\n", mod->name);
650 grub_dprintf ("modules", "init function: %p\n", mod->init);
e744219b 651
4b13b216 652 if (grub_dl_add (mod))
6a161fa9 653 {
4b13b216 654 grub_dl_unload (mod);
6a161fa9 655 return 0;
656 }
be973c1b 657
6a161fa9 658 return mod;
659}
660
7cd0df84
VS
661grub_dl_t
662grub_dl_load_core (void *addr, grub_size_t size)
663{
664 grub_dl_t mod;
665
313fb3ce
VS
666 grub_boot_time ("Parsing module");
667
7cd0df84
VS
668 mod = grub_dl_load_core_noinit (addr, size);
669
670 if (!mod)
671 return NULL;
672
673 grub_boot_time ("Initing module %s", mod->name);
674 grub_dl_init (mod);
675 grub_boot_time ("Module %s inited", mod->name);
676
677 return mod;
678}
679
6a161fa9 680/* Load a module from the file FILENAME. */
4b13b216 681grub_dl_t
682grub_dl_load_file (const char *filename)
6a161fa9 683{
1d7a72fd 684 grub_file_t file = NULL;
4b13b216 685 grub_ssize_t size;
6a161fa9 686 void *core = 0;
4b13b216 687 grub_dl_t mod = 0;
b39f9d20 688
313fb3ce
VS
689 grub_boot_time ("Loading module %s", filename);
690
ca0a4f68 691 file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE);
6a161fa9 692 if (! file)
693 return 0;
694
4b13b216 695 size = grub_file_size (file);
696 core = grub_malloc (size);
6a161fa9 697 if (! core)
1d7a72fd 698 {
699 grub_file_close (file);
700 return 0;
701 }
6a161fa9 702
4b13b216 703 if (grub_file_read (file, core, size) != (int) size)
1d7a72fd 704 {
705 grub_file_close (file);
706 grub_free (core);
707 return 0;
708 }
709
710 /* We must close this before we try to process dependencies.
711 Some disk backends do not handle gracefully multiple concurrent
712 opens of the same device. */
713 grub_file_close (file);
6a161fa9 714
4b13b216 715 mod = grub_dl_load_core (core, size);
c2aa00f0 716 grub_free (core);
b38551da 717 if (! mod)
c2aa00f0 718 return 0;
b39f9d20 719
57688121 720 mod->ref_count--;
6a161fa9 721 return mod;
722}
723
6a161fa9 724/* Load a module using a symbolic name. */
4b13b216 725grub_dl_t
726grub_dl_load (const char *name)
6a161fa9 727{
728 char *filename;
4b13b216 729 grub_dl_t mod;
d35d0d37 730 const char *grub_dl_dir = grub_env_get ("prefix");
6a161fa9 731
4b13b216 732 mod = grub_dl_get (name);
6a161fa9 733 if (mod)
a5ffe966 734 return mod;
b39f9d20 735
a6393224
VS
736 if (grub_no_modules)
737 return 0;
738
2033f53e 739 if (! grub_dl_dir) {
9c4b5c13 740 grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
2033f53e 741 return 0;
742 }
6a161fa9 743
92cd0f6e
VS
744 filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM "/%s.mod",
745 grub_dl_dir, name);
6a161fa9 746 if (! filename)
747 return 0;
b39f9d20 748
4b13b216 749 mod = grub_dl_load_file (filename);
750 grub_free (filename);
6a161fa9 751
752 if (! mod)
753 return 0;
b39f9d20 754
4b13b216 755 if (grub_strcmp (mod->name, name) != 0)
756 grub_error (GRUB_ERR_BAD_MODULE, "mismatched names");
b39f9d20 757
6a161fa9 758 return mod;
759}
760
761/* Unload the module MOD. */
a5ffe966 762int
4b13b216 763grub_dl_unload (grub_dl_t mod)
6a161fa9 764{
4b13b216 765 grub_dl_dep_t dep, depn;
6a161fa9 766
a5ffe966 767 if (mod->ref_count > 0)
768 return 0;
6a161fa9 769
770 if (mod->fini)
771 (mod->fini) ();
b39f9d20 772
4b13b216 773 grub_dl_remove (mod);
774 grub_dl_unregister_symbols (mod);
b39f9d20 775
6a161fa9 776 for (dep = mod->dep; dep; dep = depn)
777 {
778 depn = dep->next;
b39f9d20 779
3d2c7e35 780 grub_dl_unload (dep->mod);
b39f9d20 781
4b13b216 782 grub_free (dep);
6a161fa9 783 }
784
a19293cb
VS
785#ifdef GRUB_MACHINE_EMU
786 grub_dl_osdep_dl_free (mod->base);
787#else
bb416954 788 grub_free (mod->base);
a19293cb 789#endif
4b13b216 790 grub_free (mod->name);
8231fb77 791#ifdef GRUB_MODULES_MACHINE_READONLY
792 grub_free (mod->symtab);
793#endif
4b13b216 794 grub_free (mod);
a5ffe966 795 return 1;
6a161fa9 796}
797
a5ffe966 798/* Unload unneeded modules. */
6a161fa9 799void
4b13b216 800grub_dl_unload_unneeded (void)
a5ffe966 801{
4b13b216 802 /* Because grub_dl_remove modifies the list of modules, this
a5ffe966 803 implementation is tricky. */
fcaae9ec 804 grub_dl_t p = grub_dl_head;
b39f9d20 805
a5ffe966 806 while (p)
807 {
fcaae9ec 808 if (grub_dl_unload (p))
a5ffe966 809 {
4b13b216 810 p = grub_dl_head;
a5ffe966 811 continue;
812 }
813
814 p = p->next;
815 }
816}