[v3,1/5] libstb/secvar: add secure variable internal abstraction
diff mbox series

Message ID 20190903213416.16535-2-erichte@linux.ibm.com
State New
Headers show
Series
  • Add Secure Variable Support
Related show

Checks

Context Check Description
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (7b12d5489fcfd73ef7ec0cb27eff7f8a5f13b238)

Commit Message

Eric Richter Sept. 3, 2019, 9:34 p.m. UTC
This patch implements a platform-independent abstraction for storing and
retrieving secure variables, as required for host OS secure boot. This
serves as the main entry point for initializing the in-memory cache of the
secure variables, which also kicks off any platform-specific logic that may
be needed. This patch also provides core functions for the subsequent
patches in this series to utilize.

The base secure variable implementation makes use of two types of
drivers, to be selected by the platform: "storage" drivers, and
"backend" drivers. The storage driver implements the hooks required to
write the secure variables to some form of non-volatile memory, and load
the variables on boot. The backend driver defines how the variables
should be interpreted, and processed.

Secure variables are stored in two types of banks, the "variable" bank
and the "update" bank. Variables that have been validated and processed
are stored in the variable bank. This bank is effectively read-only
after the base secvar initialization. Any proposed variable updates are
instead stored in the update bank. During secvar initialization, the
backend driver processes variables from the update bank, and if valid,
adds the new variable to the variable bank.

NOTE: The name "backend" is subject to change. It operates more like a
scheme, so unless a better name comes along, it will likely change to
"scheme" or "schema" in the future.

V2:
 - added secvar device tree node as child of ibm,secureboot
 - added version and compatible properties to backend driver struct
 - added secvar_ready flag for the API to detect if secvar
    initialized successfully
 - moved pre-process step to after initial variable load
 - moved flags field from secvar struct to secvar node

V3:
 - remove the metadata secvar field
 - add probe_secvar() to bump compatible flag
 - add device tree property for backend-agnostic secure mode setting
 - remove backend minor version field
 - remove static data allocation in secvar struct

Signed-off-by: Eric Richter <erichte@linux.ibm.com>
---
 include/platform.h                 |   2 +
 include/secvar.h                   |  46 +++++++++
 libstb/Makefile.inc                |   3 +-
 libstb/secvar/Makefile.inc         |  14 +++
 libstb/secvar/backend/Makefile.inc |  11 ++
 libstb/secvar/secvar.h             |  61 +++++++++++
 libstb/secvar/secvar_main.c        | 160 +++++++++++++++++++++++++++++
 libstb/secvar/secvar_util.c        |  70 +++++++++++++
 libstb/secvar/storage/Makefile.inc |  11 ++
 9 files changed, 377 insertions(+), 1 deletion(-)
 create mode 100644 include/secvar.h
 create mode 100644 libstb/secvar/Makefile.inc
 create mode 100644 libstb/secvar/backend/Makefile.inc
 create mode 100644 libstb/secvar/secvar.h
 create mode 100644 libstb/secvar/secvar_main.c
 create mode 100644 libstb/secvar/secvar_util.c
 create mode 100644 libstb/secvar/storage/Makefile.inc

Patch
diff mbox series

diff --git a/include/platform.h b/include/platform.h
index 0b043856..412f8fc8 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -210,6 +210,8 @@  struct platform {
 					    uint32_t len);
 	int		(*nvram_write)(uint32_t dst, void *src, uint32_t len);
 
+	int (*secvar_init)(void);
+
 	/*
 	 * OCC timeout. This return how long we should wait for the OCC
 	 * before timing out. This lets us use a high value on larger FSP
diff --git a/include/secvar.h b/include/secvar.h
new file mode 100644
index 00000000..5514cfbe
--- /dev/null
+++ b/include/secvar.h
@@ -0,0 +1,46 @@ 
+/* Copyright 2019 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 _SECVAR_DRIVER_
+#define _SECVAR_DRIVER_
+
+#include <stdint.h>
+
+struct secvar;
+
+struct secvar_storage_driver {
+        int (*load_bank)(struct list_head *bank, int section);
+        int (*write_bank)(struct list_head *bank, int section);
+        int (*store_init)(void);
+};
+
+struct secvar_backend_version {
+	int major;
+	int minor;
+} __packed;
+
+struct secvar_backend_driver {
+        int (*pre_process)(void);               // Perform any pre-processing stuff (e.g. determine secure boot state)
+        int (*process)(void);                   // Process all updates
+        int (*post_process)(void);              // Perform any post-processing stuff (e.g. derive/update variables)
+        int (*validate)(struct secvar *var);    // Validate a single variable, return boolean
+        char compatible[32];			// String to use for compatible in secvar node
+};
+
+
+int secvar_main(struct secvar_storage_driver, struct secvar_backend_driver);
+
+#endif
diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc
index 6d54c5cd..d3f68496 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -8,11 +8,12 @@  LIBSTB_SRCS = container.c tpm_chip.c cvc.c secureboot.c trustedboot.c
 LIBSTB_OBJS = $(LIBSTB_SRCS:%.c=%.o)
 LIBSTB = $(LIBSTB_DIR)/built-in.a
 
+include $(SRC)/$(LIBSTB_DIR)/secvar/Makefile.inc
 include $(SRC)/$(LIBSTB_DIR)/mbedtls/Makefile.inc
 include $(SRC)/$(LIBSTB_DIR)/drivers/Makefile.inc
 include $(SRC)/$(LIBSTB_DIR)/tss/Makefile.inc
 
-$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(MBEDTLS)
+$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(SECVAR) $(MBEDTLS)
 
 libstb/create-container: libstb/create-container.c libstb/container-utils.c
 	$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) \
diff --git a/libstb/secvar/Makefile.inc b/libstb/secvar/Makefile.inc
new file mode 100644
index 00000000..75870910
--- /dev/null
+++ b/libstb/secvar/Makefile.inc
@@ -0,0 +1,14 @@ 
+# -*-Makefile-*-
+
+SECVAR_DIR = libstb/secvar
+
+SUBDIRS += $(SECVAR_DIR)
+
+include $(SECVAR_DIR)/storage/Makefile.inc
+include $(SECVAR_DIR)/backend/Makefile.inc
+
+SECVAR_SRCS = secvar_main.c secvar_util.c
+SECVAR_OBJS = $(SECVAR_SRCS:%.c=%.o)
+SECVAR = $(SECVAR_DIR)/built-in.a
+
+$(SECVAR): $(SECVAR_OBJS:%=$(SECVAR_DIR)/%) $(SECVAR_STORAGE) $(SECVAR_BACKEND)
diff --git a/libstb/secvar/backend/Makefile.inc b/libstb/secvar/backend/Makefile.inc
new file mode 100644
index 00000000..7a7ca1f7
--- /dev/null
+++ b/libstb/secvar/backend/Makefile.inc
@@ -0,0 +1,11 @@ 
+# -*-Makefile-*-
+
+SECVAR_BACKEND_DIR = libstb/secvar/backend
+
+SUBDIRS += $(SECVAR_BACKEND_DIR)
+
+SECVAR_BACKEND_SRCS =
+SECVAR_BACKEND_OBJS = $(SECVAR_BACKEND_SRCS:%.c=%.o)
+SECVAR_BACKEND = $(SECVAR_BACKEND_DIR)/built-in.a
+
+$(SECVAR_BACKEND): $(SECVAR_BACKEND_OBJS:%=$(SECVAR_BACKEND_DIR)/%)
diff --git a/libstb/secvar/secvar.h b/libstb/secvar/secvar.h
new file mode 100644
index 00000000..3118278b
--- /dev/null
+++ b/libstb/secvar/secvar.h
@@ -0,0 +1,61 @@ 
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2013-2019 IBM Corp. */
+
+#ifndef _SECVAR_H_
+#define _SECVAR_H_
+
+#include <ccan/list/list.h>
+#include <stdint.h>
+#include <secvar.h>
+
+#define SECVAR_MAX_KEY_LEN		1024
+#define SECVAR_MAX_DATA_SIZE		2048
+
+enum {
+	SECVAR_VARIABLE_BANK,
+	SECVAR_UPDATE_BANK,
+};
+
+
+struct secvar_node {
+	struct list_node link;
+	struct secvar *var;
+	uint64_t flags;		// Flag for how *var should be stored/allocated
+};
+
+#define SECVAR_FLAG_VOLATILE		0x1 // Instructs storage driver to ignore variable on writes
+#define SECVAR_FLAG_SECURE_STORAGE	0x2 // Hint for storage driver to select storage location
+
+struct secvar {
+	uint64_t key_len;
+	uint64_t data_size;
+	char key[SECVAR_MAX_KEY_LEN];
+	char data[0];
+};
+
+
+enum {
+	BACKEND_NONE = 0,
+	BACKEND_TC_COMPAT_V1,
+};
+
+extern struct list_head variable_bank;
+extern struct list_head update_bank;
+extern int secvar_enabled;
+extern int secvar_ready;
+extern struct secvar_storage_driver secvar_storage;
+extern struct secvar_backend_driver secvar_backend;
+
+// Check for secvar support, update secureboot DT compatible if so
+int probe_secvar(void);
+
+// To be called by the backend (at some point) to create the secure-mode devtree prop
+int secvar_set_secure_mode(uint64_t val);
+
+// Helper functions
+void clear_bank_list(struct list_head *bank);
+struct secvar_node *find_secvar(const char *key, uint64_t key_len, struct list_head *bank);
+int is_key_empty(const char *key, uint64_t key_len);
+int list_length(struct list_head *bank);
+
+#endif
diff --git a/libstb/secvar/secvar_main.c b/libstb/secvar/secvar_main.c
new file mode 100644
index 00000000..479c09e7
--- /dev/null
+++ b/libstb/secvar/secvar_main.c
@@ -0,0 +1,160 @@ 
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2019 IBM Corp. */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "SECVAR: " fmt
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <skiboot.h>
+#include <opal.h>
+#include <device.h>
+#include "secvar.h"
+
+struct list_head variable_bank;
+struct list_head update_bank;
+
+int secvar_enabled = 0;	// Set to 1 if secvar is supported
+int secvar_ready = 0;	// Set to 1 when base secvar inits correctly
+
+// To be filled in by platform.secvar_init
+struct secvar_storage_driver secvar_storage = {0};
+struct secvar_backend_driver secvar_backend = {0};
+
+// TODO: handle this better
+struct dt_node *secvar_node;
+
+int probe_secvar(void)
+{
+	struct dt_node *sb_node;
+	struct dt_property *sb_compat;
+
+	if (!platform.secvar_init)
+		return 0;
+
+	sb_node = dt_find_by_path(dt_root, "/ibm,secureboot/");
+	if (!sb_node)
+		return 1;
+
+	// TODO: create if doesn't exist?
+	sb_compat = (struct dt_property*) dt_find_property(sb_node, "compatible");
+	if (!sb_compat)
+		return 2;
+
+	strcpy(sb_compat->prop, "ibm,secureboot-v3");
+
+	return 0;
+}
+
+int secvar_set_secure_mode(uint64_t val)
+{
+	struct dt_property *node;
+
+	if (!secvar_node)
+		return -1;
+
+	node = (struct dt_property *) dt_find_property(secvar_node, "secure-mode");
+	if (!node)
+		return -2;
+
+	memcpy(node->prop, &val, sizeof(uint64_t));
+
+	return 0;
+}
+
+static void secvar_init_devnode(void)
+{
+	struct dt_node *sb_root;
+
+	sb_root = dt_find_by_path(dt_root, "/ibm,secureboot/");
+
+	secvar_node = dt_new(sb_root, "secvar");
+
+	dt_add_property_string(secvar_node, "compatible", secvar_backend.compatible);
+	dt_add_property_u64(secvar_node, "secure-mode", 0);
+}
+
+static void secvar_set_status(const char *status)
+{
+	struct dt_property *stat_prop;
+	if (!secvar_node)
+		return; // Fail boot?
+
+	stat_prop = (struct dt_property *) dt_find_property(secvar_node, "compatible");
+
+	if (stat_prop)
+		strcpy(stat_prop->prop, "ibm,secureboot-v3");
+	else
+		dt_add_property_string(secvar_node, "status", status);
+		// Fail boot if not successful?
+}
+
+int secvar_main(struct secvar_storage_driver storage_driver,
+               struct secvar_backend_driver backend_driver)
+{
+	int rc = OPAL_UNSUPPORTED;
+
+	secvar_storage = storage_driver;
+	secvar_backend = backend_driver;
+
+	secvar_init_devnode();
+
+	secvar_enabled = 1;
+
+	list_head_init(&variable_bank);
+	list_head_init(&update_bank);
+
+	rc = secvar_storage.store_init();
+	if (rc)
+		goto fail;
+
+
+	rc = secvar_storage.load_bank(&variable_bank, SECVAR_VARIABLE_BANK);
+	if (rc)
+		goto fail;
+
+	rc = secvar_storage.load_bank(&update_bank, SECVAR_UPDATE_BANK);
+	if (rc)
+		goto fail;
+
+	// At this point, base secvar is functional. Rest is up to the backend
+	secvar_ready = 1;
+
+	if (secvar_backend.pre_process)
+		rc = secvar_backend.pre_process();
+
+	// Process is required, error if it doesn't exist
+	if (!secvar_backend.process)
+		goto out;
+
+	rc = secvar_backend.process();
+	if (rc == OPAL_SUCCESS) {
+		dt_add_property(secvar_node, "update-status", &rc, sizeof(rc));
+		// TODO: Should being unable to write be a secvar/status = "fail"?
+		rc = secvar_storage.write_bank(&variable_bank, SECVAR_VARIABLE_BANK);
+		if (rc)
+			goto out;
+
+		rc = secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK);
+		if (rc)
+			goto out;
+	}
+	else
+		dt_add_property(secvar_node, "update-status", &rc, sizeof(rc));
+
+	// Last point of possible base secvar failure
+	secvar_set_status("okay");
+
+	if (secvar_backend.post_process)
+		rc = secvar_backend.post_process();
+	if (rc)
+		goto out;
+
+	return OPAL_SUCCESS;
+fail:
+	secvar_set_status("fail");
+out:
+	printf("Secure Variables Status %04x\n", rc);
+	return rc;
+}
diff --git a/libstb/secvar/secvar_util.c b/libstb/secvar/secvar_util.c
new file mode 100644
index 00000000..e3ceabda
--- /dev/null
+++ b/libstb/secvar/secvar_util.c
@@ -0,0 +1,70 @@ 
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2019 IBM Corp. */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "SECVAR: " fmt
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <skiboot.h>
+#include <opal.h>
+#include "secvar.h"
+
+void clear_bank_list(struct list_head *bank)
+{
+	struct secvar_node *node, *next;
+
+	if (!bank)
+		return;
+
+	list_for_each_safe(bank, node, next, link) {
+		list_del(&node->link);
+
+		if (node->var) {
+			free(node->var);
+		}
+
+		free(node);
+	}
+}
+
+struct secvar_node *find_secvar(const char *key, uint64_t key_len, struct list_head *bank)
+{
+	struct secvar_node *node = NULL;
+
+	list_for_each(bank, node, link) {
+		// Prevent matching shorter key subsets / bail early
+		if (key_len != node->var->key_len)
+			continue;
+		if (!memcmp(key, node->var->key, key_len)) {
+			return node;
+		}
+	}
+
+	return NULL;
+}
+
+
+int is_key_empty(const char *key, uint64_t key_len)
+{
+	int i;
+	for (i = 0; i < key_len; i++) {
+		if (key[i] != 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+int list_length(struct list_head *bank)
+{
+	int ret = 0;
+	struct secvar_node *node;
+
+	list_for_each(bank, node, link) {
+		ret++;
+	}
+
+	return ret;
+}
diff --git a/libstb/secvar/storage/Makefile.inc b/libstb/secvar/storage/Makefile.inc
new file mode 100644
index 00000000..c107736e
--- /dev/null
+++ b/libstb/secvar/storage/Makefile.inc
@@ -0,0 +1,11 @@ 
+# -*-Makefile-*-
+
+SECVAR_STORAGE_DIR = libstb/secvar/storage
+
+SUBDIRS += $(SECVAR_STORAGE_DIR)
+
+SECVAR_STORAGE_SRCS =
+SECVAR_STORAGE_OBJS = $(SECVAR_STORAGE_SRCS:%.c=%.o)
+SECVAR_STORAGE = $(SECVAR_STORAGE_DIR)/built-in.a
+
+$(SECVAR_STORAGE): $(SECVAR_STORAGE_OBJS:%=$(SECVAR_STORAGE_DIR)/%)