Discussion:
[PATCH v3 0/8] verifiers: Framework and EFI shim lock verifier
(too old to reply)
Daniel Kiper
2018-10-03 09:36:47 UTC
Permalink
Hi all,

Another stab at verifiers framework and EFI shim lock verifier. This time it
is not an RFC because IMO it looks pretty well.

There are still minor things to address like PGP code changes split from verifiers
introduction (patch #2) and/or rename grub-core/commands/verify_helper.c to
grub-core/commands/verifiers.c. Maybe something else but probably nothing major...

Anyway, please take a look.

Daniel

docs/grub-dev.texi | 57 ++
grub-core/Makefile.core.def | 15 +-
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/efi/shim_lock.c | 140 ++++
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 | 5 +-
grub-core/commands/nativedisk.c | 3 +-
grub-core/commands/parttool.c | 2 +-
grub-core/commands/pgp.c | 1018 +++++++++++++++++++++++++
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 | 1042 --------------------------
grub-core/commands/verify_helper.c | 228 ++++++
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 | 10 +-
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/cmdline.c | 9 +-
grub-core/lib/syslinux_parse.c | 2 +-
grub-core/loader/arm/linux.c | 8 +-
grub-core/loader/arm64/linux.c | 10 +-
grub-core/loader/efi/chainloader.c | 2 +-
grub-core/loader/i386/bsd.c | 22 +-
grub-core/loader/i386/coreboot/chainloader.c | 2 +-
grub-core/loader/i386/linux.c | 18 +-
grub-core/loader/i386/multiboot_mbi.c | 16 +-
grub-core/loader/i386/pc/chainloader.c | 4 +-
grub-core/loader/i386/pc/freedos.c | 2 +-
grub-core/loader/i386/pc/linux.c | 15 +-
grub-core/loader/i386/pc/ntldr.c | 2 +-
grub-core/loader/i386/pc/plan9.c | 13 +-
grub-core/loader/i386/pc/pxechainloader.c | 2 +-
grub-core/loader/i386/pc/truecrypt.c | 2 +-
grub-core/loader/i386/xen.c | 14 +-
grub-core/loader/i386/xen_file.c | 2 +-
grub-core/loader/i386/xnu.c | 2 +-
grub-core/loader/ia64/efi/linux.c | 7 +
grub-core/loader/linux.c | 6 +-
grub-core/loader/macho.c | 4 +-
grub-core/loader/mips/linux.c | 10 +-
grub-core/loader/multiboot.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 | 25 +-
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 | 6 +-
include/grub/dl.h | 13 +
include/grub/elfload.h | 2 +-
include/grub/file.h | 153 ++--
include/grub/lib/cmdline.h | 5 +-
include/grub/list.h | 1 +
include/grub/machoload.h | 3 +-
include/grub/verify.h | 77 ++
util/grub-fstest.c | 6 +-
util/grub-mount.c | 6 +-
87 files changed, 1931 insertions(+), 1282 deletions(-)

Daniel Kiper (4):
verifiers: Add possibility to defer verification to other verifiers
verifiers: Rename verify module to pgp module
dl: Add support for persistent modules
efi: Add EFI shim lock verifier

Vladimir Serbinenko (4):
verifiers: File type for fine-grained signature-verification controlling
verifiers: Framework core
verifiers: Add possibility to verify kernel and modules command lines
verifiers: Add the documentation
Daniel Kiper
2018-10-03 09:36:52 UTC
Permalink
Just for clarity. No functional change.

Signed-off-by: Daniel Kiper <***@oracle.com>
---
grub-core/Makefile.core.def | 4 +-
grub-core/commands/pgp.c | 1018 +++++++++++++++++++++++++++++++++++++++++++
grub-core/commands/verify.c | 1018 -------------------------------------------
3 files changed, 1020 insertions(+), 1020 deletions(-)
create mode 100644 grub-core/commands/pgp.c
delete mode 100644 grub-core/commands/verify.c

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index dfcc95d..3008b58 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -888,8 +888,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/pgp.c b/grub-core/commands/pgp.c
new file mode 100644
index 0000000..d5d7c0f
--- /dev/null
+++ b/grub-core/commands/pgp.c
@@ -0,0 +1,1018 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/command.h>
+#include <grub/crypto.h>
+#include <grub/i18n.h>
+#include <grub/gcrypt/gcrypt.h>
+#include <grub/pubkey.h>
+#include <grub/env.h>
+#include <grub/kernel.h>
+#include <grub/extcmd.h>
+#include <grub/verify.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+enum
+ {
+ OPTION_SKIP_SIG = 0
+ };
+
+static const struct grub_arg_option options[] =
+ {
+ {"skip-sig", 's', 0,
+ N_("Skip signature-checking of the public key file."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+read_packet_header (grub_file_t sig, grub_uint8_t *out_type, grub_size_t *len)
+{
+ grub_uint8_t type;
+ grub_uint8_t l;
+ grub_uint16_t l16;
+ grub_uint32_t l32;
+
+ /* New format. */
+ switch (grub_file_read (sig, &type, sizeof (type)))
+ {
+ case 1:
+ break;
+ case 0:
+ {
+ *out_type = 0xff;
+ return 0;
+ }
+ default:
+ if (grub_errno)
+ return grub_errno;
+ /* TRANSLATORS: it's about GNUPG signatures. */
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ }
+
+ if (type == 0)
+ {
+ *out_type = 0xfe;
+ return 0;
+ }
+
+ if (!(type & 0x80))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ if (type & 0x40)
+ {
+ *out_type = (type & 0x3f);
+ if (grub_file_read (sig, &l, sizeof (l)) != 1)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ if (l < 192)
+ {
+ *len = l;
+ return 0;
+ }
+ if (l < 224)
+ {
+ *len = (l - 192) << GRUB_CHAR_BIT;
+ if (grub_file_read (sig, &l, sizeof (l)) != 1)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len |= l;
+ return 0;
+ }
+ if (l == 255)
+ {
+ if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu32 (l32);
+ return 0;
+ }
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ }
+ *out_type = ((type >> 2) & 0xf);
+ switch (type & 0x3)
+ {
+ case 0:
+ if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = l;
+ return 0;
+ case 1:
+ if (grub_file_read (sig, &l16, sizeof (l16)) != sizeof (l16))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu16 (l16);
+ return 0;
+ case 2:
+ if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu32 (l32);
+ return 0;
+ }
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+}
+
+struct signature_v4_header
+{
+ grub_uint8_t type;
+ grub_uint8_t pkeyalgo;
+ grub_uint8_t hash;
+ grub_uint16_t hashed_sub;
+} GRUB_PACKED;
+
+const char *hashes[] = {
+ [0x01] = "md5",
+ [0x02] = "sha1",
+ [0x03] = "ripemd160",
+ [0x08] = "sha256",
+ [0x09] = "sha384",
+ [0x0a] = "sha512",
+ [0x0b] = "sha224"
+};
+
+struct gcry_pk_spec *grub_crypto_pk_dsa;
+struct gcry_pk_spec *grub_crypto_pk_ecdsa;
+struct gcry_pk_spec *grub_crypto_pk_rsa;
+
+static int
+dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+static int
+rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+
+struct
+{
+ const char *name;
+ grub_size_t nmpisig;
+ grub_size_t nmpipub;
+ struct gcry_pk_spec **algo;
+ int (*pad) (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+ const char *module;
+} pkalgos[] =
+ {
+ [1] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
+ [3] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
+ [17] = { "dsa", 2, 4, &grub_crypto_pk_dsa, dsa_pad, "gcry_dsa" },
+ };
+
+struct grub_public_key
+{
+ struct grub_public_key *next;
+ struct grub_public_subkey *subkeys;
+};
+
+struct grub_public_subkey
+{
+ struct grub_public_subkey *next;
+ grub_uint8_t type;
+ grub_uint32_t fingerprint[5];
+ gcry_mpi_t mpis[10];
+};
+
+static void
+free_pk (struct grub_public_key *pk)
+{
+ struct grub_public_subkey *nsk, *sk;
+ for (sk = pk->subkeys; sk; sk = nsk)
+ {
+ grub_size_t i;
+ for (i = 0; i < ARRAY_SIZE (sk->mpis); i++)
+ if (sk->mpis[i])
+ gcry_mpi_release (sk->mpis[i]);
+ nsk = sk->next;
+ grub_free (sk);
+ }
+ grub_free (pk);
+}
+
+#define READBUF_SIZE 4096
+
+struct grub_public_key *
+grub_load_public_key (grub_file_t f)
+{
+ grub_err_t err;
+ struct grub_public_key *ret;
+ struct grub_public_subkey **last = 0;
+ void *fingerprint_context = NULL;
+ grub_uint8_t *buffer = NULL;
+
+ ret = grub_zalloc (sizeof (*ret));
+ if (!ret)
+ {
+ grub_free (fingerprint_context);
+ return NULL;
+ }
+
+ buffer = grub_zalloc (READBUF_SIZE);
+ fingerprint_context = grub_zalloc (GRUB_MD_SHA1->contextsize);
+
+ if (!buffer || !fingerprint_context)
+ goto fail;
+
+ last = &ret->subkeys;
+
+ while (1)
+ {
+ grub_uint8_t type;
+ grub_size_t len;
+ grub_uint8_t v, pk;
+ grub_uint32_t creation_time;
+ grub_off_t pend;
+ struct grub_public_subkey *sk;
+ grub_size_t i;
+ grub_uint16_t len_be;
+
+ err = read_packet_header (f, &type, &len);
+
+ if (err)
+ goto fail;
+ if (type == 0xfe)
+ continue;
+ if (type == 0xff)
+ {
+ grub_free (fingerprint_context);
+ grub_free (buffer);
+ return ret;
+ }
+
+ grub_dprintf ("crypt", "len = %x\n", (int) len);
+
+ pend = grub_file_tell (f) + len;
+ if (type != 6 && type != 14
+ && type != 5 && type != 7)
+ {
+ grub_file_seek (f, pend);
+ continue;
+ }
+
+ if (grub_file_read (f, &v, sizeof (v)) != sizeof (v))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "v = %x\n", v);
+
+ if (v != 4)
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+ if (grub_file_read (f, &creation_time, sizeof (creation_time)) != sizeof (creation_time))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "time = %x\n", creation_time);
+
+ if (grub_file_read (f, &pk, sizeof (pk)) != sizeof (pk))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "pk = %x\n", pk);
+
+ if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
+ {
+ grub_file_seek (f, pend);
+ continue;
+ }
+
+ sk = grub_zalloc (sizeof (struct grub_public_subkey));
+ if (!sk)
+ goto fail;
+
+ grub_memset (fingerprint_context, 0, GRUB_MD_SHA1->contextsize);
+ GRUB_MD_SHA1->init (fingerprint_context);
+ GRUB_MD_SHA1->write (fingerprint_context, "\x99", 1);
+ len_be = grub_cpu_to_be16 (len);
+ GRUB_MD_SHA1->write (fingerprint_context, &len_be, sizeof (len_be));
+ GRUB_MD_SHA1->write (fingerprint_context, &v, sizeof (v));
+ GRUB_MD_SHA1->write (fingerprint_context, &creation_time, sizeof (creation_time));
+ GRUB_MD_SHA1->write (fingerprint_context, &pk, sizeof (pk));
+
+ for (i = 0; i < pkalgos[pk].nmpipub; i++)
+ {
+ grub_uint16_t l;
+ grub_size_t lb;
+ if (grub_file_read (f, &l, sizeof (l)) != sizeof (l))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+
+ lb = (grub_be_to_cpu16 (l) + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT;
+ if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ if (grub_file_read (f, buffer + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ grub_memcpy (buffer, &l, sizeof (l));
+
+ GRUB_MD_SHA1->write (fingerprint_context, buffer, lb + sizeof (grub_uint16_t));
+
+ if (gcry_mpi_scan (&sk->mpis[i], GCRYMPI_FMT_PGP,
+ buffer, lb + sizeof (grub_uint16_t), 0))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ }
+
+ if (i < pkalgos[pk].nmpipub)
+ {
+ grub_free (sk);
+ goto fail;
+ }
+
+ GRUB_MD_SHA1->final (fingerprint_context);
+
+ grub_memcpy (sk->fingerprint, GRUB_MD_SHA1->read (fingerprint_context), 20);
+
+ *last = sk;
+ last = &sk->next;
+
+ grub_dprintf ("crypt", "actual pos: %x, expected: %x\n", (int)grub_file_tell (f), (int)pend);
+
+ grub_file_seek (f, pend);
+ }
+ fail:
+ free_pk (ret);
+ grub_free (fingerprint_context);
+ grub_free (buffer);
+ return NULL;
+}
+
+struct grub_public_key *grub_pk_trusted;
+
+struct grub_public_subkey *
+grub_crypto_pk_locate_subkey (grub_uint64_t keyid, struct grub_public_key *pkey)
+{
+ struct grub_public_subkey *sk;
+ for (sk = pkey->subkeys; sk; sk = sk->next)
+ if (grub_memcmp (sk->fingerprint + 3, &keyid, 8) == 0)
+ return sk;
+ return 0;
+}
+
+struct grub_public_subkey *
+grub_crypto_pk_locate_subkey_in_trustdb (grub_uint64_t keyid)
+{
+ struct grub_public_key *pkey;
+ struct grub_public_subkey *sk;
+ for (pkey = grub_pk_trusted; pkey; pkey = pkey->next)
+ {
+ sk = grub_crypto_pk_locate_subkey (keyid, pkey);
+ if (sk)
+ return sk;
+ }
+ return 0;
+}
+
+
+static int
+dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
+{
+ unsigned nbits = gcry_mpi_get_nbits (sk->mpis[1]);
+ grub_dprintf ("crypt", "must be %u bits got %d bits\n", nbits,
+ (int)(8 * hash->mdlen));
+ return gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, hval,
+ nbits / 8 < (unsigned) hash->mdlen ? nbits / 8
+ : (unsigned) hash->mdlen, 0);
+}
+
+static int
+rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
+{
+ grub_size_t tlen, emlen, fflen;
+ grub_uint8_t *em, *emptr;
+ unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
+ int ret;
+ tlen = hash->mdlen + hash->asnlen;
+ emlen = (nbits + 7) / 8;
+ if (emlen < tlen + 11)
+ return 1;
+
+ em = grub_malloc (emlen);
+ if (!em)
+ return 1;
+
+ em[0] = 0x00;
+ em[1] = 0x01;
+ fflen = emlen - tlen - 3;
+ for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
+ *emptr = 0xff;
+ *emptr++ = 0x00;
+ grub_memcpy (emptr, hash->asnoid, hash->asnlen);
+ emptr += hash->asnlen;
+ grub_memcpy (emptr, hval, hash->mdlen);
+
+ ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
+ grub_free (em);
+ 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_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
+{
+ grub_size_t len;
+ grub_uint8_t h;
+ grub_uint8_t t;
+ grub_err_t err;
+ grub_uint8_t type = 0;
+ grub_uint8_t pk;
+
+ grub_memset (ctxt, 0, sizeof (*ctxt));
+
+ err = read_packet_header (sig, &type, &len);
+ if (err)
+ return err;
+
+ if (type != 0x2)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (ctxt->v != 4)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ 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"));
+
+ if (h >= ARRAY_SIZE (hashes) || hashes[h] == NULL)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, "unknown hash");
+
+ if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ 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");
+
+ ctxt->sig = sig;
+
+ ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
+ if (!ctxt->hash_context)
+ return grub_errno;
+
+ ctxt->hash->init (ctxt->hash_context);
+
+ return GRUB_ERR_NONE;
+}
+
+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;
+
+ readbuf = grub_malloc (READBUF_SIZE);
+ if (!readbuf)
+ goto fail;
+
+ 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;
+ 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);
+ }
+ }
+
+ ctxt->hash->final (ctxt->hash_context);
+
+ grub_dprintf ("crypt", "alive\n");
+
+ hval = ctxt->hash->read (ctxt->hash_context);
+
+ 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 (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].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 (readbuf);
+
+ return GRUB_ERR_NONE;
+
+ 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)
+{
+ 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
+grub_cmd_trust (grub_extcmd_context_t ctxt,
+ int argc, char **args)
+{
+ grub_file_t pkf;
+ struct grub_public_key *pk = NULL;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ 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
+ : 0));
+ if (!pkf)
+ return grub_errno;
+ pk = grub_load_public_key (pkf);
+ if (!pk)
+ {
+ grub_file_close (pkf);
+ return grub_errno;
+ }
+ grub_file_close (pkf);
+
+ pk->next = grub_pk_trusted;
+ grub_pk_trusted = pk;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_list (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_public_key *pk = NULL;
+ struct grub_public_subkey *sk = NULL;
+
+ for (pk = grub_pk_trusted; pk; pk = pk->next)
+ for (sk = pk->subkeys; sk; sk = sk->next)
+ {
+ unsigned i;
+ for (i = 0; i < 20; i += 2)
+ grub_printf ("%02x%02x ", ((grub_uint8_t *) sk->fingerprint)[i],
+ ((grub_uint8_t *) sk->fingerprint)[i + 1]);
+ grub_printf ("\n");
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_uint32_t keyid, keyid_be;
+ struct grub_public_key **pkey;
+ struct grub_public_subkey *sk;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ keyid = grub_strtoull (args[0], 0, 16);
+ if (grub_errno)
+ return grub_errno;
+ keyid_be = grub_cpu_to_be32 (keyid);
+
+ for (pkey = &grub_pk_trusted; *pkey; pkey = &((*pkey)->next))
+ {
+ struct grub_public_key *next;
+ for (sk = (*pkey)->subkeys; sk; sk = sk->next)
+ if (grub_memcmp (sk->fingerprint + 4, &keyid_be, 4) == 0)
+ break;
+ if (!sk)
+ continue;
+ next = (*pkey)->next;
+ free_pk (*pkey);
+ *pkey = next;
+ return GRUB_ERR_NONE;
+ }
+ /* TRANSLATORS: %08x is 32-bit key id. */
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), keyid);
+}
+
+static grub_err_t
+grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
+ int argc, char **args)
+{
+ grub_file_t f = NULL, sig = NULL;
+ grub_err_t err = GRUB_ERR_NONE;
+ struct grub_public_key *pk = NULL;
+
+ grub_dprintf ("crypt", "alive\n");
+
+ if (argc < 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ grub_dprintf ("crypt", "alive\n");
+
+ if (argc > 2)
+ {
+ grub_file_t pkf;
+ 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
+ : 0));
+ if (!pkf)
+ return grub_errno;
+ pk = grub_load_public_key (pkf);
+ if (!pk)
+ {
+ grub_file_close (pkf);
+ return grub_errno;
+ }
+ grub_file_close (pkf);
+ }
+
+ f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+ if (!f)
+ {
+ err = grub_errno;
+ goto fail;
+ }
+
+ sig = grub_file_open (args[1],
+ GRUB_FILE_TYPE_SIGNATURE
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (!sig)
+ {
+ err = grub_errno;
+ goto fail;
+ }
+
+ err = grub_verify_signature (f, sig, pk);
+ fail:
+ if (sig)
+ grub_file_close (sig);
+ if (f)
+ grub_file_close (f);
+ if (pk)
+ free_pk (pk);
+ return err;
+}
+
+static int sec = 0;
+
+static grub_err_t
+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;
+
+ if (!sec)
+ {
+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
+ return GRUB_ERR_NONE;
+ }
+
+ fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
+ if (!fsuf)
+ 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 grub_errno;
+
+
+ struct grub_pubkey_context *ctxt = grub_malloc (sizeof (*ctxt));
+ if (!ctxt)
+ {
+ grub_file_close (sig);
+ return grub_errno;
+ }
+ err = grub_verify_signature_init (ctxt, sig);
+ if (err)
+ {
+ grub_pubkey_close (ctxt);
+ return err;
+ }
+ *context = ctxt;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_pubkey_fini (void *ctxt)
+{
+ return grub_verify_signature_real (ctxt, NULL);
+}
+
+static char *
+grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ sec = (*val == '1') || (*val == 'e');
+ return grub_strdup (sec ? "enforce" : "no");
+}
+
+static grub_ssize_t
+pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
+{
+ grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
+ return len;
+}
+
+
+/* Filesystem descriptor. */
+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;
+
+GRUB_MOD_INIT(verify)
+{
+ const char *val;
+ struct grub_module_header *header;
+
+ val = grub_env_get ("check_signatures");
+ if (val && (val[0] == '1' || val[0] == 'e'))
+ sec = 1;
+ else
+ sec = 0;
+
+ grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec);
+ grub_env_export ("check_signatures");
+
+ grub_pk_trusted = 0;
+ FOR_MODULES (header)
+ {
+ struct grub_file pseudo_file;
+ struct grub_public_key *pk = NULL;
+
+ grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
+
+ /* Not an ELF module, skip. */
+ if (header->type != OBJ_TYPE_PUBKEY)
+ continue;
+
+ pseudo_file.fs = &pseudo_fs;
+ pseudo_file.size = (header->size - sizeof (struct grub_module_header));
+ pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
+
+ pk = grub_load_public_key (&pseudo_file);
+ if (!pk)
+ grub_fatal ("error loading initial key: %s\n", grub_errmsg);
+
+ pk->next = grub_pk_trusted;
+ grub_pk_trusted = pk;
+ }
+
+ if (!val)
+ grub_env_set ("check_signatures", grub_pk_trusted ? "enforce" : "no");
+
+ cmd = grub_register_extcmd ("verify_detached", grub_cmd_verify_signature, 0,
+ N_("[-s|--skip-sig] FILE SIGNATURE_FILE [PUBKEY_FILE]"),
+ N_("Verify detached signature."),
+ options);
+ cmd_trust = grub_register_extcmd ("trust", grub_cmd_trust, 0,
+ N_("[-s|--skip-sig] PUBKEY_FILE"),
+ N_("Add PUBKEY_FILE to trusted keys."),
+ options);
+ cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
+ 0,
+ N_("Show the list of trusted keys."));
+ 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_verifier_unregister (&grub_pubkey_verifier);
+ grub_unregister_extcmd (cmd);
+ grub_unregister_extcmd (cmd_trust);
+ grub_unregister_command (cmd_list);
+ grub_unregister_command (cmd_distrust);
+}
diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
deleted file mode 100644
index d5d7c0f..0000000
--- a/grub-core/commands/verify.c
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2013 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/types.h>
-#include <grub/misc.h>
-#include <grub/mm.h>
-#include <grub/err.h>
-#include <grub/dl.h>
-#include <grub/file.h>
-#include <grub/command.h>
-#include <grub/crypto.h>
-#include <grub/i18n.h>
-#include <grub/gcrypt/gcrypt.h>
-#include <grub/pubkey.h>
-#include <grub/env.h>
-#include <grub/kernel.h>
-#include <grub/extcmd.h>
-#include <grub/verify.h>
-
-GRUB_MOD_LICENSE ("GPLv3+");
-
-enum
- {
- OPTION_SKIP_SIG = 0
- };
-
-static const struct grub_arg_option options[] =
- {
- {"skip-sig", 's', 0,
- N_("Skip signature-checking of the public key file."), 0, ARG_TYPE_NONE},
- {0, 0, 0, 0, 0, 0}
- };
-
-static grub_err_t
-read_packet_header (grub_file_t sig, grub_uint8_t *out_type, grub_size_t *len)
-{
- grub_uint8_t type;
- grub_uint8_t l;
- grub_uint16_t l16;
- grub_uint32_t l32;
-
- /* New format. */
- switch (grub_file_read (sig, &type, sizeof (type)))
- {
- case 1:
- break;
- case 0:
- {
- *out_type = 0xff;
- return 0;
- }
- default:
- if (grub_errno)
- return grub_errno;
- /* TRANSLATORS: it's about GNUPG signatures. */
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- }
-
- if (type == 0)
- {
- *out_type = 0xfe;
- return 0;
- }
-
- if (!(type & 0x80))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- if (type & 0x40)
- {
- *out_type = (type & 0x3f);
- if (grub_file_read (sig, &l, sizeof (l)) != 1)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- if (l < 192)
- {
- *len = l;
- return 0;
- }
- if (l < 224)
- {
- *len = (l - 192) << GRUB_CHAR_BIT;
- if (grub_file_read (sig, &l, sizeof (l)) != 1)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len |= l;
- return 0;
- }
- if (l == 255)
- {
- if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len = grub_be_to_cpu32 (l32);
- return 0;
- }
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- }
- *out_type = ((type >> 2) & 0xf);
- switch (type & 0x3)
- {
- case 0:
- if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len = l;
- return 0;
- case 1:
- if (grub_file_read (sig, &l16, sizeof (l16)) != sizeof (l16))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len = grub_be_to_cpu16 (l16);
- return 0;
- case 2:
- if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len = grub_be_to_cpu32 (l32);
- return 0;
- }
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-}
-
-struct signature_v4_header
-{
- grub_uint8_t type;
- grub_uint8_t pkeyalgo;
- grub_uint8_t hash;
- grub_uint16_t hashed_sub;
-} GRUB_PACKED;
-
-const char *hashes[] = {
- [0x01] = "md5",
- [0x02] = "sha1",
- [0x03] = "ripemd160",
- [0x08] = "sha256",
- [0x09] = "sha384",
- [0x0a] = "sha512",
- [0x0b] = "sha224"
-};
-
-struct gcry_pk_spec *grub_crypto_pk_dsa;
-struct gcry_pk_spec *grub_crypto_pk_ecdsa;
-struct gcry_pk_spec *grub_crypto_pk_rsa;
-
-static int
-dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
-static int
-rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
-
-struct
-{
- const char *name;
- grub_size_t nmpisig;
- grub_size_t nmpipub;
- struct gcry_pk_spec **algo;
- int (*pad) (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
- const char *module;
-} pkalgos[] =
- {
- [1] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
- [3] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
- [17] = { "dsa", 2, 4, &grub_crypto_pk_dsa, dsa_pad, "gcry_dsa" },
- };
-
-struct grub_public_key
-{
- struct grub_public_key *next;
- struct grub_public_subkey *subkeys;
-};
-
-struct grub_public_subkey
-{
- struct grub_public_subkey *next;
- grub_uint8_t type;
- grub_uint32_t fingerprint[5];
- gcry_mpi_t mpis[10];
-};
-
-static void
-free_pk (struct grub_public_key *pk)
-{
- struct grub_public_subkey *nsk, *sk;
- for (sk = pk->subkeys; sk; sk = nsk)
- {
- grub_size_t i;
- for (i = 0; i < ARRAY_SIZE (sk->mpis); i++)
- if (sk->mpis[i])
- gcry_mpi_release (sk->mpis[i]);
- nsk = sk->next;
- grub_free (sk);
- }
- grub_free (pk);
-}
-
-#define READBUF_SIZE 4096
-
-struct grub_public_key *
-grub_load_public_key (grub_file_t f)
-{
- grub_err_t err;
- struct grub_public_key *ret;
- struct grub_public_subkey **last = 0;
- void *fingerprint_context = NULL;
- grub_uint8_t *buffer = NULL;
-
- ret = grub_zalloc (sizeof (*ret));
- if (!ret)
- {
- grub_free (fingerprint_context);
- return NULL;
- }
-
- buffer = grub_zalloc (READBUF_SIZE);
- fingerprint_context = grub_zalloc (GRUB_MD_SHA1->contextsize);
-
- if (!buffer || !fingerprint_context)
- goto fail;
-
- last = &ret->subkeys;
-
- while (1)
- {
- grub_uint8_t type;
- grub_size_t len;
- grub_uint8_t v, pk;
- grub_uint32_t creation_time;
- grub_off_t pend;
- struct grub_public_subkey *sk;
- grub_size_t i;
- grub_uint16_t len_be;
-
- err = read_packet_header (f, &type, &len);
-
- if (err)
- goto fail;
- if (type == 0xfe)
- continue;
- if (type == 0xff)
- {
- grub_free (fingerprint_context);
- grub_free (buffer);
- return ret;
- }
-
- grub_dprintf ("crypt", "len = %x\n", (int) len);
-
- pend = grub_file_tell (f) + len;
- if (type != 6 && type != 14
- && type != 5 && type != 7)
- {
- grub_file_seek (f, pend);
- continue;
- }
-
- if (grub_file_read (f, &v, sizeof (v)) != sizeof (v))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- goto fail;
- }
-
- grub_dprintf ("crypt", "v = %x\n", v);
-
- if (v != 4)
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- goto fail;
- }
- if (grub_file_read (f, &creation_time, sizeof (creation_time)) != sizeof (creation_time))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- goto fail;
- }
-
- grub_dprintf ("crypt", "time = %x\n", creation_time);
-
- if (grub_file_read (f, &pk, sizeof (pk)) != sizeof (pk))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- goto fail;
- }
-
- grub_dprintf ("crypt", "pk = %x\n", pk);
-
- if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
- {
- grub_file_seek (f, pend);
- continue;
- }
-
- sk = grub_zalloc (sizeof (struct grub_public_subkey));
- if (!sk)
- goto fail;
-
- grub_memset (fingerprint_context, 0, GRUB_MD_SHA1->contextsize);
- GRUB_MD_SHA1->init (fingerprint_context);
- GRUB_MD_SHA1->write (fingerprint_context, "\x99", 1);
- len_be = grub_cpu_to_be16 (len);
- GRUB_MD_SHA1->write (fingerprint_context, &len_be, sizeof (len_be));
- GRUB_MD_SHA1->write (fingerprint_context, &v, sizeof (v));
- GRUB_MD_SHA1->write (fingerprint_context, &creation_time, sizeof (creation_time));
- GRUB_MD_SHA1->write (fingerprint_context, &pk, sizeof (pk));
-
- for (i = 0; i < pkalgos[pk].nmpipub; i++)
- {
- grub_uint16_t l;
- grub_size_t lb;
- if (grub_file_read (f, &l, sizeof (l)) != sizeof (l))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- break;
- }
-
- lb = (grub_be_to_cpu16 (l) + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT;
- if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- break;
- }
- if (grub_file_read (f, buffer + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- break;
- }
- grub_memcpy (buffer, &l, sizeof (l));
-
- GRUB_MD_SHA1->write (fingerprint_context, buffer, lb + sizeof (grub_uint16_t));
-
- if (gcry_mpi_scan (&sk->mpis[i], GCRYMPI_FMT_PGP,
- buffer, lb + sizeof (grub_uint16_t), 0))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- break;
- }
- }
-
- if (i < pkalgos[pk].nmpipub)
- {
- grub_free (sk);
- goto fail;
- }
-
- GRUB_MD_SHA1->final (fingerprint_context);
-
- grub_memcpy (sk->fingerprint, GRUB_MD_SHA1->read (fingerprint_context), 20);
-
- *last = sk;
- last = &sk->next;
-
- grub_dprintf ("crypt", "actual pos: %x, expected: %x\n", (int)grub_file_tell (f), (int)pend);
-
- grub_file_seek (f, pend);
- }
- fail:
- free_pk (ret);
- grub_free (fingerprint_context);
- grub_free (buffer);
- return NULL;
-}
-
-struct grub_public_key *grub_pk_trusted;
-
-struct grub_public_subkey *
-grub_crypto_pk_locate_subkey (grub_uint64_t keyid, struct grub_public_key *pkey)
-{
- struct grub_public_subkey *sk;
- for (sk = pkey->subkeys; sk; sk = sk->next)
- if (grub_memcmp (sk->fingerprint + 3, &keyid, 8) == 0)
- return sk;
- return 0;
-}
-
-struct grub_public_subkey *
-grub_crypto_pk_locate_subkey_in_trustdb (grub_uint64_t keyid)
-{
- struct grub_public_key *pkey;
- struct grub_public_subkey *sk;
- for (pkey = grub_pk_trusted; pkey; pkey = pkey->next)
- {
- sk = grub_crypto_pk_locate_subkey (keyid, pkey);
- if (sk)
- return sk;
- }
- return 0;
-}
-
-
-static int
-dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
-{
- unsigned nbits = gcry_mpi_get_nbits (sk->mpis[1]);
- grub_dprintf ("crypt", "must be %u bits got %d bits\n", nbits,
- (int)(8 * hash->mdlen));
- return gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, hval,
- nbits / 8 < (unsigned) hash->mdlen ? nbits / 8
- : (unsigned) hash->mdlen, 0);
-}
-
-static int
-rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
-{
- grub_size_t tlen, emlen, fflen;
- grub_uint8_t *em, *emptr;
- unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
- int ret;
- tlen = hash->mdlen + hash->asnlen;
- emlen = (nbits + 7) / 8;
- if (emlen < tlen + 11)
- return 1;
-
- em = grub_malloc (emlen);
- if (!em)
- return 1;
-
- em[0] = 0x00;
- em[1] = 0x01;
- fflen = emlen - tlen - 3;
- for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
- *emptr = 0xff;
- *emptr++ = 0x00;
- grub_memcpy (emptr, hash->asnoid, hash->asnlen);
- emptr += hash->asnlen;
- grub_memcpy (emptr, hval, hash->mdlen);
-
- ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
- grub_free (em);
- 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_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
-{
- grub_size_t len;
- grub_uint8_t h;
- grub_uint8_t t;
- grub_err_t err;
- grub_uint8_t type = 0;
- grub_uint8_t pk;
-
- grub_memset (ctxt, 0, sizeof (*ctxt));
-
- err = read_packet_header (sig, &type, &len);
- if (err)
- return err;
-
- if (type != 0x2)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- if (ctxt->v != 4)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- 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"));
-
- if (h >= ARRAY_SIZE (hashes) || hashes[h] == NULL)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, "unknown hash");
-
- if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- 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");
-
- ctxt->sig = sig;
-
- ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
- if (!ctxt->hash_context)
- return grub_errno;
-
- ctxt->hash->init (ctxt->hash_context);
-
- return GRUB_ERR_NONE;
-}
-
-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;
-
- readbuf = grub_malloc (READBUF_SIZE);
- if (!readbuf)
- goto fail;
-
- 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;
- 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);
- }
- }
-
- ctxt->hash->final (ctxt->hash_context);
-
- grub_dprintf ("crypt", "alive\n");
-
- hval = ctxt->hash->read (ctxt->hash_context);
-
- 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 (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].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 (readbuf);
-
- return GRUB_ERR_NONE;
-
- 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)
-{
- 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
-grub_cmd_trust (grub_extcmd_context_t ctxt,
- int argc, char **args)
-{
- grub_file_t pkf;
- struct grub_public_key *pk = NULL;
-
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
-
- 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
- : 0));
- if (!pkf)
- return grub_errno;
- pk = grub_load_public_key (pkf);
- if (!pk)
- {
- grub_file_close (pkf);
- return grub_errno;
- }
- grub_file_close (pkf);
-
- pk->next = grub_pk_trusted;
- grub_pk_trusted = pk;
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_cmd_list (grub_command_t cmd __attribute__ ((unused)),
- int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
-{
- struct grub_public_key *pk = NULL;
- struct grub_public_subkey *sk = NULL;
-
- for (pk = grub_pk_trusted; pk; pk = pk->next)
- for (sk = pk->subkeys; sk; sk = sk->next)
- {
- unsigned i;
- for (i = 0; i < 20; i += 2)
- grub_printf ("%02x%02x ", ((grub_uint8_t *) sk->fingerprint)[i],
- ((grub_uint8_t *) sk->fingerprint)[i + 1]);
- grub_printf ("\n");
- }
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)),
- int argc, char **args)
-{
- grub_uint32_t keyid, keyid_be;
- struct grub_public_key **pkey;
- struct grub_public_subkey *sk;
-
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
- keyid = grub_strtoull (args[0], 0, 16);
- if (grub_errno)
- return grub_errno;
- keyid_be = grub_cpu_to_be32 (keyid);
-
- for (pkey = &grub_pk_trusted; *pkey; pkey = &((*pkey)->next))
- {
- struct grub_public_key *next;
- for (sk = (*pkey)->subkeys; sk; sk = sk->next)
- if (grub_memcmp (sk->fingerprint + 4, &keyid_be, 4) == 0)
- break;
- if (!sk)
- continue;
- next = (*pkey)->next;
- free_pk (*pkey);
- *pkey = next;
- return GRUB_ERR_NONE;
- }
- /* TRANSLATORS: %08x is 32-bit key id. */
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), keyid);
-}
-
-static grub_err_t
-grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
- int argc, char **args)
-{
- grub_file_t f = NULL, sig = NULL;
- grub_err_t err = GRUB_ERR_NONE;
- struct grub_public_key *pk = NULL;
-
- grub_dprintf ("crypt", "alive\n");
-
- if (argc < 2)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
-
- grub_dprintf ("crypt", "alive\n");
-
- if (argc > 2)
- {
- grub_file_t pkf;
- 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
- : 0));
- if (!pkf)
- return grub_errno;
- pk = grub_load_public_key (pkf);
- if (!pk)
- {
- grub_file_close (pkf);
- return grub_errno;
- }
- grub_file_close (pkf);
- }
-
- f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
- if (!f)
- {
- err = grub_errno;
- goto fail;
- }
-
- sig = grub_file_open (args[1],
- GRUB_FILE_TYPE_SIGNATURE
- | GRUB_FILE_TYPE_NO_DECOMPRESS);
- if (!sig)
- {
- err = grub_errno;
- goto fail;
- }
-
- err = grub_verify_signature (f, sig, pk);
- fail:
- if (sig)
- grub_file_close (sig);
- if (f)
- grub_file_close (f);
- if (pk)
- free_pk (pk);
- return err;
-}
-
-static int sec = 0;
-
-static grub_err_t
-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;
-
- if (!sec)
- {
- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
- return GRUB_ERR_NONE;
- }
-
- fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
- if (!fsuf)
- 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 grub_errno;
-
-
- struct grub_pubkey_context *ctxt = grub_malloc (sizeof (*ctxt));
- if (!ctxt)
- {
- grub_file_close (sig);
- return grub_errno;
- }
- err = grub_verify_signature_init (ctxt, sig);
- if (err)
- {
- grub_pubkey_close (ctxt);
- return err;
- }
- *context = ctxt;
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_pubkey_fini (void *ctxt)
-{
- return grub_verify_signature_real (ctxt, NULL);
-}
-
-static char *
-grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)),
- const char *val)
-{
- sec = (*val == '1') || (*val == 'e');
- return grub_strdup (sec ? "enforce" : "no");
-}
-
-static grub_ssize_t
-pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
-{
- grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
- return len;
-}
-
-
-/* Filesystem descriptor. */
-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;
-
-GRUB_MOD_INIT(verify)
-{
- const char *val;
- struct grub_module_header *header;
-
- val = grub_env_get ("check_signatures");
- if (val && (val[0] == '1' || val[0] == 'e'))
- sec = 1;
- else
- sec = 0;
-
- grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec);
- grub_env_export ("check_signatures");
-
- grub_pk_trusted = 0;
- FOR_MODULES (header)
- {
- struct grub_file pseudo_file;
- struct grub_public_key *pk = NULL;
-
- grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
-
- /* Not an ELF module, skip. */
- if (header->type != OBJ_TYPE_PUBKEY)
- continue;
-
- pseudo_file.fs = &pseudo_fs;
- pseudo_file.size = (header->size - sizeof (struct grub_module_header));
- pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
-
- pk = grub_load_public_key (&pseudo_file);
- if (!pk)
- grub_fatal ("error loading initial key: %s\n", grub_errmsg);
-
- pk->next = grub_pk_trusted;
- grub_pk_trusted = pk;
- }
-
- if (!val)
- grub_env_set ("check_signatures", grub_pk_trusted ? "enforce" : "no");
-
- cmd = grub_register_extcmd ("verify_detached", grub_cmd_verify_signature, 0,
- N_("[-s|--skip-sig] FILE SIGNATURE_FILE [PUBKEY_FILE]"),
- N_("Verify detached signature."),
- options);
- cmd_trust = grub_register_extcmd ("trust", grub_cmd_trust, 0,
- N_("[-s|--skip-sig] PUBKEY_FILE"),
- N_("Add PUBKEY_FILE to trusted keys."),
- options);
- cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
- 0,
- N_("Show the list of trusted keys."));
- 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_verifier_unregister (&grub_pubkey_verifier);
- grub_unregister_extcmd (cmd);
- grub_unregister_extcmd (cmd_trust);
- grub_unregister_command (cmd_list);
- grub_unregister_command (cmd_distrust);
-}
--
1.7.10.4
Ross Philipson
2018-10-05 16:24:18 UTC
Permalink
Post by Daniel Kiper
Just for clarity. No functional change.
---
grub-core/Makefile.core.def | 4 +-
grub-core/commands/pgp.c | 1018 +++++++++++++++++++++++++++++++++++++++++++
grub-core/commands/verify.c | 1018 -------------------------------------------
3 files changed, 1020 insertions(+), 1020 deletions(-)
create mode 100644 grub-core/commands/pgp.c
delete mode 100644 grub-core/commands/verify.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index dfcc95d..3008b58 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -888,8 +888,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/pgp.c b/grub-core/commands/pgp.c
new file mode 100644
index 0000000..d5d7c0f
--- /dev/null
+++ b/grub-core/commands/pgp.c
@@ -0,0 +1,1018 @@
[snip]
Post by Daniel Kiper
diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
deleted file mode 100644
index d5d7c0f..0000000
--- a/grub-core/commands/verify.c
+++ /dev/null
@@ -1,1018 +0,0 @@
[snip]

Scanning through this in a split view, the new file looks exactly the
same as the old one. Shouldn't this just be a git mv (a rename commit)
instead of deleting the old file and adding a new one?
Daniel Kiper
2018-10-09 14:11:53 UTC
Permalink
Post by Ross Philipson
Post by Daniel Kiper
Just for clarity. No functional change.
---
grub-core/Makefile.core.def | 4 +-
grub-core/commands/pgp.c | 1018 +++++++++++++++++++++++++++++++++++++++++++
grub-core/commands/verify.c | 1018 -------------------------------------------
3 files changed, 1020 insertions(+), 1020 deletions(-)
create mode 100644 grub-core/commands/pgp.c
delete mode 100644 grub-core/commands/verify.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index dfcc95d..3008b58 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -888,8 +888,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/pgp.c b/grub-core/commands/pgp.c
new file mode 100644
index 0000000..d5d7c0f
--- /dev/null
+++ b/grub-core/commands/pgp.c
@@ -0,0 +1,1018 @@
[snip]
Post by Daniel Kiper
diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
deleted file mode 100644
index d5d7c0f..0000000
--- a/grub-core/commands/verify.c
+++ /dev/null
@@ -1,1018 +0,0 @@
[snip]
Scanning through this in a split view, the new file looks exactly the
same as the old one. Shouldn't this just be a git mv (a rename commit)
instead of deleting the old file and adding a new one?
I did "git mv" but "git format-patch" produced this. I am not sure that
"git format-patch" is sufficiently smart to produce shorter stuff.

Daniel
Michel Hermier
2018-10-09 14:17:01 UTC
Permalink
This is to be expected. Patch file format is dumb and doesn't know about
files moving.
Michel Hermier
2018-10-09 14:20:41 UTC
Permalink
That said maybe it's better for readability to do it in 2 patch, one for
moving the file and one for the renaming.
Ross Philipson
2018-10-09 14:44:02 UTC
Permalink
Post by Michel Hermier
That said maybe it's better for readability to do it in 2 patch, one for
moving the file and one for the renaming.
I did a test and I thought format generated something more sane but
maybe I only ended up doing "git show". Maybe just put a note under the
snip line that format-patch is turning a "git mv" into a ton of
duplicated patch code.

Thanks
Konrad Rzeszutek Wilk
2018-10-09 15:06:05 UTC
Permalink
Post by Daniel Kiper
I did "git mv" but "git format-patch" produced this. I am not sure that
"git format-patch" is sufficiently smart to produce shorter stuff.
Look at the -M param for git format-patch.
Daniel Kiper
2018-10-03 09:36:55 UTC
Permalink
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 verification to other verifiers.

Signed-off-by: Daniel Kiper <***@oracle.com>
---
v3 - suggestions/fixes:
- disable module unload,
- disable the iorw and memrw modules loading,
- disable boot if the iorw and memrw modules are loaded,
- defer GRUB2 modules verification to other verifiers.
---
grub-core/Makefile.core.def | 6 ++
grub-core/commands/efi/shim_lock.c | 140 ++++++++++++++++++++++++++++++++++++
2 files changed, 146 insertions(+)
create mode 100644 grub-core/commands/efi/shim_lock.c

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 3008b58..4a7c15f 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -900,6 +900,12 @@ module = {
};

module = {
+ name = shim_lock;
+ common = commands/efi/shim_lock.c;
+ enable = x86_64_efi;
+};
+
+module = {
name = hdparm;
common = commands/hdparm.c;
enable = pci;
diff --git a/grub-core/commands/efi/shim_lock.c b/grub-core/commands/efi/shim_lock.c
new file mode 100644
index 0000000..1bbf624
--- /dev/null
+++ b/grub-core/commands/efi/shim_lock.c
@@ -0,0 +1,140 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * EFI shim lock verifier.
+ */
+
+#include <grub/dl.h>
+#include <grub/efi/efi.h>
+#include <grub/err.h>
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/verify.h>
+
+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[] = {/* "acpi", ??? */ "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;
+ }
+
+ *flags = GRUB_VERIFY_FLAGS_DEFER;
+
+ 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);
+}
--
1.7.10.4
Daniel Kiper
2018-10-03 09:36:54 UTC
Permalink
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 <***@oracle.com>
---
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 fc20c65..6bbce31 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 2bca56c..fee27a1 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,
--
1.7.10.4
Daniel Kiper
2018-10-03 09:36:48 UTC
Permalink
This post might be inappropriate. Click to display it.
Ross Philipson
2018-10-03 17:33:26 UTC
Permalink
Post by Daniel Kiper
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.
---
- remove unneeded grub-core/commands/i386/nthibr.c
(suggested by Matthew Garrett).
---
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 | 53 ++++-----
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 | 10 +-
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 | 6 +-
include/grub/elfload.h | 2 +-
include/grub/file.h | 151 +++++++++++++++++++-------
include/grub/machoload.h | 3 +-
util/grub-fstest.c | 6 +-
util/grub-mount.c | 6 +-
70 files changed, 297 insertions(+), 225 deletions(-)
diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c
index 9f02f22..5a1499a 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 d1a47b5..944449b 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 88d9044..ba5f006 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 cc23ee6..e9c3b25 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 132cadb..d41d521 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 3ff6d55..4f81aa1 100644
--- a/grub-core/commands/file.c
+++ b/grub-core/commands/file.c
@@ -165,7 +165,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)
{
- 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 d186873..0f18f2c 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
+ : 0));
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
+ : 0));
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
+ : 0));
if (!file)
{
if (!keep)
diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c
index 4c884b3..eaa1246 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 7712e2a..c818131 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 f35d3a3..c05d612 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 b32f3c7..db7a8f0 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 acd93d1..ada72df 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 : 0));
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 : 0));
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 c25161c..2cdb2ac 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;
@@ -234,8 +234,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 a3a1182..fc20c65 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 2f56a87..c278f37 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 693e2cb..22b46b1 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 7dd32e4..ddda6e7 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 5f06642..13c6ed9 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 cfab6763..ff01a05 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 042645f..c13a9b8 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 67cb1c7..3616318 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
+ : 0));
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
+ : 0));
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;
@@ -892,7 +895,7 @@ grub_pubkey_open (grub_file_t io, const char *filename)
ret = grub_malloc (sizeof (*ret));
if (!ret)
{
- grub_file_close (sig);
+ grub_free (fsuf);
return NULL;
}
*ret = *io;
@@ -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 2d8deae..9406d93 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 f6813b1..a819347 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 53d76a6..85a2925 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 87eef62..1402e0b 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 4880cef..4d02e62 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 0297839..d6829bb 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 dbed647..1b59293 100644
--- a/grub-core/io/bufio.c
+++ b/grub-core/io/bufio.c
@@ -43,7 +43,8 @@ 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 +58,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)
io->size);
@@ -88,11 +89,12 @@ grub_bufio_open (grub_file_t io, int size)
}
grub_file_t
-grub_buffile_open (const char *name, int size)
+grub_buffile_open (const char *name, enum grub_file_type type,
+ grub_size_t size)
{
grub_file_t io, file;
- io = grub_file_open (name);
+ io = grub_file_open (name, type);
if (! io)
return 0;
diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
index 86ea8cf..7760d8b 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 7559c6c..84edf6d 100644
--- a/grub-core/io/lzopio.c
+++ b/grub-core/io/lzopio.c
}
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 ebed0eb..ec8e232 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 a3536ad..42afeed 100644
--- a/grub-core/io/xzio.c
+++ b/grub-core/io/xzio.c
}
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 e394cd9..f8d58f0 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 4f282c9..9d7149b 100644
--- a/grub-core/kern/elf.c
+++ b/grub-core/kern/elf.c
}
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 668f893..6431542 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;
+ }
This doesn't seem like it is related to adding file type information.
Was the setting of the name just something that was already missing/broken?
Post by Daniel Kiper
}
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 28ba3ae..c96d85e 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 adc8563..f706b1a 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 7f96515..d34da14 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 2cb78ee..0a19ebb 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 4eab55a..b4e40ac 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -652,7 +652,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 ef3a322..976fea7 100644
--- a/grub-core/loader/i386/pc/chainloader.c
+++ b/grub-core/loader/i386/pc/chainloader.c
@@ -172,8 +172,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 478f3c5..aac6c97 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 531b58d..0a5aa0c 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 1b88f40..f0d7414 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 814a49d..0351090 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 e60c62b..acb0611 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 9ea4fde..cbeeec7 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 3073f64..85cc8d9 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 : 0));
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 77a93e7..9af5d66 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 59ef73a..e64ed08 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 be6fa0f..471b214 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 59b195e..085f9c6 100644
--- a/grub-core/loader/macho.c
+++ b/grub-core/loader/macho.c
}
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 5f383be..7b28ba7 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 40c67e8..5fbec33 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 : 0));
if (! file)
return grub_errno;
diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
index c9885b1..84c8b93 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 534a744..8089804 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 721b9c3..7a7cf2b 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 e6d345f..d01e6f2 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 169c126..719ebf4 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 78a70a8..1b03dfd 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 ac5d69f..a1e5c5a 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 21b0d9d..31359a4 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 e1a01e9..777e713 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 c7a16fa..7cb9d1d 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 acdd0c8..0ff72d1 100644
--- a/include/grub/bufio.h
+++ b/include/grub/bufio.h
@@ -22,7 +22,9 @@
#include <grub/file.h>
-grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, int size);
-grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, int size);
+grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, grub_size_t size);
+grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name,
+ enum grub_file_type type,
+ grub_size_t size);
#endif /* ! GRUB_BUFIO_H */
diff --git a/include/grub/elfload.h b/include/grub/elfload.h
index 9a7ae4e..dbb609c 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 739488c..e2795d1 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -25,6 +25,108 @@
#include <grub/fs.h>
#include <grub/disk.h>
+enum grub_file_type
+ {
+ /* 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 +179,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 +226,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 1eec118..f1157f4 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 a358ae4..f0a17d0 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 : 0)
+ | 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 a25db8a..e32b502 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)
Daniel Kiper
2018-10-09 13:43:29 UTC
Permalink
[...]
Post by Ross Philipson
Post by Daniel Kiper
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;
+ }
This doesn't seem like it is related to adding file type information.
Was the setting of the name just something that was already missing/broken?
Looks strange... I will take closer look at Vladimir patches
and try to remove the clutter...

Daniel
Daniel Kiper
2018-10-03 09:36:53 UTC
Permalink
From: Vladimir Serbinenko <***@gmail.com>

Signed-off-by: Vladimir Serbinenko <***@gmail.com>
Signed-off-by: Daniel Kiper <***@oracle.com>
---
v3 - suggestions/fixes:
- improve the documentation.
---
docs/grub-dev.texi | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)

diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index a9f4de6..ad72705 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,62 @@ 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 hash interface with @samp{init}/@samp{write}/@samp{fini}.
+
+There are eesntially 2 ways of using it: hashing and whole-file verification:
+
+With hashing approach:
+During @samp{init} you decide whether you want to check given file and init context.
+In @samp{write} you update you hashing state.
+In @samp{fini} you check that hash matches the expected value/passes some check/...
+
+With whole-file verification:
+During @samp{init} you decide whether you want to check given file and init context.
+In @samp{write} you verify file and return 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 API:
+
+Every time a file is opened your @samp{init} function is called with file descriptor
+and file type. Your function can have following outcomes:
+
+@itemize
+
+@item returning no error and setting @samp{*flags} to @samp{GRUB_VERIFY_FLAGS_DEFER}.
+In this case verification is deferred to others 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 your verifier is considered
+to have skipped verification
+
+@item returning error. Then opening of the file will fail due to failed 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 following section
+
+@end itemize
+
+In the fourth case your @samp{write} will be called with chunks of file. If you need the whole file in a single
+chunk then during @samp{init} set 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 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
--
1.7.10.4
Ross Philipson
2018-10-05 16:43:08 UTC
Permalink
Post by Daniel Kiper
---
- improve the documentation.
---
docs/grub-dev.texi | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index a9f4de6..ad72705 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -84,6 +84,7 @@ This edition documents version @value{VERSION}.
* Copying This Manual:: Copying This Manual
@end menu
@@ -1949,6 +1950,62 @@ the graphics mode that was in use before @code{grub_video_setup()} was called
might fix some of the problems.
+
+structure pointing to your functions.
+
+
First : should be a ;
Post by Daniel Kiper
+
"update your..."
Post by Daniel Kiper
+
+
+verify. Returning no error means successful verification and an error stops the current
s/and/or maybe?
Post by Daniel Kiper
+action.
+
+
+
+
+In this case verification is deferred to others active verifiers. Verification fails if
+nobody cares or selected verifier fails
+
+In this case your verifier will not be called anymore and your verifier is considered
+to have skipped verification
+
+
+In this case verification is done as described in following section
+
+
+an error and the the file will be considered as having failed the verification. If you return no error then
+verification continues.
+
+succeded verification.
succeeded
Post by Daniel Kiper
+
@node Copying This Manual
@appendix Copying This Manual
I noticed a lot of the text is missing articles, mainly "the" in a lot
of places. Not sure if this was intentional to keep the text more
abbreviated or not.
Daniel Kiper
2018-10-09 14:26:20 UTC
Permalink
Post by Ross Philipson
Post by Daniel Kiper
---
- improve the documentation.
---
docs/grub-dev.texi | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index a9f4de6..ad72705 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -84,6 +84,7 @@ This edition documents version @value{VERSION}.
* Copying This Manual:: Copying This Manual
@end menu
@@ -1949,6 +1950,62 @@ the graphics mode that was in use before @code{grub_video_setup()} was called
might fix some of the problems.
+
+structure pointing to your functions.
+
+
First : should be a ;
Post by Daniel Kiper
+
"update your..."
Post by Daniel Kiper
+
+
+verify. Returning no error means successful verification and an error stops the current
s/and/or maybe?
Post by Daniel Kiper
+action.
+
+
+
+
+In this case verification is deferred to others active verifiers. Verification fails if
+nobody cares or selected verifier fails
+
+In this case your verifier will not be called anymore and your verifier is considered
+to have skipped verification
+
+
+In this case verification is done as described in following section
+
+
+an error and the the file will be considered as having failed the verification. If you return no error then
+verification continues.
+
+succeded verification.
succeeded
Post by Daniel Kiper
+
@node Copying This Manual
@appendix Copying This Manual
I noticed a lot of the text is missing articles, mainly "the" in a lot
of places. Not sure if this was intentional to keep the text more
abbreviated or not.
Ohhh... At least in my case it was not intentional. Well, from my POV,
as not native speaker, I do not care... :-))) Both things work for me.
I do not see the difference (my English teacher would kill me here).
Hence, it is difficult for me to use articles correctly (FYI I am
working on that). However, I am aware that this is very important for
native speakers. So, if you can add the missing stuff for me I will be
more than happy.

Daniel
Ross Philipson
2018-10-09 14:46:28 UTC
Permalink
Post by Daniel Kiper
Post by Ross Philipson
Post by Daniel Kiper
---
- improve the documentation.
---
docs/grub-dev.texi | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index a9f4de6..ad72705 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -84,6 +84,7 @@ This edition documents version @value{VERSION}.
* Copying This Manual:: Copying This Manual
@end menu
@@ -1949,6 +1950,62 @@ the graphics mode that was in use before @code{grub_video_setup()} was called
might fix some of the problems.
+
+structure pointing to your functions.
+
+
First : should be a ;
Post by Daniel Kiper
+
"update your..."
Post by Daniel Kiper
+
+
+verify. Returning no error means successful verification and an error stops the current
s/and/or maybe?
Post by Daniel Kiper
+action.
+
+
+
+
+In this case verification is deferred to others active verifiers. Verification fails if
+nobody cares or selected verifier fails
+
+In this case your verifier will not be called anymore and your verifier is considered
+to have skipped verification
+
+
+In this case verification is done as described in following section
+
+
+an error and the the file will be considered as having failed the verification. If you return no error then
+verification continues.
+
+succeded verification.
succeeded
Post by Daniel Kiper
+
@node Copying This Manual
@appendix Copying This Manual
I noticed a lot of the text is missing articles, mainly "the" in a lot
of places. Not sure if this was intentional to keep the text more
abbreviated or not.
Ohhh... At least in my case it was not intentional. Well, from my POV,
as not native speaker, I do not care... :-))) Both things work for me.
I do not see the difference (my English teacher would kill me here).
Hence, it is difficult for me to use articles correctly (FYI I am
working on that). However, I am aware that this is very important for
native speakers. So, if you can add the missing stuff for me I will be
more than happy.
Understood. I will reply to the original patch with my suggested
corrections since this reply chain is getting ugly.

Thanks
Post by Daniel Kiper
Daniel
Ross Philipson
2018-10-09 14:59:37 UTC
Permalink
Post by Daniel Kiper
---
- improve the documentation.
---
docs/grub-dev.texi | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index a9f4de6..ad72705 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -84,6 +84,7 @@ This edition documents version @value{VERSION}.
* Copying This Manual:: Copying This Manual
@end menu
@@ -1949,6 +1950,62 @@ the graphics mode that was in use before @code{grub_video_setup()} was called
might fix some of the problems.
+
+structure pointing to your functions.
+
"... by the hash ..."
Post by Daniel Kiper
+> +There are eesntially 2 ways of using it: hashing and whole-file
verification:

eesntially -> essentially

The first : could be replaced with a , or ; depending on your mood :)
Post by Daniel Kiper
+
"With the hashing approach:"
"... check the given ..."
"you hashing" -> "your hasking"
"... that the hash ..."
Post by Daniel Kiper
+
"... check the given ..."
"... verify the file and return an error ..."
Post by Daniel Kiper
+
+verify. Returning no error means successful verification and an error stops the current
+action.
+
"... of the API ..."
Post by Daniel Kiper
+
"... a file descriptor..."
"... have the following ..."
Post by Daniel Kiper
+
+
+In this case verification is deferred to others active verifiers. Verification fails if
others -> other
Post by Daniel Kiper
+nobody cares or selected verifier fails
+
+In this case your verifier will not be called anymore and your verifier is considered
considered -> assumed
Post by Daniel Kiper
+to have skipped verification
+
+
+In this case verification is done as described in following section
"... in the following ..."
Post by Daniel Kiper
+
+
"... of the file ..."
"... set the bit..."
Post by Daniel Kiper
+an error and the the file will be considered as having failed the verification. If you return no error then
+verification continues.
+
You may need some commas around "if it exists" but I am not 100% sure
what is intended here.
Post by Daniel Kiper
+succeded verification.
+
@node Copying This Manual
@appendix Copying This Manual
Just my suggestions. Since the original text went back and forth between
complete grammar and abbreviated grammar, it is probably best to make it
all consistent.

Thanks
Ross

Daniel Kiper
2018-10-03 09:36:51 UTC
Permalink
This way if a verifier requires verification of a given file it can
defer task to other verifier 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 <***@oracle.com>
---
grub-core/commands/verify_helper.c | 23 ++++++++++++++++++++---
include/grub/verify.h | 3 ++-
2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/grub-core/commands/verify_helper.c b/grub-core/commands/verify_helper.c
index 7effc5f..ba8b03d 100644
--- a/grub-core/commands/verify_helper.c
+++ b/grub-core/commands/verify_helper.c
@@ -83,6 +83,7 @@ grub_verify_helper_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_verify_helper_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)
+ {
+ 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_verify_helper_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)
continue;
err = ver->write (context, verified->buf, ret->size);
if (err)
diff --git a/include/grub/verify.h b/include/grub/verify.h
index 9f892d8..c385e3d 100644
--- a/include/grub/verify.h
+++ b/include/grub/verify.h
@@ -22,7 +22,8 @@
enum grub_verify_flags
{
GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1,
- GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2
+ GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2,
+ GRUB_VERIFY_FLAGS_DEFER = 4
};

enum grub_verify_string_type
--
1.7.10.4
Ross Philipson
2018-10-05 16:09:43 UTC
Permalink
Post by Daniel Kiper
This way if a verifier requires verification of a given file it can
defer task to other verifier 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.
---
grub-core/commands/verify_helper.c | 23 ++++++++++++++++++++---
include/grub/verify.h | 3 ++-
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/grub-core/commands/verify_helper.c b/grub-core/commands/verify_helper.c
index 7effc5f..ba8b03d 100644
--- a/grub-core/commands/verify_helper.c
+++ b/grub-core/commands/verify_helper.c
@@ -83,6 +83,7 @@ grub_verify_helper_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_verify_helper_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)
+ {
+ 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;
+ }
I don't really understand the logic here. Is the idea that if it was
deferred and no one in the chain verified it, it ends up being an error?
Why is that?

Also defer has different meanings. I think in this context it means
defer verification to another authority as opposed to defer until later.
Post by Daniel Kiper
+
+ /* No verifiers wanted to verify. Just return underlying file. */
+ return io;
+ }
ret = grub_malloc (sizeof (*ret));
if (!ret)
@@ -160,7 +175,9 @@ grub_verify_helper_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)
continue;
err = ver->write (context, verified->buf, ret->size);
if (err)
diff --git a/include/grub/verify.h b/include/grub/verify.h
index 9f892d8..c385e3d 100644
--- a/include/grub/verify.h
+++ b/include/grub/verify.h
@@ -22,7 +22,8 @@
enum grub_verify_flags
{
GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1,
- GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2
+ GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2,
+ GRUB_VERIFY_FLAGS_DEFER = 4
What is the difference between skip verification and defer?
Post by Daniel Kiper
};
enum grub_verify_string_type
Daniel Kiper
2018-10-09 13:57:56 UTC
Permalink
Post by Ross Philipson
Post by Daniel Kiper
This way if a verifier requires verification of a given file it can
defer task to other verifier 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.
---
grub-core/commands/verify_helper.c | 23 ++++++++++++++++++++---
include/grub/verify.h | 3 ++-
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/grub-core/commands/verify_helper.c b/grub-core/commands/verify_helper.c
index 7effc5f..ba8b03d 100644
--- a/grub-core/commands/verify_helper.c
+++ b/grub-core/commands/verify_helper.c
@@ -83,6 +83,7 @@ grub_verify_helper_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_verify_helper_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)
+ {
+ 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;
+ }
I don't really understand the logic here. Is the idea that if it was
deferred and no one in the chain verified it, it ends up being an error?
Yep.
Post by Ross Philipson
Why is that?
Some verifiers may not be able to verify a given file themselves. So, they
may require that it have to be done by somebody else. shim_lock verifier
is good example. The commit message explains it.
Post by Ross Philipson
Also defer has different meanings. I think in this context it means
defer verification to another authority as opposed to defer until later.
Yes, exactly. I will improve the commit message.
Post by Ross Philipson
Post by Daniel Kiper
+ /* No verifiers wanted to verify. Just return underlying file. */
+ return io;
+ }
ret = grub_malloc (sizeof (*ret));
if (!ret)
@@ -160,7 +175,9 @@ grub_verify_helper_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)
continue;
err = ver->write (context, verified->buf, ret->size);
if (err)
diff --git a/include/grub/verify.h b/include/grub/verify.h
index 9f892d8..c385e3d 100644
--- a/include/grub/verify.h
+++ b/include/grub/verify.h
@@ -22,7 +22,8 @@
enum grub_verify_flags
{
GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1,
- GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2
+ GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2,
+ GRUB_VERIFY_FLAGS_DEFER = 4
What is the difference between skip verification and defer?
Skip == I do not care here. Defer == "defer verification to another authority".

Daniel
Daniel Kiper
2018-10-03 09:36:50 UTC
Permalink
From: Vladimir Serbinenko <***@gmail.com>

Signed-off-by: Vladimir Serbinenko <***@gmail.com>
Signed-off-by: Daniel Kiper <***@oracle.com>
---
grub-core/commands/verify_helper.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/verify_helper.c b/grub-core/commands/verify_helper.c
index 6e60dbf..7effc5f 100644
--- a/grub-core/commands/verify_helper.c
+++ b/grub-core/commands/verify_helper.c
@@ -186,6 +186,20 @@ grub_verify_helper_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(verify_helper)
{
grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verify_helper_open);
diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
index d5e10ee..ed0b149 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 b4f609d..80293fb 100644
--- a/grub-core/loader/arm/linux.c
+++ b/grub-core/loader/arm/linux.c
@@ -28,6 +28,7 @@
#include <grub/cpu/linux.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
+#include <grub/verify.h>

GRUB_MOD_LICENSE ("GPLv3+");

@@ -383,8 +384,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 1f86229..b8315b5 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -32,6 +32,7 @@
#include <grub/efi/pe32.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
+#include <grub/verify.h>

GRUB_MOD_LICENSE ("GPLv3+");

@@ -339,9 +340,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 d34da14..c26edb4 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -35,6 +35,7 @@
#include <grub/ns8250.h>
#include <grub/bsdlabel.h>
#include <grub/crypto.h>
+#include <grub/verify.h>
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/int.h>
#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 b4e40ac..c408b10 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -969,11 +969,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 dc98dbc..ad3cc29 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 0a5aa0c..47ea294 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 0351090..3755015 100644
--- a/grub-core/loader/i386/pc/plan9.c
+++ b/grub-core/loader/i386/pc/plan9.c
@@ -33,6 +33,7 @@
#include <grub/mm.h>
#include <grub/cpu/relocator.h>
#include <grub/extcmd.h>
+#include <grub/verify.h>

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 85cc8d9..5b5968e 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -40,6 +40,7 @@
#include <grub/xen_file.h>
#include <grub/linux.h>
#include <grub/i386/memory.h>
+#include <grub/verify.h>

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 96fce71..6477d70 100644
--- a/grub-core/loader/ia64/efi/linux.c
+++ b/grub-core/loader/ia64/efi/linux.c
@@ -33,6 +33,7 @@
#include <grub/i18n.h>
#include <grub/env.h>
#include <grub/linux.h>
+#include <grub/verify.h>

GRUB_MOD_LICENSE ("GPLv3+");

@@ -501,6 +502,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 7b28ba7..e256c44 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 747e108..53da786 100644
--- a/grub-core/loader/multiboot_mbi2.c
+++ b/grub-core/loader/multiboot_mbi2.c
@@ -1038,10 +1038,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
@@ -1050,6 +1048,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)
@@ -1068,8 +1067,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 6e81464..c114e7d 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 67ef048..abe46fa 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 84c8b93..ff66be4 100644
--- a/grub-core/loader/xnu.c
+++ b/grub-core/loader/xnu.c
@@ -33,6 +33,7 @@
#include <grub/extcmd.h>
#include <grub/env.h>
#include <grub/i18n.h>
+#include <grub/verify.h>

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 1fe8d01..cdca09b 100644
--- a/include/grub/lib/cmdline.h
+++ b/include/grub/lib/cmdline.h
@@ -21,11 +21,12 @@
#define GRUB_CMDLINE_HEADER 1

#include <grub/types.h>
+#include <grub/verify.h>

#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 298120f..9f892d8 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);
--
1.7.10.4
Daniel Kiper
2018-10-03 09:36:49 UTC
Permalink
From: Vladimir Serbinenko <***@gmail.com>

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 <***@gmail.com>
Signed-off-by: Daniel Kiper <***@oracle.com>
---
v3 - suggestions/fixes:
- minor improvement and cleanups.
---
grub-core/Makefile.core.def | 5 +
grub-core/commands/verify.c | 565 +++++++++++++++++-------------------
grub-core/commands/verify_helper.c | 197 +++++++++++++
include/grub/file.h | 2 +-
include/grub/list.h | 1 +
include/grub/verify.h | 65 +++++
6 files changed, 538 insertions(+), 297 deletions(-)
create mode 100644 grub-core/commands/verify_helper.c
create mode 100644 include/grub/verify.h

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 9590e87..dfcc95d 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -895,6 +895,11 @@ module = {
};

module = {
+ name = verify_helper;
+ common = commands/verify_helper.c;
+};
+
+module = {
name = hdparm;
common = commands/hdparm.c;
enable = pci;
diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
index 3616318..d5d7c0f 100644
--- a/grub-core/commands/verify.c
+++ b/grub-core/commands/verify.c
@@ -30,16 +30,10 @@
#include <grub/env.h>
#include <grub/kernel.h>
#include <grub/extcmd.h>
+#include <grub/verify.h>

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,22 +439,26 @@ rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
return ret;
}

-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)
+struct grub_pubkey_context
{
- grub_size_t len;
+ 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_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
+{
+ grub_size_t len;
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_uint8_t pk;
+
+ grub_memset (ctxt, 0, sizeof (*ctxt));

err = read_packet_header (sig, &type, &len);
if (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,232 @@ 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;
+ ctxt->sig = sig;

- context = grub_zalloc (hash->contextsize);
- readbuf = grub_zalloc (READBUF_SIZE);
- if (!context || !readbuf)
- goto fail;
-
- 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);
- }
-
- 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);
- }
- }
-
- hash->final (context);
-
- grub_dprintf ("crypt", "alive\n");
-
- hval = hash->read (context);
-
- if (grub_file_read (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 (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 (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");
-
- if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
- readbuf, lb + sizeof (grub_uint16_t), 0))
- goto fail;
- grub_dprintf ("crypt", "alive\n");
- }
-
- 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].pad (&hmpi, hval, 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);
-
- return GRUB_ERR_NONE;
-
- fail:
- grub_free (context);
- grub_free (readbuf);
- if (!grub_errno)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
+ if (!ctxt->hash_context)
return grub_errno;
+
+ ctxt->hash->init (ctxt->hash_context);
+
+ return GRUB_ERR_NONE;
+}
+
+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;
+
+ readbuf = grub_malloc (READBUF_SIZE);
+ if (!readbuf)
+ goto fail;
+
+ 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;
+ 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);
+ }
}
+
+ ctxt->hash->final (ctxt->hash_context);
+
+ grub_dprintf ("crypt", "alive\n");
+
+ hval = ctxt->hash->read (ctxt->hash_context);
+
+ 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 (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].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 (readbuf);
+
+ return GRUB_ERR_NONE;
+
+ 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 +866,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;

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;
+ return grub_errno;

- ret = grub_malloc (sizeof (*ret));
- if (!ret)
- {
- grub_free (fsuf);
- return NULL;
- }
- *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,
- "big file signature isn't implemented yet");
- grub_file_close (sig);
- grub_free (ret);
- return NULL;
- }
- verified = grub_malloc (sizeof (*verified));
- if (!verified)
- {
- 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)
+ struct grub_pubkey_context *ctxt = grub_malloc (sizeof (*ctxt));
+ if (!ctxt)
{
- 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 +935,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 +959,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 +1004,13 @@ GRUB_MOD_INIT(verify)
cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust,
N_("PUBKEY_ID"),
N_("Remove PUBKEY_ID from trusted keys."));
+
+ grub_verifier_register (&grub_pubkey_verifier);
}

GRUB_MOD_FINI(verify)
{
- grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY);
+ grub_verifier_unregister (&grub_pubkey_verifier);
grub_unregister_extcmd (cmd);
grub_unregister_extcmd (cmd_trust);
grub_unregister_command (cmd_list);
diff --git a/grub-core/commands/verify_helper.c b/grub-core/commands/verify_helper.c
new file mode 100644
index 0000000..6e60dbf
--- /dev/null
+++ b/grub-core/commands/verify_helper.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 <http://www.gnu.org/licenses/>.
+ *
+ * Verifiers helper.
+ */
+
+#include <grub/file.h>
+#include <grub/verify.h>
+#include <grub/dl.h>
+
+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_verify_helper_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(verify_helper)
+{
+ grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verify_helper_open);
+}
+
+GRUB_MOD_FINI(verify_helper)
+{
+ grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY);
+}
diff --git a/include/grub/file.h b/include/grub/file.h
index e2795d1..c55901c 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -170,7 +170,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 d170ff6..b13acb9 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 0000000..298120f
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/file.h>
+#include <grub/list.h>
+
+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));
+}
--
1.7.10.4
Ross Philipson
2018-10-03 17:55:08 UTC
Permalink
Post by Daniel Kiper
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.
---
- minor improvement and cleanups.
---
grub-core/Makefile.core.def | 5 +
grub-core/commands/verify.c | 565 +++++++++++++++++-------------------
grub-core/commands/verify_helper.c | 197 +++++++++++++
include/grub/file.h | 2 +-
include/grub/list.h | 1 +
include/grub/verify.h | 65 +++++
6 files changed, 538 insertions(+), 297 deletions(-)
create mode 100644 grub-core/commands/verify_helper.c
create mode 100644 include/grub/verify.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 9590e87..dfcc95d 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -895,6 +895,11 @@ module = {
};
module = {
+ name = verify_helper;
+ common = commands/verify_helper.c;
+};
+
+module = {
name = hdparm;
common = commands/hdparm.c;
enable = pci;
diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
index 3616318..d5d7c0f 100644
--- a/grub-core/commands/verify.c
+++ b/grub-core/commands/verify.c
@@ -30,16 +30,10 @@
#include <grub/env.h>
#include <grub/kernel.h>
#include <grub/extcmd.h>
+#include <grub/verify.h>
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,22 +439,26 @@ rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
return ret;
}
-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)
+struct grub_pubkey_context
{
- grub_size_t len;
+ 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_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
+{
+ grub_size_t len;
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_uint8_t pk;
+
+ grub_memset (ctxt, 0, sizeof (*ctxt));
err = read_packet_header (sig, &type, &len);
if (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,232 @@ 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;
+ ctxt->sig = sig;
- context = grub_zalloc (hash->contextsize);
- readbuf = grub_zalloc (READBUF_SIZE);
- if (!context || !readbuf)
- goto fail;
-
- 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);
- }
-
- 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);
- }
- }
-
- hash->final (context);
-
- grub_dprintf ("crypt", "alive\n");
-
- hval = hash->read (context);
-
- if (grub_file_read (sig, hash_start, sizeof (hash_start)) != sizeof (hash_start))
- goto fail;
- if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
- goto fail;
-
-
- 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");
-
- if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
- readbuf, lb + sizeof (grub_uint16_t), 0))
- goto fail;
- grub_dprintf ("crypt", "alive\n");
- }
-
- 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].pad (&hmpi, hval, 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);
-
- return GRUB_ERR_NONE;
-
- grub_free (context);
- grub_free (readbuf);
- if (!grub_errno)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
+ if (!ctxt->hash_context)
return grub_errno;
+
+ ctxt->hash->init (ctxt->hash_context);
+
+ return GRUB_ERR_NONE;
+}
+
+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;
+
+ readbuf = grub_malloc (READBUF_SIZE);
+ if (!readbuf)
+ goto fail;
+
+ 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;
+ 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);
+ }
}
+
+ ctxt->hash->final (ctxt->hash_context);
+
+ grub_dprintf ("crypt", "alive\n");
+
+ hval = ctxt->hash->read (ctxt->hash_context);
+
+ 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;
+
+
+ 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 (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].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 (readbuf);
+
+ return GRUB_ERR_NONE;
+
+ 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);
+ grub_pubkey_close_real (&ctxt);
+ return grub_errno;
}
static grub_err_t
@@ -819,134 +866,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;
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;
+ return grub_errno;
- ret = grub_malloc (sizeof (*ret));
- if (!ret)
- {
- grub_free (fsuf);
- return NULL;
- }
- *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,
- "big file signature isn't implemented yet");
- grub_file_close (sig);
- grub_free (ret);
- return NULL;
- }
- verified = grub_malloc (sizeof (*verified));
- if (!verified)
- {
- 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)
+ struct grub_pubkey_context *ctxt = grub_malloc (sizeof (*ctxt));
+ if (!ctxt)
{
- 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 +935,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,
+ };
If I am reading this correctly, most of the first part of this is
re-factoring the signature/pubkey verifier code to fit in with your new
framework of verifiers, is that correct? So even though a bunch of code
moved around and changed to some degree, it should be functionally
basically the same?

Just trying to wrap my head around it - these are a lot of changes...
Post by Daniel Kiper
static grub_extcmd_t cmd, cmd_trust;
static grub_command_t cmd_distrust, cmd_list;
@@ -986,8 +959,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 +1004,13 @@ GRUB_MOD_INIT(verify)
cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust,
N_("PUBKEY_ID"),
N_("Remove PUBKEY_ID from trusted keys."));
+
+ grub_verifier_register (&grub_pubkey_verifier);
}
GRUB_MOD_FINI(verify)
{
- grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY);
+ grub_verifier_unregister (&grub_pubkey_verifier);
grub_unregister_extcmd (cmd);
grub_unregister_extcmd (cmd_trust);
grub_unregister_command (cmd_list);
diff --git a/grub-core/commands/verify_helper.c b/grub-core/commands/verify_helper.c
new file mode 100644
index 0000000..6e60dbf
--- /dev/null
+++ b/grub-core/commands/verify_helper.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 <http://www.gnu.org/licenses/>.
+ *
+ * Verifiers helper.
+ */
+
+#include <grub/file.h>
+#include <grub/verify.h>
+#include <grub/dl.h>
+
+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_verify_helper_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;
+
+ ver->close (context);
+ verified_free (verified);
+ grub_free (ret);
+ return NULL;
+}
+
+GRUB_MOD_INIT(verify_helper)
+{
+ grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verify_helper_open);
+}
+
+GRUB_MOD_FINI(verify_helper)
+{
+ grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY);
+}
diff --git a/include/grub/file.h b/include/grub/file.h
index e2795d1..c55901c 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -170,7 +170,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,
I guess this kind of goes with my question above. Previously there was
only one "verifier" and that was the pubkey verifier. Now the pubkey
verifier will be one of many right?
Post by Daniel Kiper
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 d170ff6..b13acb9 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 0000000..298120f
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/file.h>
+#include <grub/list.h>
+
+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));
+}
Daniel Kiper
2018-10-09 13:48:23 UTC
Permalink
[...]
Post by Ross Philipson
Post by Daniel Kiper
+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,
+ };
If I am reading this correctly, most of the first part of this is
re-factoring the signature/pubkey verifier code to fit in with your new
framework of verifiers, is that correct? So even though a bunch of code
moved around and changed to some degree, it should be functionally
basically the same?
That is the goal...

[...]
Post by Ross Philipson
Post by Daniel Kiper
diff --git a/include/grub/file.h b/include/grub/file.h
index e2795d1..c55901c 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -170,7 +170,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,
I guess this kind of goes with my question above. Previously there was
only one "verifier" and that was the pubkey verifier. Now the pubkey
verifier will be one of many right?
Yep.

Daniel
Loading...