From patchwork Mon Jun 10 12:26:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1113090 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45MtBv0h6vz9s4V for ; Mon, 10 Jun 2019 22:45:11 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 45MtBt1TctzDqNF for ; Mon, 10 Jun 2019 22:45:10 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 45MtBc0fVTzDqMC for ; Mon, 10 Jun 2019 22:44:55 +1000 (AEST) Received: from pps.filterd (m0098420.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5ACP7bZ094570 for ; Mon, 10 Jun 2019 08:27:24 -0400 Received: from e06smtp01.uk.ibm.com (e06smtp01.uk.ibm.com [195.75.94.97]) by mx0b-001b2d01.pphosted.com with ESMTP id 2t1nce503m-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 10 Jun 2019 08:27:24 -0400 Received: from localhost by e06smtp01.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 10 Jun 2019 13:27:22 +0100 Received: from b06avi18626390.portsmouth.uk.ibm.com (9.149.26.192) by e06smtp01.uk.ibm.com (192.168.101.131) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Mon, 10 Jun 2019 13:27:20 +0100 Received: from d06av23.portsmouth.uk.ibm.com (d06av23.portsmouth.uk.ibm.com [9.149.105.59]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5ACRClc28836290 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 10 Jun 2019 12:27:12 GMT Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BBA59A405E; Mon, 10 Jun 2019 12:27:18 +0000 (GMT) Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BE6D3A405D; Mon, 10 Jun 2019 12:27:17 +0000 (GMT) Received: from yorha.ibmuc.com (unknown [9.80.225.168]) by d06av23.portsmouth.uk.ibm.com (Postfix) with ESMTP; Mon, 10 Jun 2019 12:27:17 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Mon, 10 Jun 2019 07:26:44 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190610122649.16618-1-erichte@linux.ibm.com> References: <20190610122649.16618-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19061012-4275-0000-0000-00000340F710 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19061012-4276-0000-0000-000038510402 Message-Id: <20190610122649.16618-3-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-10_06:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=4 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906100087 Subject: [Skiboot] [PATCH 2/7] libstb/secvar: add secure variable internal abstraction X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: nayna@linux.ibm.com Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" 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. Signed-off-by: Eric Richter --- include/platform.h | 1 + include/secvar.h | 39 +++++++++++++ libstb/Makefile.inc | 3 +- libstb/secureboot.c | 2 + libstb/secvar/Makefile.inc | 14 +++++ libstb/secvar/backend/Makefile.inc | 11 ++++ libstb/secvar/secvar.h | 71 ++++++++++++++++++++++++ libstb/secvar/secvar_main.c | 89 ++++++++++++++++++++++++++++++ libstb/secvar/secvar_util.c | 88 +++++++++++++++++++++++++++++ libstb/secvar/storage/Makefile.inc | 11 ++++ 10 files changed, 328 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 diff --git a/include/platform.h b/include/platform.h index b29966f9..97e93c2a 100644 --- a/include/platform.h +++ b/include/platform.h @@ -186,6 +186,7 @@ struct platform { int (*secboot_read)(void *dst, uint32_t src, uint32_t len); int (*secboot_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..3a64e8ae --- /dev/null +++ b/include/secvar.h @@ -0,0 +1,39 @@ +/* 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_ + +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_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 + int version; // Which backend version in use +}; + + +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/secureboot.c b/libstb/secureboot.c index 1578f52e..68c81ebf 100644 --- a/libstb/secureboot.c +++ b/libstb/secureboot.c @@ -170,6 +170,8 @@ void secureboot_init(void) if (cvc_init()) secureboot_enforce(); + if (platform.secvar_init) + platform.secvar_init(); secure_init = true; } 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..d02a0cef --- /dev/null +++ b/libstb/secvar/secvar.h @@ -0,0 +1,71 @@ +/* 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_H_ +#define _SECVAR_H_ + +#include +#include +#include + +#define SECVAR_MAX_KEY_LEN 1024 +#define SECVAR_MAX_METADATA_SIZE 1024 +#define SECVAR_MAX_DATA_SIZE 2048 + +enum { + SECVAR_VARIABLE_BANK, + SECVAR_UPDATE_BANK, +}; + + +struct secvar_node { + struct list_node link; + struct secvar *var; +}; + +#define SECVAR_FLAG_VOLATILE 0x1 +struct secvar { + char key[SECVAR_MAX_KEY_LEN]; + char metadata[SECVAR_MAX_METADATA_SIZE]; + char data[SECVAR_MAX_DATA_SIZE]; + uint64_t key_len; + uint64_t metadata_size; + uint64_t data_size; + uint64_t flags; +}; + +#define SECVAR_FLAG_VOLATILE 0x1 // Hint for storage driver to ignore variable on writes +#define SECVAR_FLAG_DYN_ALLOC 0x2 // Set when metadata and/or data needs to be freed +#define SECVAR_FLAG_SECURE_STORAGE 0x4 // Hint for storage driver to select storage location + +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 struct secvar_storage_driver secvar_storage; +extern struct secvar_backend_driver secvar_backend; + +// Helper functions +void clear_bank_list(struct list_head *bank); +struct secvar_node *find_secvar(char *key, uint64_t key_len, struct list_head *bank); +int is_key_empty(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..4a3c97a8 --- /dev/null +++ b/libstb/secvar/secvar_main.c @@ -0,0 +1,89 @@ +/* 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 pr_fmt +#define pr_fmt(fmt) "SECVAR: " fmt +#endif + +#include +#include +#include +#include +#include "secvar.h" + +struct list_head variable_bank; +struct list_head update_bank; +int secvar_enabled = 0; + +// To be filled in by platform.secvar_init +struct secvar_storage_driver secvar_storage = {0}; +struct secvar_backend_driver secvar_backend = {0}; + +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; + + list_head_init(&variable_bank); + list_head_init(&update_bank); + + rc = secvar_storage.store_init(); + if (rc) + goto out; + + if (secvar_backend.pre_process) + rc = secvar_backend.pre_process(); + if (rc) + goto out; + + rc = secvar_storage.load_bank(&variable_bank, SECVAR_VARIABLE_BANK); + if (rc) + goto out; + + rc = secvar_storage.load_bank(&update_bank, SECVAR_UPDATE_BANK); + if (rc) + goto out; + + if (secvar_backend.process) + rc = secvar_backend.process(); + if (rc) + goto out; + + 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; + + // TODO: maybe this should just be part of .process()? + if (secvar_backend.post_process) + rc = secvar_backend.post_process(); + if (rc) + goto out; + + secvar_enabled = 1; + + return OPAL_SUCCESS; + +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..5d79c991 --- /dev/null +++ b/libstb/secvar/secvar_util.c @@ -0,0 +1,88 @@ +/* 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 pr_fmt +#define pr_fmt(fmt) "SECVAR: " fmt +#endif + +#include +#include +#include +#include +#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); + continue; + } + + if (node->var->flags & SECVAR_FLAG_DYN_ALLOC) { + free(node->var); + } + + free(node); + } +} + +struct secvar_node *find_secvar(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(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)/%)