diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi index a9f4de631..ca40874e5 100644 --- a/docs/grub-dev.texi +++ b/docs/grub-dev.texi @@ -84,6 +84,7 @@ This edition documents version @value{VERSION}. * Video Subsystem:: * PFF2 Font File Format:: * Graphical Menu Software Design:: +* Verifiers framework:: * Copying This Manual:: Copying This Manual * Index:: @end menu @@ -1949,6 +1950,63 @@ the graphics mode that was in use before @code{grub_video_setup()} was called might fix some of the problems. +@node Verifiers framework +@chapter Verifiers framework + +To register your own verifier call @samp{grub_verifier_register} with a structure +pointing to your functions. + +The interface is inspired by the hash interface with @samp{init}/@samp{write}/@samp{fini}. + +There are essentially 2 ways of using it, hashing and whole-file verification. + +With the hashing approach: +During @samp{init} you decide whether you want to check the given file and init context. +In @samp{write} you update your hashing state. +In @samp{fini} you check that the hash matches the expected value/passes some check/... + +With whole-file verification: +During @samp{init} you decide whether you want to check the given file and init context. +In @samp{write} you verify the file and return an error if it fails. +You don't have @samp{fini}. + +Additional @samp{verify_string} receives various strings like kernel parameters +to verify. Returning no error means successful verification and an error stops +the current action. + +Detailed description of the API: + +Every time a file is opened your @samp{init} function is called with file descriptor +and file type. Your function can have the following outcomes: + +@itemize + +@item returning no error and setting @samp{*flags} to @samp{GRUB_VERIFY_FLAGS_DEFER_AUTH}. +In this case verification is deferred to other active verifiers. Verification +fails if nobody cares or selected verifier fails. + +@item returning no error and setting @samp{*flags} to @samp{GRUB_VERIFY_FLAGS_SKIP_VERIFICATION}. +In this case your verifier will not be called anymore and it is assumed to have +skipped verification. + +@item returning no error and not setting @samp{*flags} to @samp{GRUB_VERIFY_FLAGS_SKIP_VERIFICATION} +In this case verification is done as described in the following section. + +@item returning an error. Then opening of the file will fail due to failed verification. + +@end itemize + +In the third case your @samp{write} will be called with chunks of the file. If +you need the whole file in a single chunk then during @samp{init} set the bit +@samp{GRUB_VERIFY_FLAGS_SINGLE_CHUNK} in @samp{*flags}. During @samp{init} you +may set @samp{*context} if you need additional context. At every iteration you +may return an error and the file will be considered as having failed the +verification. If you return no error then verification continues. + +Optionally at the end of the file @samp{fini}, if it exists, is called with just +the context. If you return no error during any of @samp{init}, @samp{write} and +@samp{fini} then the file is considered as having succeded verification. + @node Copying This Manual @appendix Copying This Manual diff --git a/docs/grub.texi b/docs/grub.texi index 137b894fa..514fdd1ca 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -5465,6 +5465,7 @@ environment variables and commands are listed in the same order. @menu * Authentication and authorisation:: Users and access control * Using digital signatures:: Booting digitally signed code +* UEFI secure boot and shim:: Booting digitally signed PE files @end menu @node Authentication and authorisation @@ -5627,6 +5628,20 @@ or BIOS) configuration to cause the machine to boot from a different (attacker-controlled) device. GRUB is at best only one link in a secure boot chain. +@node UEFI secure boot and shim +@section UEFI secure boot and shim support + +The GRUB, except the @command{chainloader} command, works with the UEFI secure +boot and the shim. This functionality is provided by the shim_lock module. It +is recommend to build in this and other required modules into the @file{core.img}. +All modules not stored in the @file{core.img} and the ACPI tables for the +@command{acpi} command have to be signed, e.g. using PGP. Additionally, the +@command{iorw} and the @command{memrw} commands are prohibited if the UEFI +secure boot is enabled. This is done due to security reasons. All above +mentioned requirements are enforced by the shim_lock module. And itself it +is a persistent module which means that it cannot be unloaded if it was +loaded into the memory. + @node Platform limitations @chapter Platform limitations diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 104513847..d1a00de90 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -99,6 +99,8 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/tis.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slaunch.h endif if COND_i386_efi @@ -108,6 +110,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slaunch.h endif if COND_i386_coreboot @@ -164,6 +167,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slaunch.h endif if COND_ia64_efi diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 2c1d62cee..8ae66b6df 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -198,6 +198,8 @@ kernel = { x86 = kern/i386/tsc.c; x86 = kern/i386/tsc_pit.c; + x86 = kern/tpm.c; + x86 = kern/tis.c; i386_efi = kern/i386/efi/tsc.c; x86_64_efi = kern/i386/efi/tsc.c; i386_efi = kern/i386/tsc_pmtimer.c; @@ -889,12 +891,23 @@ module = { }; module = { - name = verify; - common = commands/verify.c; + name = pgp; + common = commands/pgp.c; cflags = '$(CFLAGS_POSIX)'; cppflags = '-I$(srcdir)/lib/posix_wrap'; }; +module = { + name = verifiers; + common = commands/verifiers.c; +}; + +module = { + name = shim_lock; + common = commands/efi/shim_lock.c; + enable = x86_64_efi; +}; + module = { name = hdparm; common = commands/hdparm.c; @@ -1695,6 +1708,14 @@ module = { enable = noemu; }; +module = { + name = slaunch; + x86 = loader/i386/slaunch.c; + x86 = loader/i386/slaunch_txt.c; + x86 = loader/i386/slaunch_skinit.c; + enable = x86; +}; + module = { name = fdt; arm64 = loader/efi/fdt.c; diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c index 9f02f2201..5a1499aa0 100644 --- a/grub-core/commands/acpi.c +++ b/grub-core/commands/acpi.c @@ -635,7 +635,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) grub_size_t size; char *buf; - file = grub_file_open (args[i]); + file = grub_file_open (args[i], GRUB_FILE_TYPE_ACPI_TABLE); if (! file) { free_tables (); diff --git a/grub-core/commands/blocklist.c b/grub-core/commands/blocklist.c index d1a47b504..944449b77 100644 --- a/grub-core/commands/blocklist.c +++ b/grub-core/commands/blocklist.c @@ -121,8 +121,8 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); - grub_file_filter_disable_compression (); - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_PRINT_BLOCKLIST + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (! file) return grub_errno; diff --git a/grub-core/commands/cat.c b/grub-core/commands/cat.c index 88d904436..ba5f0061a 100644 --- a/grub-core/commands/cat.c +++ b/grub-core/commands/cat.c @@ -56,7 +56,7 @@ grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args) if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_CAT); if (! file) return grub_errno; diff --git a/grub-core/commands/cmp.c b/grub-core/commands/cmp.c index cc23ee67e..e9c3b25d3 100644 --- a/grub-core/commands/cmp.c +++ b/grub-core/commands/cmp.c @@ -45,8 +45,8 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), grub_printf_ (N_("Compare file `%s' with `%s':\n"), args[0], args[1]); - file1 = grub_file_open (args[0]); - file2 = grub_file_open (args[1]); + file1 = grub_file_open (args[0], GRUB_FILE_TYPE_CMP); + file2 = grub_file_open (args[1], GRUB_FILE_TYPE_CMP); if (! file1 || ! file2) goto cleanup; diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c index 132cadbc7..d41d521a4 100644 --- a/grub-core/commands/efi/loadbios.c +++ b/grub-core/commands/efi/loadbios.c @@ -169,7 +169,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), if (argc > 1) { - file = grub_file_open (argv[1]); + file = grub_file_open (argv[1], GRUB_FILE_TYPE_VBE_DUMP); if (! file) return grub_errno; @@ -183,7 +183,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), return grub_errno; } - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_VBE_DUMP); if (! file) return grub_errno; diff --git a/grub-core/commands/efi/shim_lock.c b/grub-core/commands/efi/shim_lock.c new file mode 100644 index 000000000..01246b0fc --- /dev/null +++ b/grub-core/commands/efi/shim_lock.c @@ -0,0 +1,141 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + * EFI shim lock verifier. + */ + +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_EFI_SHIM_LOCK_GUID \ + { 0x605dab50, 0xe046, 0x4300, \ + { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \ + } + +struct grub_efi_shim_lock_protocol +{ + grub_efi_status_t + (*verify) (void *buffer, grub_uint32_t size); +}; +typedef struct grub_efi_shim_lock_protocol grub_efi_shim_lock_protocol_t; + +static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID; +static grub_efi_shim_lock_protocol_t *sl; + +/* List of modules which cannot be loaded if UEFI secure boot mode is enabled. */ +static const char * const disabled_mods[] = {"iorw", "memrw", NULL}; + +static grub_err_t +shim_lock_init (grub_file_t io, enum grub_file_type type, + void **context __attribute__ ((unused)), + enum grub_verify_flags *flags) +{ + const char *b, *e; + int i; + + *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; + + if (!sl) + return GRUB_ERR_NONE; + + switch (type & GRUB_FILE_TYPE_MASK) + { + case GRUB_FILE_TYPE_GRUB_MODULE: + /* Establish GRUB module name. */ + b = grub_strrchr (io->name, '/'); + e = grub_strrchr (io->name, '.'); + + b = b ? (b + 1) : io->name; + e = e ? e : io->name + grub_strlen (io->name); + e = (e > b) ? e : io->name + grub_strlen (io->name); + + for (i = 0; disabled_mods[i]; i++) + if (!grub_strncmp (b, disabled_mods[i], grub_strlen (b) - grub_strlen (e))) + { + grub_error (GRUB_ERR_ACCESS_DENIED, + N_("module cannot be loaded in UEFI secure boot mode: %s"), + io->name); + return GRUB_ERR_ACCESS_DENIED; + } + + /* Fall through. */ + + case GRUB_FILE_TYPE_ACPI_TABLE: + *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; + + return GRUB_ERR_NONE; + + case GRUB_FILE_TYPE_LINUX_KERNEL: + case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: + case GRUB_FILE_TYPE_BSD_KERNEL: + case GRUB_FILE_TYPE_XNU_KERNEL: + case GRUB_FILE_TYPE_PLAN9_KERNEL: + for (i = 0; disabled_mods[i]; i++) + if (grub_dl_get (disabled_mods[i])) + { + grub_error (GRUB_ERR_ACCESS_DENIED, + N_("cannot boot due to dangerous module in memory: %s"), + disabled_mods[i]); + return GRUB_ERR_ACCESS_DENIED; + } + + *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; + + /* Fall through. */ + + default: + return GRUB_ERR_NONE; + } +} + +static grub_err_t +shim_lock_write (void *context __attribute__ ((unused)), void *buf, grub_size_t size) +{ + if (sl->verify (buf, size) != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad shim signature")); + + return GRUB_ERR_NONE; +} + +struct grub_file_verifier shim_lock = + { + .name = "shim_lock", + .init = shim_lock_init, + .write = shim_lock_write + }; + +GRUB_MOD_INIT(shim_lock) +{ + sl = grub_efi_locate_protocol (&shim_lock_guid, 0); + grub_verifier_register (&shim_lock); + + if (!sl) + return; + + grub_dl_set_persistent (mod); +} + +GRUB_MOD_FINI(shim_lock) +{ + grub_verifier_unregister (&shim_lock); +} diff --git a/grub-core/commands/file.c b/grub-core/commands/file.c index 12fba99e0..9cacebf78 100644 --- a/grub-core/commands/file.c +++ b/grub-core/commands/file.c @@ -163,7 +163,7 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args) if (type == -1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no type specified"); - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL); if (!file) return grub_errno; switch (type) @@ -546,7 +546,8 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args) case IS_XNU64: case IS_XNU32: { - macho = grub_macho_open (args[0], (type == IS_XNU64)); + macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, + (type == IS_XNU64)); if (!macho) break; /* FIXME: more checks? */ diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c index d18687351..456ba908b 100644 --- a/grub-core/commands/hashsum.c +++ b/grub-core/commands/hashsum.c @@ -113,7 +113,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, if (hash->mdlen > GRUB_CRYPTO_MAX_MDLEN) return grub_error (GRUB_ERR_BUG, "mdlen is too long"); - hashlist = grub_file_open (hashfilename); + hashlist = grub_file_open (hashfilename, GRUB_FILE_TYPE_HASHLIST); if (!hashlist) return grub_errno; @@ -141,17 +141,15 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, filename = grub_xasprintf ("%s/%s", prefix, p); if (!filename) return grub_errno; - if (!uncompress) - grub_file_filter_disable_compression (); - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_TO_HASH + | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS + : GRUB_FILE_TYPE_NONE)); grub_free (filename); } else - { - if (!uncompress) - grub_file_filter_disable_compression (); - file = grub_file_open (p); - } + file = grub_file_open (p, GRUB_FILE_TYPE_TO_HASH + | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS + : GRUB_FILE_TYPE_NONE)); if (!file) { grub_file_close (hashlist); @@ -242,9 +240,9 @@ grub_cmd_hashsum (struct grub_extcmd_context *ctxt, grub_file_t file; grub_err_t err; unsigned j; - if (!uncompress) - grub_file_filter_disable_compression (); - file = grub_file_open (args[i]); + file = grub_file_open (args[i], GRUB_FILE_TYPE_TO_HASH + | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS + : GRUB_FILE_TYPE_NONE)); if (!file) { if (!keep) diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c index 4c884b3a1..eaa12465b 100644 --- a/grub-core/commands/hexdump.c +++ b/grub-core/commands/hexdump.c @@ -90,7 +90,7 @@ grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args) { grub_file_t file; - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_HEXCAT); if (! file) return 0; diff --git a/grub-core/commands/i386/pc/play.c b/grub-core/commands/i386/pc/play.c index 7712e2a36..c81813105 100644 --- a/grub-core/commands/i386/pc/play.c +++ b/grub-core/commands/i386/pc/play.c @@ -93,7 +93,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)), grub_uint32_t tempo; grub_file_t file; - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_AUDIO); if (! file) return grub_errno; diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c index f35d3a369..c05d6128a 100644 --- a/grub-core/commands/keylayouts.c +++ b/grub-core/commands/keylayouts.c @@ -220,7 +220,7 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), else filename = argv[0]; - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_KEYBOARD_LAYOUT); if (! file) goto fail; diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c index b32f3c74c..db7a8f002 100644 --- a/grub-core/commands/legacycfg.c +++ b/grub-core/commands/legacycfg.c @@ -55,7 +55,7 @@ legacy_file (const char *filename) if (!suffix) return grub_errno; - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG); if (! file) { grub_free (suffix); diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c index acd93d123..3fd664aac 100644 --- a/grub-core/commands/loadenv.c +++ b/grub-core/commands/loadenv.c @@ -44,7 +44,8 @@ static const struct grub_arg_option options[] = PUBKEY filter (that insists upon properly signed files) as well. PUBKEY filter is restored before the function returns. */ static grub_file_t -open_envblk_file (char *filename, int untrusted) +open_envblk_file (char *filename, + enum grub_file_type type) { grub_file_t file; char *buf = 0; @@ -72,13 +73,7 @@ open_envblk_file (char *filename, int untrusted) grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG); } - /* The filters that are disabled will be re-enabled by the call to - grub_file_open() after this particular file is opened. */ - grub_file_filter_disable_compression (); - if (untrusted) - grub_file_filter_disable_pubkey (); - - file = grub_file_open (filename); + file = grub_file_open (filename, type); grub_free (buf); return file; @@ -171,7 +166,10 @@ grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args) whitelist.list = args; /* state[0] is the -f flag; state[1] is the --skip-sig flag */ - file = open_envblk_file ((state[0].set) ? state[0].arg : 0, state[1].set); + file = open_envblk_file ((state[0].set) ? state[0].arg : 0, + GRUB_FILE_TYPE_LOADENV + | (state[1].set + ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE)); if (! file) return grub_errno; @@ -206,7 +204,10 @@ grub_cmd_list_env (grub_extcmd_context_t ctxt, grub_file_t file; grub_envblk_t envblk; - file = open_envblk_file ((state[0].set) ? state[0].arg : 0, 0); + file = open_envblk_file ((state[0].set) ? state[0].arg : 0, + GRUB_FILE_TYPE_LOADENV + | (state[1].set + ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE)); if (! file) return grub_errno; @@ -390,7 +391,8 @@ grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified"); file = open_envblk_file ((state[0].set) ? state[0].arg : 0, - 1 /* allow untrusted */); + GRUB_FILE_TYPE_SAVEENV + | GRUB_FILE_TYPE_SKIP_SIGNATURE); if (! file) return grub_errno; diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c index 0eaf83652..f0d3c1cae 100644 --- a/grub-core/commands/ls.c +++ b/grub-core/commands/ls.c @@ -129,8 +129,8 @@ print_files_long (const char *filename, const struct grub_dirhook_info *info, /* XXX: For ext2fs symlinks are detected as files while they should be reported as directories. */ - grub_file_filter_disable_compression (); - file = grub_file_open (pathname); + file = grub_file_open (pathname, GRUB_FILE_TYPE_GET_SIZE + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (! file) { grub_errno = 0; @@ -225,8 +225,8 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) struct grub_dirhook_info info; grub_errno = 0; - grub_file_filter_disable_compression (); - file = grub_file_open (dirname); + file = grub_file_open (dirname, GRUB_FILE_TYPE_GET_SIZE + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (! file) goto fail; diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c index a3a118241..6bbce3128 100644 --- a/grub-core/commands/minicmd.c +++ b/grub-core/commands/minicmd.c @@ -43,7 +43,7 @@ grub_mini_cmd_cat (struct grub_command *cmd __attribute__ ((unused)), if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_CAT); if (! file) return grub_errno; @@ -137,6 +137,9 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)), if (! mod) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module"); + if (grub_dl_is_persistent (mod)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module"); + if (grub_dl_unref (mod) <= 0) grub_dl_unload (mod); diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c index 2f56a870e..c278f377b 100644 --- a/grub-core/commands/nativedisk.c +++ b/grub-core/commands/nativedisk.c @@ -242,7 +242,8 @@ grub_cmd_nativedisk (grub_command_t cmd __attribute__ ((unused)), if (! filename) goto fail; - file = grub_file_open (filename); + file = grub_file_open (filename, + GRUB_FILE_TYPE_GRUB_MODULE); grub_free (filename); if (! file) goto fail; diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c index 693e2cb42..22b46b187 100644 --- a/grub-core/commands/parttool.c +++ b/grub-core/commands/parttool.c @@ -193,7 +193,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file; - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); if (file) { char *buf = 0; diff --git a/grub-core/commands/verify.c b/grub-core/commands/pgp.c similarity index 70% rename from grub-core/commands/verify.c rename to grub-core/commands/pgp.c index 67cb1c785..29e74a640 100644 --- a/grub-core/commands/verify.c +++ b/grub-core/commands/pgp.c @@ -30,16 +30,10 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); -struct grub_verified -{ - grub_file_t file; - void *buf; -}; -typedef struct grub_verified *grub_verified_t; - enum { OPTION_SKIP_SIG = 0 @@ -445,23 +439,27 @@ rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, return ret; } +struct grub_pubkey_context +{ + grub_file_t sig; + struct signature_v4_header v4; + grub_uint8_t v; + const gcry_md_spec_t *hash; + void *hash_context; +}; + static grub_err_t -grub_verify_signature_real (char *buf, grub_size_t size, - grub_file_t f, grub_file_t sig, - struct grub_public_key *pkey) +grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig) { grub_size_t len; - grub_uint8_t v; grub_uint8_t h; grub_uint8_t t; grub_uint8_t pk; - const gcry_md_spec_t *hash; - struct signature_v4_header v4; grub_err_t err; - grub_size_t i; - gcry_mpi_t mpis[10]; grub_uint8_t type = 0; + grub_memset (ctxt, 0, sizeof (*ctxt)); + err = read_packet_header (sig, &type, &len); if (err) return err; @@ -469,18 +467,18 @@ grub_verify_signature_real (char *buf, grub_size_t size, if (type != 0x2) return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); - if (grub_file_read (sig, &v, sizeof (v)) != sizeof (v)) + if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v)) return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); - if (v != 4) + if (ctxt->v != 4) return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); - if (grub_file_read (sig, &v4, sizeof (v4)) != sizeof (v4)) + if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4)) return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); - h = v4.hash; - t = v4.type; - pk = v4.pkeyalgo; + h = ctxt->v4.hash; + t = ctxt->v4.type; + pk = ctxt->v4.pkeyalgo; if (t != 0) return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); @@ -491,183 +489,233 @@ grub_verify_signature_real (char *buf, grub_size_t size, if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL) return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); - hash = grub_crypto_lookup_md_by_name (hashes[h]); - if (!hash) + ctxt->hash = grub_crypto_lookup_md_by_name (hashes[h]); + if (!ctxt->hash) return grub_error (GRUB_ERR_BAD_SIGNATURE, "hash `%s' not loaded", hashes[h]); grub_dprintf ("crypt", "alive\n"); - { - void *context = NULL; - unsigned char *hval; - grub_ssize_t rem = grub_be_to_cpu16 (v4.hashed_sub); - grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6); - grub_uint8_t s; - grub_uint16_t unhashed_sub; - grub_ssize_t r; - grub_uint8_t hash_start[2]; - gcry_mpi_t hmpi; - grub_uint64_t keyid = 0; - struct grub_public_subkey *sk; - grub_uint8_t *readbuf = NULL; - - context = grub_zalloc (hash->contextsize); - readbuf = grub_zalloc (READBUF_SIZE); - if (!context || !readbuf) - goto fail; + ctxt->sig = sig; - hash->init (context); - if (buf) - hash->write (context, buf, size); - else - while (1) - { - r = grub_file_read (f, readbuf, READBUF_SIZE); - if (r < 0) - goto fail; - if (r == 0) - break; - hash->write (context, readbuf, r); - } + ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize); + if (!ctxt->hash_context) + return grub_errno; - hash->write (context, &v, sizeof (v)); - hash->write (context, &v4, sizeof (v4)); - while (rem) - { - r = grub_file_read (sig, readbuf, - rem < READBUF_SIZE ? rem : READBUF_SIZE); - if (r < 0) - goto fail; - if (r == 0) - break; - hash->write (context, readbuf, r); - rem -= r; - } - hash->write (context, &v, sizeof (v)); - s = 0xff; - hash->write (context, &s, sizeof (s)); - hash->write (context, &headlen, sizeof (headlen)); - r = grub_file_read (sig, &unhashed_sub, sizeof (unhashed_sub)); - if (r != sizeof (unhashed_sub)) - goto fail; - { - grub_uint8_t *ptr; - grub_uint32_t l; - rem = grub_be_to_cpu16 (unhashed_sub); - if (rem > READBUF_SIZE) - goto fail; - r = grub_file_read (sig, readbuf, rem); - if (r != rem) - goto fail; - for (ptr = readbuf; ptr < readbuf + rem; ptr += l) - { - if (*ptr < 192) - l = *ptr++; - else if (*ptr < 255) - { - if (ptr + 1 >= readbuf + rem) - break; - l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192; - ptr += 2; - } - else - { - if (ptr + 5 >= readbuf + rem) - break; - l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1)); - ptr += 5; - } - if (*ptr == 0x10 && l >= 8) - keyid = grub_get_unaligned64 (ptr + 1); - } - } + ctxt->hash->init (ctxt->hash_context); - hash->final (context); + return GRUB_ERR_NONE; +} - grub_dprintf ("crypt", "alive\n"); +static grub_err_t +grub_pubkey_write (void *ctxt_, void *buf, grub_size_t size) +{ + struct grub_pubkey_context *ctxt = ctxt_; + ctxt->hash->write (ctxt->hash_context, buf, size); + return GRUB_ERR_NONE; +} - hval = hash->read (context); +static grub_err_t +grub_verify_signature_real (struct grub_pubkey_context *ctxt, + struct grub_public_key *pkey) +{ + gcry_mpi_t mpis[10]; + grub_uint8_t pk = ctxt->v4.pkeyalgo; + grub_size_t i; + grub_uint8_t *readbuf = NULL; + unsigned char *hval; + grub_ssize_t rem = grub_be_to_cpu16 (ctxt->v4.hashed_sub); + grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6); + grub_uint8_t s; + grub_uint16_t unhashed_sub; + grub_ssize_t r; + grub_uint8_t hash_start[2]; + gcry_mpi_t hmpi; + grub_uint64_t keyid = 0; + struct grub_public_subkey *sk; + + readbuf = grub_malloc (READBUF_SIZE); + if (!readbuf) + goto fail; - if (grub_file_read (sig, hash_start, sizeof (hash_start)) != sizeof (hash_start)) + ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v)); + ctxt->hash->write (ctxt->hash_context, &ctxt->v4, sizeof (ctxt->v4)); + while (rem) + { + r = grub_file_read (ctxt->sig, readbuf, + rem < READBUF_SIZE ? rem : READBUF_SIZE); + if (r < 0) + goto fail; + if (r == 0) + break; + ctxt->hash->write (ctxt->hash_context, readbuf, r); + rem -= r; + } + ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v)); + s = 0xff; + ctxt->hash->write (ctxt->hash_context, &s, sizeof (s)); + ctxt->hash->write (ctxt->hash_context, &headlen, sizeof (headlen)); + r = grub_file_read (ctxt->sig, &unhashed_sub, sizeof (unhashed_sub)); + if (r != sizeof (unhashed_sub)) + goto fail; + { + grub_uint8_t *ptr; + grub_uint32_t l; + rem = grub_be_to_cpu16 (unhashed_sub); + if (rem > READBUF_SIZE) goto fail; - if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0) + r = grub_file_read (ctxt->sig, readbuf, rem); + if (r != rem) goto fail; + for (ptr = readbuf; ptr < readbuf + rem; ptr += l) + { + if (*ptr < 192) + l = *ptr++; + else if (*ptr < 255) + { + if (ptr + 1 >= readbuf + rem) + break; + l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192; + ptr += 2; + } + else + { + if (ptr + 5 >= readbuf + rem) + break; + l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1)); + ptr += 5; + } + if (*ptr == 0x10 && l >= 8) + keyid = grub_get_unaligned64 (ptr + 1); + } + } - grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (sig)); + ctxt->hash->final (ctxt->hash_context); - for (i = 0; i < pkalgos[pk].nmpisig; i++) - { - grub_uint16_t l; - grub_size_t lb; - grub_dprintf ("crypt", "alive\n"); - if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l)) - goto fail; - grub_dprintf ("crypt", "alive\n"); - lb = (grub_be_to_cpu16 (l) + 7) / 8; - grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l)); - if (lb > READBUF_SIZE - sizeof (grub_uint16_t)) - goto fail; - grub_dprintf ("crypt", "alive\n"); - if (grub_file_read (sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb) - goto fail; - grub_dprintf ("crypt", "alive\n"); - grub_memcpy (readbuf, &l, sizeof (l)); - grub_dprintf ("crypt", "alive\n"); + grub_dprintf ("crypt", "alive\n"); - if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP, - readbuf, lb + sizeof (grub_uint16_t), 0)) - goto fail; - grub_dprintf ("crypt", "alive\n"); - } + hval = ctxt->hash->read (ctxt->hash_context); - if (pkey) - sk = grub_crypto_pk_locate_subkey (keyid, pkey); - else - sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid); - if (!sk) - { - /* TRANSLATORS: %08x is 32-bit key id. */ - grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), - keyid); + if (grub_file_read (ctxt->sig, hash_start, sizeof (hash_start)) != sizeof (hash_start)) + goto fail; + if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0) + goto fail; + + grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (ctxt->sig)); + + for (i = 0; i < pkalgos[pk].nmpisig; i++) + { + grub_uint16_t l; + grub_size_t lb; + grub_dprintf ("crypt", "alive\n"); + if (grub_file_read (ctxt->sig, &l, sizeof (l)) != sizeof (l)) goto fail; - } + grub_dprintf ("crypt", "alive\n"); + lb = (grub_be_to_cpu16 (l) + 7) / 8; + grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l)); + if (lb > READBUF_SIZE - sizeof (grub_uint16_t)) + goto fail; + grub_dprintf ("crypt", "alive\n"); + if (grub_file_read (ctxt->sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb) + goto fail; + grub_dprintf ("crypt", "alive\n"); + grub_memcpy (readbuf, &l, sizeof (l)); + grub_dprintf ("crypt", "alive\n"); + + if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP, + readbuf, lb + sizeof (grub_uint16_t), 0)) + goto fail; + grub_dprintf ("crypt", "alive\n"); + } - if (pkalgos[pk].pad (&hmpi, hval, hash, sk)) + if (pkey) + sk = grub_crypto_pk_locate_subkey (keyid, pkey); + else + sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid); + if (!sk) + { + /* TRANSLATORS: %08x is 32-bit key id. */ + grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), + keyid); goto fail; - if (!*pkalgos[pk].algo) - { - grub_dl_load (pkalgos[pk].module); - grub_errno = GRUB_ERR_NONE; - } + } - if (!*pkalgos[pk].algo) - { - grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"), - pkalgos[pk].module); - goto fail; - } - if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0)) + if (pkalgos[pk].pad (&hmpi, hval, ctxt->hash, sk)) + goto fail; + if (!*pkalgos[pk].algo) + { + grub_dl_load (pkalgos[pk].module); + grub_errno = GRUB_ERR_NONE; + } + + if (!*pkalgos[pk].algo) + { + grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"), + pkalgos[pk].module); goto fail; + } + if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0)) + goto fail; - grub_free (context); - grub_free (readbuf); + grub_free (readbuf); - return GRUB_ERR_NONE; + return GRUB_ERR_NONE; - fail: - grub_free (context); - grub_free (readbuf); - if (!grub_errno) - return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); - return grub_errno; - } + fail: + grub_free (readbuf); + if (!grub_errno) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); + return grub_errno; +} + +static void +grub_pubkey_close_real (struct grub_pubkey_context *ctxt) +{ + if (ctxt->sig) + grub_file_close (ctxt->sig); + if (ctxt->hash_context) + grub_free (ctxt->hash_context); +} + +static void +grub_pubkey_close (void *ctxt) +{ + grub_pubkey_close_real (ctxt); + grub_free (ctxt); } grub_err_t grub_verify_signature (grub_file_t f, grub_file_t sig, struct grub_public_key *pkey) { - return grub_verify_signature_real (0, 0, f, sig, pkey); + grub_err_t err; + struct grub_pubkey_context ctxt; + grub_uint8_t *readbuf = NULL; + + err = grub_verify_signature_init (&ctxt, sig); + if (err) + return err; + + readbuf = grub_zalloc (READBUF_SIZE); + if (!readbuf) + goto fail; + + while (1) + { + grub_ssize_t r; + r = grub_file_read (f, readbuf, READBUF_SIZE); + if (r < 0) + goto fail; + if (r == 0) + break; + err = grub_pubkey_write (&ctxt, readbuf, r); + if (err) + return err; + } + + grub_verify_signature_real (&ctxt, pkey); + fail: + grub_pubkey_close_real (&ctxt); + return grub_errno; } static grub_err_t @@ -680,10 +728,12 @@ grub_cmd_trust (grub_extcmd_context_t ctxt, if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); - grub_file_filter_disable_compression (); - if (ctxt->state[OPTION_SKIP_SIG].set) - grub_file_filter_disable_pubkey (); - pkf = grub_file_open (args[0]); + pkf = grub_file_open (args[0], + GRUB_FILE_TYPE_PUBLIC_KEY_TRUST + | GRUB_FILE_TYPE_NO_DECOMPRESS + | (ctxt->state[OPTION_SKIP_SIG].set + ? GRUB_FILE_TYPE_SKIP_SIGNATURE + : GRUB_FILE_TYPE_NONE)); if (!pkf) return grub_errno; pk = grub_load_public_key (pkf); @@ -771,10 +821,12 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt, if (argc > 2) { grub_file_t pkf; - grub_file_filter_disable_compression (); - if (ctxt->state[OPTION_SKIP_SIG].set) - grub_file_filter_disable_pubkey (); - pkf = grub_file_open (args[2]); + pkf = grub_file_open (args[2], + GRUB_FILE_TYPE_PUBLIC_KEY + | GRUB_FILE_TYPE_NO_DECOMPRESS + | (ctxt->state[OPTION_SKIP_SIG].set + ? GRUB_FILE_TYPE_SKIP_SIGNATURE + : GRUB_FILE_TYPE_NONE)); if (!pkf) return grub_errno; pk = grub_load_public_key (pkf); @@ -786,16 +838,16 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt, grub_file_close (pkf); } - grub_file_filter_disable_all (); - f = grub_file_open (args[0]); + f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE); if (!f) { err = grub_errno; goto fail; } - grub_file_filter_disable_all (); - sig = grub_file_open (args[1]); + sig = grub_file_open (args[1], + GRUB_FILE_TYPE_SIGNATURE + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (!sig) { err = grub_errno; @@ -815,135 +867,52 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt, static int sec = 0; -static void -verified_free (grub_verified_t verified) -{ - if (verified) - { - grub_free (verified->buf); - grub_free (verified); - } -} - -static grub_ssize_t -verified_read (struct grub_file *file, char *buf, grub_size_t len) -{ - grub_verified_t verified = file->data; - - grub_memcpy (buf, (char *) verified->buf + file->offset, len); - return len; -} - static grub_err_t -verified_close (struct grub_file *file) -{ - grub_verified_t verified = file->data; - - grub_file_close (verified->file); - verified_free (verified); - file->data = 0; - - /* device and name are freed by parent */ - file->device = 0; - file->name = 0; - - return grub_errno; -} - -struct grub_fs verified_fs = -{ - .name = "verified_read", - .read = verified_read, - .close = verified_close -}; - -static grub_file_t -grub_pubkey_open (grub_file_t io, const char *filename) +grub_pubkey_init (grub_file_t io, enum grub_file_type type __attribute__ ((unused)), + void **context, enum grub_verify_flags *flags) { grub_file_t sig; char *fsuf, *ptr; grub_err_t err; - grub_file_filter_t curfilt[GRUB_FILE_FILTER_MAX]; - grub_file_t ret; - grub_verified_t verified; + struct grub_pubkey_context *ctxt; if (!sec) - return io; - if (io->device->disk && - (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID - || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID)) - return io; - fsuf = grub_malloc (grub_strlen (filename) + sizeof (".sig")); + { + *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; + return GRUB_ERR_NONE; + } + + fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig")); if (!fsuf) - return NULL; - ptr = grub_stpcpy (fsuf, filename); + return grub_errno; + ptr = grub_stpcpy (fsuf, io->name); grub_memcpy (ptr, ".sig", sizeof (".sig")); - grub_memcpy (curfilt, grub_file_filters_enabled, - sizeof (curfilt)); - grub_file_filter_disable_all (); - sig = grub_file_open (fsuf); - grub_memcpy (grub_file_filters_enabled, curfilt, - sizeof (curfilt)); + sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE); grub_free (fsuf); if (!sig) - return NULL; - - ret = grub_malloc (sizeof (*ret)); - if (!ret) - { - grub_file_close (sig); - return NULL; - } - *ret = *io; + return grub_errno; - ret->fs = &verified_fs; - ret->not_easily_seekable = 0; - if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1)) - { - grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "big file signature isn't implemented yet"); - grub_file_close (sig); - grub_free (ret); - return NULL; - } - verified = grub_malloc (sizeof (*verified)); - if (!verified) + ctxt = grub_malloc (sizeof (*ctxt)); + if (!ctxt) { grub_file_close (sig); - grub_free (ret); - return NULL; - } - verified->buf = grub_malloc (ret->size); - if (!verified->buf) - { - grub_file_close (sig); - grub_free (verified); - grub_free (ret); - return NULL; - } - if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size) - { - if (!grub_errno) - grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), - filename); - grub_file_close (sig); - verified_free (verified); - grub_free (ret); - return NULL; + return grub_errno; } - - err = grub_verify_signature_real (verified->buf, ret->size, 0, sig, NULL); - grub_file_close (sig); + err = grub_verify_signature_init (ctxt, sig); if (err) { - verified_free (verified); - grub_free (ret); - return NULL; + grub_pubkey_close (ctxt); + return err; } - verified->file = io; - ret->data = verified; - return ret; + *context = ctxt; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_pubkey_fini (void *ctxt) +{ + return grub_verify_signature_real (ctxt, NULL); } static char * @@ -967,8 +936,16 @@ struct grub_fs pseudo_fs = { .name = "pseudo", .read = pseudo_read -}; + }; +struct grub_file_verifier grub_pubkey_verifier = + { + .name = "pgp", + .init = grub_pubkey_init, + .fini = grub_pubkey_fini, + .write = grub_pubkey_write, + .close = grub_pubkey_close, + }; static grub_extcmd_t cmd, cmd_trust; static grub_command_t cmd_distrust, cmd_list; @@ -983,8 +960,6 @@ GRUB_MOD_INIT(verify) sec = 1; else sec = 0; - - grub_file_filter_register (GRUB_FILE_FILTER_PUBKEY, grub_pubkey_open); grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec); grub_env_export ("check_signatures"); @@ -1030,11 +1005,13 @@ GRUB_MOD_INIT(verify) cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust, N_("PUBKEY_ID"), N_("Remove PUBKEY_ID from trusted keys.")); + + grub_verifier_register (&grub_pubkey_verifier); } GRUB_MOD_FINI(verify) { - grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY); + grub_verifier_unregister (&grub_pubkey_verifier); grub_unregister_extcmd (cmd); grub_unregister_extcmd (cmd_trust); grub_unregister_command (cmd_list); diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index 7dd32e445..ddda6e7c5 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -81,8 +81,8 @@ iterate_device (const char *name, void *data) if (! buf) return 1; - grub_file_filter_disable_compression (); - file = grub_file_open (buf); + file = grub_file_open (buf, GRUB_FILE_TYPE_FS_SEARCH + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (file) { found = 1; diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c index 5f06642f6..13c6ed953 100644 --- a/grub-core/commands/test.c +++ b/grub-core/commands/test.c @@ -355,8 +355,8 @@ test_parse (char **args, int *argn, int argc) if (grub_strcmp (args[*argn], "-s") == 0) { grub_file_t file; - grub_file_filter_disable_compression (); - file = grub_file_open (args[*argn + 1]); + file = grub_file_open (args[*argn + 1], GRUB_FILE_TYPE_GET_SIZE + | GRUB_FILE_TYPE_NO_DECOMPRESS); update_val (file && (grub_file_size (file) != 0), &ctx); if (file) grub_file_close (file); diff --git a/grub-core/commands/testload.c b/grub-core/commands/testload.c index cfab6763d..ff01a0516 100644 --- a/grub-core/commands/testload.c +++ b/grub-core/commands/testload.c @@ -57,7 +57,7 @@ grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)), if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_TESTLOAD); if (! file) return grub_errno; diff --git a/grub-core/commands/testspeed.c b/grub-core/commands/testspeed.c index 042645f8d..c13a9b8d8 100644 --- a/grub-core/commands/testspeed.c +++ b/grub-core/commands/testspeed.c @@ -61,7 +61,7 @@ grub_cmd_testspeed (grub_extcmd_context_t ctxt, int argc, char **args) if (buffer == NULL) return grub_errno; - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_TESTLOAD); if (file == NULL) goto quit; diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c new file mode 100644 index 000000000..c638d5f43 --- /dev/null +++ b/grub-core/commands/verifiers.c @@ -0,0 +1,228 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + * Verifiers helper. + */ + +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +struct grub_file_verifier *grub_file_verifiers; + +struct grub_verified +{ + grub_file_t file; + void *buf; +}; +typedef struct grub_verified *grub_verified_t; + +static void +verified_free (grub_verified_t verified) +{ + if (verified) + { + grub_free (verified->buf); + grub_free (verified); + } +} + +static grub_ssize_t +verified_read (struct grub_file *file, char *buf, grub_size_t len) +{ + grub_verified_t verified = file->data; + + grub_memcpy (buf, (char *) verified->buf + file->offset, len); + return len; +} + +static grub_err_t +verified_close (struct grub_file *file) +{ + grub_verified_t verified = file->data; + + grub_file_close (verified->file); + verified_free (verified); + file->data = 0; + + /* Device and name are freed by parent. */ + file->device = 0; + file->name = 0; + + return grub_errno; +} + +struct grub_fs verified_fs = +{ + .name = "verified_read", + .read = verified_read, + .close = verified_close +}; + +static grub_file_t +grub_verifiers_open (grub_file_t io, enum grub_file_type type) +{ + grub_verified_t verified = NULL; + struct grub_file_verifier *ver; + void *context; + grub_file_t ret = 0; + grub_err_t err; + int defer = 0; + + grub_dprintf ("verify", "file: %s type: %d\n", io->name, type); + + if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE + || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE + || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE)) + return io; + + if (io->device->disk && + (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID + || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID)) + return io; + + FOR_LIST_ELEMENTS(ver, grub_file_verifiers) + { + enum grub_verify_flags flags = 0; + err = ver->init (io, type, &context, &flags); + if (err) + goto fail_noclose; + if (flags & GRUB_VERIFY_FLAGS_DEFER_AUTH) + { + defer = 1; + continue; + } + if (!(flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION)) + break; + } + + if (!ver) + { + if (defer) + { + grub_error (GRUB_ERR_ACCESS_DENIED, + N_("verification requested but nobody cares: %s"), io->name); + goto fail_noclose; + } + + /* No verifiers wanted to verify. Just return underlying file. */ + return io; + } + + ret = grub_malloc (sizeof (*ret)); + if (!ret) + { + goto fail; + } + *ret = *io; + + ret->fs = &verified_fs; + ret->not_easily_seekable = 0; + if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1)) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("big file signature isn't implemented yet")); + goto fail; + } + verified = grub_malloc (sizeof (*verified)); + if (!verified) + { + goto fail; + } + verified->buf = grub_malloc (ret->size); + if (!verified->buf) + { + goto fail; + } + if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + io->name); + goto fail; + } + + err = ver->write (context, verified->buf, ret->size); + if (err) + goto fail; + + err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE; + if (err) + goto fail; + + if (ver->close) + ver->close (context); + + FOR_LIST_ELEMENTS_NEXT(ver, grub_file_verifiers) + { + enum grub_verify_flags flags = 0; + err = ver->init (io, type, &context, &flags); + if (err) + goto fail_noclose; + if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION || + /* Verification done earlier. So, we are happy here. */ + flags & GRUB_VERIFY_FLAGS_DEFER_AUTH) + continue; + err = ver->write (context, verified->buf, ret->size); + if (err) + goto fail; + + err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE; + if (err) + goto fail; + + if (ver->close) + ver->close (context); + } + + verified->file = io; + ret->data = verified; + return ret; + + fail: + ver->close (context); + fail_noclose: + verified_free (verified); + grub_free (ret); + return NULL; +} + +grub_err_t +grub_verify_string (char *str, enum grub_verify_string_type type) +{ + struct grub_file_verifier *ver; + FOR_LIST_ELEMENTS(ver, grub_file_verifiers) + { + grub_err_t err; + err = ver->verify_string ? ver->verify_string (str, type) : GRUB_ERR_NONE; + if (err) + return err; + } + return GRUB_ERR_NONE; +} + +GRUB_MOD_INIT(verifiers) +{ + grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open); +} + +GRUB_MOD_FINI(verifiers) +{ + grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY); +} diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c index 2d8deaeaf..9406d931c 100644 --- a/grub-core/disk/loopback.c +++ b/grub-core/disk/loopback.c @@ -92,7 +92,8 @@ grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) if (argc < 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); - file = grub_file_open (args[1]); + file = grub_file_open (args[1], GRUB_FILE_TYPE_LOOPBACK + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (! file) return grub_errno; diff --git a/grub-core/efiemu/main.c b/grub-core/efiemu/main.c index f6813b1ed..a81934725 100644 --- a/grub-core/efiemu/main.c +++ b/grub-core/efiemu/main.c @@ -187,7 +187,7 @@ grub_efiemu_load_file (const char *filename) grub_file_t file; grub_err_t err; - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE); if (! file) return grub_errno; diff --git a/grub-core/font/font.c b/grub-core/font/font.c index 53d76a64d..85a292557 100644 --- a/grub-core/font/font.c +++ b/grub-core/font/font.c @@ -418,7 +418,7 @@ grub_font_load (const char *filename) #endif if (filename[0] == '(' || filename[0] == '/' || filename[0] == '+') - file = grub_buffile_open (filename, 1024); + file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024); else { const char *prefix = grub_env_get ("prefix"); @@ -438,7 +438,7 @@ grub_font_load (const char *filename) ptr = grub_stpcpy (ptr, filename); ptr = grub_stpcpy (ptr, ".pf2"); *ptr = 0; - file = grub_buffile_open (fullname, 1024); + file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024); grub_free (fullname); } if (!file) diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c index 87eef621d..1402e0bc2 100644 --- a/grub-core/fs/zfs/zfscrypt.c +++ b/grub-core/fs/zfs/zfscrypt.c @@ -425,7 +425,7 @@ grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args) if (argc > 0) { grub_file_t file; - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY); if (!file) return grub_errno; real_size = grub_file_read (file, buf, 1024); diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c index 4880cefe3..4d02e62c1 100644 --- a/grub-core/gettext/gettext.c +++ b/grub-core/gettext/gettext.c @@ -291,7 +291,7 @@ grub_mofile_open (struct grub_gettext_context *ctx, /* Using fd_mo and not another variable because it's needed for grub_gettext_get_info. */ - fd = grub_file_open (filename); + fd = grub_file_open (filename, GRUB_FILE_TYPE_GETTEXT_CATALOG); if (!fd) return grub_errno; diff --git a/grub-core/gfxmenu/theme_loader.c b/grub-core/gfxmenu/theme_loader.c index 02978392c..d6829bb5e 100644 --- a/grub-core/gfxmenu/theme_loader.c +++ b/grub-core/gfxmenu/theme_loader.c @@ -743,7 +743,7 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) p.view = view; p.theme_dir = grub_get_dirname (theme_path); - file = grub_file_open (theme_path); + file = grub_file_open (theme_path, GRUB_FILE_TYPE_THEME); if (! file) { grub_free (p.theme_dir); diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c index 22438277d..bb5b87662 100644 --- a/grub-core/io/bufio.c +++ b/grub-core/io/bufio.c @@ -43,7 +43,7 @@ typedef struct grub_bufio *grub_bufio_t; static struct grub_fs grub_bufio_fs; grub_file_t -grub_bufio_open (grub_file_t io, int size) +grub_bufio_open (grub_file_t io, grub_size_t size) { grub_file_t file; grub_bufio_t bufio = 0; @@ -57,7 +57,7 @@ grub_bufio_open (grub_file_t io, int size) else if (size > GRUB_BUFIO_MAX_SIZE) size = GRUB_BUFIO_MAX_SIZE; - if ((size < 0) || ((unsigned) size > io->size)) + if (size > io->size) size = ((io->size > GRUB_BUFIO_MAX_SIZE) ? GRUB_BUFIO_MAX_SIZE : io->size); @@ -81,11 +81,11 @@ grub_bufio_open (grub_file_t io, int size) } grub_file_t -grub_buffile_open (const char *name, int size) +grub_buffile_open (const char *name, enum grub_file_type type, grub_size_t size) { grub_file_t io, file; - io = grub_file_open (name); + io = grub_file_open (name, type); if (! io) return 0; diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c index 86ea8cfde..7760d8b97 100644 --- a/grub-core/io/gzio.c +++ b/grub-core/io/gzio.c @@ -1156,11 +1156,14 @@ initialize_tables (grub_gzio_t gzio) even if IO does not contain data compressed by gzip, return a valid file object. Note that this function won't close IO, even if an error occurs. */ static grub_file_t -grub_gzio_open (grub_file_t io, const char *name __attribute__ ((unused))) +grub_gzio_open (grub_file_t io, enum grub_file_type type) { grub_file_t file; grub_gzio_t gzio = 0; + if (type & GRUB_FILE_TYPE_NO_DECOMPRESS) + return io; + file = (grub_file_t) grub_zalloc (sizeof (*file)); if (! file) return 0; diff --git a/grub-core/io/lzopio.c b/grub-core/io/lzopio.c index 7559c6c9c..84edf6dd2 100644 --- a/grub-core/io/lzopio.c +++ b/grub-core/io/lzopio.c @@ -407,12 +407,14 @@ test_header (grub_file_t file) } static grub_file_t -grub_lzopio_open (grub_file_t io, - const char *name __attribute__ ((unused))) +grub_lzopio_open (grub_file_t io, enum grub_file_type type) { grub_file_t file; grub_lzopio_t lzopio; + if (type & GRUB_FILE_TYPE_NO_DECOMPRESS) + return io; + file = (grub_file_t) grub_zalloc (sizeof (*file)); if (!file) return 0; diff --git a/grub-core/io/offset.c b/grub-core/io/offset.c index ebed0ebe6..ec8e23208 100644 --- a/grub-core/io/offset.c +++ b/grub-core/io/offset.c @@ -69,7 +69,8 @@ grub_file_offset_close (grub_file_t file) } grub_file_t -grub_file_offset_open (grub_file_t parent, grub_off_t start, grub_off_t size) +grub_file_offset_open (grub_file_t parent, enum grub_file_type type, + grub_off_t start, grub_off_t size) { struct grub_offset_file *off_data; grub_file_t off_file, last_off_file; @@ -95,10 +96,10 @@ grub_file_offset_open (grub_file_t parent, grub_off_t start, grub_off_t size) last_off_file = NULL; for (filter = GRUB_FILE_FILTER_COMPRESSION_FIRST; off_file && filter <= GRUB_FILE_FILTER_COMPRESSION_LAST; filter++) - if (grub_file_filters_enabled[filter]) + if (grub_file_filters[filter]) { last_off_file = off_file; - off_file = grub_file_filters_enabled[filter] (off_file, parent->name); + off_file = grub_file_filters[filter] (off_file, type); } if (!off_file) diff --git a/grub-core/io/xzio.c b/grub-core/io/xzio.c index a3536ad73..42afeedcd 100644 --- a/grub-core/io/xzio.c +++ b/grub-core/io/xzio.c @@ -169,12 +169,14 @@ test_footer (grub_file_t file) } static grub_file_t -grub_xzio_open (grub_file_t io, - const char *name __attribute__ ((unused))) +grub_xzio_open (grub_file_t io, enum grub_file_type type) { grub_file_t file; grub_xzio_t xzio; + if (type & GRUB_FILE_TYPE_NO_DECOMPRESS) + return io; + file = (grub_file_t) grub_zalloc (sizeof (*file)); if (!file) return 0; diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index e394cd96f..f8d58f029 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -688,7 +688,7 @@ grub_dl_load_file (const char *filename) grub_boot_time ("Loading module %s", filename); - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE); if (! file) return 0; diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 4f282c9cf..9d7149b38 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -136,12 +136,12 @@ grub_elf_file (grub_file_t file, const char *filename) } grub_elf_t -grub_elf_open (const char *name) +grub_elf_open (const char *name, enum grub_file_type type) { grub_file_t file; grub_elf_t elf; - file = grub_file_open (name); + file = grub_file_open (name, type); if (! file) return 0; diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c index 668f8930b..643154237 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c @@ -28,8 +28,7 @@ void (*EXPORT_VAR (grub_grubnet_fini)) (void); -grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX]; -grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX]; +grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX]; /* Get the device part of the filename NAME. It is enclosed by parentheses. */ char * @@ -59,7 +58,7 @@ grub_file_get_device_name (const char *name) } grub_file_t -grub_file_open (const char *name) +grub_file_open (const char *name, enum grub_file_type type) { grub_device_t device = 0; grub_file_t file = 0, last_file = 0; @@ -114,18 +113,20 @@ grub_file_open (const char *name) file->name = grub_strdup (name); grub_errno = GRUB_ERR_NONE; - for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters_enabled); + for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters); filter++) - if (grub_file_filters_enabled[filter]) + if (grub_file_filters[filter]) { last_file = file; - file = grub_file_filters_enabled[filter] (file, name); + file = grub_file_filters[filter] (file, type); + if (file && file != last_file) + { + file->name = grub_strdup (name); + grub_errno = GRUB_ERR_NONE; + } } if (!file) grub_file_close (last_file); - - grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, - sizeof (grub_file_filters_enabled)); return file; @@ -137,9 +138,6 @@ grub_file_open (const char *name) grub_free (file); - grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, - sizeof (grub_file_filters_enabled)); - return 0; } diff --git a/grub-core/kern/tis.c b/grub-core/kern/tis.c new file mode 100644 index 000000000..0dfa0e658 --- /dev/null +++ b/grub-core/kern/tis.c @@ -0,0 +1,279 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2018 Daniel P. Smith, Apertus Solutions, LLC + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + * The code in this file is based on the article "Writing a TPM Device Driver" + * published on http://ptgmedia.pearsoncmg.com. + */ + +#include +#include +#include +#include +#include +#include + +#ifdef __x86_64__ +#define MMIO_BASE 0xFED40000ULL +#else +#define MMIO_BASE 0xFED40000 +#endif + +#define MAX_LOCALITY 4 + +/* macros to access registers at locality ’’l’’ */ +#define ACCESS(l) (0x0000 | ((l) << 12)) +#define STS(l) (0x0018 | ((l) << 12)) +#define DATA_FIFO(l) (0x0024 | ((l) << 12)) +#define DID_VID(l) (0x0F00 | ((l) << 12)) +/* access bits */ +#define ACCESS_ACTIVE_LOCALITY 0x20 /* (R)*/ +#define ACCESS_RELINQUISH_LOCALITY 0x20 /* (W) */ +#define ACCESS_REQUEST_USE 0x02 /* (W) */ +/* status bits */ +#define STS_VALID 0x80 /* (R) */ +#define STS_COMMAND_READY 0x40 /* (R) */ +#define STS_DATA_AVAIL 0x10 /* (R) */ +#define STS_DATA_EXPECT 0x08 /* (R) */ +#define STS_GO 0x20 /* (W) */ + +#define NO_LOCALITY 0xFF + +static grub_uint8_t locality = NO_LOCALITY; + +static grub_uint8_t +grub_read8 (grub_uint32_t field) +{ + void *mmio_addr = (void*)(MMIO_BASE | field); + + return grub_readb(mmio_addr); +} + +static void +grub_write8 (unsigned char val, grub_uint32_t field) +{ + void *mmio_addr = (void*)(MMIO_BASE | field); + + grub_writeb(val, mmio_addr); +} + +static grub_uint32_t +grub_read32 (grub_uint32_t field) +{ + void *mmio_addr = (void*)(MMIO_BASE | field); + + return grub_readl(mmio_addr); +} + +__attribute__((unused)) /* TODO not used yet */ +static void +grub_write32 (unsigned int val, grub_uint32_t field) +{ + void *mmio_addr = (void*)(MMIO_BASE | field); + + grub_writel(val, mmio_addr); +} + +static inline void +grub_io_delay (void) +{ + __asm__ __volatile__ ("outb %al, $0x80"); +} + +static grub_uint32_t +grub_burst_wait (void) +{ + grub_uint32_t count = 0; + + while (count == 0) + { + count = grub_read8 (STS(locality) + 1); + count += grub_read8 (STS(locality) + 2) << 8; + + if (count == 0) + grub_io_delay (); /* wait for FIFO to drain */ + } + + return count; +} + +grub_uint8_t +grub_tis_request_locality (grub_uint8_t l) +{ + grub_write8 (ACCESS_RELINQUISH_LOCALITY, ACCESS(locality)); + grub_write8 (ACCESS_REQUEST_USE, ACCESS(l)); + + /* wait for locality to be granted */ + if (grub_read8 (ACCESS(l) & ACCESS_ACTIVE_LOCALITY)) + { + if (l <= MAX_LOCALITY) + locality = l; + else + locality = NO_LOCALITY; + } + + return locality; +} + +grub_uint8_t +grub_tis_init (void) +{ + grub_uint32_t vendor; + grub_uint8_t i; + + for (i=0; i<=MAX_LOCALITY; i++) + grub_write8 (ACCESS_RELINQUISH_LOCALITY, ACCESS(i)); + + if (grub_tis_request_locality (0) == NO_LOCALITY) + return 0; + + vendor = grub_read32 (DID_VID(0)); + if ((vendor & 0xFFFF) == 0xFFFF) + return 0; + + return 1; +} + +grub_size_t +grub_tis_send (struct grub_tpm_cmd_buf *buf) +{ + grub_uint8_t status, *buf_ptr; + grub_uint32_t burstcnt = 0; + grub_uint32_t count = 0; + + if (locality > MAX_LOCALITY) + return 0; + + grub_write8 (STS_COMMAND_READY, STS(locality)); + + buf_ptr = (grub_uint8_t *) buf; + + /* send all but the last byte */ + while (count < (buf->size - 1)) + { + burstcnt = grub_burst_wait(); + for (; burstcnt > 0 && count < buf->size - 1; burstcnt--) + { + grub_write8 (buf_ptr[count], DATA_FIFO(locality)); + count++; + } + + /* check for overflow */ + for (status = 0; (status & STS_VALID) == 0; ) + status = grub_read8(STS(locality)); + + if ((status & STS_DATA_EXPECT) == 0) + return 0; + } + + /* write last byte */ + grub_write8 (buf_ptr[count], DATA_FIFO(locality)); + + /* make sure it stuck */ + for (status = 0; (status & STS_VALID) == 0; ) + status = grub_read8(STS(locality)); + + if ((status & STS_DATA_EXPECT) != 0) + return 0; + + /* go and do it */ + grub_write8 (STS_GO, STS(locality)); + + return (grub_size_t)count; +} + +static grub_size_t +grub_recv_data (unsigned char *buf, grub_size_t len) +{ + grub_size_t size = 0; + grub_uint8_t status, *bufptr; + grub_uint32_t burstcnt = 0; + + bufptr = (grub_uint8_t *)buf; + + status = grub_read8 (STS(locality)); + while ((status & (STS_DATA_AVAIL | STS_VALID)) + == (STS_DATA_AVAIL | STS_VALID) + && size < len) + { + burstcnt = grub_burst_wait (); + for (; burstcnt > 0 && size < len; burstcnt--) + { + *bufptr = grub_read8 (DATA_FIFO(locality)); + bufptr++; + size++; + } + + status = grub_read8 (STS(locality)); + } + + return size; +} + +grub_size_t +grub_tis_recv (struct grub_tpm_resp_buf *buf) +{ + grub_uint32_t expected; + grub_uint8_t status, *buf_ptr; + grub_size_t size = 0; + + buf_ptr = (grub_uint8_t *)buf; + + /* ensure that there is data available */ + status = grub_read8 (STS(locality)); + if ((status & (STS_DATA_AVAIL | STS_VALID)) + != (STS_DATA_AVAIL | STS_VALID)) + goto err; + + /* read first 6 bytes, including tag and paramsize */ + if ((size = grub_recv_data (buf_ptr, 6)) < 6) + goto err; + + buf_ptr += 6; + + expected = grub_be_to_cpu32 (buf->size); + if (expected > sizeof(struct grub_tpm_resp_buf)) + goto err; + + /* read all data, except last byte */ + if ((size += grub_recv_data (buf_ptr, expected - 7)) + < expected - 1) + goto err; + + buf_ptr += expected - 7; + + /* check for receive underflow */ + status = grub_read8 (STS(locality)); + if ((status & (STS_DATA_AVAIL | STS_VALID)) + != (STS_DATA_AVAIL | STS_VALID)) + goto err; + + /* read last byte */ + if ((size += grub_recv_data (buf_ptr, 1)) != expected) + goto err; + + /* make sure we read everything */ + status = grub_read8 (STS(locality)); + if ((status & (STS_DATA_AVAIL | STS_VALID)) + == (STS_DATA_AVAIL | STS_VALID)) + goto err; + + grub_write8 (STS_COMMAND_READY, STS(locality)); + + return size; +err: + return 0; +} diff --git a/grub-core/kern/tpm.c b/grub-core/kern/tpm.c new file mode 100644 index 000000000..03c1b5fbe --- /dev/null +++ b/grub-core/kern/tpm.c @@ -0,0 +1,52 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2018 Daniel P. Smith, Apertus Solutions, LLC + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + * The code in this file is based on the article "Writing a TPM Device Driver" + * published on http://ptgmedia.pearsoncmg.com. + */ + +#include +#include +#include +#include +#include + +grub_uint8_t +grub_tpm_pcr_extend (struct grub_tpm_digest *d) +{ + grub_size_t bytes; + struct grub_tpm_cmd_buf send; + struct grub_tpm_resp_buf resp; + + send.tag = TPM_TAG_RQU_COMMAND; + send.size = sizeof(struct grub_tpm_extend_cmd) + 6; + send.cmd.extend.ordinal = TPM_ORD_EXTEND; + send.cmd.extend.pcr_num = d->pcr; + grub_memcpy(&(send.cmd.extend.digest), &(d->digest), sizeof(TPM_DIGEST)); + + if (send.size != grub_tis_send(&send)) + return 0; + + bytes = sizeof(struct grub_tpm_extend_resp) + 10; + if (bytes != grub_tis_recv(&resp)) + return 0; + + if (resp.result != TPM_SUCCESS) + return 0; + + return 1; +} diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c index d5e10ee87..ed0b149dc 100644 --- a/grub-core/lib/cmdline.c +++ b/grub-core/lib/cmdline.c @@ -62,12 +62,13 @@ unsigned int grub_loader_cmdline_size (int argc, char *argv[]) return size; } -int grub_create_loader_cmdline (int argc, char *argv[], char *buf, - grub_size_t size) +grub_err_t +grub_create_loader_cmdline (int argc, char *argv[], char *buf, + grub_size_t size, enum grub_verify_string_type type) { int i, space; unsigned int arg_size; - char *c; + char *c, *orig_buf = buf; for (i = 0; i < argc; i++) { @@ -104,5 +105,5 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf, *buf = 0; - return i; + return grub_verify_string (orig_buf, type); } diff --git a/grub-core/lib/syslinux_parse.c b/grub-core/lib/syslinux_parse.c index 28ba3aef0..c96d85ee5 100644 --- a/grub-core/lib/syslinux_parse.c +++ b/grub-core/lib/syslinux_parse.c @@ -696,7 +696,7 @@ syslinux_parse_real (struct syslinux_menu *menu) char *buf = NULL; grub_err_t err = GRUB_ERR_NONE; - file = grub_file_open (menu->filename); + file = grub_file_open (menu->filename, GRUB_FILE_TYPE_CONFIG); if (!file) return grub_errno; while ((grub_free (buf), buf = grub_file_getline (file))) diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c index e64c79a95..9addcb9a8 100644 --- a/grub-core/loader/arm/linux.c +++ b/grub-core/loader/arm/linux.c @@ -28,6 +28,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -399,8 +400,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* Create kernel command line. */ grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); - grub_create_loader_cmdline (argc, argv, - linux_args + sizeof (LINUX_IMAGE) - 1, size); + err = grub_create_loader_cmdline (argc, argv, + linux_args + sizeof (LINUX_IMAGE) - 1, size, + GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; return GRUB_ERR_NONE; diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c index 746edd104..4b1810082 100644 --- a/grub-core/loader/arm64/linux.c +++ b/grub-core/loader/arm64/linux.c @@ -31,6 +31,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -301,9 +302,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); - grub_create_loader_cmdline (argc, argv, - linux_args + sizeof (LINUX_IMAGE) - 1, - cmdline_size); + err = grub_create_loader_cmdline (argc, argv, + linux_args + sizeof (LINUX_IMAGE) - 1, + cmdline_size, + GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; if (grub_errno == GRUB_ERR_NONE) { diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c index adc856366..f706b1ac3 100644 --- a/grub-core/loader/efi/chainloader.c +++ b/grub-core/loader/efi/chainloader.c @@ -219,7 +219,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), b = grub_efi_system_table->boot_services; - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); if (! file) goto fail; diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 7f96515da..c26edb4a9 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef GRUB_MACHINE_PCBIOS #include #endif @@ -416,6 +417,8 @@ grub_freebsd_add_meta_module (const char *filename, const char *type, grub_addr_t addr, grub_uint32_t size) { const char *name; + grub_err_t err; + name = grub_strrchr (filename, '/'); if (name) name++; @@ -469,6 +472,9 @@ grub_freebsd_add_meta_module (const char *filename, const char *type, *(p++) = ' '; } *p = 0; + err = grub_verify_string (cmdline, GRUB_VERIFY_MODULE_CMDLINE); + if (err) + return err; } } @@ -1457,7 +1463,7 @@ grub_bsd_load (int argc, char *argv[]) goto fail; } - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL); if (!file) goto fail; @@ -1534,7 +1540,7 @@ grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) if (err) return err; - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL); if (! file) return grub_errno; @@ -1693,7 +1699,7 @@ grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) { grub_file_t file; - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL); if (! file) return grub_errno; @@ -1802,7 +1808,7 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)), goto fail; } - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_ENV); if ((!file) || (!file->size)) goto fail; @@ -1907,7 +1913,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), return 0; } - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_MODULE); if ((!file) || (!file->size)) goto fail; @@ -1958,7 +1964,7 @@ grub_netbsd_module_load (char *filename, grub_uint32_t type) void *src; grub_err_t err; - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_NETBSD_MODULE); if ((!file) || (!file->size)) goto fail; @@ -2048,7 +2054,7 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), return 0; } - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_MODULE_ELF); if (!file) return grub_errno; if (!file->size) @@ -2088,7 +2094,7 @@ grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)), if (!openbsd_ramdisk.max_size) return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk"); - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_OPENBSD_RAMDISK); if (! file) return grub_errno; diff --git a/grub-core/loader/i386/coreboot/chainloader.c b/grub-core/loader/i386/coreboot/chainloader.c index 2cb78eee0..0a19ebb9c 100644 --- a/grub-core/loader/i386/coreboot/chainloader.c +++ b/grub-core/loader/i386/coreboot/chainloader.c @@ -439,7 +439,7 @@ grub_cmd_chain (grub_command_t cmd __attribute__ ((unused)), grub_loader_unset (); - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_COREBOOT_CHAINLOADER); if (!file) return grub_errno; diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 083f9417c..b0d5e1fe6 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -34,6 +34,7 @@ #include #include #include +#include #include GRUB_MOD_LICENSE ("GPLv3+"); @@ -79,6 +80,8 @@ static grub_efi_uintn_t efi_mmap_size; #else static const grub_size_t efi_mmap_size = 0; #endif +static grub_err_t (*grub_slaunch_func) (struct grub_slaunch_params*) = NULL; +static struct grub_slaunch_params slparams; /* FIXME */ #if 0 @@ -95,6 +98,12 @@ static struct idt_descriptor idt_desc = }; #endif +void +grub_linux_slaunch_set (grub_err_t (*sfunc) (struct grub_slaunch_params*)) +{ + grub_slaunch_func = sfunc; +} + static inline grub_size_t page_align (grub_size_t size) { @@ -654,6 +663,15 @@ grub_linux_boot (void) } #endif + /* If a secondary loader was set for secure launch, call it here. */ + if (grub_slaunch_func) + { + slparams.params = ctx.params; + slparams.real_mode_target = ctx.real_mode_target; + slparams.prot_mode_target = prot_mode_target; + return grub_slaunch_func (&slparams); + } + /* FIXME. */ /* asm volatile ("lidt %0" : : "m" (idt_desc)); */ state.ebp = state.edi = state.ebx = 0; @@ -695,7 +713,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); if (! file) goto fail; @@ -1012,11 +1030,17 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (!linux_cmdline) goto fail; grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); - grub_create_loader_cmdline (argc, argv, - linux_cmdline - + sizeof (LINUX_IMAGE) - 1, - maximal_cmdline_size - - (sizeof (LINUX_IMAGE) - 1)); + { + grub_err_t err; + err = grub_create_loader_cmdline (argc, argv, + linux_cmdline + + sizeof (LINUX_IMAGE) - 1, + maximal_cmdline_size + - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; + } len = prot_file_size; if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index dc98dbcae..ad3cc292f 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -673,10 +673,8 @@ grub_multiboot_init_mbi (int argc, char *argv[]) return grub_errno; cmdline_size = len; - grub_create_loader_cmdline (argc, argv, cmdline, - cmdline_size); - - return GRUB_ERR_NONE; + return grub_create_loader_cmdline (argc, argv, cmdline, + cmdline_size, GRUB_VERIFY_KERNEL_CMDLINE); } grub_err_t @@ -685,6 +683,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size, { struct module *newmod; grub_size_t len = 0; + grub_err_t err; newmod = grub_malloc (sizeof (*newmod)); if (!newmod) @@ -704,8 +703,13 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size, newmod->cmdline_size = len; total_modcmd += ALIGN_UP (len, 4); - grub_create_loader_cmdline (argc, argv, newmod->cmdline, - newmod->cmdline_size); + err = grub_create_loader_cmdline (argc, argv, newmod->cmdline, + newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE); + if (err) + { + grub_free (newmod); + return grub_errno; + } if (modules_last) modules_last->next = newmod; diff --git a/grub-core/loader/i386/pc/chainloader.c b/grub-core/loader/i386/pc/chainloader.c index c79c4fe0f..54d717182 100644 --- a/grub-core/loader/i386/pc/chainloader.c +++ b/grub-core/loader/i386/pc/chainloader.c @@ -156,8 +156,8 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) grub_dl_ref (my_mod); - grub_file_filter_disable_compression (); - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_PCCHAINLOADER + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (! file) goto fail; diff --git a/grub-core/loader/i386/pc/freedos.c b/grub-core/loader/i386/pc/freedos.c index 478f3c513..aac6c9715 100644 --- a/grub-core/loader/i386/pc/freedos.c +++ b/grub-core/loader/i386/pc/freedos.c @@ -110,7 +110,7 @@ grub_cmd_freedos (grub_command_t cmd __attribute__ ((unused)), if (!rel) goto fail; - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEDOS); if (! file) goto fail; diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index a293b17aa..89c6a7436 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -139,7 +139,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); if (! file) goto fail; @@ -334,11 +334,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* Create kernel command line. */ grub_memcpy ((char *)grub_linux_real_chunk + GRUB_LINUX_CL_OFFSET, LINUX_IMAGE, sizeof (LINUX_IMAGE)); - grub_create_loader_cmdline (argc, argv, - (char *)grub_linux_real_chunk - + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1, - maximal_cmdline_size - - (sizeof (LINUX_IMAGE) - 1)); + err = grub_create_loader_cmdline (argc, argv, + (char *)grub_linux_real_chunk + + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1, + maximal_cmdline_size + - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; if (grub_linux_is_bzimage) grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR; diff --git a/grub-core/loader/i386/pc/ntldr.c b/grub-core/loader/i386/pc/ntldr.c index 1b88f40d8..f0d74145b 100644 --- a/grub-core/loader/i386/pc/ntldr.c +++ b/grub-core/loader/i386/pc/ntldr.c @@ -90,7 +90,7 @@ grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), if (!rel) goto fail; - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_NTLDR); if (! file) goto fail; diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c index 814a49d50..37550155d 100644 --- a/grub-core/loader/i386/pc/plan9.c +++ b/grub-core/loader/i386/pc/plan9.c @@ -33,6 +33,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -413,7 +414,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[]) if (!rel) goto fail; - fill_ctx.file = grub_file_open (argv[0]); + fill_ctx.file = grub_file_open (argv[0], GRUB_FILE_TYPE_PLAN9_KERNEL); if (! fill_ctx.file) goto fail; @@ -505,6 +506,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[]) configptr = grub_stpcpy (configptr, "bootfile="); configptr = grub_stpcpy (configptr, bootpath); *configptr++ = '\n'; + char *cmdline = configptr; { int i; for (i = 1; i < argc; i++) @@ -513,6 +515,15 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[]) *configptr++ = '\n'; } } + + { + grub_err_t err; + *configptr = '\0'; + err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; + } + configptr = grub_stpcpy (configptr, fill_ctx.pmap); { diff --git a/grub-core/loader/i386/pc/pxechainloader.c b/grub-core/loader/i386/pc/pxechainloader.c index e60c62b1b..acb061169 100644 --- a/grub-core/loader/i386/pc/pxechainloader.c +++ b/grub-core/loader/i386/pc/pxechainloader.c @@ -99,7 +99,7 @@ grub_cmd_pxechain (grub_command_t cmd __attribute__ ((unused)), if (!rel) goto fail; - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_PXECHAINLOADER); if (! file) goto fail; diff --git a/grub-core/loader/i386/pc/truecrypt.c b/grub-core/loader/i386/pc/truecrypt.c index 9ea4fde42..cbeeec7be 100644 --- a/grub-core/loader/i386/pc/truecrypt.c +++ b/grub-core/loader/i386/pc/truecrypt.c @@ -99,7 +99,7 @@ grub_cmd_truecrypt (grub_command_t cmd __attribute__ ((unused)), grub_dl_ref (my_mod); - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_TRUECRYPT); if (! file) goto fail; diff --git a/grub-core/loader/i386/slaunch.c b/grub-core/loader/i386/slaunch.c new file mode 100644 index 000000000..ba2a5fc19 --- /dev/null +++ b/grub-core/loader/i386/slaunch.c @@ -0,0 +1,224 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE("GPLv3+"); + +static grub_dl_t my_mod; +static struct grub_slaunch_module *modules = NULL, *modules_last = NULL; +static struct grub_relocator *relocator = NULL; + +struct grub_slaunch_module* +grub_slaunch_get_modules( void) +{ + return modules; +} + +static grub_err_t +grub_slaunch_add_module (void *addr, grub_addr_t target, grub_size_t size) +{ + struct grub_slaunch_module *newmod; + + newmod = grub_malloc (sizeof (*newmod)); + if (!newmod) + return grub_errno; + newmod->addr = (grub_uint8_t*)addr; + newmod->target = target; + newmod->size = size; + newmod->next = 0; + + if (modules_last) + modules_last->next = newmod; + else + modules = newmod; + modules_last = newmod; + + return GRUB_ERR_NONE; +} + +static void +grub_slaunch_free (void) +{ + struct grub_slaunch_module *cur, *next; + + for (cur = modules; cur; cur = next) + { + next = cur->next; + grub_free (cur); + } + modules = NULL; + modules_last = NULL; + + grub_relocator_unload (relocator); + relocator = NULL; +} + +static grub_err_t +grub_cmd_slaunch (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_uint32_t manufacturer[3]; + grub_uint32_t eax, edx, ebx, ecx; + grub_uint64_t msr_value; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("argument expected")); + + /* Should be executing on the BSP */ + msr_value = grub_rdmsr (GRUB_MSR_X86_APICBASE); + if (! (msr_value & GRUB_MSR_X86_APICBASE_BSP)) + return grub_error (GRUB_ERR_BAD_DEVICE, N_("secure launch must run on BSP")); + + if (! grub_cpu_is_cpuid_supported ()) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("CPUID not supported")); + + grub_cpuid (0, eax, manufacturer[0], manufacturer[2], manufacturer[1]); + + if (grub_memcmp (argv[0], "txt", 3) == 0) + { + if (grub_memcmp (manufacturer, "GenuineIntel", 12) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Intel platform required for TXT")); + + grub_cpuid(GRUB_X86_CPUID_FEATURES, eax, ebx, ecx, edx); + if (! (ecx & GRUB_VMX_CPUID_FEATURE) || ! (ecx & GRUB_SMX_CPUID_FEATURE) ) + return grub_error (GRUB_ERR_BAD_DEVICE, + N_("CPU does not support Intel TXT")); + + msr_value = grub_rdmsr (GRUB_MSR_X86_FEATURE_CONTROL); + if (! (msr_value & GRUB_MSR_X86_ENABLE_VMX_IN_SMX)) + return grub_error (GRUB_ERR_BAD_DEVICE, + N_("Intel TXT is not enabled")); + + grub_linux_slaunch_set (grub_slaunch_boot_txt); + } + else if (grub_memcmp (argv[0], "skinit", 6) == 0) + { + if (grub_memcmp (manufacturer, "AuthenticAMD", 12) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("AMD platform required for SKINIT")); + + grub_cpuid (GRUB_AMD_CPUID_FEATURES, eax, ebx, ecx, edx); + if (! (ecx & GRUB_SVM_CPUID_FEATURE) ) + return grub_error (GRUB_ERR_BAD_DEVICE, N_("CPU does not support AMD SVM")); + + /* Check whether SVM feature is disabled in BIOS */ + msr_value = grub_rdmsr (GRUB_MSR_AMD64_VM_CR); + if (msr_value & GRUB_MSR_SVM_VM_CR_SVM_DISABLE) + return grub_error (GRUB_ERR_BAD_DEVICE, "BIOS has AMD SVM disabled"); + + grub_linux_slaunch_set (grub_slaunch_boot_skinit); + } + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument")); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file; + grub_ssize_t size; + grub_err_t err; + grub_relocator_chunk_t ch; + void *addr = NULL; + grub_addr_t target; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + if (! relocator) + { + relocator = grub_relocator_new (); + if (! relocator) + return grub_errno; + } + + file = grub_file_open (argv[0], GRUB_FILE_TYPE_SLAUNCH_MODULE); + if (! file) + return grub_errno; + + size = grub_file_size (file); + if (size == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("file size is zero")); + + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0x4000000, (0xffffffff - size) + 1, + size, 0x1000, + GRUB_RELOCATOR_PREFERENCE_NONE, 1); + if (err) + { + grub_file_close (file); + return err; + } + + addr = get_virtual_current_address (ch); + target = get_physical_target_address (ch); + + err = grub_slaunch_add_module (addr, target, size); + if (err) + { + grub_file_close (file); + return err; + } + + + if (grub_file_read (file, addr, size) != size) + { + grub_file_close (file); + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[0]); + return grub_errno; + } + + grub_file_close (file); + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_slaunch, cmd_slaunch_module; + +GRUB_MOD_INIT(slaunch) +{ + cmd_slaunch = + grub_register_command ("slaunch", grub_cmd_slaunch, + 0, N_("Launch Secure Loader")); + cmd_slaunch_module = + grub_register_command ("slaunch_module", grub_cmd_slaunch_module, + 0, N_("Secure Loader module command")); + my_mod = mod; +} + +GRUB_MOD_FINI(slaunch) +{ + grub_slaunch_free (); + grub_unregister_command (cmd_slaunch_module); + grub_unregister_command (cmd_slaunch); +} diff --git a/grub-core/loader/i386/slaunch_skinit.c b/grub-core/loader/i386/slaunch_skinit.c new file mode 100644 index 000000000..3c3f00f2b --- /dev/null +++ b/grub-core/loader/i386/slaunch_skinit.c @@ -0,0 +1,34 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +grub_err_t +grub_slaunch_boot_skinit (struct grub_slaunch_params *slparams) +{ + slparams = slparams; + + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/i386/slaunch_txt.c b/grub-core/loader/i386/slaunch_txt.c new file mode 100644 index 000000000..26fdd5306 --- /dev/null +++ b/grub-core/loader/i386/slaunch_txt.c @@ -0,0 +1,35 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +grub_err_t +grub_slaunch_boot_txt (struct grub_slaunch_params *slparams) +{ + slparams = slparams; + + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c index 3073f64d5..1a99ca72c 100644 --- a/grub-core/loader/i386/xen.c +++ b/grub-core/loader/i386/xen.c @@ -40,6 +40,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -647,8 +648,11 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), grub_create_loader_cmdline (argc - 1, argv + 1, (char *) xen_state.next_start.cmd_line, sizeof (xen_state.next_start.cmd_line) - 1); + err = grub_verify_string (xen_state.next_start.cmd_line, GRUB_VERIFY_MODULE_CMDLINE); + if (err) + return err; - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); if (!file) return grub_errno; @@ -893,9 +897,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), xen_state.max_addr = ALIGN_UP (xen_state.max_addr, PAGE_SIZE); - if (nounzip) - grub_file_filter_disable_compression (); - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_INITRD | + (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE)); if (!file) return grub_errno; size = grub_file_size (file); @@ -909,6 +912,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), grub_create_loader_cmdline (argc - 1, argv + 1, get_virtual_current_address (ch), cmdline_len); + err = grub_verify_string (get_virtual_current_address (ch), GRUB_VERIFY_MODULE_CMDLINE); + if (err) + goto fail; xen_state.module_info_page[xen_state.n_modules].cmdline = xen_state.max_addr - xen_state.modules_target_start; diff --git a/grub-core/loader/i386/xen_file.c b/grub-core/loader/i386/xen_file.c index 99fad4cad..52b75fad8 100644 --- a/grub-core/loader/i386/xen_file.c +++ b/grub-core/loader/i386/xen_file.c @@ -78,7 +78,7 @@ grub_xen_file (grub_file_t file) Trim it. */ if (grub_memcmp (magic, XZ_MAGIC, sizeof (XZ_MAGIC) - 1) == 0) payload_length -= 4; - off_file = grub_file_offset_open (file, payload_offset, + off_file = grub_file_offset_open (file, GRUB_FILE_TYPE_LINUX_KERNEL, payload_offset, payload_length); if (!off_file) goto fail; diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index 59ef73a73..e64ed08f5 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -487,7 +487,7 @@ grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)), if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_XNU_DEVPROP); if (! file) return grub_errno; size = grub_file_size (file); diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c index 750330d45..e325fe0ee 100644 --- a/grub-core/loader/ia64/efi/linux.c +++ b/grub-core/loader/ia64/efi/linux.c @@ -33,6 +33,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -543,6 +544,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), p = grub_stpcpy (p, argv[i]); } cmdline[10] = '='; + + *p = '\0'; + + err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; boot_param->command_line = (grub_uint64_t) cmdline; boot_param->efi_systab = (grub_uint64_t) grub_efi_system_table; diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c index be6fa0f4d..471b214d6 100644 --- a/grub-core/loader/linux.c +++ b/grub-core/loader/linux.c @@ -173,7 +173,6 @@ grub_initrd_init (int argc, char *argv[], eptr = grub_strchr (ptr, ':'); if (eptr) { - grub_file_filter_disable_compression (); initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr); if (!initrd_ctx->components[i].newc_name) { @@ -198,8 +197,9 @@ grub_initrd_init (int argc, char *argv[], root = 0; newc = 0; } - grub_file_filter_disable_compression (); - initrd_ctx->components[i].file = grub_file_open (fname); + initrd_ctx->components[i].file = grub_file_open (fname, + GRUB_FILE_TYPE_LINUX_INITRD + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (!initrd_ctx->components[i].file) { grub_initrd_close (initrd_ctx); diff --git a/grub-core/loader/macho.c b/grub-core/loader/macho.c index 59b195e27..085f9c689 100644 --- a/grub-core/loader/macho.c +++ b/grub-core/loader/macho.c @@ -188,12 +188,12 @@ grub_macho_file (grub_file_t file, const char *filename, int is_64bit) } grub_macho_t -grub_macho_open (const char *name, int is_64bit) +grub_macho_open (const char *name, enum grub_file_type type, int is_64bit) { grub_file_t file; grub_macho_t macho; - file = grub_file_open (name); + file = grub_file_open (name, type); if (! file) return 0; diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c index 5f383be3d..e256c440f 100644 --- a/grub-core/loader/mips/linux.c +++ b/grub-core/loader/mips/linux.c @@ -237,7 +237,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); - elf = grub_elf_open (argv[0]); + elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); if (! elf) return grub_errno; @@ -327,6 +327,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), linux_argv++; linux_args += ALIGN_UP (sizeof ("a0"), 4); + char *params = linux_args; + #ifdef GRUB_MACHINE_MIPS_LOONGSON { unsigned mtype = grub_arch_machine; @@ -352,6 +354,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); } + *linux_args = '\0'; + + err = grub_verify_string (params, GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + return err; + /* Reserve space for rd arguments. */ rd_addr_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground; linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 40c67e824..4a98d7082 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -321,7 +321,7 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_MULTIBOOT_KERNEL); if (! file) return grub_errno; @@ -387,10 +387,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); - if (nounzip) - grub_file_filter_disable_compression (); - - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_MULTIBOOT_MODULE + | (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE)); if (! file) return grub_errno; diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 4df659595..97ff6e324 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -1074,10 +1074,8 @@ grub_multiboot2_init_mbi (int argc, char *argv[]) return grub_errno; cmdline_size = len; - grub_create_loader_cmdline (argc, argv, cmdline, - cmdline_size); - - return GRUB_ERR_NONE; + return grub_create_loader_cmdline (argc, argv, cmdline, cmdline_size, + GRUB_VERIFY_KERNEL_CMDLINE); } grub_err_t @@ -1086,6 +1084,7 @@ grub_multiboot2_add_module (grub_addr_t start, grub_size_t size, { struct module *newmod; grub_size_t len = 0; + grub_err_t err; newmod = grub_malloc (sizeof (*newmod)); if (!newmod) @@ -1104,8 +1103,10 @@ grub_multiboot2_add_module (grub_addr_t start, grub_size_t size, newmod->cmdline_size = len; total_modcmd += ALIGN_UP (len, MULTIBOOT_TAG_ALIGN); - grub_create_loader_cmdline (argc, argv, newmod->cmdline, - newmod->cmdline_size); + err = grub_create_loader_cmdline (argc, argv, newmod->cmdline, + newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE); + if (err) + return err; if (modules_last) modules_last->next = newmod; diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c index 6e814649f..c114e7df4 100644 --- a/grub-core/loader/powerpc/ieee1275/linux.c +++ b/grub-core/loader/powerpc/ieee1275/linux.c @@ -302,8 +302,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* Create kernel command line. */ grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); - grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, - size); + if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, + size)) + goto out; out: diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c index 67ef04883..abe46faa0 100644 --- a/grub-core/loader/sparc64/ieee1275/linux.c +++ b/grub-core/loader/sparc64/ieee1275/linux.c @@ -340,8 +340,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* Create kernel command line. */ grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); - grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, - size); + if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, + size, GRUB_VERIFY_KERNEL_CMDLINE)) + goto out; out: if (elf) diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c index c9885b1bc..ff66be4bf 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -33,6 +33,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -351,7 +352,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), grub_xnu_unload (); - macho = grub_macho_open (args[0], 0); + macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 0); if (! macho) return grub_errno; @@ -425,6 +426,10 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), if (ptr != grub_xnu_cmdline) *(ptr - 1) = 0; + err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + return err; + #if defined (__i386) && !defined (GRUB_MACHINE_EFI) err = grub_efiemu_autocore (); if (err) @@ -456,7 +461,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), grub_xnu_unload (); - macho = grub_macho_open (args[0], 1); + macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 1); if (! macho) return grub_errno; @@ -534,6 +539,10 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), if (ptr != grub_xnu_cmdline) *(ptr - 1) = 0; + err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + return err; + #if defined (__i386) && !defined (GRUB_MACHINE_EFI) err = grub_efiemu_autocore (); if (err) @@ -674,7 +683,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile, macho = 0; if (infoplistname) - infoplist = grub_file_open (infoplistname); + infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST); else infoplist = 0; grub_errno = GRUB_ERR_NONE; @@ -771,7 +780,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first")); - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_MKEXT); if (! file) return grub_errno; @@ -885,7 +894,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first")); - file = grub_file_open (args[0]); + file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_RAMDISK); if (! file) return grub_errno; @@ -925,7 +934,7 @@ grub_xnu_check_os_bundle_required (char *plistname, if (binname) *binname = 0; - file = grub_file_open (plistname); + file = grub_file_open (plistname, GRUB_FILE_TYPE_XNU_INFO_PLIST); if (! file) return 0; @@ -1210,7 +1219,7 @@ grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired, grub_strcpy (binname + grub_strlen (binname), "/"); grub_strcpy (binname + grub_strlen (binname), binsuffix); grub_dprintf ("xnu", "%s:%s\n", ctx.plistname, binname); - binfile = grub_file_open (binname); + binfile = grub_file_open (binname, GRUB_FILE_TYPE_XNU_KEXT); if (! binfile) grub_errno = GRUB_ERR_NONE; @@ -1253,7 +1262,7 @@ grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)), /* User explicitly specified plist and binary. */ if (grub_strcmp (args[1], "-") != 0) { - binfile = grub_file_open (args[1]); + binfile = grub_file_open (args[1], GRUB_FILE_TYPE_XNU_KEXT); if (! binfile) return grub_errno; } diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c index 534a74438..8089804d4 100644 --- a/grub-core/loader/xnu_resume.c +++ b/grub-core/loader/xnu_resume.c @@ -53,8 +53,8 @@ grub_xnu_resume (char *imagename) grub_addr_t target_image; grub_err_t err; - grub_file_filter_disable_compression (); - file = grub_file_open (imagename); + file = grub_file_open (imagename, GRUB_FILE_TYPE_XNU_HIBERNATE_IMAGE + | GRUB_FILE_TYPE_NO_DECOMPRESS); if (! file) return 0; diff --git a/grub-core/normal/autofs.c b/grub-core/normal/autofs.c index 721b9c325..7a7cf2b0f 100644 --- a/grub-core/normal/autofs.c +++ b/grub-core/normal/autofs.c @@ -33,12 +33,6 @@ autoload_fs_module (void) { grub_named_list_t p; int ret = 0; - grub_file_filter_t grub_file_filters_was[GRUB_FILE_FILTER_MAX]; - - grub_memcpy (grub_file_filters_was, grub_file_filters_enabled, - sizeof (grub_file_filters_enabled)); - grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, - sizeof (grub_file_filters_enabled)); while ((p = fs_module_list) != NULL) { @@ -56,9 +50,6 @@ autoload_fs_module (void) grub_free (p); } - grub_memcpy (grub_file_filters_enabled, grub_file_filters_was, - sizeof (grub_file_filters_enabled)); - return ret; } @@ -82,7 +73,7 @@ read_fs_list (const char *prefix) tmp_autoload_hook = grub_fs_autoload_hook; grub_fs_autoload_hook = NULL; - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); if (file) { /* Override previous fs.lst. */ diff --git a/grub-core/normal/crypto.c b/grub-core/normal/crypto.c index e6d345f33..d01e6f271 100644 --- a/grub-core/normal/crypto.c +++ b/grub-core/normal/crypto.c @@ -94,7 +94,7 @@ read_crypto_list (const char *prefix) return; } - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); grub_free (filename); if (!file) { diff --git a/grub-core/normal/dyncmd.c b/grub-core/normal/dyncmd.c index 169c126f5..719ebf477 100644 --- a/grub-core/normal/dyncmd.c +++ b/grub-core/normal/dyncmd.c @@ -106,7 +106,7 @@ read_command_list (const char *prefix) { grub_file_t file; - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); if (file) { char *buf = NULL; diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index 78a70a8bf..1b03dfd57 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -123,7 +123,7 @@ read_config_file (const char *config) } /* Try to open the config file. */ - rawfile = grub_file_open (config); + rawfile = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); if (! rawfile) return 0; diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c index ac5d69f0f..a1e5c5a0d 100644 --- a/grub-core/normal/term.c +++ b/grub-core/normal/term.c @@ -331,7 +331,7 @@ read_terminal_list (const char *prefix) return; } - file = grub_file_open (filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); grub_free (filename); if (!file) { diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c index 21b0d9ded..31359a4c9 100644 --- a/grub-core/video/readers/jpeg.c +++ b/grub-core/video/readers/jpeg.c @@ -772,7 +772,7 @@ grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, grub_file_t file; struct grub_jpeg_data *data; - file = grub_buffile_open (filename, 0); + file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0); if (!file) return grub_errno; diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c index e1a01e99f..777e71334 100644 --- a/grub-core/video/readers/png.c +++ b/grub-core/video/readers/png.c @@ -1086,7 +1086,7 @@ grub_video_reader_png (struct grub_video_bitmap **bitmap, grub_file_t file; struct grub_png_data *data; - file = grub_buffile_open (filename, 0); + file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0); if (!file) return grub_errno; diff --git a/grub-core/video/readers/tga.c b/grub-core/video/readers/tga.c index c7a16fa9c..7cb9d1d2a 100644 --- a/grub-core/video/readers/tga.c +++ b/grub-core/video/readers/tga.c @@ -297,7 +297,7 @@ grub_video_reader_tga (struct grub_video_bitmap **bitmap, grub_memset (&data, 0, sizeof (data)); - data.file = grub_buffile_open (filename, 0); + data.file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0); if (! data.file) return grub_errno; diff --git a/include/grub/bufio.h b/include/grub/bufio.h index acdd0c882..0ff72d103 100644 --- a/include/grub/bufio.h +++ b/include/grub/bufio.h @@ -22,7 +22,9 @@ #include -grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, int size); -grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, int size); +grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, grub_size_t size); +grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, + enum grub_file_type type, + grub_size_t size); #endif /* ! GRUB_BUFIO_H */ diff --git a/include/grub/dl.h b/include/grub/dl.h index 2bca56ce0..fee27a14c 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -175,6 +175,7 @@ struct grub_dl { char *name; int ref_count; + int persistent; grub_dl_dep_t dep; grub_dl_segment_t segment; Elf_Sym *symtab; @@ -240,6 +241,18 @@ grub_dl_get (const char *name) return 0; } +static inline void +grub_dl_set_persistent (grub_dl_t mod) +{ + mod->persistent = 1; +} + +static inline int +grub_dl_is_persistent (grub_dl_t mod) +{ + return mod->persistent; +} + #endif grub_err_t grub_dl_register_symbol (const char *name, void *addr, diff --git a/include/grub/elfload.h b/include/grub/elfload.h index 9a7ae4ebb..dbb609c9b 100644 --- a/include/grub/elfload.h +++ b/include/grub/elfload.h @@ -42,7 +42,7 @@ typedef int (*grub_elf32_phdr_iterate_hook_t) typedef int (*grub_elf64_phdr_iterate_hook_t) (grub_elf_t elf, Elf64_Phdr *phdr, void *arg); -grub_elf_t grub_elf_open (const char *); +grub_elf_t grub_elf_open (const char *, enum grub_file_type type); grub_elf_t grub_elf_file (grub_file_t file, const char *filename); grub_err_t grub_elf_close (grub_elf_t); diff --git a/include/grub/file.h b/include/grub/file.h index 739488cbe..c0a0c08ec 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -25,6 +25,112 @@ #include #include +enum grub_file_type + { + GRUB_FILE_TYPE_NONE = 0, + /* GRUB module to be loaded. */ + GRUB_FILE_TYPE_GRUB_MODULE, + /* Loopback file to be represented as disk. */ + GRUB_FILE_TYPE_LOOPBACK, + /* Linux kernel to be loaded. */ + GRUB_FILE_TYPE_LINUX_KERNEL, + /* Linux initrd. */ + GRUB_FILE_TYPE_LINUX_INITRD, + + /* Multiboot kernel. */ + GRUB_FILE_TYPE_MULTIBOOT_KERNEL, + /* Multiboot module. */ + GRUB_FILE_TYPE_MULTIBOOT_MODULE, + + GRUB_FILE_TYPE_BSD_KERNEL, + GRUB_FILE_TYPE_FREEBSD_ENV, + GRUB_FILE_TYPE_FREEBSD_MODULE, + GRUB_FILE_TYPE_FREEBSD_MODULE_ELF, + GRUB_FILE_TYPE_NETBSD_MODULE, + GRUB_FILE_TYPE_OPENBSD_RAMDISK, + + GRUB_FILE_TYPE_XNU_INFO_PLIST, + GRUB_FILE_TYPE_XNU_MKEXT, + GRUB_FILE_TYPE_XNU_KEXT, + GRUB_FILE_TYPE_XNU_KERNEL, + GRUB_FILE_TYPE_XNU_RAMDISK, + GRUB_FILE_TYPE_XNU_HIBERNATE_IMAGE, + GRUB_FILE_XNU_DEVPROP, + + GRUB_FILE_TYPE_PLAN9_KERNEL, + + GRUB_FILE_TYPE_NTLDR, + GRUB_FILE_TYPE_TRUECRYPT, + GRUB_FILE_TYPE_FREEDOS, + GRUB_FILE_TYPE_PXECHAINLOADER, + GRUB_FILE_TYPE_PCCHAINLOADER, + + GRUB_FILE_TYPE_COREBOOT_CHAINLOADER, + + GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE, + + /* File holding signature. */ + GRUB_FILE_TYPE_SIGNATURE, + /* File holding public key to verify signature once. */ + GRUB_FILE_TYPE_PUBLIC_KEY, + /* File holding public key to add to trused keys. */ + GRUB_FILE_TYPE_PUBLIC_KEY_TRUST, + /* File of which we intend to print a blocklist to the user. */ + GRUB_FILE_TYPE_PRINT_BLOCKLIST, + /* File we intend to use for test loading or testing speed. */ + GRUB_FILE_TYPE_TESTLOAD, + /* File we open only to get its size. E.g. in ls output. */ + GRUB_FILE_TYPE_GET_SIZE, + /* Font file. */ + GRUB_FILE_TYPE_FONT, + /* File holding encryption key for encrypted ZFS. */ + GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY, + /* File we open n grub-fstest. */ + GRUB_FILE_TYPE_FSTEST, + /* File we open n grub-mount. */ + GRUB_FILE_TYPE_MOUNT, + /* File which we attempt to identify the type of. */ + GRUB_FILE_TYPE_FILE_ID, + /* File holding ACPI table. */ + GRUB_FILE_TYPE_ACPI_TABLE, + /* File we intend show to user. */ + GRUB_FILE_TYPE_CAT, + GRUB_FILE_TYPE_HEXCAT, + /* One of pair of files we intend to compare. */ + GRUB_FILE_TYPE_CMP, + /* List of hashes for hashsum. */ + GRUB_FILE_TYPE_HASHLIST, + /* File hashed by hashsum. */ + GRUB_FILE_TYPE_TO_HASH, + /* Keyboard layout. */ + GRUB_FILE_TYPE_KEYBOARD_LAYOUT, + /* Picture file. */ + GRUB_FILE_TYPE_PIXMAP, + /* *.lst shipped by GRUB. */ + GRUB_FILE_TYPE_GRUB_MODULE_LIST, + /* config file. */ + GRUB_FILE_TYPE_CONFIG, + GRUB_FILE_TYPE_THEME, + GRUB_FILE_TYPE_GETTEXT_CATALOG, + GRUB_FILE_TYPE_FS_SEARCH, + GRUB_FILE_TYPE_AUDIO, + GRUB_FILE_TYPE_VBE_DUMP, + + GRUB_FILE_TYPE_LOADENV, + GRUB_FILE_TYPE_SAVEENV, + + GRUB_FILE_TYPE_VERIFY_SIGNATURE, + + /* Secure Launch module. */ + GRUB_FILE_TYPE_SLAUNCH_MODULE, + + GRUB_FILE_TYPE_MASK = 0xffff, + + /* --skip-sig is specified. */ + GRUB_FILE_TYPE_SKIP_SIGNATURE = 0x10000, + GRUB_FILE_TYPE_NO_DECOMPRESS = 0x20000 + }; + /* File description. */ struct grub_file { @@ -68,7 +174,7 @@ extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook); /* Filters with lower ID are executed first. */ typedef enum grub_file_filter_id { - GRUB_FILE_FILTER_PUBKEY, + GRUB_FILE_FILTER_VERIFY, GRUB_FILE_FILTER_GZIO, GRUB_FILE_FILTER_XZIO, GRUB_FILE_FILTER_LZOPIO, @@ -77,61 +183,26 @@ typedef enum grub_file_filter_id GRUB_FILE_FILTER_COMPRESSION_LAST = GRUB_FILE_FILTER_LZOPIO, } grub_file_filter_id_t; -typedef grub_file_t (*grub_file_filter_t) (grub_file_t in, const char *filename); +typedef grub_file_t (*grub_file_filter_t) (grub_file_t in, enum grub_file_type type); -extern grub_file_filter_t EXPORT_VAR(grub_file_filters_all)[GRUB_FILE_FILTER_MAX]; -extern grub_file_filter_t EXPORT_VAR(grub_file_filters_enabled)[GRUB_FILE_FILTER_MAX]; +extern grub_file_filter_t EXPORT_VAR(grub_file_filters)[GRUB_FILE_FILTER_MAX]; static inline void grub_file_filter_register (grub_file_filter_id_t id, grub_file_filter_t filter) { - grub_file_filters_all[id] = filter; - grub_file_filters_enabled[id] = filter; + grub_file_filters[id] = filter; } static inline void grub_file_filter_unregister (grub_file_filter_id_t id) { - grub_file_filters_all[id] = 0; - grub_file_filters_enabled[id] = 0; -} - -static inline void -grub_file_filter_disable (grub_file_filter_id_t id) -{ - grub_file_filters_enabled[id] = 0; -} - -static inline void -grub_file_filter_disable_compression (void) -{ - grub_file_filter_id_t id; - - for (id = GRUB_FILE_FILTER_COMPRESSION_FIRST; - id <= GRUB_FILE_FILTER_COMPRESSION_LAST; id++) - grub_file_filters_enabled[id] = 0; -} - -static inline void -grub_file_filter_disable_all (void) -{ - grub_file_filter_id_t id; - - for (id = 0; - id < GRUB_FILE_FILTER_MAX; id++) - grub_file_filters_enabled[id] = 0; -} - -static inline void -grub_file_filter_disable_pubkey (void) -{ - grub_file_filters_enabled[GRUB_FILE_FILTER_PUBKEY] = 0; + grub_file_filters[id] = 0; } /* Get a device name from NAME. */ char *EXPORT_FUNC(grub_file_get_device_name) (const char *name); -grub_file_t EXPORT_FUNC(grub_file_open) (const char *name); +grub_file_t EXPORT_FUNC(grub_file_open) (const char *name, enum grub_file_type type); grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf, grub_size_t len); grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset); @@ -159,8 +230,8 @@ grub_file_seekable (const grub_file_t file) } grub_file_t -grub_file_offset_open (grub_file_t parent, grub_off_t start, - grub_off_t size); +grub_file_offset_open (grub_file_t parent, enum grub_file_type type, + grub_off_t start, grub_off_t size); void grub_file_offset_close (grub_file_t file); diff --git a/include/grub/i386/cpuid.h b/include/grub/i386/cpuid.h index f7ae4b0a4..8176e5d11 100644 --- a/include/grub/i386/cpuid.h +++ b/include/grub/i386/cpuid.h @@ -19,6 +19,19 @@ #ifndef GRUB_CPU_CPUID_HEADER #define GRUB_CPU_CPUID_HEADER 1 +/* General */ +#define GRUB_X86_CPUID_VENDOR 0x00000000 +#define GRUB_X86_CPUID_FEATURES 0x00000001 + +/* Intel */ +#define GRUB_VMX_CPUID_FEATURE (1<<5) +#define GRUB_SMX_CPUID_FEATURE (1<<6) + +/* AMD */ +#define GRUB_AMD_CPUID_FEATURES 0x80000001 +#define GRUB_SVM_CPUID_FEATURE (1<<2) +#define GRUB_AMD_CPUID_FUNC 0x8000000a + extern unsigned char grub_cpuid_has_longmode; extern unsigned char grub_cpuid_has_pae; diff --git a/include/grub/i386/mmio.h b/include/grub/i386/mmio.h new file mode 100644 index 000000000..6a4c4946a --- /dev/null +++ b/include/grub/i386/mmio.h @@ -0,0 +1,105 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MMIO_H +#define GRUB_MMIO_H 1 + +#include + +#define grub_mb() __asm__ __volatile__ ("mfence" : : : "memory") +#define grub_rmb() __asm__ __volatile__ ("lfence" : : : "memory") +#define grub_wmb() __asm__ __volatile__ ("sfence" : : : "memory") +#define grub_barrier() __asm__ __volatile__ ("" : : : "memory") + +static __inline grub_uint8_t +grub_readb (void *addr) +{ + grub_uint8_t _v; + + grub_barrier(); + _v = (*(volatile grub_uint8_t*)(addr)); + grub_rmb(); + return _v; +} + +static __inline grub_uint16_t +grub_readw (void *addr) +{ + grub_uint16_t _v; + + grub_barrier(); + _v = (*(volatile grub_uint16_t*)(addr)); + grub_rmb(); + return _v; +} + +static __inline grub_uint32_t +grub_readl (void *addr) +{ + grub_uint32_t _v; + + grub_barrier(); + _v = (*(volatile grub_uint32_t*)(addr)); + grub_rmb(); + return _v; +} + +static __inline grub_uint64_t +grub_readq (void *addr) +{ + grub_uint64_t _v; + + grub_barrier(); + _v = (*(volatile grub_uint64_t*)(addr)); + grub_rmb(); + return _v; +} + +static __inline void +grub_writeb (grub_uint8_t value, void *addr) +{ + grub_wmb(); + (*(volatile grub_uint8_t *)(addr)) = value; + grub_barrier(); +} + +static __inline void +grub_writew (grub_uint16_t value, void *addr) +{ + grub_wmb(); + (*(volatile grub_uint16_t *)(addr)) = value; + grub_barrier(); +} + +static __inline void +grub_writel (grub_uint32_t value, void *addr) +{ + grub_wmb(); + (*(volatile grub_uint32_t *)(addr)) = value; + grub_barrier(); +} + +static __inline void +grub_writeq (grub_uint64_t value, void *addr) +{ + grub_wmb(); + (*(volatile grub_uint64_t *)(addr)) = value; + grub_barrier(); +} + +#endif diff --git a/include/grub/i386/msr.h b/include/grub/i386/msr.h new file mode 100644 index 000000000..a0c5d39e7 --- /dev/null +++ b/include/grub/i386/msr.h @@ -0,0 +1,82 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * + * The definitions in this header are extracted from the Trusted Computing + * Group's "TPM Main Specification", Parts 1-3. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_X86_MSR_H +#define GRUB_X86_MSR_H 1 + +/* General */ + +#define GRUB_MSR_X86_APICBASE 0x0000001b +#define GRUB_MSR_X86_APICBASE_BSP (1<<8) +#define GRUB_MSR_X86_APICBASE_ENABLE (1<<11) +#define GRUB_MSR_X86_APICBASE_BASE (0xfffff<<12) + +#define GRUB_MSR_X86_FEATURE_CONTROL 0x0000003a +#define GRUB_MSR_X86_ENABLE_VMX_IN_SMX (1<<1) + +#define GRUB_MSR_X86_MCG_CAP 0x00000179 +#define GRUB_MSR_MCG_BANKCNT_MASK 0xff /* Number of banks */ +#define GRUB_MSR_X86_MCG_STATUS 0x0000017a +#define GRUB_MSR_MCG_STATUS_MCIP (1ULL<<2) /* MC in progress */ + +#define GRUB_MSR_X86_MC0_STATUS 0x00000401 + +#define GRUB_MSR_X86_EFER 0xc0000080 /* Extended features */ +#define GRUB_MSR_EFER_SVME (1<<12) /* Enable virtualization */ + +/* AMD Specific */ + +#define GRUB_MSR_AMD64_PATCH_LEVEL 0x0000008b +#define GRUB_MSR_AMD64_PATCH_CLEAR 0xc0010021 /* AMD-specific microcode + patch clear */ +#define GRUB_MSR_AMD64_VM_CR 0xc0010114 +#define GRUB_MSR_SVM_VM_CR_SVM_DISABLE 4 + +static inline grub_uint64_t +grub_rdmsr(grub_uint32_t msr) +{ + grub_uint64_t val = 0; + +#ifdef __x86_64__ + asm volatile("rdmsr" : "=A" (val) : "c" (msr)); +#else + grub_uint32_t low, high; + asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); + val = ((low) | (grub_uint64_t)(high) << 32); +#endif + + return val; +} + +static inline void +grub_wrmsr(grub_uint32_t msr, grub_uint64_t val) +{ +#ifdef __x86_64__ + asm volatile("wrmsr" : "=A" (val) : "c" (msr)); +#else + grub_uint32_t low, high; + high = (grub_uint32_t) ((val & 0xFFFFFFFF00000000LL) >> 32); + low = (grub_uint32_t) (val & 0xFFFFFFFFLL); + asm volatile("wrmsr" : "=a" (low), "=d" (high) : "c" (msr)); +#endif +} + +#endif diff --git a/include/grub/i386/txt.h b/include/grub/i386/txt.h new file mode 100644 index 000000000..b9a392197 --- /dev/null +++ b/include/grub/i386/txt.h @@ -0,0 +1,475 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + * Intel TXT definitions header file. + */ + +#ifndef GRUB_TXT_H +#define GRUB_TXT_H 1 + +#include +#include + +/* Intel TXT Software Developers Guide */ + +/* Appendix A TXT Execution Technology Authenticated Code Modules */ +/* A.1 Authenticated Code Module Format */ + +#define GRUB_TXT_ACM_MODULE_TYPE 2 + +#define GRUB_TXT_ACM_MODULE_SUB_TYPE_TXT_ACM 0 +#define GRUB_TXT_ACM_MODULE_SUB_TYPE_S_ACM 1 + +#define GRUB_TXT_ACM_HEADER_LEN_0_0 161 +#define GRUB_TXT_ACM_HEADER_LEN_3_0 224 + +#define GRUB_TXT_ACM_HEADER_VERSION_0_0 0x0000 +#define GRUB_TXT_ACM_HEADER_VERSION_3_0 0x0300 + +#define GRUB_TXT_ACM_FLAG_PREPRODUCTION (1<<14) +#define GRUB_TXT_ACM_FLAG_DEBUG_SIGNED (1<<15) + +#define GRUB_TXT_ACM_MODULE_VENDOR_INTEL 0x00008086 + +struct grub_txt_acm_header +{ + grub_uint16_t module_type; + grub_uint16_t module_sub_type; + grub_uint32_t header_len; + grub_uint32_t header_version; + grub_uint16_t chipset_id; + grub_uint16_t flags; + grub_uint32_t module_vendor; + grub_uint32_t date; /* e.g 20131231H == December 31, 2013 */ + grub_uint32_t size; /* multiples of 4 bytes */ + grub_uint16_t txt_svn; + grub_uint16_t se_svn; + grub_uint32_t code_control; + grub_uint32_t error_entry_point; + grub_uint32_t gdt_limit; + grub_uint32_t gdt_base; + grub_uint32_t seg_sel; + grub_uint32_t entry_point; + grub_uint8_t reserved2[64]; + grub_uint32_t key_size; + grub_uint32_t scratch_size; + /* RSA Pub Key and Signature */ +} GRUB_PACKED; + +/* Appendix B SMX Interaction with Platform */ +/* B.1 Intel Trusted Execution Technology Configuration Registers */ + +#ifdef __x86_64__ +#define GRUB_TXT_PUB_CONFIG_REGS 0xfed30000ULL +#define GRUB_TXT_PRIV_CONFIG_REGS 0xfed20000ULL +#else +#define GRUB_TXT_PUB_CONFIG_REGS 0xfed30000 +#define GRUB_TXT_PRIV_CONFIG_REGS 0xfed20000 +#endif + +#define GRUB_TXT_STS 0x0000 +#define GRUB_TXT_ESTS 0x0008 +#define GRUB_TXT_ERRORCODE 0x0030 +#define GRUB_TXT_CMD_RESET 0x0038 +#define GRUB_TXT_CMD_CLOSE_PRIVATE 0x0048 +#define GRUB_TXT_VER_FSBIF 0x0100 +#define GRUB_TXT_DIDVID 0x0110 +#define GRUB_TXT_VER_QPIIF 0x0200 +#define GRUB_TXT_CMD_UNLOCK_MEM_CONFIG 0x0218 +#define GRUB_TXT_SINIT_BASE 0x0270 +#define GRUB_TXT_SINIT_SIZE 0x0278 +#define GRUB_TXT_MLE_JOIN 0x0290 +#define GRUB_TXT_HEAP_BASE 0x0300 +#define GRUB_TXT_HEAP_SIZE 0x0308 +#define GRUB_TXT_MSEG_BASE 0x0310 +#define GRUB_TXT_MSEG_SIZE 0x0318 +#define GRUB_TXT_DPR 0x0330 +#define GRUB_TXT_CMD_OPEN_LOCALITY1 0x0380 +#define GRUB_TXT_CMD_CLOSE_LOCALITY1 0x0388 +#define GRUB_TXT_CMD_OPEN_LOCALITY2 0x0390 +#define GRUB_TXT_CMD_CLOSE_LOCALITY2 0x0398 +#define GRUB_TXT_PUBLIC_KEY 0x0400 +#define GRUB_TXT_CMD_SECRETS 0x08e0 +#define GRUB_TXT_CMD_NO_SECRETS 0x08e8 +#define GRUB_TXT_E2STS 0x08f0 + +/* Appendix C Intel TXT Heap Memory */ + +/* Ext Data Structs */ + +struct grub_txt_heap_uuid +{ + grub_uint32_t data1; + grub_uint16_t data2; + grub_uint16_t data3; + grub_uint16_t data4; + grub_uint8_t data5[6]; +} GRUB_PACKED; + +struct grub_txt_heap_ext_data_element +{ + grub_uint32_t type; + grub_uint32_t size; + /* Data */ +} GRUB_PACKED; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_END 0 + +struct grub_txt_heap_end_element +{ + grub_uint32_t type; + grub_uint32_t size; +} GRUB_PACKED; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1 + +struct grub_txt_heap_bios_spec_ver_element +{ + grub_uint16_t spec_ver_major; + grub_uint16_t spec_ver_minor; + grub_uint16_t spec_ver_revision; +} HEAP_BIOS_SPEC_VER_ELEMENT; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_ACM 2 + +struct grub_txt_heap_acm_element +{ + grub_uint32_t num_acms; + /* Array of num_acms grub_uint64_t addresses */ +} GRUB_PACKED; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_STM 3 + +struct grub_txt_heap_stm_element +{ + /* STM specific BIOS properties */ +} GRUB_PACKED; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_CUSTOM 4 + +struct grub_txt_heap_custom_element +{ + struct grub_txt_heap_uuid uuid; + /* Vendor Data */ +} GRUB_PACKED; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR 5 + +struct grub_txt_heap_event_log_element +{ + grub_uint64_t event_log_phys_addr; +} GRUB_PACKED; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_MADT 6 + +struct grub_txt_heap_madt_element +{ + /* Copy of ACPI MADT table */ +} GRUB_PACKED; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 8 + +struct grub_txt_heap_event_log_pointer2_1_element +{ + grub_uint64_t phys_addr; + grub_uint32_t allocated_event_container_size; + grub_uint32_t first_record_offset; + grub_uint32_t next_record_offset; +} GRUB_PACKED; + +#define GRUB_TXT_HEAP_EXTDATA_TYPE_MCFG 8 + +struct grub_txt_heap_mcfg_element +{ + /* Copy of ACPI MCFG table */ +} GRUB_PACKED; + +/* TXT Heap Tables */ + +struct grub_txt_bios_data +{ + grub_uint32_t version; /* Currently 5 for TPM 1.2 and 6 for TPM 2.0 */ + grub_uint32_t bios_sinit_size; + grub_uint64_t reserved1; + grub_uint64_t reserved22; + grub_uint32_t num_logical_procs; + /* Versions >= 5 with updates in version 6 */ + grub_uint32_t sinit_flags; + grub_uint32_t mle_flags; + /* Versions >= 4 */ + /* Ext Data Elements */ +} GRUB_PACKED; + +#define GRUB_TXT_MAX_EVENT_LOG_SIZE 5*4*1024 /* 4k*5 */ + +struct grub_txt_os_mle_data +{ + grub_uint32_t zero_page_addr; + grub_uint8_t event_log_buffer[GRUB_TXT_MAX_EVENT_LOG_SIZE]; +} GRUB_PACKED; + +struct grub_txt_os_sinit_data +{ + grub_uint32_t version; /* Currently 6 for TPM 1.2 and 7 for TPM 2.0 */ + grub_uint32_t flags; + grub_uint64_t mle_ptab; + grub_uint64_t mle_size; + grub_uint64_t mle_hdr_base; + grub_uint64_t vtd_pmr_lo_base; + grub_uint64_t vtd_pmr_lo_size; + grub_uint64_t vtd_pmr_hi_base; + grub_uint64_t vtd_pmr_hi_size; + grub_uint64_t lcp_po_base; + grub_uint64_t lcp_po_size; + grub_uint32_t capabilities; + /* Version = 5 */ + grub_uint64_t efi_rsdt_ptr; + /* Versions >= 6 */ + /* Ext Data Elements */ +} GRUB_PACKED; + +struct grub_txt_sinit_mle_data +{ + grub_uint32_t version; /* Current values are 6 through 9 */ + /* Versions <= 8 */ + grub_uint8_t bios_acm_id[20]; + grub_uint32_t edx_senter_flags; + grub_uint64_t mseg_valid; + grub_uint8_t sinit_hash[20]; + grub_uint8_t mle_hash[20]; + grub_uint8_t stm_hash[20]; + grub_uint8_t lcp_policy_hash[20]; + grub_uint32_t lcp_policy_control; + /* Versions >= 7 */ + grub_uint32_t rlp_wakeup_addr; + grub_uint32_t reserved; + grub_uint32_t num_of_sinit_mdrs; + grub_uint32_t sinit_mdrs_table_offset; + grub_uint32_t sinit_vtd_dmar_table_size; + grub_uint32_t sinit_vtd_dmar_table_offset; + /* Versions >= 8 */ + grub_uint32_t processor_scrtm_status; + /* Versions >= 9 */ + /* Ext Data Elements */ +} GRUB_PACKED; + +struct grub_txt_sinit_memory_descriptor_records +{ + grub_uint64_t address; + grub_uint64_t length; + grub_uint8_t type; + grub_uint8_t reserved[7]; +} GRUB_PACKED; + +/* Section 2 Measured Launch Environment */ +/* 2.1 MLE Architecture Overview */ +/* Table 1. MLE Header structure */ + +struct grub_txt_mle_header +{ + grub_uint8_t uuid[16]; + grub_uint32_t header_len; + grub_uint32_t version; + grub_uint32_t entry_point; + grub_uint32_t first_valid_page; + grub_uint32_t mle_start; + grub_uint32_t mle_end; + grub_uint32_t capabilities; + grub_uint32_t cmdline_start; + grub_uint32_t cmdline_end; +} GRUB_PACKED; + +/* TXT register and heap access */ + +static inline grub_uint64_t +grub_txt_read_reg (grub_uint32_t reg, grub_uint8_t read_public) +{ + grub_uint8_t *addr = (grub_uint8_t*)(read_public ? GRUB_TXT_PUB_CONFIG_REGS : + GRUB_TXT_PRIV_CONFIG_REGS); + return grub_readq(addr + reg); +} + +static inline void +grub_txt_write_reg (grub_uint32_t reg, grub_uint64_t val, grub_uint8_t read_public) +{ + grub_uint8_t *addr = (grub_uint8_t*)(read_public ? GRUB_TXT_PUB_CONFIG_REGS : + GRUB_TXT_PRIV_CONFIG_REGS); + grub_writeq(val, addr + reg); +} + +static inline grub_uint8_t* +grub_txt_get_heap (void) +{ +#ifdef __x86_64__ + return (grub_uint8_t*)grub_txt_read_reg (GRUB_TXT_HEAP_BASE, 1); +#else + return (grub_uint8_t*)(grub_uint32_t)grub_txt_read_reg (GRUB_TXT_HEAP_BASE, 1); +#endif +} + +static inline grub_uint64_t +grub_txt_bios_data_size (grub_uint8_t *heap) +{ + return *(grub_uint64_t *)heap; +} + +static inline struct grub_txt_bios_data* +grub_txt_bios_data_start (grub_uint8_t *heap) +{ + return (struct grub_txt_bios_data*)(heap + sizeof (grub_uint64_t)); +} + +static inline grub_uint64_t +grub_txt_os_mle_data_size (grub_uint8_t *heap) +{ + return *(grub_uint64_t *)(heap + grub_txt_bios_data_size (heap)); +} + +static inline struct grub_txt_os_mle_data* +grub_txt_os_mle_data_start (grub_uint8_t *heap) +{ + return (struct grub_txt_os_mle_data*)(heap + grub_txt_bios_data_size (heap) + + sizeof (grub_uint64_t)); +} + +static inline grub_uint64_t +grub_txt_os_sinit_data_size (grub_uint8_t *heap) +{ + return *(grub_uint64_t *)(heap + grub_txt_bios_data_size (heap) + + grub_txt_os_mle_data_size (heap)); +} + +static inline struct grub_txt_os_sinit_data * +grub_txt_os_sinit_data_start (grub_uint8_t *heap) +{ + return (struct grub_txt_os_sinit_data*)(heap + + grub_txt_bios_data_size (heap) + + grub_txt_os_mle_data_size (heap) + sizeof (grub_uint64_t)); +} + +static inline grub_uint64_t +grub_txt_sinit_mle_data_size (grub_uint8_t *heap) +{ + return *(grub_uint64_t *)(heap + grub_txt_bios_data_size (heap) + + grub_txt_os_mle_data_size (heap) + + grub_txt_os_sinit_data_size (heap)); +} + +static inline struct grub_txt_sinit_mle_data* +grub_txt_sinit_mle_data_start (grub_uint8_t *heap) +{ + return (struct grub_txt_sinit_mle_data*)(heap + + grub_txt_bios_data_size (heap) + + grub_txt_os_mle_data_size (heap) + + grub_txt_os_sinit_data_size (heap) + + sizeof (grub_uint64_t)); +} + +/* Intel 64 and IA-32 Architectures Software Developer’s Manual */ +/* Volume 2 (2A, 2B, 2C & 2D): Instruction Set Reference, A-Z */ + +/* CHAPTER 6 SAFER MODE EXTENSIONS REFERENCE */ + +#define GRUB_SMX_LEAF_CAPABILITIES 0 +#define GRUB_SMX_LEAF_UNDEFINED 1 +#define GRUB_SMX_LEAF_ENTERACCS 2 +#define GRUB_SMX_LEAF_EXITAC 3 +#define GRUB_SMX_LEAF_SENTER 4 +#define GRUB_SMX_LEAF_SEXIT 5 +#define GRUB_SMX_LEAF_PARAMETERS 6 +#define GRUB_SMX_LEAF_SMCTRL 7 +#define GRUB_SMX_LEAF_WAKEUP 8 + +#define GRUB_SMX_CAPABILITY_CHIPSET_PRESENT (1<<0) +#define GRUB_SMX_CAPABILITY_UNDEFINED (1<<1) +#define GRUB_SMX_CAPABILITY_ENTERACCS (1<<2) +#define GRUB_SMX_CAPABILITY_EXITAC (1<<3) +#define GRUB_SMX_CAPABILITY_SENTER (1<<4) +#define GRUB_SMX_CAPABILITY_SEXIT (1<<5) +#define GRUB_SMX_CAPABILITY_PARAMETERS (1<<6) +#define GRUB_SMX_CAPABILITY_SMCTRL (1<<7) +#define GRUB_SMX_CAPABILITY_WAKEUP (1<<8) +#define GRUB_SMX_CAPABILITY_EXTENDED_LEAFS (1<<31) + +static inline grub_uint32_t +grub_txt_getsec_capabilities (grub_uint32_t index) +{ + grub_uint32_t caps; + + __asm__ __volatile__ (".byte 0x0f,0x37\n" + : "=a" (caps) + : "a" (GRUB_SMX_LEAF_CAPABILITIES), "b" (index)); + return caps; +} + +static inline void +grub_txt_getsec_enteraccs (grub_uint32_t acm_phys_addr, grub_uint32_t acm_size) +{ + __asm__ __volatile__ (".byte 0x0f,0x37\n" : + : "a" (GRUB_SMX_LEAF_ENTERACCS), + "b" (acm_phys_addr), "c" (acm_size)); +} + +static inline void +grub_txt_getsec_exitac (grub_uint32_t near_jump) +{ + __asm__ __volatile__ (".byte 0x0f,0x37\n" : + : "a" (GRUB_SMX_LEAF_EXITAC), "b" (near_jump)); +} + +static inline void +grub_txt_getsec_senter (grub_uint32_t acm_phys_addr, grub_uint32_t acm_size) +{ + __asm__ __volatile__ (".byte 0x0f,0x37\n" : + : "a" (GRUB_SMX_LEAF_SENTER), + "b" (acm_phys_addr), "c" (acm_size)); +} + +static inline void +grub_txt_getsec_sexit (void) +{ + __asm__ __volatile__ (".byte 0x0f,0x37\n" : : "a" (GRUB_SMX_LEAF_SEXIT)); +} + +#define GRUB_SMX_PARAMETER_TYPE_MASK 0x1f + +static inline void +grub_txt_getsec_parameters (grub_uint32_t index, grub_uint32_t *eax_out, + grub_uint32_t *ebx_out, grub_uint32_t *ecx_out) +{ + if (!eax_out || !ebx_out || !ecx_out) + return; + + __asm__ __volatile__ (".byte 0x0f,0x37\n" + : "=a" (*eax_out), "=b" (*ebx_out), "=c" (*ecx_out) + : "a" (GRUB_SMX_LEAF_PARAMETERS), "b" (index)); +} + +static inline void +grub_txt_getsec_smctrl (void) +{ + __asm__ __volatile__ (".byte 0x0f,0x37\n" : + : "a" (GRUB_SMX_LEAF_SMCTRL), "b" (0)); +} + +static inline void +grub_txt_getsec_wakeup (void) +{ + __asm__ __volatile__ (".byte 0x0f,0x37\n" : : "a" (GRUB_SMX_LEAF_WAKEUP)); +} + +#endif diff --git a/include/grub/lib/cmdline.h b/include/grub/lib/cmdline.h index 1fe8d0179..cdca09b7a 100644 --- a/include/grub/lib/cmdline.h +++ b/include/grub/lib/cmdline.h @@ -21,11 +21,12 @@ #define GRUB_CMDLINE_HEADER 1 #include +#include #define LINUX_IMAGE "BOOT_IMAGE=" unsigned int grub_loader_cmdline_size (int argc, char *argv[]); -int grub_create_loader_cmdline (int argc, char *argv[], char *buf, - grub_size_t size); +grub_err_t grub_create_loader_cmdline (int argc, char *argv[], char *buf, + grub_size_t size, enum grub_verify_string_type type); #endif /* ! GRUB_CMDLINE_HEADER */ diff --git a/include/grub/list.h b/include/grub/list.h index d170ff6da..b13acb962 100644 --- a/include/grub/list.h +++ b/include/grub/list.h @@ -35,6 +35,7 @@ void EXPORT_FUNC(grub_list_push) (grub_list_t *head, grub_list_t item); void EXPORT_FUNC(grub_list_remove) (grub_list_t item); #define FOR_LIST_ELEMENTS(var, list) for ((var) = (list); (var); (var) = (var)->next) +#define FOR_LIST_ELEMENTS_NEXT(var, list) for ((var) = (var)->next; (var); (var) = (var)->next) #define FOR_LIST_ELEMENTS_SAFE(var, nxt, list) for ((var) = (list), (nxt) = ((var) ? (var)->next : 0); (var); (var) = (nxt), ((nxt) = (var) ? (var)->next : 0)) static inline void * diff --git a/include/grub/machoload.h b/include/grub/machoload.h index 1eec118f1..f1157f410 100644 --- a/include/grub/machoload.h +++ b/include/grub/machoload.h @@ -49,7 +49,8 @@ struct grub_macho_file }; typedef struct grub_macho_file *grub_macho_t; -grub_macho_t grub_macho_open (const char *, int is_64bit); +grub_macho_t grub_macho_open (const char *, enum grub_file_type type, + int is_64bit); grub_macho_t grub_macho_file (grub_file_t file, const char *filename, int is_64bit); grub_err_t grub_macho_close (grub_macho_t); diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h new file mode 100644 index 000000000..9d10926a1 --- /dev/null +++ b/include/grub/slaunch.h @@ -0,0 +1,60 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + * Main secure launch definitions header file. + */ + +#ifndef GRUB_SLAUNCH_H +#define GRUB_SLAUNCH_H 1 + +#include +#include + +#define GRUB_SL_BOOTPARAMS_OFFSET 0x12c + +struct grub_slaunch_info +{ + grub_uint32_t sl_version; + grub_uint32_t sl_entry; /* Field updated by boot build tool */ + grub_uint32_t sl_mle_hdr; /* Field updated by boot build tool */ + grub_uint32_t sl_flags; + grub_uint32_t sl_dev_map; +} GRUB_PACKED; + +struct grub_slaunch_params +{ + struct linux_kernel_params *params; + grub_addr_t real_mode_target; + grub_addr_t prot_mode_target; +}; + +struct grub_slaunch_module +{ + struct grub_slaunch_module *next; + grub_uint8_t *addr; + grub_addr_t target; + grub_size_t size; +}; + +struct grub_slaunch_module *grub_slaunch_get_modules (void); + +grub_err_t grub_slaunch_boot_txt (struct grub_slaunch_params *slparams); +grub_err_t grub_slaunch_boot_skinit (struct grub_slaunch_params *slparams); + +void grub_linux_slaunch_set (grub_err_t (*sfunc) (struct grub_slaunch_params*)); + +#endif diff --git a/include/grub/tis.h b/include/grub/tis.h new file mode 100644 index 000000000..d25548ef1 --- /dev/null +++ b/include/grub/tis.h @@ -0,0 +1,156 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2018 Daniel P. Smith, Apertus Solutions, LLC + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + * The definitions in this header are extracted from the Trusted Computing + * Group's "TPM Main Specification", Parts 1-3. + */ + +#ifndef GRUB_TIS_H +#define GRUB_TIS_H 1 + +#include + +/* Section 2.2.3 */ +#define TPM_AUTH_DATA_USAGE grub_uint8_t +#define TPM_PAYLOAD_TYPE grub_uint8_t +#define TPM_VERSION_BYTE grub_uint8_t +#define TPM_TAG grub_uint16_t +#define TPM_PROTOCOL_ID grub_uint16_t +#define TPM_STARTUP_TYPE grub_uint16_t +#define TPM_ENC_SCHEME grub_uint16_t +#define TPM_SIG_SCHEME grub_uint16_t +#define TPM_MIGRATE_SCHEME grub_uint16_t +#define TPM_PHYSICAL_PRESENCE grub_uint16_t +#define TPM_ENTITY_TYPE grub_uint16_t +#define TPM_KEY_USAGE grub_uint16_t +#define TPM_EK_TYPE grub_uint16_t +#define TPM_STRUCTURE_TAG grub_uint16_t +#define TPM_PLATFORM_SPECIFIC grub_uint16_t +#define TPM_COMMAND_CODE grub_uint32_t +#define TPM_CAPABILITY_AREA grub_uint32_t +#define TPM_KEY_FLAGS grub_uint32_t +#define TPM_ALGORITHM_ID grub_uint32_t +#define TPM_MODIFIER_INDICATOR grub_uint32_t +#define TPM_ACTUAL_COUNT grub_uint32_t +#define TPM_TRANSPORT_ATTRIBUTES grub_uint32_t +#define TPM_AUTHHANDLE grub_uint32_t +#define TPM_DIRINDEX grub_uint32_t +#define TPM_KEY_HANDLE grub_uint32_t +#define TPM_PCRINDEX grub_uint32_t +#define TPM_RESULT grub_uint32_t +#define TPM_RESOURCE_TYPE grub_uint32_t +#define TPM_KEY_CONTROL grub_uint32_t +#define TPM_NV_INDEX grub_uint32_t The +#define TPM_FAMILY_ID grub_uint32_t +#define TPM_FAMILY_VERIFICATION grub_uint32_t +#define TPM_STARTUP_EFFECTS grub_uint32_t +#define TPM_SYM_MODE grub_uint32_t +#define TPM_FAMILY_FLAGS grub_uint32_t +#define TPM_DELEGATE_INDEX grub_uint32_t +#define TPM_CMK_DELEGATE grub_uint32_t +#define TPM_COUNT_ID grub_uint32_t +#define TPM_REDIT_COMMAND grub_uint32_t +#define TPM_TRANSHANDLE grub_uint32_t +#define TPM_HANDLE grub_uint32_t +#define TPM_FAMILY_OPERATION grub_uint32_t + +/* Section 6 */ +#define TPM_TAG_RQU_COMMAND 0x00C1 +#define TPM_TAG_RQU_AUTH1_COMMAND 0x00C2 +#define TPM_TAG_RQU_AUTH2_COMMAND 0x00C3 +#define TPM_TAG_RSP_COMMAND 0x00C4 +#define TPM_TAG_RSP_AUTH1_COMMAND 0x00C5 +#define TPM_TAG_RSP_AUTH2_COMMAND 0x00C6 + +/* Section 16 */ +#define TPM_SUCCESS 0x0 + +/* Section 17 */ +#define TPM_ORD_EXTEND 0x00000014 + +#define SHA1_DIGEST_SIZE 20 + +/* Section 5.4 */ +struct grub_tpm_sha1_digest +{ + grub_uint8_t digest[SHA1_DIGEST_SIZE]; +}; + +struct grub_tpm_digest +{ + TPM_PCRINDEX pcr; + union + { + struct grub_tpm_sha1_digest sha1; + } digest; +}; + +#define TPM_DIGEST struct grub_tpm_digest +#define TPM_CHOSENID_HASH TPM_DIGEST +#define TPM_COMPOSITE_HASH TPM_DIGEST +#define TPM_DIRVALUE TPM_DIGEST +#define TPM_HMAC TPM_DIGEST +#define TPM_PCRVALUE TPM_DIGEST +#define TPM_AUDITDIGEST TPM_DIGEST +#define TPM_DAA_TPM_SEED TPM_DIGEST +#define TPM_DAA_CONTEXT_SEED TPM_DIGEST + +struct grub_tpm_extend_cmd +{ + TPM_COMMAND_CODE ordinal; + TPM_PCRINDEX pcr_num; + TPM_DIGEST digest; +}; + +struct grub_tpm_extend_resp +{ + TPM_COMMAND_CODE ordinal; + TPM_PCRVALUE digest; +}; + +struct grub_tpm_cmd_buf +{ + TPM_TAG tag; + grub_uint32_t size; + TPM_RESULT result; + union + { + struct grub_tpm_extend_cmd extend; + } cmd; +}; + +struct grub_tpm_resp_buf +{ + TPM_TAG tag; + grub_uint32_t size; + TPM_RESULT result; + union + { + struct grub_tpm_extend_resp extend; + } resp; +}; + +/* TPM Interface Specification functions */ +grub_uint8_t EXPORT_FUNC(grub_tis_request_locality) (grub_uint8_t l); +grub_uint8_t EXPORT_FUNC(grub_tis_init) (void); +grub_size_t EXPORT_FUNC(grub_tis_send) (struct grub_tpm_cmd_buf *buf); +grub_size_t EXPORT_FUNC(grub_tis_recv) (struct grub_tpm_resp_buf *buf); + +/* TPM Commands */ +grub_uint8_t EXPORT_FUNC(grub_tpm_pcr_extend) (struct grub_tpm_digest *d); + +#endif diff --git a/include/grub/verify.h b/include/grub/verify.h new file mode 100644 index 000000000..79022b422 --- /dev/null +++ b/include/grub/verify.h @@ -0,0 +1,78 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +enum grub_verify_flags + { + GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, + GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, + /* Defer verification to another authority. */ + GRUB_VERIFY_FLAGS_DEFER_AUTH = 4 + }; + +enum grub_verify_string_type + { + GRUB_VERIFY_KERNEL_CMDLINE, + GRUB_VERIFY_MODULE_CMDLINE, + }; + +struct grub_file_verifier +{ + struct grub_file_verifier *next; + struct grub_file_verifier **prev; + + const char *name; + + /* + * Check if file needs to be verified and set up context. + * init/read/fini is structured in the same way as hash interface. + */ + grub_err_t (*init) (grub_file_t io, enum grub_file_type type, + void **context, enum grub_verify_flags *flags); + + /* + * Right now we pass the whole file in one call but it may + * change in the future. If you insist on single buffer you + * need to set GRUB_VERIFY_FLAGS_SINGLE_CHUNK in verify_flags. + */ + grub_err_t (*write) (void *context, void *buf, grub_size_t size); + + grub_err_t (*fini) (void *context); + void (*close) (void *context); + + grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type); +}; + +extern struct grub_file_verifier *grub_file_verifiers; + +static inline void +grub_verifier_register (struct grub_file_verifier *ver) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_file_verifiers), GRUB_AS_LIST (ver)); +} + +static inline void +grub_verifier_unregister (struct grub_file_verifier *ver) +{ + grub_list_remove (GRUB_AS_LIST (ver)); +} + +grub_err_t +grub_verify_string (char *str, enum grub_verify_string_type type); diff --git a/util/grub-fstest.c b/util/grub-fstest.c index a358ae471..7074e8e41 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -120,9 +120,9 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len, void return; } - if (uncompress == 0) - grub_file_filter_disable_compression (); - file = grub_file_open (pathname); + file = grub_file_open (pathname, ((uncompress == 0) + ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE) + | GRUB_FILE_TYPE_FSTEST); if (!file) { grub_util_error (_("cannot open `%s': %s"), pathname, diff --git a/util/grub-mount.c b/util/grub-mount.c index a25db8a71..e32b502e7 100644 --- a/util/grub-mount.c +++ b/util/grub-mount.c @@ -208,7 +208,7 @@ fuse_getattr (const char *path, struct stat *st) if (!ctx.file_info.dir) { grub_file_t file; - file = grub_file_open (path); + file = grub_file_open (path, GRUB_FILE_TYPE_GET_SIZE); if (! file && grub_errno == GRUB_ERR_BAD_FILE_TYPE) { grub_errno = GRUB_ERR_NONE; @@ -244,7 +244,7 @@ static int fuse_open (const char *path, struct fuse_file_info *fi __attribute__ ((unused))) { grub_file_t file; - file = grub_file_open (path); + file = grub_file_open (path, GRUB_FILE_TYPE_MOUNT); if (! file) return translate_error (); files[first_fd++] = file; @@ -308,7 +308,7 @@ fuse_readdir_call_fill (const char *filename, grub_file_t file; char *tmp; tmp = xasprintf ("%s/%s", ctx->path, filename); - file = grub_file_open (tmp); + file = grub_file_open (tmp, GRUB_FILE_TYPE_GET_SIZE); free (tmp); /* Symlink to directory. */ if (! file && grub_errno == GRUB_ERR_BAD_FILE_TYPE)