[Skiboot] [PATCH v2 02/20] libstb: import stb_init() breaking it into multiple files

Claudio Carvalho cclaudio at linux.vnet.ibm.com
Sat Dec 9 15:52:16 AEDT 2017


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 at linux.vnet.ibm.com>
---
 libstb/Makefile.inc      |   2 +-
 libstb/cvc.c             | 194 +++++++++++++++++++++++++++++++++++++++++++++++
 libstb/cvc.h             |  27 +++++++
 libstb/secureboot.c      | 148 ++++++++++++++++++++++++++++++++++++
 libstb/secureboot.h      |  31 ++++++++
 libstb/tpm_chip.c        |  27 ++-----
 libstb/tpm_chip.h        |   2 +-
 libstb/trustedboot.c     |  66 ++++++++++++++++
 libstb/trustedboot.h     |  22 ++++++
 libstb/tss/trustedboot.H |   6 +-
 10 files changed, 501 insertions(+), 24 deletions(-)
 create mode 100644 libstb/cvc.c
 create mode 100644 libstb/cvc.h
 create mode 100644 libstb/secureboot.c
 create mode 100644 libstb/secureboot.h
 create mode 100644 libstb/trustedboot.c
 create mode 100644 libstb/trustedboot.h

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, &reg_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 */
-- 
2.7.4



More information about the Skiboot mailing list