From: Ross Philipson <ross.philip...@oracle.com>

Signed-off-by: Ross Philipson <ross.philip...@oracle.com>
Signed-off-by: Daniel Kiper <daniel.ki...@oracle.com>
Signed-off-by: Krystian Hebel <krystian.he...@3mdeb.com>
---
 grub-core/loader/i386/txt/verify.c | 277 +++++++++++++++++++++++++++++
 1 file changed, 277 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..26e21d7ec
--- /dev/null
+++ b/grub-core/loader/i386/txt/verify.c
@@ -0,0 +1,277 @@
+/*
+ * 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/safemath.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)
+{
+  if (elt->size != GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE +
+                   sizeof (struct grub_txt_heap_bios_spec_ver_element))
+    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_uint64_t acm_addrs_size;
+  grub_uint32_t i;
+
+  if (elt->size < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE +
+                  sizeof (struct grub_txt_heap_acm_element) ||
+       grub_mul (elt->acm.num_acms, sizeof (grub_uint64_t), &acm_addrs_size) ||
+       elt->size - (GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE + sizeof (elt->acm)) !=
+                    acm_addrs_size)
+    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 (elt->acm.num_acms == 0)
+    grub_printf ("WARNING: HEAP_ACM element has no ACM addrs\n");
+
+  for (i = 0; i < elt->acm.num_acms; i++)
+    {
+      if (elt->acm.addr[i] == 0)
+        return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                    N_("HEAP_ACM element ACM addr (%d) is NULL"), i);
+
+      if (elt->acm.addr[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)
+{
+  if (elt->size < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE +
+                  sizeof (struct grub_txt_heap_custom_element))
+     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_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 < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE)
+     return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                 N_("TXT heap ext data elements too small"));
+
+  for ( ; ; )
+    {
+      if (elts_size < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE ||
+          elt->size < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE ||
+          elts_size < elt->size)
+        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 != GRUB_ERR_NONE)
+              return err;
+            break;
+          case GRUB_TXT_HEAP_EXTDATA_TYPE_ACM:
+            err = verify_acm_elt (elt);
+            if (err != GRUB_ERR_NONE)
+              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 != GRUB_ERR_NONE)
+              return err;
+            break;
+          /* These shouldn't be present in BIOS data, treat them as errors */
+          case GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR:
+          case GRUB_TXT_HEAP_EXTDATA_TYPE_MADT:
+          case GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1:
+          case GRUB_TXT_HEAP_EXTDATA_TYPE_MCFG:
+          default:
+            return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                               N_("unknown element: type: %u, size: %u\n"),
+                               elt->type, elt->size);
+        }
+
+      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, errorcode, heap_base, heap_size;
+  grub_uint64_t bios_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_X86_CPUID_FEATURES_ECX_SMX))
+    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.
+   */
+
+  errorcode = grub_txt_reg_pub_read32 (GRUB_TXT_ERRORCODE);
+  /* 0 - no previous SENTER, 0xC0000001 - previous SENTER succeeded */
+  if (errorcode != 0 && errorcode != 0xC0000001)
+     return grub_error (GRUB_ERR_BAD_DEVICE,
+                        N_("TXT_ERRORCODE reports failure: 0x%08" 
PRIxGRUB_UINT32_T),
+                        errorcode);
+
+  if (grub_txt_reg_pub_read8 (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 reasonable.
+   */
+
+  txt_heap = grub_txt_get_heap ();
+  heap_base = grub_txt_reg_pub_read32 (GRUB_TXT_HEAP_BASE);
+  heap_size = grub_txt_reg_pub_read32 (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 < sizeof (grub_uint64_t) + sizeof (*bios_data) ||
+      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 < 3)
+     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);
+
+  /*
+   * grub_uint32_t mle_flags is supposed to be added in version 5, however, the
+   * only ACM in 630744_003 package that is version 4 (Sandy Bridge & Ivy 
Bridge
+   * SNB_IVB_SINIT_20190708_PW.bin) seems to also have this field, or at least
+   * a placeholder for it.
+   */
+  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.46.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to