From: chench246 <chench...@hotmail.com> TPCM(Trusted Platform Control Module) is a Chinese standard and is compatible with TPM. --- grub-core/Makefile.core.def | 7 ++ grub-core/commands/efi/tpcm.c | 163 ++++++++++++++++++++++++++++++++++ grub-core/commands/tpcm.c | 99 +++++++++++++++++++++ include/grub/efi/tpcm.h | 60 +++++++++++++ include/grub/err.h | 3 +- 5 files changed, 331 insertions(+), 1 deletion(-) create mode 100755 grub-core/commands/efi/tpcm.c create mode 100755 grub-core/commands/tpcm.c create mode 100644 include/grub/efi/tpcm.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 063ef5dd7..f1250601b 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2562,6 +2562,13 @@ module = { enable = efi; }; +module = { + name = tpcm; + common = commands/tpcm.c; + efi = commands/efi/tpcm.c; + enable = x86_64_efi; +}; + module = { name = tr; common = commands/tr.c; diff --git a/grub-core/commands/efi/tpcm.c b/grub-core/commands/efi/tpcm.c new file mode 100755 index 000000000..bc97e800c --- /dev/null +++ b/grub-core/commands/efi/tpcm.c @@ -0,0 +1,163 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2018 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 TPCM support code. + */ + +#include <grub/err.h> +#include <grub/efi/tpcm.h> + + +static grub_uint32_t g_measured_id = STAGE_START; + +/* + get_tpcm_stage: + TPCM does not make a distinction with the type of + measured target, so we use g_measured_id directly + for the stage. + */ +static grub_uint32_t get_tpcm_stage(void) +{ + grub_uint32_t stage = STAGE_INVALID; + + stage = g_measured_id; + + if (stage < STAGE_START || stage > STAGE_END) + stage = STAGE_INVALID; + + return stage; +} + +/* + update_measured_id: + update g_measured_id +1 every time measured, and g_measured_id + will never be decreased. + */ +static void update_measured_id(void) +{ + g_measured_id++; +} + +/* + measure_memory: + measure the memery region--(addr, size) through the TPCM protocol. + if TPCM protocol is not exist in BIOS, it will return SUCC to keep + compatible with non-measurement-support bios; if TPCM protocol is + exist but not enabled, it will also return SUCC. + */ +static grub_err_t measure_memory(enum grub_file_type type __attribute__((unused)), + char *desc, + grub_addr_t addr, + grub_size_t size) +{ + grub_efi_handle_t *handles = 0; + grub_efi_uintn_t num_handles; + grub_efi_handle_t grub_c2p_handle = 0; + grub_err_t test_c2p_err = GRUB_ERR_BAD_OS; + grub_guid_t c2p_guid = C2PGUID; + grub_uint32_t measure_result = 0; + grub_uint32_t control_result = 0; + grub_efi_boolean_t verify_enable = 0; + grub_size_t desc_len = 0; + + handles = grub_efi_locate_handle(GRUB_EFI_BY_PROTOCOL, &c2p_guid, NULL, &num_handles); + if (handles && (num_handles > 0)) + { + struct c2p_protocol *c2p; + + grub_c2p_handle = handles[0]; + grub_dprintf ("tpcm", "measue memory addr 0x%lx size 0x%lx \n", addr, size); + c2p = grub_efi_open_protocol(grub_c2p_handle, &c2p_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (c2p) + { + verify_enable = c2p->verify_is_enabled (c2p); + if (verify_enable) + { + struct addr_range range; + grub_efi_status_t status = 0; + grub_uint32_t stage = STAGE_INVALID; + + range.start = addr; + range.length = size; + + stage = get_tpcm_stage(); + if (stage != STAGE_INVALID) + { + desc_len = grub_strlen(desc) + 1; + status = c2p->verify_raw (c2p, stage, (grub_uint64_t)desc, desc_len, 1, &range, &measure_result, &control_result); + if ((!status) && ((control_result & MEASURE_ACTION_MASK) == 0) ) + { + grub_dprintf ("tpcm", "verify_raw success. stage[%d]desc:[%s]\n", stage, desc); + test_c2p_err = GRUB_ERR_NONE; + } + else + { + grub_dprintf ("tpcm", "verify_raw error\n"); + while(1) + { + grub_error (GRUB_ERR_TPCM_VERIFY, "tpcm verify error. stage[%d]desc[%s]\n", stage, desc); + asm volatile ("hlt"); + } + } + } + else { + grub_dprintf ("tpcm", "invalid stage\n"); + } + + update_measured_id(); + + } + else { + grub_dprintf ("tpcm", "image verify not enabled\n"); + test_c2p_err = GRUB_ERR_NONE; + } + } + else + grub_dprintf ("tpcm", "open c2p protocol failed\n"); + } + else + { + /* keep compatible with non-measurement-support bios. */ + grub_dprintf ("tpcm", "not found C2P protocol\n"); + test_c2p_err = GRUB_ERR_NONE; + } + + return test_c2p_err; +} + +/* + grub_tpcm_measure_memory: + */ +grub_err_t grub_tpcm_measure_memory(void *context, grub_addr_t buf, grub_size_t size) +{ + char *p_context = (char *)context; + char *p, *p_desc; + char tmp[TPCM_MAX_BUF_SIZE] = {'0'}; + enum grub_file_type type; + + if (!p_context) + return GRUB_ERR_BUG; + + p = grub_strchr(p_context, '|'); + p_desc = p + 1; + grub_memcpy(tmp, p_context, (p-p_context)); + type = grub_strtoul(tmp, 0, 10); + + return measure_memory(type, p_desc, buf, size); +} + diff --git a/grub-core/commands/tpcm.c b/grub-core/commands/tpcm.c new file mode 100755 index 000000000..1c8bd77ce --- /dev/null +++ b/grub-core/commands/tpcm.c @@ -0,0 +1,99 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2018 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/>. + * + * Core TPCM support code. + */ + +#include <grub/err.h> +#include <grub/verify.h> +#include <grub/dl.h> +#include <grub/efi/tpcm.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +static char context_buf[TPCM_MAX_BUF_SIZE]; + +static grub_err_t grub_tpcm_verify_init(grub_file_t io, + enum grub_file_type type, + void **context, + enum grub_verify_flags *flags) +{ + grub_memset(context_buf, 0, TPCM_MAX_BUF_SIZE); + grub_snprintf(context_buf, TPCM_MAX_BUF_SIZE, "%d|%s", (type & GRUB_FILE_TYPE_MASK), io->name); + *context = context_buf; + *flags |= GRUB_VERIFY_FLAGS_SINGLE_CHUNK; + + return GRUB_ERR_NONE; +} + +static grub_err_t grub_tpcm_verify_write(void *context, void *buf , grub_size_t size ) +{ + return grub_tpcm_measure_memory(context, (grub_addr_t)buf, size); +} + +static grub_err_t grub_tpcm_verify_string (char *str, enum grub_verify_string_type type) +{ + const char *prefix = NULL; + char *description, *context; + grub_err_t status; + + switch (type) + { + case GRUB_VERIFY_KERNEL_CMDLINE: + prefix = "kernel_cmdline: "; + break; + case GRUB_VERIFY_MODULE_CMDLINE: + prefix = "module_cmdline: "; + break; + case GRUB_VERIFY_COMMAND: + prefix = "grub_cmd: "; + break; + } + + context = grub_zalloc(grub_strlen (str) + grub_strlen (prefix) + 1 + 4); /* 4 for type */ + if (!context) + return grub_errno; + + grub_snprintf(context, 4, "%d|", (type & GRUB_FILE_TYPE_MASK)); + description = context + grub_strlen(context); + grub_memcpy(description, prefix, grub_strlen (prefix)); + grub_memcpy(description + grub_strlen (prefix), str, grub_strlen (str) + 1); + + status = grub_tpcm_measure_memory(context, (grub_addr_t)str, grub_strlen(str)); + + grub_free(context); + + return status; +} + +struct grub_file_verifier grub_tpcm_verifier = { + .name = "tpcm", + .init = grub_tpcm_verify_init, + .write = grub_tpcm_verify_write, + .verify_string = grub_tpcm_verify_string, +}; + +GRUB_MOD_INIT (tpcm) +{ + grub_verifier_register(&grub_tpcm_verifier); +} + +GRUB_MOD_FINI (tpcm) +{ + grub_verifier_unregister(&grub_tpcm_verifier); +} + diff --git a/include/grub/efi/tpcm.h b/include/grub/efi/tpcm.h new file mode 100644 index 000000000..a4e0c765a --- /dev/null +++ b/include/grub/efi/tpcm.h @@ -0,0 +1,60 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2018 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/>. + */ + +#ifndef GRUB_EFI_TPCM_HEADER +#define GRUB_EFI_TPCM_HEADER 1 + +#include <grub/file.h> +#include <grub/efi/api.h> +#include <grub/efi/efi.h> + +#define C2PGUID {0xf89ab5cd, 0x2829, 0x422f, {0xa5, 0xf3, 0x03, 0x28, 0xe0, 0x6c, 0xfc, 0xbb}} +#define MEASURE_RESULT_MASK (0xff00) +#define MEASURE_RESULT_SHIFT (16) +#define MEASURE_ACTION_MASK (0x1) +#define TPCM_MAX_BUF_SIZE 128 + +/* + stage layout: + 2000~2999: +1 every time +*/ + +#define STAGE_START 2000 +#define STAGE_END 2999 +#define STAGE_INVALID 3000 + +struct addr_range { + grub_uint64_t start; + grub_uint64_t length; +}; +struct c2p_protocol { + grub_efi_status_t (__grub_efi_api *verify_raw) (struct c2p_protocol *this, + grub_uint32_t measure_stage, + grub_uint64_t image_info, + grub_uint32_t image_info_size, + grub_uint32_t num_addr_range, + struct addr_range ranges[], + grub_uint32_t *measure_result, + grub_uint32_t *control_result); + grub_efi_boolean_t (__grub_efi_api *verify_is_enabled)(struct c2p_protocol *this); +}; +typedef struct c2p_protocol c2p_protocol_t; + +grub_err_t grub_tpcm_measure_memory(void *context, grub_addr_t buf, grub_size_t size); + +#endif diff --git a/include/grub/err.h b/include/grub/err.h index 1c07034cd..f5268dd47 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -73,7 +73,8 @@ typedef enum GRUB_ERR_NET_NO_DOMAIN, GRUB_ERR_EOF, GRUB_ERR_BAD_SIGNATURE, - GRUB_ERR_BAD_FIRMWARE + GRUB_ERR_BAD_FIRMWARE, + GRUB_ERR_TPCM_VERIFY } grub_err_t; -- 2.17.1 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel