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