[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200504232132.23570-18-daniel.kiper@oracle.com>
Date: Tue, 5 May 2020 01:21:31 +0200
From: Daniel Kiper <daniel.kiper@...cle.com>
To: grub-devel@....org, linux-kernel@...r.kernel.org,
trenchboot-devel@...glegroups.com, x86@...nel.org
Cc: alexander.burmashev@...cle.com, andrew.cooper3@...rix.com,
ard.biesheuvel@...aro.org, dpsmith@...rtussolutions.com,
eric.snowberg@...cle.com, javierm@...hat.com,
kanth.ghatraju@...cle.com, konrad.wilk@...cle.com,
krystian.hebel@...eb.com, lukasz.hawrylko@...ux.intel.com,
michal.zygowski@...eb.com, mjg59@...gle.com, phcoder@...il.com,
pirot.krol@...eb.com, pjones@...hat.com, ross.philipson@...cle.com
Subject: [GRUB PATCH RFC 17/18] i386/txt: Add Intel TXT verification routines
From: Ross Philipson <ross.philipson@...cle.com>
Signed-off-by: Ross Philipson <ross.philipson@...cle.com>
Signed-off-by: Daniel Kiper <daniel.kiper@...cle.com>
---
grub-core/loader/i386/txt/verify.c | 297 +++++++++++++++++++++++++++++++++++++
1 file changed, 297 insertions(+)
create mode 100644 grub-core/loader/i386/txt/verify.c
diff --git a/grub-core/loader/i386/txt/verify.c b/grub-core/loader/i386/txt/verify.c
new file mode 100644
index 000000000..97f3b325d
--- /dev/null
+++ b/grub-core/loader/i386/txt/verify.c
@@ -0,0 +1,297 @@
+/*
+ * verify.c: verify that platform and processor supports Intel(r) TXT
+ *
+ * Copyright (c) 2003-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2020 Oracle and/or its affiliates.
+ *
+ * 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/loader.h>
+#include <grub/memory.h>
+#include <grub/normal.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/cpu/relocator.h>
+#include <grub/i386/cpuid.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/txt.h>
+
+/* Current max that the secure launch can handle */
+#define TXT_MAX_CPUS 512
+
+static grub_err_t
+verify_bios_spec_ver_elt (struct grub_txt_heap_ext_data_element *elt)
+{
+ grub_uint8_t *ptr = (grub_uint8_t *)elt;
+ struct grub_txt_heap_bios_spec_ver_element *bios_spec_ver_elt =
+ (struct grub_txt_heap_bios_spec_ver_element *)ptr;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*bios_spec_ver_elt) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_BIOS_SPEC_VER element has wrong size (%d)"),
+ elt->size);
+
+ /* Any values are allowed */
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+verify_acm_elt (struct grub_txt_heap_ext_data_element *elt)
+{
+ grub_uint8_t *ptr = ((grub_uint8_t *)elt + sizeof(*elt));
+ struct grub_txt_heap_acm_element *acm_elt =
+ (struct grub_txt_heap_acm_element *)ptr;
+ grub_uint64_t *acm_addrs;
+ grub_uint32_t i;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*acm_elt) +
+ acm_elt->num_acms*sizeof(grub_uint64_t) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_ACM element has wrong size (%d)"),
+ elt->size);
+
+ /* No addrs is not error, but print warning. */
+ if ( acm_elt->num_acms == 0 )
+ grub_printf ("WARNING: HEAP_ACM element has no ACM addrs\n");
+
+ acm_addrs = (grub_uint64_t *)(ptr + sizeof(*acm_elt));
+ for ( i = 0; i < acm_elt->num_acms; i++ )
+ {
+ if ( acm_addrs[i] == 0 )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_ACM element ACM addr (%d) is NULL"), i);
+
+ if ( acm_addrs[i] >= 0x100000000UL )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_ACM element ACM addr (%d) is >4GB"), i);
+
+ /* Not going to check if ACM addrs are valid ACMs */
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+verify_custom_elt (struct grub_txt_heap_ext_data_element *elt)
+{
+ grub_uint8_t *ptr = (grub_uint8_t *)elt;
+ struct grub_txt_heap_custom_element *custom_elt =
+ (struct grub_txt_heap_custom_element *)ptr;
+
+ if ( elt->size < sizeof(*elt) + sizeof(*custom_elt) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_CUSTOM element has wrong size (%d)"),
+ elt->size);
+
+ /* Any values are allowed */
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+verify_evt_log_ptr_elt (struct grub_txt_heap_ext_data_element *elt)
+{
+ grub_uint8_t *ptr = (grub_uint8_t *)elt;
+ struct grub_txt_heap_tpm_event_log_element *elog_elt =
+ (struct grub_txt_heap_tpm_event_log_element *)ptr;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*elog_elt) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_EVENT_LOG_POINTER element has wrong size (%d)"),
+ elt->size);
+
+ /* TODO: Sort out how to do this verifier once the event log handling is in place
+ *
+ * return verify_evt_log((event_log_container_t *)(unsigned long)
+ * elog_elt->event_log_phys_addr);
+ */
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+verify_ext_data_elts(struct grub_txt_heap_ext_data_element *elts,
+ grub_uint64_t elts_size)
+{
+ struct grub_txt_heap_ext_data_element *elt = elts;
+ grub_err_t err;
+
+ if ( elts_size < sizeof(*elt) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("TXT heap ext data elements too small"));
+
+ for ( ; ; )
+ {
+ if ( elts_size < elt->size || elt->size == 0 )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("TXT heap invalid element size: type: %d, size: %d"),
+ elt->type, elt->size);
+
+ switch ( elt->type )
+ {
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_END:
+ return GRUB_ERR_NONE;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_BIOS_SPEC_VER:
+ err = verify_bios_spec_ver_elt (elt);
+ if ( err )
+ return err;
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_ACM:
+ err = verify_acm_elt (elt);
+ if ( err )
+ return err;
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_STM:
+ /* Nothing to check, platform specific */
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_CUSTOM:
+ err = verify_custom_elt (elt);
+ if ( err )
+ return err;
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR:
+ err = verify_evt_log_ptr_elt (elt);
+ if ( err )
+ return err;
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_MADT:
+ /* Copy of ACPI MADT, not validating */
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1:
+ /* TODO TBOOT did not verify this, not sure why or how to do it */
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_MCFG:
+ /* Copy of ACPI MCFG, not validating */
+ break;
+ default:
+ /* TODO: What kind of element??? Improve the message. */
+ grub_printf ("WARNING: unknown element: type: %u, size: %u\n", elt->type, elt->size);
+ break;
+ }
+
+ elts_size -= elt->size;
+ elt = (struct grub_txt_heap_ext_data_element *)((grub_uint8_t *)elt + elt->size);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_txt_verify_platform (void)
+{
+ grub_uint8_t *txt_heap;
+ grub_uint32_t eax, ebx, ecx, edx;
+ grub_uint64_t bios_size, heap_base, heap_size, msr;
+ grub_err_t err = GRUB_ERR_NONE;
+ struct grub_txt_bios_data *bios_data;
+ struct grub_txt_heap_ext_data_element *elts;
+
+ grub_cpuid (GRUB_X86_CPUID_FEATURES, eax, ebx, ecx, edx);
+
+ if (!(ecx & GRUB_SMX_CPUID_FEATURE))
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("CPU does not support SMX"));
+
+ msr = grub_rdmsr (GRUB_MSR_X86_FEATURE_CONTROL);
+
+ if ((msr & (GRUB_MSR_X86_SENTER_FUNCTIONS | GRUB_MSR_X86_SENTER_ENABLE)) !=
+ (GRUB_MSR_X86_SENTER_FUNCTIONS | GRUB_MSR_X86_SENTER_ENABLE))
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("GETSEC[SENTER] is not enabled"));
+
+ /*
+ * TODO
+ * TXT Specification
+ * 4.5 SGX Requirement for TXT Platform
+ * Secure Launch currently does not support interop with SGX since it does
+ * not have TPM support to write the SE NVRAM index.
+ * Eventually need the verify_IA32_se_svn_status routine to be called here.
+ */
+
+ if (grub_txt_reg_pub_readq (GRUB_TXT_ESTS) & GRUB_TXT_ESTS_TXT_RESET)
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("TXT_RESET.STS is set and GETSEC[SENTER] is disabled"));
+
+ /*
+ * Verify that the BIOS information in the TXT heap that was setup by the
+ * BIOS ACM is sane.
+ */
+
+ txt_heap = grub_txt_get_heap ();
+ heap_base = grub_txt_reg_pub_readq (GRUB_TXT_HEAP_BASE);
+ heap_size = grub_txt_reg_pub_readq (GRUB_TXT_HEAP_SIZE);
+
+ if ( txt_heap == NULL || heap_base == 0 || heap_size == 0 )
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("TXT heap is not configured correctly"));
+
+ bios_size = grub_txt_bios_data_size (txt_heap);
+ if ( bios_size == 0 || bios_size > heap_size )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("invalid size of the TXT heap BIOS data table"));
+
+ bios_data = grub_txt_bios_data_start (txt_heap);
+
+ /* Check version */
+ if ( bios_data->version < 5 )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("unsupported BIOS data version (%d)"), bios_data->version);
+
+ if ( bios_data->num_logical_procs > TXT_MAX_CPUS )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("BIOS reports too many CPUs for secure launch (%d)"),
+ bios_data->num_logical_procs);
+
+ if ( bios_data->version >= 4 && bios_size > sizeof(*bios_data) + sizeof(bios_size) )
+ {
+ elts = (struct grub_txt_heap_ext_data_element *) ((grub_uint8_t *)bios_data + sizeof(*bios_data));
+ err = verify_ext_data_elts(elts, bios_size - sizeof(*bios_data));
+ }
+
+ return err;
+}
--
2.11.0
Powered by blists - more mailing lists