diff options
author | Claudio Carvalho <cclaudio@linux.vnet.ibm.com> | 2017-12-09 02:52:16 -0200 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2017-12-18 21:30:57 -0600 |
commit | 594c7a6ae3cccd4a7eeb5ce2c31d2f958672325c (patch) | |
tree | f710a3d8ac4bef339eb8cc23734a92f1a162a1ed /libstb | |
parent | 4fb528b394115ff8dd832b980032d7656aece099 (diff) | |
download | skiboot-594c7a6ae3cccd4a7eeb5ce2c31d2f958672325c.zip skiboot-594c7a6ae3cccd4a7eeb5ce2c31d2f958672325c.tar.gz skiboot-594c7a6ae3cccd4a7eeb5ce2c31d2f958672325c.tar.bz2 |
libstb: import stb_init() breaking it into multiple files
This imports stb_init() from stb.c, but breaking it into multiple files
in order to make the code easier to read and to maintain. New files
created: secureboot.c, trustedboot.c and cvc.c.
The secureboot_init() in secureboot.c also initializes the hardware key
hash and the hardware key hash size, which are used to call the CVC
verify wrapper. These variables were initialized in the romcode_probe()
function, libstb/drivers/romcode.c.
The cvc_init() in cvc.c is slightly modified from what exists in
stb_init(). Now it calls cvc_register() and cvc_service_register().
Signed-off-by: Claudio Carvalho <cclaudio@linux.vnet.ibm.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'libstb')
-rw-r--r-- | libstb/Makefile.inc | 2 | ||||
-rw-r--r-- | libstb/cvc.c | 194 | ||||
-rw-r--r-- | libstb/cvc.h | 27 | ||||
-rw-r--r-- | libstb/secureboot.c | 148 | ||||
-rw-r--r-- | libstb/secureboot.h | 31 | ||||
-rw-r--r-- | libstb/tpm_chip.c | 27 | ||||
-rw-r--r-- | libstb/tpm_chip.h | 2 | ||||
-rw-r--r-- | libstb/trustedboot.c | 66 | ||||
-rw-r--r-- | libstb/trustedboot.h | 22 | ||||
-rw-r--r-- | libstb/tss/trustedboot.H | 6 |
10 files changed, 501 insertions, 24 deletions
diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc index 0122ca2..7b90bd5 100644 --- a/libstb/Makefile.inc +++ b/libstb/Makefile.inc @@ -4,7 +4,7 @@ LIBSTB_DIR = libstb SUBDIRS += $(LIBSTB_DIR) -LIBSTB_SRCS = container.c rom.c tpm_chip.c stb.c +LIBSTB_SRCS = container.c rom.c tpm_chip.c stb.c cvc.c secureboot.c trustedboot.c LIBSTB_OBJS = $(LIBSTB_SRCS:%.c=%.o) LIBSTB = $(LIBSTB_DIR)/built-in.o diff --git a/libstb/cvc.c b/libstb/cvc.c new file mode 100644 index 0000000..86d292d --- /dev/null +++ b/libstb/cvc.c @@ -0,0 +1,194 @@ +/* Copyright 2013-2017 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef pr_fmt +#define pr_fmt(fmt) "STB: " fmt +#endif + +#include <skiboot.h> +#include <string.h> +#include <chip.h> +#include <xscom.h> +#include <inttypes.h> +#include "secureboot.h" +#include "cvc.h" + +struct container_verification_code { + uint64_t start_addr; + uint64_t end_addr; + struct list_head service_list; +}; + +static struct container_verification_code *cvc = NULL; +static void *secure_rom_mem = NULL; + +struct cvc_service { + int id; + uint64_t addr; /* base_addr + offset */ + uint32_t version; + struct list_node link; +}; + +static struct { + enum cvc_service_id id; + const char *name; +} cvc_service_map[] = { + { CVC_SHA512_SERVICE, "sha512" }, + { CVC_VERIFY_SERVICE, "verify" }, +}; + +static struct cvc_service *cvc_find_service(enum cvc_service_id id) +{ + struct cvc_service *service; + if (!cvc) + return NULL; + + list_for_each(&cvc->service_list, service, link) { + if (service->id == id) + return service; + } + return NULL; +} + +static const char *cvc_service_map_name(enum cvc_service_id id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cvc_service_map); i++) { + if (cvc_service_map[i].id == id) + return cvc_service_map[i].name; + } + return NULL; +} + +static void cvc_register(uint64_t start_addr, uint64_t end_addr) +{ + if (cvc) + return; + + cvc = malloc(sizeof(struct container_verification_code)); + assert(cvc); + cvc->start_addr = start_addr; + cvc->end_addr = end_addr; + list_head_init(&cvc->service_list); + prlog(PR_INFO, "Found CVC @ %" PRIx64 "-%" PRIx64 "\n", + start_addr, end_addr); +} + +static void cvc_service_register(uint32_t id, uint32_t offset, uint32_t version) +{ + struct cvc_service *service; + const char *name; + + if (!cvc) + return; + + /* Service already registered? */ + if (cvc_find_service(id)) + return; + + if (cvc->start_addr + offset > cvc->end_addr) { + prlog(PR_WARNING, "CVC service @ %x out of range, " + "id=%d\n", offset, id); + return; + } + + name = cvc_service_map_name(id); + if (!name) { + prlog(PR_ERR, "CVC service %d not supported\n", id); + return; + } + + service = malloc(sizeof(struct cvc_service)); + assert(service); + service->id = id; + service->version = version; + service->addr = cvc->start_addr + offset; + list_add_tail(&cvc->service_list, &service->link); + prlog(PR_INFO, "Found CVC-%s @ %" PRIx64 ", version=%d\n", + name, service->addr, service->version); +} + +#define SECURE_ROM_MEMORY_SIZE (16 * 1024) +#define SECURE_ROM_XSCOM_ADDRESS 0x02020017 + +#define SECURE_ROM_SHA512_OFFSET 0x20 +#define SECURE_ROM_VERIFY_OFFSET 0x30 + +static int cvc_secure_rom_init(void) { + const uint32_t reg_addr = SECURE_ROM_XSCOM_ADDRESS; + uint64_t reg_data; + struct proc_chip *chip; + + if (!secure_rom_mem) { + secure_rom_mem = malloc(SECURE_ROM_MEMORY_SIZE); + assert(secure_rom_mem); + } + /* + * The logic that contains the ROM within the processor is implemented + * in a way that it only responds to CI (cache inhibited) operations. + * Due to performance issues we copy the verification code from the + * secure ROM to RAM. We use memcpy_from_ci() to do that. + */ + chip = next_chip(NULL); + xscom_read(chip->id, reg_addr, ®_data); + memcpy_from_ci(secure_rom_mem, (void*) reg_data, + SECURE_ROM_MEMORY_SIZE); + cvc_register((uint64_t)&secure_rom_mem, + (uint64_t)&secure_rom_mem + SECURE_ROM_MEMORY_SIZE-1); + cvc_service_register(CVC_SHA512_SERVICE, SECURE_ROM_SHA512_OFFSET, 1); + cvc_service_register(CVC_VERIFY_SERVICE, SECURE_ROM_VERIFY_OFFSET, 1); + return 0; +} + +int cvc_init(void) +{ + struct dt_node *node; + int version; + int rc = 0; + + if (cvc) + return 0; + + node = dt_find_by_path(dt_root, "/ibm,secureboot"); + if (!node) + return -1; + + if (!secureboot_is_compatible(node, &version, NULL)) { + /** + * @fwts-label CVCNotCompatible + * @fwts-advice Compatible CVC driver not found. Probably, + * hostboot/mambo/skiboot has updated the + * /ibm,secureboot/compatible without adding a driver that + * supports it. + */ + prlog(PR_ERR, "%s FAILED, /ibm,secureboot not compatible.\n", + __func__); + return -1; + } + + /* Only in P8 the CVC is stored in a secure ROM */ + if (version == IBM_SECUREBOOT_V1 && + proc_gen == proc_gen_p8) { + rc = cvc_secure_rom_init(); + } else { + prlog(PR_ERR, "%s FAILED. /ibm,secureboot not supported\n", + __func__); + return -1; + } + + return rc; +} diff --git a/libstb/cvc.h b/libstb/cvc.h new file mode 100644 index 0000000..3d7079e --- /dev/null +++ b/libstb/cvc.h @@ -0,0 +1,27 @@ +/* Copyright 2013-2017 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CVC_H +#define __CVC_H + +enum cvc_service_id { + CVC_SHA512_SERVICE, + CVC_VERIFY_SERVICE, +}; + +int cvc_init(void); + +#endif /* __CVC_H */ diff --git a/libstb/secureboot.c b/libstb/secureboot.c new file mode 100644 index 0000000..cdb6ea5 --- /dev/null +++ b/libstb/secureboot.c @@ -0,0 +1,148 @@ +/* Copyright 2013-2017 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef pr_fmt +#define pr_fmt(fmt) "STB: " fmt +#endif + +#include <skiboot.h> +#include <device.h> +#include <nvram.h> +#include "secureboot.h" +#include "container.h" +#include "cvc.h" + +static const void* hw_key_hash = NULL; +static size_t hw_key_hash_size; +static bool secure_mode = false; + +static struct { + enum secureboot_version version; + const char *compat; +} secureboot_map[] = { + { IBM_SECUREBOOT_V1, "ibm,secureboot-v1" }, +}; + +static void secureboot_enforce(void) +{ + /* Sanity check */ + if (!secure_mode) + return; + + /* + * TODO: Ideally, the BMC should decide what security policy to apply + * (power off, reboot, switch PNOR sides, etc). We may need to provide + * extra info to BMC other than just abort. Terminate Immediate + * Attention ? (TI) + */ + prlog(PR_EMERG, "enforcing secure mode ...\n"); + abort(); +} + +bool secureboot_is_compatible(struct dt_node *node, int *version, const char **compat) +{ + int i; + + if (!node) + return false; + + for (i = 0; i < ARRAY_SIZE(secureboot_map); i++) { + if (dt_node_is_compatible(node, secureboot_map[i].compat)) { + if (version) + *version = secureboot_map[i].version; + if (compat) + *compat = secureboot_map[i].compat; + return true; + } + } + return false; +} + +void secureboot_init(void) +{ + struct dt_node *node; + const char *hash_algo; + const char *compat = NULL; + int version; + size_t size; + + node = dt_find_by_path(dt_root, "/ibm,secureboot"); + if (!node) { + prlog(PR_NOTICE, "secure boot not supported\n"); + return; + } + + if (!secureboot_is_compatible(node, &version, &compat)) { + /** + * @fwts-label SecureBootNotCompatible + * @fwts-advice Compatible secureboot driver not found. Probably, + * hostboot/mambo/skiboot has updated the + * /ibm,secureboot/compatible without adding a driver that + * supports it. + */ + prlog(PR_ERR, "%s FAILED, /ibm,secureboot not compatible.\n", + __func__); + return; + } + + prlog(PR_NOTICE, "Found %s\n", compat); + + if (nvram_query_eq("force-secure-mode", "always")) { + secure_mode = true; + prlog(PR_NOTICE, "secure mode on (FORCED by nvram)\n"); + } else { + secure_mode = dt_has_node_property(node, "secure-enabled", NULL); + prlog(PR_NOTICE, "secure mode %s\n", + secure_mode ? "on" : "off"); + } + + if (!secure_mode) + return; + + if (version == IBM_SECUREBOOT_V1) { + hash_algo = dt_prop_get(node, "hash-algo"); + if (strcmp(hash_algo, "sha512")) { + /** + * @fwts-label HashAlgoInvalid + * @fwts-advice Hash algorithm invalid, secureboot + * containers version 1 requires sha512. If you're + * running the latest POWER firmware, so probably there + * is a bug in the device tree received from hostboot. + */ + prlog(PR_EMERG, "secureboot init FAILED, hash-algo=%s " + "not supported\n", hash_algo); + secureboot_enforce(); + } + hw_key_hash_size = SHA512_DIGEST_LENGTH; + } else { + prlog(PR_ERR, "%s FAILED. /ibm,secureboot not supported", + __func__); + secureboot_enforce(); + } + + hw_key_hash = dt_prop_get_def_size(node, "hw-key-hash", NULL, &size); + if (!hw_key_hash) { + prlog(PR_EMERG, "hw-key-hash not found\n"); + secureboot_enforce(); + } + if (size != hw_key_hash_size) { + prlog(PR_EMERG, "hw_key-hash wrong size %zd (expected=%zd)\n", + size, hw_key_hash_size); + secureboot_enforce(); + } + if (cvc_init()) + secureboot_enforce(); +} diff --git a/libstb/secureboot.h b/libstb/secureboot.h new file mode 100644 index 0000000..6643160 --- /dev/null +++ b/libstb/secureboot.h @@ -0,0 +1,31 @@ +/* Copyright 2013-2017 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SECUREBOOT_H +#define __SECUREBOOT_H + +#include <device.h> +#include "container.h" +#include "cvc.h" + +enum secureboot_version { + IBM_SECUREBOOT_V1, +}; + +bool secureboot_is_compatible(struct dt_node *node, int *version, const char **compat); +void secureboot_init(void); + +#endif /* __SECUREBOOT_H */ diff --git a/libstb/tpm_chip.c b/libstb/tpm_chip.c index 6791f4c..988e56f 100644 --- a/libstb/tpm_chip.c +++ b/libstb/tpm_chip.c @@ -168,32 +168,21 @@ disable: return STB_ERROR; } -void tpm_init(void) +int tpm_init(void) { - if (!list_empty(&tpm_list)) { - /** - * @fwts-label TPMAlreadyInitialized - * @fwts-advice TPM already initialized. Check if tpm is being - * initialized more than once. - */ - prlog(PR_WARNING, "TPM: tpm device(s) already initialized\n"); - return; - } + if (!list_empty(&tpm_list)) + return 0; list_head_init(&tpm_list); /* tpm drivers supported */ tpm_i2c_nuvoton_probe(); - if (list_empty(&tpm_list)) - /** - * @fwts-label NoTPMRegistered - * @fwts-advice No TPM chip has been initialized. We may not - * have a compatible tpm driver or there is no tpm node in the - * device tree with the expected bindings. - */ - prlog(PR_ERR, "TPM: no tpm chip registered\n"); - + if (list_empty(&tpm_list)) { + prlog(PR_INFO, "no compatible tpm device found!"); + return -1; + } + return 0; } void tpm_cleanup(void) diff --git a/libstb/tpm_chip.h b/libstb/tpm_chip.h index d7363e7..fed5619 100644 --- a/libstb/tpm_chip.h +++ b/libstb/tpm_chip.h @@ -102,7 +102,7 @@ extern int tpm_extendl(TPM_Pcr pcr, /* Add status property to the TPM devices */ extern void tpm_add_status_property(void); -extern void tpm_init(void); +extern int tpm_init(void); extern void tpm_cleanup(void); #endif /* __TPM_H */ diff --git a/libstb/trustedboot.c b/libstb/trustedboot.c new file mode 100644 index 0000000..9644d1a --- /dev/null +++ b/libstb/trustedboot.c @@ -0,0 +1,66 @@ +/* Copyright 2013-2017 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef pr_fmt +#define pr_fmt(fmt) "STB: " fmt +#endif + +#include <skiboot.h> +#include <device.h> +#include <nvram.h> +#include "secureboot.h" +#include "trustedboot.h" +#include "tpm_chip.h" + +static bool trusted_mode = false; + +void trustedboot_init(void) +{ + struct dt_node *node; + + node = dt_find_by_path(dt_root, "/ibm,secureboot"); + if (!node) { + prlog(PR_NOTICE, "trusted boot not supported\n"); + return; + } + + if (!secureboot_is_compatible(node, NULL, NULL)) { + /** + * @fwts-label TrustedBootNotCompatible + * @fwts-advice Compatible trustedboot driver not found. Probably, + * hostboot/mambo/skiboot has updated the + * /ibm,secureboot/compatible without adding a driver that + * supports it. + */ + prlog(PR_ERR, "trustedboot init FAILED, '%s' node not " + "compatible.\n", node->name); + return; + } + + if (nvram_query_eq("force-trusted-mode", "true")) { + trusted_mode = true; + prlog(PR_NOTICE, "trusted mode on (FORCED by nvram)\n"); + } else { + trusted_mode = dt_has_node_property(node, "trusted-enabled", NULL); + prlog(PR_NOTICE, "trusted mode %s\n", + trusted_mode ? "on" : "off"); + } + + if (!trusted_mode) + return; + cvc_init(); + tpm_init(); +} diff --git a/libstb/trustedboot.h b/libstb/trustedboot.h new file mode 100644 index 0000000..4597514 --- /dev/null +++ b/libstb/trustedboot.h @@ -0,0 +1,22 @@ +/* Copyright 2013-2017 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TRUSTEDBOOT_H +#define __TRUSTEDBOOT_H + +void trustedboot_init(void); + +#endif /* __TRUSTEDBOOT_H */ diff --git a/libstb/tss/trustedboot.H b/libstb/tss/trustedboot.H index dccee1a..bee3b49 100644 --- a/libstb/tss/trustedboot.H +++ b/libstb/tss/trustedboot.H @@ -19,8 +19,8 @@ * codes to equivalent routines and types in skiboot. ***************************************************************/ -#ifndef __TRUSTEDBOOT_H -#define __TRUSTEDBOOT_H +#ifndef __TSS_TRUSTEDBOOT_H +#define __TSS_TRUSTEDBOOT_H #include <skiboot.h> #include <stdint.h> @@ -69,4 +69,4 @@ typedef enum { IMPLEMENTATION_PCR = 24 } TPM_Pcr; -#endif +#endif /* __TSS_TRUSTEDBOOT_H */ |