From 0fe4388eb9ba710dcc4771379086c86c46639a29 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Tue, 30 Oct 2018 14:12:50 +0100 Subject: [PATCH 01/14] bufio: Use grub_size_t instead of plain int for size Signed-off-by: Vladimir Serbinenko Signed-off-by: Daniel Kiper --- grub-core/io/bufio.c | 6 +++--- include/grub/bufio.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c index 22438277d..71b100646 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,7 +81,7 @@ 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, grub_size_t size) { grub_file_t io, file; diff --git a/include/grub/bufio.h b/include/grub/bufio.h index acdd0c882..77eb8ee56 100644 --- a/include/grub/bufio.h +++ b/include/grub/bufio.h @@ -22,7 +22,7 @@ #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, grub_size_t size); #endif /* ! GRUB_BUFIO_H */ From 859194699f6a523881617c351bee0daeff981aaf Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Tue, 30 Oct 2018 14:12:51 +0100 Subject: [PATCH 02/14] verifiers: File type for fine-grained signature-verification controlling Let's provide file type info to the I/O layer. This way verifiers framework and its users will be able to differentiate files and verify only required ones. This is preparatory patch. Signed-off-by: Vladimir Serbinenko Signed-off-by: Daniel Kiper --- grub-core/commands/acpi.c | 2 +- grub-core/commands/blocklist.c | 4 +- grub-core/commands/cat.c | 2 +- grub-core/commands/cmp.c | 4 +- grub-core/commands/efi/loadbios.c | 4 +- grub-core/commands/file.c | 5 +- grub-core/commands/hashsum.c | 22 ++- grub-core/commands/hexdump.c | 2 +- grub-core/commands/i386/pc/play.c | 2 +- grub-core/commands/keylayouts.c | 2 +- grub-core/commands/legacycfg.c | 2 +- grub-core/commands/loadenv.c | 24 +-- grub-core/commands/ls.c | 8 +- grub-core/commands/minicmd.c | 2 +- grub-core/commands/nativedisk.c | 3 +- grub-core/commands/parttool.c | 2 +- grub-core/commands/search.c | 4 +- grub-core/commands/test.c | 4 +- grub-core/commands/testload.c | 2 +- grub-core/commands/testspeed.c | 2 +- grub-core/commands/verify.c | 51 ++++--- grub-core/disk/loopback.c | 3 +- grub-core/efiemu/main.c | 2 +- grub-core/font/font.c | 4 +- grub-core/fs/zfs/zfscrypt.c | 2 +- grub-core/gettext/gettext.c | 2 +- grub-core/gfxmenu/theme_loader.c | 2 +- grub-core/io/bufio.c | 4 +- grub-core/io/gzio.c | 5 +- grub-core/io/lzopio.c | 6 +- grub-core/io/offset.c | 7 +- grub-core/io/xzio.c | 6 +- grub-core/kern/dl.c | 2 +- grub-core/kern/elf.c | 4 +- grub-core/kern/file.c | 22 ++- grub-core/lib/syslinux_parse.c | 2 +- grub-core/loader/efi/chainloader.c | 2 +- grub-core/loader/i386/bsd.c | 16 +- grub-core/loader/i386/coreboot/chainloader.c | 2 +- grub-core/loader/i386/linux.c | 2 +- grub-core/loader/i386/pc/chainloader.c | 4 +- grub-core/loader/i386/pc/freedos.c | 2 +- grub-core/loader/i386/pc/linux.c | 2 +- grub-core/loader/i386/pc/ntldr.c | 2 +- grub-core/loader/i386/pc/plan9.c | 2 +- grub-core/loader/i386/pc/pxechainloader.c | 2 +- grub-core/loader/i386/pc/truecrypt.c | 2 +- grub-core/loader/i386/xen.c | 7 +- grub-core/loader/i386/xen_file.c | 2 +- grub-core/loader/i386/xnu.c | 2 +- grub-core/loader/linux.c | 6 +- grub-core/loader/macho.c | 4 +- grub-core/loader/mips/linux.c | 2 +- grub-core/loader/multiboot.c | 8 +- grub-core/loader/xnu.c | 16 +- grub-core/loader/xnu_resume.c | 4 +- grub-core/normal/autofs.c | 11 +- grub-core/normal/crypto.c | 2 +- grub-core/normal/dyncmd.c | 2 +- grub-core/normal/main.c | 2 +- grub-core/normal/term.c | 2 +- grub-core/video/readers/jpeg.c | 2 +- grub-core/video/readers/png.c | 2 +- grub-core/video/readers/tga.c | 2 +- include/grub/bufio.h | 4 +- include/grub/elfload.h | 2 +- include/grub/file.h | 152 ++++++++++++++----- include/grub/machoload.h | 3 +- util/grub-fstest.c | 6 +- util/grub-mount.c | 6 +- 70 files changed, 292 insertions(+), 221 deletions(-) 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/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..fc20c6563 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; 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/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/verify.c b/grub-core/commands/verify.c index 67cb1c785..f0dfeceeb 100644 --- a/grub-core/commands/verify.c +++ b/grub-core/commands/verify.c @@ -680,10 +680,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 +773,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 +790,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; @@ -858,33 +862,32 @@ struct grub_fs verified_fs = }; static grub_file_t -grub_pubkey_open (grub_file_t io, const char *filename) +grub_pubkey_open (grub_file_t io, enum grub_file_type type) { 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; + 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 (!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")); + fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig")); if (!fsuf) return NULL; - ptr = grub_stpcpy (fsuf, filename); + 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; @@ -918,7 +921,7 @@ grub_pubkey_open (grub_file_t io, const char *filename) if (!verified->buf) { grub_file_close (sig); - grub_free (verified); + verified_free (verified); grub_free (ret); return NULL; } @@ -926,7 +929,7 @@ grub_pubkey_open (grub_file_t io, const char *filename) { if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), - filename); + io->name); grub_file_close (sig); verified_free (verified); grub_free (ret); 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 71b100646..bb5b87662 100644 --- a/grub-core/io/bufio.c +++ b/grub-core/io/bufio.c @@ -81,11 +81,11 @@ grub_bufio_open (grub_file_t io, grub_size_t size) } grub_file_t -grub_buffile_open (const char *name, grub_size_t 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/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/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..d34da14d9 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -1457,7 +1457,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 +1534,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 +1693,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 +1802,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 +1907,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 +1958,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 +2048,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 +2088,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..7ec71abad 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -695,7 +695,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; 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..ae769bb2e 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; 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..0351090da 100644 --- a/grub-core/loader/i386/pc/plan9.c +++ b/grub-core/loader/i386/pc/plan9.c @@ -413,7 +413,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; 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/xen.c b/grub-core/loader/i386/xen.c index 3073f64d5..8a93a527a 100644 --- a/grub-core/loader/i386/xen.c +++ b/grub-core/loader/i386/xen.c @@ -648,7 +648,7 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), (char *) xen_state.next_start.cmd_line, sizeof (xen_state.next_start.cmd_line) - 1); - file = grub_file_open (argv[0]); + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); if (!file) return grub_errno; @@ -893,9 +893,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); 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/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..7b28ba731 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; 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/xnu.c b/grub-core/loader/xnu.c index c9885b1bc..84c8b939c 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -351,7 +351,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; @@ -456,7 +456,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; @@ -674,7 +674,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 +771,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 +885,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 +925,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 +1210,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 +1253,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 77eb8ee56..0ff72d103 100644 --- a/include/grub/bufio.h +++ b/include/grub/bufio.h @@ -23,6 +23,8 @@ #include 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, 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/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..5b47c5f91 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -25,6 +25,109 @@ #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, + + 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 { @@ -77,61 +180,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 +227,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/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/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) From ad5ab166350a9f46585d8ea0a05d566a46f34da2 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Tue, 30 Oct 2018 14:12:52 +0100 Subject: [PATCH 03/14] verifiers: Framework core Verifiers framework provides core file verification functionality which can be used by various security mechanisms, e.g., UEFI secure boot, TPM, PGP signature verification, etc. The patch contains PGP code changes and probably they should be extracted to separate patch for the sake of clarity. Signed-off-by: Vladimir Serbinenko Signed-off-by: Daniel Kiper --- grub-core/Makefile.core.def | 5 + grub-core/commands/verifiers.c | 197 ++++++++++++ grub-core/commands/verify.c | 530 ++++++++++++++++----------------- include/grub/file.h | 2 +- include/grub/list.h | 1 + include/grub/verify.h | 65 ++++ 6 files changed, 521 insertions(+), 279 deletions(-) create mode 100644 grub-core/commands/verifiers.c create mode 100644 include/grub/verify.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 2c1d62cee..c8502d7fa 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -895,6 +895,11 @@ module = { cppflags = '-I$(srcdir)/lib/posix_wrap'; }; +module = { + name = verifiers; + common = commands/verifiers.c; +}; + module = { name = hdparm; common = commands/hdparm.c; diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c new file mode 100644 index 000000000..fde88318d --- /dev/null +++ b/grub-core/commands/verifiers.c @@ -0,0 +1,197 @@ +/* + * 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; + + 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_SKIP_VERIFICATION)) + break; + } + + if (!ver) + /* 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) + 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_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/commands/verify.c b/grub-core/commands/verify.c index f0dfeceeb..29e74a640 100644 --- a/grub-core/commands/verify.c +++ b/grub-core/commands/verify.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; +} + +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; - hval = hash->read (context); + 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 @@ -819,134 +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, enum grub_file_type type) +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_t ret; - grub_verified_t verified; - - 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; + 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; + { + *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; + return GRUB_ERR_NONE; + } + fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig")); if (!fsuf) - return NULL; + return grub_errno; ptr = grub_stpcpy (fsuf, io->name); grub_memcpy (ptr, ".sig", sizeof (".sig")); 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); - verified_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"), - io->name); - 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 * @@ -970,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; @@ -986,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"); @@ -1033,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/include/grub/file.h b/include/grub/file.h index 5b47c5f91..19dda67f6 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -171,7 +171,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, 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/verify.h b/include/grub/verify.h new file mode 100644 index 000000000..298120f57 --- /dev/null +++ b/include/grub/verify.h @@ -0,0 +1,65 @@ +/* + * 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 + }; + +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); +}; + +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)); +} From fb27b69224ec2600fefb7c12125722111b19ec10 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Tue, 30 Oct 2018 14:12:53 +0100 Subject: [PATCH 04/14] verifiers: Add possibility to verify kernel and modules command lines Signed-off-by: Vladimir Serbinenko Signed-off-by: Daniel Kiper --- grub-core/commands/verifiers.c | 14 ++++++++++++++ grub-core/lib/cmdline.c | 9 +++++---- grub-core/loader/arm/linux.c | 8 ++++++-- grub-core/loader/arm64/linux.c | 10 +++++++--- grub-core/loader/i386/bsd.c | 6 ++++++ grub-core/loader/i386/linux.c | 16 +++++++++++----- grub-core/loader/i386/multiboot_mbi.c | 16 ++++++++++------ grub-core/loader/i386/pc/linux.c | 13 ++++++++----- grub-core/loader/i386/pc/plan9.c | 11 +++++++++++ grub-core/loader/i386/xen.c | 7 +++++++ grub-core/loader/ia64/efi/linux.c | 7 +++++++ grub-core/loader/mips/linux.c | 8 ++++++++ grub-core/loader/multiboot_mbi2.c | 13 +++++++------ grub-core/loader/powerpc/ieee1275/linux.c | 5 +++-- grub-core/loader/sparc64/ieee1275/linux.c | 5 +++-- grub-core/loader/xnu.c | 9 +++++++++ include/grub/lib/cmdline.h | 5 +++-- include/grub/verify.h | 11 +++++++++++ 18 files changed, 136 insertions(+), 37 deletions(-) diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c index fde88318d..59ea418a2 100644 --- a/grub-core/commands/verifiers.c +++ b/grub-core/commands/verifiers.c @@ -186,6 +186,20 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) 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); 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/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/i386/bsd.c b/grub-core/loader/i386/bsd.c index d34da14d9..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; } } diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 7ec71abad..2f3e08263 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -1012,11 +1012,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/linux.c b/grub-core/loader/i386/pc/linux.c index ae769bb2e..89c6a7436 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -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/plan9.c b/grub-core/loader/i386/pc/plan9.c index 0351090da..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+"); @@ -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/xen.c b/grub-core/loader/i386/xen.c index 8a93a527a..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,6 +648,9 @@ 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], GRUB_FILE_TYPE_LINUX_KERNEL); if (!file) @@ -908,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/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/mips/linux.c b/grub-core/loader/mips/linux.c index 7b28ba731..e256c440f 100644 --- a/grub-core/loader/mips/linux.c +++ b/grub-core/loader/mips/linux.c @@ -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_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 84c8b939c..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+"); @@ -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) @@ -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) 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/verify.h b/include/grub/verify.h index 298120f57..9f892d8fe 100644 --- a/include/grub/verify.h +++ b/include/grub/verify.h @@ -25,6 +25,12 @@ enum grub_verify_flags GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2 }; +enum grub_verify_string_type + { + GRUB_VERIFY_KERNEL_CMDLINE, + GRUB_VERIFY_MODULE_CMDLINE, + }; + struct grub_file_verifier { struct grub_file_verifier *next; @@ -48,6 +54,8 @@ struct grub_file_verifier 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; @@ -63,3 +71,6 @@ 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); From 225cb302cc8691bc419ab8e63dde177e30443086 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Tue, 30 Oct 2018 14:12:54 +0100 Subject: [PATCH 05/14] verifiers: Add possibility to defer verification to other verifiers This way if a verifier requires verification of a given file it can defer task to another verifier (another authority) if it is not able to do it itself. E.g. shim_lock verifier, posted as a subsequent patch, is able to verify only PE files. This means that it is not able to verify any of GRUB2 modules which have to be trusted on UEFI systems with secure boot enabled. So, it can defer verification to other verifier, e.g. PGP one. I silently assume that other verifiers are trusted and will do good job for us. Or at least they will not do any harm. Signed-off-by: Daniel Kiper --- grub-core/commands/verifiers.c | 23 ++++++++++++++++++++--- include/grub/verify.h | 4 +++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c index 59ea418a2..c638d5f43 100644 --- a/grub-core/commands/verifiers.c +++ b/grub-core/commands/verifiers.c @@ -83,6 +83,7 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) 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); @@ -102,13 +103,27 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) 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) - /* No verifiers wanted to verify. Just return underlying file. */ - return io; + { + 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) @@ -160,7 +175,9 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) err = ver->init (io, type, &context, &flags); if (err) goto fail_noclose; - if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION) + 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) diff --git a/include/grub/verify.h b/include/grub/verify.h index 9f892d8fe..79022b422 100644 --- a/include/grub/verify.h +++ b/include/grub/verify.h @@ -22,7 +22,9 @@ enum grub_verify_flags { GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, - GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2 + GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, + /* Defer verification to another authority. */ + GRUB_VERIFY_FLAGS_DEFER_AUTH = 4 }; enum grub_verify_string_type From 1816e8d0f7b85c08ef1ffbf0d67ef5ea7c1e4911 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Tue, 30 Oct 2018 14:12:55 +0100 Subject: [PATCH 06/14] verifiers: Rename verify module to pgp module Just for clarity. No functional change. Signed-off-by: Daniel Kiper --- grub-core/Makefile.core.def | 4 ++-- grub-core/commands/{verify.c => pgp.c} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename grub-core/commands/{verify.c => pgp.c} (100%) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index c8502d7fa..40f42b68e 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -889,8 +889,8 @@ module = { }; module = { - name = verify; - common = commands/verify.c; + name = pgp; + common = commands/pgp.c; cflags = '$(CFLAGS_POSIX)'; cppflags = '-I$(srcdir)/lib/posix_wrap'; }; diff --git a/grub-core/commands/verify.c b/grub-core/commands/pgp.c similarity index 100% rename from grub-core/commands/verify.c rename to grub-core/commands/pgp.c From d7e6b658bd2c0ef58c42b0e18686c7d1a6043dac Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Tue, 30 Oct 2018 14:12:56 +0100 Subject: [PATCH 07/14] verifiers: Add the documentation Signed-off-by: Vladimir Serbinenko Signed-off-by: Daniel Kiper --- docs/grub-dev.texi | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) 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 From 41261435ddc4ddfd86c47015a7fa4dc3651bf26c Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Tue, 30 Oct 2018 14:12:57 +0100 Subject: [PATCH 08/14] dl: Add support for persistent modules This type of modules cannot be unloaded. This is useful if a given functionality, e.g. UEFI secure boot shim signature verification, should not be disabled if it was enabled at some point in time. Somebody may say that we can use standalone GRUB2 here. That is true. However, the code is not so big nor complicated hence it make sense to support modularized configs too. Signed-off-by: Daniel Kiper --- grub-core/commands/minicmd.c | 3 +++ include/grub/dl.h | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c index fc20c6563..6bbce3128 100644 --- a/grub-core/commands/minicmd.c +++ b/grub-core/commands/minicmd.c @@ -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/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, From cf2874e66dcba1ff528b0cd7f98787042d0d1563 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Tue, 30 Oct 2018 14:12:58 +0100 Subject: [PATCH 09/14] efi: Add EFI shim lock verifier This module provides shim lock verification for various kernels if UEFI secure boot is enabled on a machine. It is recommended to put this module into GRUB2 standalone image (avoid putting iorw and memrw modules into it; they are disallowed if UEFI secure boot is enabled). However, it is also possible to use it as a normal module. Though such configurations are more fragile and less secure due to various limitations. If the module is loaded and UEFI secure boot is enabled then: - module itself cannot be unloaded (persistent module), - the iorw and memrw modules cannot be loaded, - if the iorw and memrw modules are loaded then machine boot is disabled, - GRUB2 defers modules and ACPI tables verification to other verifiers. Signed-off-by: Daniel Kiper --- docs/grub.texi | 15 +++ grub-core/Makefile.core.def | 6 ++ grub-core/commands/efi/shim_lock.c | 141 +++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 grub-core/commands/efi/shim_lock.c 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.core.def b/grub-core/Makefile.core.def index 40f42b68e..0fd1ba424 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -900,6 +900,12 @@ module = { 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; 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); +} From 6d63859fc98bb62a52c0176c310ddbe6a42f519e Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Fri, 14 Dec 2018 11:27:21 -0500 Subject: [PATCH 10/14] i386: Add basic platform support for secure launch Signed-off-by: Ross Philipson --- include/grub/i386/cpuid.h | 13 +++++ include/grub/i386/mmio.h | 105 ++++++++++++++++++++++++++++++++++++++ include/grub/i386/msr.h | 82 +++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 include/grub/i386/mmio.h create mode 100644 include/grub/i386/msr.h 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 From d262942042531d761ee03f038c94ff340a1ed050 Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Fri, 14 Dec 2018 12:26:21 -0500 Subject: [PATCH 11/14] kern/tpm: Adding basic TPM 1.2 support Signed-off-by: Daniel P. Smith Signed-off-by: Ross Philipson --- grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 2 + grub-core/kern/tis.c | 279 ++++++++++++++++++++++++++++++++++++ grub-core/kern/tpm.c | 52 +++++++ include/grub/tis.h | 156 ++++++++++++++++++++ 5 files changed, 490 insertions(+) create mode 100644 grub-core/kern/tis.c create mode 100644 grub-core/kern/tpm.c create mode 100644 include/grub/tis.h diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 104513847..dff5f143b 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -99,6 +99,7 @@ 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 endif if COND_i386_efi diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 0fd1ba424..5d7d7d0b9 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; 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/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 From 8006f4f56f2699cd3df45ec6e0f8a5129773c687 Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Fri, 14 Dec 2018 12:37:53 -0500 Subject: [PATCH 12/14] slaunch: Add main secure launch definitions header Signed-off-by: Ross Philipson --- grub-core/Makefile.am | 3 +++ include/grub/slaunch.h | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 include/grub/slaunch.h diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index dff5f143b..d1a00de90 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -100,6 +100,7 @@ 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 @@ -109,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 @@ -165,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/include/grub/slaunch.h b/include/grub/slaunch.h new file mode 100644 index 000000000..84f3ffa0b --- /dev/null +++ b/include/grub/slaunch.h @@ -0,0 +1,50 @@ +/* + * 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; +}; + +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 From ba5994b71f435d403a10b0ac6d943f5cf50a993a Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Fri, 14 Dec 2018 12:49:37 -0500 Subject: [PATCH 13/14] slaunch: Add secure launch base framework Signed-off-by: Ross Philipson --- grub-core/Makefile.core.def | 8 + grub-core/loader/i386/linux.c | 18 ++ grub-core/loader/i386/slaunch.c | 224 +++++++++++++++++++++++++ grub-core/loader/i386/slaunch_skinit.c | 34 ++++ grub-core/loader/i386/slaunch_txt.c | 35 ++++ include/grub/file.h | 3 + include/grub/slaunch.h | 10 ++ 7 files changed, 332 insertions(+) create mode 100644 grub-core/loader/i386/slaunch.c create mode 100644 grub-core/loader/i386/slaunch_skinit.c create mode 100644 grub-core/loader/i386/slaunch_txt.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 5d7d7d0b9..8ae66b6df 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1708,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/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 2f3e08263..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; 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/include/grub/file.h b/include/grub/file.h index 19dda67f6..c0a0c08ec 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -121,6 +121,9 @@ enum grub_file_type GRUB_FILE_TYPE_VERIFY_SIGNATURE, + /* Secure Launch module. */ + GRUB_FILE_TYPE_SLAUNCH_MODULE, + GRUB_FILE_TYPE_MASK = 0xffff, /* --skip-sig is specified. */ diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h index 84f3ffa0b..9d10926a1 100644 --- a/include/grub/slaunch.h +++ b/include/grub/slaunch.h @@ -42,6 +42,16 @@ struct grub_slaunch_params 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); From 32b69b59ba3bb7bbcd890be516d72404addf8f54 Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Fri, 14 Dec 2018 12:56:36 -0500 Subject: [PATCH 14/14] txt: Add Intel TXT definitions header file Signed-off-by: Ross Philipson --- include/grub/i386/txt.h | 475 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 include/grub/i386/txt.h 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