|
|
c6c771 |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
c6c771 |
From: Stefan Berger <stefanb@linux.ibm.com>
|
|
|
c6c771 |
Date: Sun, 15 Mar 2020 12:37:10 -0400
|
|
|
c6c771 |
Subject: [PATCH] ibmvtpm: Add support for trusted boot using a vTPM 2.0
|
|
|
c6c771 |
|
|
|
c6c771 |
Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275
|
|
|
c6c771 |
PowerPC platform. With this patch grub now measures text and binary data
|
|
|
c6c771 |
into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform
|
|
|
c6c771 |
does.
|
|
|
c6c771 |
|
|
|
c6c771 |
This patch requires Daniel Axtens's patches for claiming more memory.
|
|
|
c6c771 |
|
|
|
c6c771 |
For vTPM support to work on PowerVM, system driver levels 1010.30
|
|
|
c6c771 |
or 1020.00 are required.
|
|
|
c6c771 |
|
|
|
c6c771 |
Note: Previous versions of firmware levels with the 2hash-ext-log
|
|
|
c6c771 |
API call have a bug that, once this API call is invoked, has the
|
|
|
c6c771 |
effect of disabling the vTPM driver under Linux causing an error
|
|
|
c6c771 |
message to be displayed in the Linux kernel log. Those users will
|
|
|
c6c771 |
have to update their machines to the firmware levels mentioned
|
|
|
c6c771 |
above.
|
|
|
c6c771 |
|
|
|
c6c771 |
Cc: Eric Snowberg <eric.snowberg@oracle.com>
|
|
|
c6c771 |
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
|
|
|
c6c771 |
---
|
|
|
c6c771 |
grub-core/Makefile.core.def | 7 ++
|
|
|
c6c771 |
grub-core/commands/ieee1275/ibmvtpm.c | 152 ++++++++++++++++++++++++++++++++++
|
|
|
c6c771 |
include/grub/ieee1275/ieee1275.h | 3 +
|
|
|
c6c771 |
3 files changed, 162 insertions(+)
|
|
|
c6c771 |
create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c
|
|
|
c6c771 |
|
|
|
c6c771 |
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
|
|
|
c6c771 |
index ef06f8c95a..b11f74e6b2 100644
|
|
|
c6c771 |
--- a/grub-core/Makefile.core.def
|
|
|
c6c771 |
+++ b/grub-core/Makefile.core.def
|
|
|
c6c771 |
@@ -1104,6 +1104,13 @@ module = {
|
|
|
c6c771 |
enable = powerpc_ieee1275;
|
|
|
c6c771 |
};
|
|
|
c6c771 |
|
|
|
c6c771 |
+module = {
|
|
|
c6c771 |
+ name = tpm;
|
|
|
c6c771 |
+ common = commands/tpm.c;
|
|
|
c6c771 |
+ ieee1275 = commands/ieee1275/ibmvtpm.c;
|
|
|
c6c771 |
+ enable = powerpc_ieee1275;
|
|
|
c6c771 |
+};
|
|
|
c6c771 |
+
|
|
|
c6c771 |
module = {
|
|
|
c6c771 |
name = terminal;
|
|
|
c6c771 |
common = commands/terminal.c;
|
|
|
c6c771 |
diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
|
|
|
c6c771 |
new file mode 100644
|
|
|
c6c771 |
index 0000000000..e68b8448bc
|
|
|
c6c771 |
--- /dev/null
|
|
|
c6c771 |
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
|
|
|
c6c771 |
@@ -0,0 +1,152 @@
|
|
|
c6c771 |
+/*
|
|
|
c6c771 |
+ * GRUB -- GRand Unified Bootloader
|
|
|
c6c771 |
+ * Copyright (C) 2021 Free Software Foundation, Inc.
|
|
|
c6c771 |
+ * Copyright (C) 2021 IBM Corporation
|
|
|
c6c771 |
+ *
|
|
|
c6c771 |
+ * GRUB is free software: you can redistribute it and/or modify
|
|
|
c6c771 |
+ * it under the terms of the GNU General Public License as published by
|
|
|
c6c771 |
+ * the Free Software Foundation, either version 3 of the License, or
|
|
|
c6c771 |
+ * (at your option) any later version.
|
|
|
c6c771 |
+ *
|
|
|
c6c771 |
+ * GRUB is distributed in the hope that it will be useful,
|
|
|
c6c771 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
c6c771 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
c6c771 |
+ * GNU General Public License for more details.
|
|
|
c6c771 |
+ *
|
|
|
c6c771 |
+ * You should have received a copy of the GNU General Public License
|
|
|
c6c771 |
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
|
|
c6c771 |
+ *
|
|
|
c6c771 |
+ * IBM vTPM support code.
|
|
|
c6c771 |
+ */
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+#include <grub/err.h>
|
|
|
c6c771 |
+#include <grub/types.h>
|
|
|
c6c771 |
+#include <grub/tpm.h>
|
|
|
c6c771 |
+#include <grub/ieee1275/ieee1275.h>
|
|
|
c6c771 |
+#include <grub/mm.h>
|
|
|
c6c771 |
+#include <grub/misc.h>
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+static grub_ieee1275_ihandle_t tpm_ihandle;
|
|
|
c6c771 |
+static grub_uint8_t tpm_version;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0)
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+static void
|
|
|
c6c771 |
+tpm_get_tpm_version (void)
|
|
|
c6c771 |
+{
|
|
|
c6c771 |
+ grub_ieee1275_phandle_t vtpm;
|
|
|
c6c771 |
+ char buffer[20];
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) &&
|
|
|
c6c771 |
+ !grub_ieee1275_get_property (vtpm, "compatible", buffer,
|
|
|
c6c771 |
+ sizeof (buffer), NULL) &&
|
|
|
c6c771 |
+ !grub_strcmp (buffer, "IBM,vtpm20"))
|
|
|
c6c771 |
+ tpm_version = 2;
|
|
|
c6c771 |
+}
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+static grub_err_t
|
|
|
c6c771 |
+tpm_init (void)
|
|
|
c6c771 |
+{
|
|
|
c6c771 |
+ static int init_success = 0;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ if (!init_success)
|
|
|
c6c771 |
+ {
|
|
|
c6c771 |
+ if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0) {
|
|
|
c6c771 |
+ tpm_ihandle = IEEE1275_IHANDLE_INVALID;
|
|
|
c6c771 |
+ return GRUB_ERR_UNKNOWN_DEVICE;
|
|
|
c6c771 |
+ }
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ init_success = 1;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ tpm_get_tpm_version ();
|
|
|
c6c771 |
+ }
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ return GRUB_ERR_NONE;
|
|
|
c6c771 |
+}
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+static int
|
|
|
c6c771 |
+ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
|
|
|
c6c771 |
+ grub_uint32_t eventtype,
|
|
|
c6c771 |
+ const char *description,
|
|
|
c6c771 |
+ grub_size_t description_size,
|
|
|
c6c771 |
+ void *buf, grub_size_t size)
|
|
|
c6c771 |
+{
|
|
|
c6c771 |
+ struct tpm_2hash_ext_log
|
|
|
c6c771 |
+ {
|
|
|
c6c771 |
+ struct grub_ieee1275_common_hdr common;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t method;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t ihandle;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t size;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t buf;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t description_size;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t description;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t eventtype;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t pcrindex;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t catch_result;
|
|
|
c6c771 |
+ grub_ieee1275_cell_t rc;
|
|
|
c6c771 |
+ }
|
|
|
c6c771 |
+ args;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
|
|
|
c6c771 |
+ args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
|
|
|
c6c771 |
+ args.ihandle = tpm_ihandle;
|
|
|
c6c771 |
+ args.pcrindex = pcrindex;
|
|
|
c6c771 |
+ args.eventtype = eventtype;
|
|
|
c6c771 |
+ args.description = (grub_ieee1275_cell_t) description;
|
|
|
c6c771 |
+ args.description_size = description_size;
|
|
|
c6c771 |
+ args.buf = (grub_ieee1275_cell_t) buf;
|
|
|
c6c771 |
+ args.size = (grub_ieee1275_cell_t) size;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
|
|
c6c771 |
+ return -1;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ /*
|
|
|
c6c771 |
+ * catch_result is set if firmware does not support 2hash-ext-log
|
|
|
c6c771 |
+ * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
|
|
|
c6c771 |
+ */
|
|
|
c6c771 |
+ if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
|
|
|
c6c771 |
+ return -1;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ return 0;
|
|
|
c6c771 |
+}
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+static grub_err_t
|
|
|
c6c771 |
+tpm2_log_event (unsigned char *buf,
|
|
|
c6c771 |
+ grub_size_t size, grub_uint8_t pcr,
|
|
|
c6c771 |
+ const char *description)
|
|
|
c6c771 |
+{
|
|
|
c6c771 |
+ static int error_displayed = 0;
|
|
|
c6c771 |
+ int err;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ err = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
|
|
|
c6c771 |
+ description,
|
|
|
c6c771 |
+ grub_strlen(description) + 1,
|
|
|
c6c771 |
+ buf, size);
|
|
|
c6c771 |
+ if (err && !error_displayed)
|
|
|
c6c771 |
+ {
|
|
|
c6c771 |
+ error_displayed++;
|
|
|
c6c771 |
+ return grub_error (GRUB_ERR_BAD_DEVICE,
|
|
|
c6c771 |
+ "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
|
|
|
c6c771 |
+ }
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ return GRUB_ERR_NONE;
|
|
|
c6c771 |
+}
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+grub_err_t
|
|
|
c6c771 |
+grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
|
|
|
c6c771 |
+ const char *description)
|
|
|
c6c771 |
+{
|
|
|
c6c771 |
+ grub_err_t err = tpm_init();
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ /* Absence of a TPM isn't a failure. */
|
|
|
c6c771 |
+ if (err != GRUB_ERR_NONE)
|
|
|
c6c771 |
+ return GRUB_ERR_NONE;
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
|
|
|
c6c771 |
+ pcr, size, description);
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ if (tpm_version == 2)
|
|
|
c6c771 |
+ return tpm2_log_event (buf, size, pcr, description);
|
|
|
c6c771 |
+
|
|
|
c6c771 |
+ return GRUB_ERR_NONE;
|
|
|
c6c771 |
+}
|
|
|
c6c771 |
diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
|
|
|
c6c771 |
index 131808d619..87b9f95d34 100644
|
|
|
c6c771 |
--- a/include/grub/ieee1275/ieee1275.h
|
|
|
c6c771 |
+++ b/include/grub/ieee1275/ieee1275.h
|
|
|
c6c771 |
@@ -24,6 +24,9 @@
|
|
|
c6c771 |
#include <grub/types.h>
|
|
|
c6c771 |
#include <grub/machine/ieee1275.h>
|
|
|
c6c771 |
|
|
|
c6c771 |
+#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0)
|
|
|
c6c771 |
+#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1)
|
|
|
c6c771 |
+
|
|
|
c6c771 |
struct grub_ieee1275_mem_region
|
|
|
c6c771 |
{
|
|
|
c6c771 |
unsigned int start;
|