From patchwork Tue Sep 3 21:34:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1157342 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46NKwb5XPsz9sBF for ; Wed, 4 Sep 2019 07:34:39 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 46NKwZ4jDlzDqnR for ; Wed, 4 Sep 2019 07:34:38 +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.156.1; 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 (mx0a-001b2d01.pphosted.com [148.163.156.1]) (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 46NKwR6NyszDqm6 for ; Wed, 4 Sep 2019 07:34:28 +1000 (AEST) Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x83LWg45020706 for ; Tue, 3 Sep 2019 17:34:26 -0400 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0a-001b2d01.pphosted.com with ESMTP id 2usx1nuvgf-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 03 Sep 2019 17:34:26 -0400 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 3 Sep 2019 22:34:24 +0100 Received: from b06cxnps4075.portsmouth.uk.ibm.com (9.149.109.197) by e06smtp04.uk.ibm.com (192.168.101.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 3 Sep 2019 22:34:21 +0100 Received: from d06av26.portsmouth.uk.ibm.com (d06av26.portsmouth.uk.ibm.com [9.149.105.62]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x83LYJRG32243740 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 3 Sep 2019 21:34:19 GMT Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 772DAAE05A; Tue, 3 Sep 2019 21:34:19 +0000 (GMT) Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CF23FAE04D; Tue, 3 Sep 2019 21:34:18 +0000 (GMT) Received: from yorha.ibmuc.com (unknown [9.80.226.234]) by d06av26.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 3 Sep 2019 21:34:18 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 3 Sep 2019 16:34:12 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190903213416.16535-1-erichte@linux.ibm.com> References: <20190903213416.16535-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19090321-0016-0000-0000-000002A64190 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19090321-0017-0000-0000-00003306ABC3 Message-Id: <20190903213416.16535-2-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-09-03_05:, , 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-1906280000 definitions=main-1909030214 Subject: [Skiboot] [PATCH v3 1/5] 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. 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 --- 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 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 + +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 +#include +#include + +#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 +#include +#include +#include +#include +#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 +#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->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)/%) From patchwork Tue Sep 3 21:34:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1157343 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (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 46NKx03K2Qz9sBF for ; Wed, 4 Sep 2019 07:35:00 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 46NKx02VhnzDqnx for ; Wed, 4 Sep 2019 07:35:00 +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.156.1; 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 (mx0a-001b2d01.pphosted.com [148.163.156.1]) (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 46NKwR6MF2zDqlD for ; Wed, 4 Sep 2019 07:34:28 +1000 (AEST) Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x83LWe6Q089638 for ; Tue, 3 Sep 2019 17:34:25 -0400 Received: from e06smtp03.uk.ibm.com (e06smtp03.uk.ibm.com [195.75.94.99]) by mx0a-001b2d01.pphosted.com with ESMTP id 2usx8qbkeb-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 03 Sep 2019 17:34:25 -0400 Received: from localhost by e06smtp03.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 3 Sep 2019 22:34:23 +0100 Received: from b06cxnps4076.portsmouth.uk.ibm.com (9.149.109.198) by e06smtp03.uk.ibm.com (192.168.101.133) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 3 Sep 2019 22:34:22 +0100 Received: from d06av26.portsmouth.uk.ibm.com (d06av26.portsmouth.uk.ibm.com [9.149.105.62]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x83LYKcp45220094 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 3 Sep 2019 21:34:20 GMT Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 65449AE04D; Tue, 3 Sep 2019 21:34:20 +0000 (GMT) Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BE262AE045; Tue, 3 Sep 2019 21:34:19 +0000 (GMT) Received: from yorha.ibmuc.com (unknown [9.80.226.234]) by d06av26.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 3 Sep 2019 21:34:19 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 3 Sep 2019 16:34:13 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190903213416.16535-1-erichte@linux.ibm.com> References: <20190903213416.16535-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19090321-0012-0000-0000-000003464036 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19090321-0013-0000-0000-000021808FEE Message-Id: <20190903213416.16535-3-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-09-03_05:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1011 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1906280000 definitions=main-1909030214 Subject: [Skiboot] [PATCH v3 2/5] libstb: add support for ibm, secureboot-v3 and initialize secure variables if supported by the platform 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" Platforms determine whether or not they support secure boot by implementing a specific hook. Prior to initializing firmware secureboot, the platform hook for secure variables is checked. If it has been implemented, we increase the secureboot version to "ibm,secureboot-v3" indicating secure variables are supported. Signed-off-by: Eric Richter --- core/init.c | 4 ++++ libstb/cvc.c | 2 +- libstb/secureboot.c | 7 ++++++- libstb/secureboot.h | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/init.c b/core/init.c index cd333dcb..fa2d425a 100644 --- a/core/init.c +++ b/core/init.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1163,6 +1164,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) /* Set the console level */ console_log_level(); + /* Check for secvar support, update secureboot compatible if so */ + probe_secvar(); + /* Secure/Trusted Boot init. We look for /ibm,secureboot in DT */ secureboot_init(); trustedboot_init(); diff --git a/libstb/cvc.c b/libstb/cvc.c index dca4ac85..4642cb2a 100644 --- a/libstb/cvc.c +++ b/libstb/cvc.c @@ -268,7 +268,7 @@ int cvc_init(void) rc = cvc_secure_rom_init(); } else if (version == IBM_SECUREBOOT_SOFTROM) { softrom = true; - } else if (version == IBM_SECUREBOOT_V2) { + } else if ((version == IBM_SECUREBOOT_V2 ) || (version == IBM_SECUREBOOT_V3)) { rc = cvc_reserved_mem_init(node); } else { prlog(PR_ERR, "%s FAILED. /ibm,secureboot not supported\n", diff --git a/libstb/secureboot.c b/libstb/secureboot.c index bfc98f2a..a7d418cf 100644 --- a/libstb/secureboot.c +++ b/libstb/secureboot.c @@ -25,6 +25,7 @@ static struct { { IBM_SECUREBOOT_V1, "ibm,secureboot-v1" }, { IBM_SECUREBOOT_SOFTROM, "ibm,secureboot-v1-softrom" }, { IBM_SECUREBOOT_V2, "ibm,secureboot-v2" }, + { IBM_SECUREBOOT_V3, "ibm,secureboot-v3" }, }; static void secureboot_enforce(void) @@ -124,7 +125,8 @@ void secureboot_init(void) } hw_key_hash_size = SHA512_DIGEST_LENGTH; - } else if (version == IBM_SECUREBOOT_V2) { + } else if (version == IBM_SECUREBOOT_V2 || + version == IBM_SECUREBOOT_V3) { hw_key_hash_size = dt_prop_get_u32(node, "hw-key-hash-size"); if (hw_key_hash_size == 0) { @@ -157,6 +159,9 @@ void secureboot_init(void) if (cvc_init()) secureboot_enforce(); + if (version == IBM_SECUREBOOT_V3) { + platform.secvar_init(); + } secure_init = true; } diff --git a/libstb/secureboot.h b/libstb/secureboot.h index 426483ff..719c6817 100644 --- a/libstb/secureboot.h +++ b/libstb/secureboot.h @@ -13,6 +13,7 @@ enum secureboot_version { IBM_SECUREBOOT_V1, IBM_SECUREBOOT_SOFTROM, IBM_SECUREBOOT_V2, + IBM_SECUREBOOT_V3, }; bool secureboot_is_compatible(struct dt_node *node, int *version, const char **compat); From patchwork Tue Sep 3 21:34:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1157344 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 46NKxL1LtBz9sBF for ; Wed, 4 Sep 2019 07:35:18 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 46NKxJ6SFPzDqlD for ; Wed, 4 Sep 2019 07:35:16 +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.156.1; 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 (mx0a-001b2d01.pphosted.com [148.163.156.1]) (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 46NKwS31f6zDqm9 for ; Wed, 4 Sep 2019 07:34:29 +1000 (AEST) Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x83LX6Op046760 for ; Tue, 3 Sep 2019 17:34:26 -0400 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0a-001b2d01.pphosted.com with ESMTP id 2usxpwtpdn-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 03 Sep 2019 17:34:26 -0400 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 3 Sep 2019 22:34:24 +0100 Received: from b06avi18878370.portsmouth.uk.ibm.com (9.149.26.194) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 3 Sep 2019 22:34:23 +0100 Received: from d06av26.portsmouth.uk.ibm.com (d06av26.portsmouth.uk.ibm.com [9.149.105.62]) by b06avi18878370.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x83LYLT939715146 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 3 Sep 2019 21:34:21 GMT Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 59B2CAE057; Tue, 3 Sep 2019 21:34:21 +0000 (GMT) Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AD19DAE04D; Tue, 3 Sep 2019 21:34:20 +0000 (GMT) Received: from yorha.ibmuc.com (unknown [9.80.226.234]) by d06av26.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 3 Sep 2019 21:34:20 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 3 Sep 2019 16:34:14 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190903213416.16535-1-erichte@linux.ibm.com> References: <20190903213416.16535-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19090321-0020-0000-0000-000003674217 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19090321-0021-0000-0000-000021BCADF6 Message-Id: <20190903213416.16535-4-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-09-03_05:, , 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-1906280000 definitions=main-1909030214 Subject: [Skiboot] [PATCH v3 3/5] libstb/secvar: add secvar api implementation 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 provides the OPAL runtime service frontend for the host OS to retrieve secure variables, and append new ones for processing on the next reboot. These calls operate on the internal abstraction or utilize the platform-provided driver hooks, and therefore this API should not need to be updated to support changes in storage or backend drivers. Included are the following functions: - opal_secvar_get() - opal_secvar_get_next() - opal_secvar_enqueue_update() opal_secvar_get() retrieves the data blob associated with a given key. The data buffer may be set to NULL to only query for variable size. This runtime service only operates on the variable bank. opal_secvar_get_next() can be used to iterate through the list of variable keys in the variable bank. Supplying an empty key (or zero key length) returns the key of the first variable in the variable bank. Supplying a valid key returns the key of the next variable in sequence. opal_secvar_enqueue_update() provides a method for the host OS to submit a new variable for processing on next boot, by appending it to the update bank. As this does not affect the variable bank, appending a variable via this runtime service will not affect the output of the previous set of functions. The update queue is only processed during secvar initialization. V2: - removed opal_secvar_backend, replaced by DT node - removed unnecessary argument casting - all calls return OPAL_RESOURCE if secvar failed to init V3: - remove metadata from API parameters - remove opal_secvar_get_size - change enqueue to replace an update with a repeat name, rather than enqueueing the duplicate - change enqueue to unstage an update matching a key if size is zero - make all key parameters const where possible - rename key_size to key_buf_size in _get_next - fix leaking node when enqueue could not allocate the secvar Signed-off-by: Eric Richter --- ccan/list/list.h | 38 +++++++++ include/opal-api.h | 5 +- libstb/secvar/Makefile.inc | 2 +- libstb/secvar/secvar_api.c | 158 +++++++++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 libstb/secvar/secvar_api.c diff --git a/ccan/list/list.h b/ccan/list/list.h index 7cd3a83e..fdeddeb4 100644 --- a/ccan/list/list.h +++ b/ccan/list/list.h @@ -523,4 +523,42 @@ static inline struct list_node *list_node_from_off_(void *ptr, size_t off) (container_off_var(var, member) + \ check_type(var->member, struct list_node)) + +#if HAVE_TYPEOF +#define list_typeof(var) typeof(var) +#else +#define list_typeof(var) void * +#endif + + +/* Returns member, or NULL if at end of list. */ +static inline void *list_entry_or_null(const struct list_head *h, + const struct list_node *n, + size_t off) +{ + if (n == &h->n) + return NULL; + return (char *)n - off; +} + +/** + * list_next - get the next entry in a list + * @h: the list_head + * @i: a pointer to an entry in the list. + * @member: the list_node member of the structure + * + * If @i was the last entry in the list, returns NULL. + * + * Example: + * struct child *second; + * second = list_next(&parent->children, first, list); + * if (!second) + * printf("No second child!\n"); + */ +#define list_next(h, i, member) \ + ((list_typeof(i))list_entry_or_null(list_debug(h), \ + (i)->member.next, \ + list_off_var_((i), member))) + + #endif /* CCAN_LIST_H */ diff --git a/include/opal-api.h b/include/opal-api.h index ee66bbbb..a7746789 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -222,7 +222,10 @@ #define OPAL_MPIPL_UPDATE 173 #define OPAL_MPIPL_REGISTER_TAG 174 #define OPAL_MPIPL_QUERY_TAG 175 -#define OPAL_LAST 175 +#define OPAL_SECVAR_GET 176 +#define OPAL_SECVAR_GET_NEXT 177 +#define OPAL_SECVAR_ENQUEUE_UPDATE 178 +#define OPAL_LAST 178 #define QUIESCE_HOLD 1 /* Spin all calls at entry */ #define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */ diff --git a/libstb/secvar/Makefile.inc b/libstb/secvar/Makefile.inc index 75870910..50316b48 100644 --- a/libstb/secvar/Makefile.inc +++ b/libstb/secvar/Makefile.inc @@ -7,7 +7,7 @@ SUBDIRS += $(SECVAR_DIR) include $(SECVAR_DIR)/storage/Makefile.inc include $(SECVAR_DIR)/backend/Makefile.inc -SECVAR_SRCS = secvar_main.c secvar_util.c +SECVAR_SRCS = secvar_main.c secvar_util.c secvar_api.c SECVAR_OBJS = $(SECVAR_SRCS:%.c=%.o) SECVAR = $(SECVAR_DIR)/built-in.a diff --git a/libstb/secvar/secvar_api.c b/libstb/secvar/secvar_api.c new file mode 100644 index 00000000..3483837a --- /dev/null +++ b/libstb/secvar/secvar_api.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: Apache-2.0 +/* Copyright 2019 IBM Corp. */ + +#ifndef pr_fmt +#define pr_fmt(fmt) "SECVAR_API: " fmt +#endif + +#include +#include "secvar.h" + + +static int64_t opal_secvar_get(const char *key, uint64_t key_len, void *data, uint64_t *data_size) +{ + struct secvar_node *node; + int64_t rc = OPAL_SUCCESS; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key) + return OPAL_PARAMETER; + if (key_len == 0) + return OPAL_PARAMETER; + // Data size must be set, data is optional for size query + if (!data_size) + return OPAL_PARAMETER; + + node = find_secvar(key, key_len, &variable_bank); + + if (!node) + return OPAL_EMPTY; // Variable not found, bail early + + if (!data) + rc = OPAL_SUCCESS; + else if (*data_size < node->var->data_size) + rc = OPAL_PARTIAL; + else + memcpy(data, node->var->data, node->var->data_size); + + *data_size = node->var->data_size; + + return rc; +} +opal_call(OPAL_SECVAR_GET, opal_secvar_get, 4); + + +static int64_t opal_secvar_get_next(char *key, uint64_t *key_len, uint64_t key_buf_size) +{ + struct secvar_node *node; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key_len) + return OPAL_PARAMETER; + if (key_buf_size == 0) + return OPAL_PARAMETER; + if (*key_len > SECVAR_MAX_KEY_LEN) + return OPAL_PARAMETER; + if (*key_len > key_buf_size) + return OPAL_PARAMETER; + if (!key) + return OPAL_PARAMETER; + + if (!is_key_empty(key, *key_len)) { + node = find_secvar(key, *key_len, &variable_bank); + if (!node) + return OPAL_PARAMETER; + + node = list_next(&variable_bank, node, link); + } else + node = list_top(&variable_bank, struct secvar_node, link); + + if (!node) + return OPAL_EMPTY; + + if (key_buf_size < node->var->key_len) { + *key_len = node->var->key_len; + return OPAL_PARTIAL; + } + + *key_len = node->var->key_len; + memcpy(key, node->var->key, node->var->key_len); + + return OPAL_SUCCESS; +} +opal_call(OPAL_SECVAR_GET_NEXT, opal_secvar_get_next, 3); + + +static int64_t opal_secvar_enqueue_update(const char *key, uint64_t key_len, void *data, uint64_t data_size) +{ + struct secvar_node *node; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!secvar_storage.write_bank) + return OPAL_HARDWARE; + if (!key) + return OPAL_PARAMETER; + if (key_len == 0) + return OPAL_PARAMETER; + if (key_len > SECVAR_MAX_KEY_LEN) + return OPAL_PARAMETER; + if ((!data) && (data_size != 0)) + return OPAL_PARAMETER; + if (data_size > SECVAR_MAX_DATA_SIZE) + return OPAL_PARAMETER; + + // Key should not be empty + if (is_key_empty(key, key_len)) + return OPAL_PARAMETER; + + node = find_secvar(key, key_len, &update_bank); + + // Unstage an update + if (data_size == 0) { + if (!node) + return OPAL_EMPTY; + + if (node->var) + free(node->var); + list_del(&node->link); + free(node); + goto out; + } + + if (node) { + list_del(&node->link); + memset(node->var, 0x00, sizeof(struct secvar) + node->var->data_size); + } else { + node = zalloc(sizeof(struct secvar_node)); + if (!node) + return OPAL_NO_MEM; + node->var = zalloc(sizeof(struct secvar) + data_size); + } + + if (!node->var) { + free(node); + return OPAL_NO_MEM; + } + + memcpy(node->var->key, key, key_len); + node->var->key_len = key_len; + memcpy(node->var->data, data, data_size); + node->var->data_size = data_size; + + list_add_tail(&update_bank, &node->link); + +out: + secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK); + + return OPAL_SUCCESS; +} +opal_call(OPAL_SECVAR_ENQUEUE_UPDATE, opal_secvar_enqueue_update, 4); From patchwork Tue Sep 3 21:34:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1157346 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 46NKxy06nKz9sDB for ; Wed, 4 Sep 2019 07:35:50 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 46NKxx5lq1zDqmT for ; Wed, 4 Sep 2019 07:35:49 +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.156.1; 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 (mx0a-001b2d01.pphosted.com [148.163.156.1]) (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 46NKwV5QcjzDqm9 for ; Wed, 4 Sep 2019 07:34:33 +1000 (AEST) Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x83LWfBX114287 for ; Tue, 3 Sep 2019 17:34:31 -0400 Received: from e06smtp01.uk.ibm.com (e06smtp01.uk.ibm.com [195.75.94.97]) by mx0a-001b2d01.pphosted.com with ESMTP id 2usymk12n9-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 03 Sep 2019 17:34:31 -0400 Received: from localhost by e06smtp01.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 3 Sep 2019 22:34:26 +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) Tue, 3 Sep 2019 22:34:23 +0100 Received: from d06av26.portsmouth.uk.ibm.com (d06av26.portsmouth.uk.ibm.com [9.149.105.62]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x83LXxT942205478 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 3 Sep 2019 21:33:59 GMT Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 48F0EAE053; Tue, 3 Sep 2019 21:34:22 +0000 (GMT) Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A1A0AAE057; Tue, 3 Sep 2019 21:34:21 +0000 (GMT) Received: from yorha.ibmuc.com (unknown [9.80.226.234]) by d06av26.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 3 Sep 2019 21:34:21 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 3 Sep 2019 16:34:15 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190903213416.16535-1-erichte@linux.ibm.com> References: <20190903213416.16535-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19090321-4275-0000-0000-00000360B187 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19090321-4276-0000-0000-00003872F4B3 Message-Id: <20190903213416.16535-5-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-09-03_05:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 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-1906280000 definitions=main-1909030214 Subject: [Skiboot] [PATCH v3 4/5] doc: add opal secure variable documentation 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 contains the work-in-progress documentation for the secure variable design in OPAL. Future revisions of this patch set will (hopefully) add new pieces of documentation here. V3: - removed metadata - removed get_size - updated _get semantics for size queries - added/expanded device tree properties Signed-off-by: Eric Richter --- doc/device-tree/ibm,secureboot.rst | 10 ++ doc/device-tree/secvar.rst | 84 +++++++++++++ doc/opal-api/opal-secvar.rst | 188 +++++++++++++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 doc/device-tree/secvar.rst create mode 100644 doc/opal-api/opal-secvar.rst diff --git a/doc/device-tree/ibm,secureboot.rst b/doc/device-tree/ibm,secureboot.rst index 42c4ed7d..b4729a9d 100644 --- a/doc/device-tree/ibm,secureboot.rst +++ b/doc/device-tree/ibm,secureboot.rst @@ -21,6 +21,13 @@ Required properties It described by the ibm,cvc child node. + ibm,secureboot-v3 : The container-verification-code + is stored in a reserved memory. + It described by the ibm,cvc child + node. Secure variables are + supported. `secvar` node should + be created. + secure-enabled: this property exists when the firmware stack is booting in secure mode (hardware secure boot jumper asserted). @@ -33,6 +40,9 @@ Required properties hw-key-hash-size: hw-key-hash size + secvar: this node is created if the platform supports secure + variables. Contains information about the current + secvar status, see 'secvar.rst'. Obsolete properties ------------------- diff --git a/doc/device-tree/secvar.rst b/doc/device-tree/secvar.rst new file mode 100644 index 00000000..c439a123 --- /dev/null +++ b/doc/device-tree/secvar.rst @@ -0,0 +1,84 @@ +.. _device-tree/ibm,secureboot/secvar: + +secvar +====== + +The ``secvar`` node provides secure variable information for the secure +boot of the target OS. + +Required properties +------------------- + +.. code-block:: none + + compatible: this property is set based on the current secure + variable scheme as set by the platform. + + status: set to "fail" if the secure variables could not + be initialized, validated, or some other + catastrophic failure. + + update-status: contains the return code of the update queue + process run during initialization. Signifies if + updates were processed or not, and if there was + an error. See table below + + secure-mode: a u64 bitfield set by the backend to determine + what secure mode we should be in, and if host + secure boot should be enforced. + +Example +------- + +.. code-block:: dts + + secvar { + compatible = "ibm,edk2-compat-v1"; + status = "okay"; + secure-mode = "1"; + }; + +Update Status +------------- + +The update status property should be set by the backend driver to a value +that best fits its error condtion. The following table defines the +general intent of each error code, check backend specific documentation +for more detail. + ++-----------------+-----------------------------------------------+ +| update-status | Generic Reason | ++-----------------|-----------------------------------------------+ +| OPAL_SUCCESS | Updates were found and processed successfully | ++-----------------|-----------------------------------------------+ +| OPAL_EMPTY | No updates were found, none processed | ++-----------------|-----------------------------------------------+ +| OPAL_PARAMETER | Unable to parse data in the update section | ++-----------------|-----------------------------------------------+ +| OPAL_PERMISSION | Update failed to apply, possible auth failure | ++-----------------|-----------------------------------------------+ +| OPAL_HARDWARE | Misc. storage-related error | ++-----------------|-----------------------------------------------+ +| OPAL_RESOURCE | Out of space (somewhere) | ++-----------------|-----------------------------------------------+ +| OPAL_NO_MEM | Out of memory | ++-----------------+-----------------------------------------------+ + +Secure Mode +----------- + ++-----------------------+------------------------+ +| backend specific-bits | generic mode bits | ++-----------------------+------------------------+ +64 32 0 + +The secure mode property should be set by the backend driver. The least +significant 32 bits are reserved for generic modes, shared across all +possible backends. The other 32 bits are open for backends to determine +their own modes. Any kernel must be made aware of any custom modes. + +At the moment, only one general-purpose bit is defined: + +``#define SECVAR_SECURE_MODE_ENFORCING 0x1`` + +which signals that a kernel should enforce host secure boot. diff --git a/doc/opal-api/opal-secvar.rst b/doc/opal-api/opal-secvar.rst new file mode 100644 index 00000000..d304db8f --- /dev/null +++ b/doc/opal-api/opal-secvar.rst @@ -0,0 +1,188 @@ +OPAL Secure Variable API +======================== + +Overview +-------- + +In order to support host OS secure boot on POWER systems, the platform needs +some form of tamper-resistant persistant storage for authorized public keys. +Furthermore, these keys must be retrieveable by the host kernel, and new +keys must be able to be submitted. + +OPAL exposes an abstracted "variable" API, in which these keys can be stored +and retrieved. At a high level, ``opal_secvar_get`` retrieves a specific +variable corresponding to a particular key. ``opal_secvar_get_next`` can be +used to iterate through the keys of the stored variables. +``opal_secvar_enqueue_update`` can be used to submit a new variable for +processing on next boot. + +OPAL_SECVAR_GET +=============== +:: + + #define OPAL_SECVAR_GET 173 + +``OPAL_SECVAR_GET`` call retrieves a data blob associated with the supplied +key. + + +Parameters +---------- +:: + + char *key + uint64_t key_len + void *data + uint64_t *data_size + +``key`` + a buffer used to associate with the variable data. May +be any encoding, but must not be all zeroes + +``key_len`` + size of the key buffer in bytes + +``data`` + return buffer to store the data blob of the requested variable if +a match was found. May be set to NULL to only query the size into +``data_size`` + +``data_size`` + reference to the size of the ``data`` buffer. OPAL sets this to +the size of the requested variable if found. + + +Return Values +------------- + +``OPAL_SUCCESS`` + the requested data blob was copied successfully. ``data`` was NULL, +and the ``data_size`` value was set successfully + +``OPAL_PARAMETER`` + ``key`` is NULL. ``key_len`` is zero. ``data_size`` is NULL. + +``OPAL_EMPTY`` + no variable with the supplied ``key`` was found + +``OPAL_PARTIAL`` + the buffer size provided in ``data_size`` was insufficient. +``data_size`` is set to the minimum required size. + +``OPAL_UNSUPPORTED`` + secure variables are not supported by the platform + +``OPAL_RESOURCE`` + secure variables are supported, but did not initialize properly + +OPAL_SECVAR_GET_NEXT +==================== +:: + + #define OPAL_SECVAR_GET_NEXT 174 + +``OPAL_SECVAR_GET_NEXT`` returns the key of the next variable in the secure +variable bank in sequence. + +Parameters +---------- +:: + + char *key + uint64_t *key_len + uint64_t key_buf_size + + +``key`` + name of the previous variable or empty. The key of the next +variable in sequence will be copied to ``key``. If passed as empty, +returns the first variable in the bank + +``key_len`` + length in bytes of the key in the ``key`` buffer. OPAL sets +this to the length in bytes of the next variable in sequence + +``key_buf_size`` + maximum size of the ``key`` buffer. The next key will not be +copied if this value is less than the length of the next key + + +Return Values +------------- + +``OPAL_SUCCESS`` + the key and length of the next variable in sequence was copied +successfully + +``OPAL_PARAMETER`` + ``key`` or ``key_length`` is NULL. ``key_size`` is zero. +``key_length`` is impossibly large. No variable with the associated +``key`` was found + +``OPAL_EMPTY`` + end of list reached + +``OPAL_PARTIAL`` + the size specified in ``key_size`` is insufficient for the next +variable's key length. ``key_length`` is set to the next variable's +length, but ``key`` is untouched + +``OPAL_UNSUPPORTED`` + secure variables are not supported by the platform + +``OPAL_RESOURCE`` + secure variables are supported, but did not initialize properly + +OPAL_SECVAR_ENQUEUE_UPDATE +========================== +:: + + #define OPAL_SECVAR_ENQUEUE_UPDATE 175 + +``OPAL_SECVAR_ENQUEUE`` call appends the supplied variable data to the +queue for processing on next boot. + +Parameters +---------- +:: + + char *key + uint64_t key_len + void *data + uint64_t data_size + +``key`` + a buffer used to associate with the variable data. May +be any encoding, but must not be all zeroes + +``key_len`` + size of the key buffer in bytes + +``data`` + buffer containing the blob of data to enqueue + +``data_size`` + size of the ``data`` buffer + +Return Values +------------- + +``OPAL_SUCCESS`` + the variable was appended to the update queue bank successfully + +``OPAL_PARAMETER`` + ``key`` or ``data`` was NULL. ``key`` was empty. ``key_len`` or +``data_size`` was zero. ``key_len``, ``data_size`` is larger than +the maximum size + +``OPAL_NO_MEM`` + OPAL was unable to allocate memory for the variable update + +``OPAL_HARDWARE`` + OPAL was unable to write the update to persistant storage + +``OPAL_UNSUPPORTED`` + secure variables are not supported by the platform + +``OPAL_RESOURCE`` + secure variables are supported, but did not initialize properly From patchwork Tue Sep 3 21:34:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1157347 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (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 46NKyH0y52z9sDB for ; Wed, 4 Sep 2019 07:36:07 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 46NKyG3WtXzDqlD for ; Wed, 4 Sep 2019 07:36:06 +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 46NKwV5QGmzDqlD for ; Wed, 4 Sep 2019 07:34:33 +1000 (AEST) Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x83LWhaw042604 for ; Tue, 3 Sep 2019 17:34:28 -0400 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0b-001b2d01.pphosted.com with ESMTP id 2usxwtac7f-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 03 Sep 2019 17:34:28 -0400 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 3 Sep 2019 22:34:26 +0100 Received: from b06cxnps3074.portsmouth.uk.ibm.com (9.149.109.194) by e06smtp04.uk.ibm.com (192.168.101.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 3 Sep 2019 22:34:25 +0100 Received: from d06av26.portsmouth.uk.ibm.com (d06av26.portsmouth.uk.ibm.com [9.149.105.62]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x83LYNos59703536 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 3 Sep 2019 21:34:23 GMT Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 57A15AE04D; Tue, 3 Sep 2019 21:34:23 +0000 (GMT) Received: from d06av26.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 91056AE057; Tue, 3 Sep 2019 21:34:22 +0000 (GMT) Received: from yorha.ibmuc.com (unknown [9.80.226.234]) by d06av26.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 3 Sep 2019 21:34:22 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 3 Sep 2019 16:34:16 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190903213416.16535-1-erichte@linux.ibm.com> References: <20190903213416.16535-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19090321-0016-0000-0000-000002A64193 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19090321-0017-0000-0000-00003306ABC6 Message-Id: <20190903213416.16535-6-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-09-03_05:, , 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-1906280000 definitions=main-1909030214 Subject: [Skiboot] [PATCH v3 5/5] secvar/test: add rudimentary secvar API unit testing 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 adds an initial port of the userspace unit tests for exercising the API that were originally developed out of tree. Future revisions will adjust the naming schemes and general formatting to match that of other tests within skiboot. Signed-off-by: Eric Richter --- libstb/secvar/test/Makefile.check | 46 +++++++ libstb/secvar/test/secvar-test-enqueue.c | 158 +++++++++++++++++++++++ libstb/secvar/test/secvar-test-getvar.c | 109 ++++++++++++++++ libstb/secvar/test/secvar-test-nextvar.c | 132 +++++++++++++++++++ libstb/secvar/test/secvar-test-void.c | 24 ++++ libstb/secvar/test/secvar_api_test.c | 91 +++++++++++++ libstb/secvar/test/secvar_common_test.c | 62 +++++++++ 7 files changed, 622 insertions(+) create mode 100644 libstb/secvar/test/Makefile.check create mode 100644 libstb/secvar/test/secvar-test-enqueue.c create mode 100644 libstb/secvar/test/secvar-test-getvar.c create mode 100644 libstb/secvar/test/secvar-test-nextvar.c create mode 100644 libstb/secvar/test/secvar-test-void.c create mode 100644 libstb/secvar/test/secvar_api_test.c create mode 100644 libstb/secvar/test/secvar_common_test.c diff --git a/libstb/secvar/test/Makefile.check b/libstb/secvar/test/Makefile.check new file mode 100644 index 00000000..0b172039 --- /dev/null +++ b/libstb/secvar/test/Makefile.check @@ -0,0 +1,46 @@ +# -*-Makefile-*- +SECVAR_TEST_DIR = libstb/secvar/test +#SUBDIRS = $(SECVAR_TEST_DIR) + +SECVAR_TEST = $(patsubst %.c, %, $(wildcard $(SECVAR_TEST_DIR)/secvar-test-*.c)) + +HOSTCFLAGS+=-I . -I include + +.PHONY : secvar-check +secvar-check: $(SECVAR_TEST:%=%-check) $(SECVAR_TEST:%=%-gcov-run) +secvar-check: $(SECVAR_TEST_NOSTUB:%=%-check) $(SECVAR_TEST_NOSTUB:%=%-gcov-run) + +.PHONY : secvar-coverage +secvar-coverage: $(SECVAR_TEST:%=%-gcov-run) +secvar-coverage: $(SECVAR_TEST_NOSTUB:%=%-gcov-run) + +check: secvar-check +coverage: secvar-coverage + +# TODO: create pnor image for only tests that need it +$(SECVAR_TEST:%=%-gcov-run) : %-run: % + @dd if=/dev/zero of=secboot.img bs=128k count=1 2> /dev/null + $(call QTEST, TEST-COVERAGE ,$< , $<) + @$(RM) -f secboot.img + +$(SECVAR_TEST:%=%-check) : %-check: % + @dd if=/dev/zero of=secboot.img bs=128k count=1 2> /dev/null + $(call QTEST, RUN-TEST ,$(VALGRIND) $<, $<) + @$(RM) -f secboot.img + +$(SECVAR_TEST) : core/test/stubs.o + +$(SECVAR_TEST) : % : %.c + $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) -O0 -g -I include -I . -I libfdt -o $@ $< core/test/stubs.o, $<) + +$(SECVAR_TEST:%=%-gcov): %-gcov : %.c % + $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) $(HOSTGCOVCFLAGS) -I include -I . -I libfdt -lgcov -o $@ $< core/test/stubs.o, $<) + +-include $(wildcard libstb/secvar/test/*.d) + +clean: secvar-test-clean + +secvar-test-clean: + $(RM) -f libstb/secvar/test/*.[od] $(SECVAR_TEST) $(SECVAR_TEST:%=%-gcov) + $(RM) -f libstb/secvar/test/*.gcda libstb/secvar/test/*.gcno + $(RM) -f secboot.img diff --git a/libstb/secvar/test/secvar-test-enqueue.c b/libstb/secvar/test/secvar-test-enqueue.c new file mode 100644 index 00000000..385e9934 --- /dev/null +++ b/libstb/secvar/test/secvar-test-enqueue.c @@ -0,0 +1,158 @@ +/* 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. + */ +#include "secvar_api_test.c" + +const char *secvar_test_name = "enqueue"; + +// Stub storage function, enqueue only cares that this succeeds +static int temp_write_bank(struct list_head *bank, int section) +{ + (void) bank, (void) section; + return OPAL_SUCCESS; +} + +int run_test(void) +{ + int64_t rc; + + struct secvar_node *node; + char key[1024] = {0}; + + uint64_t data_size = 128; + char *data = zalloc(data_size); + + /*** Bad cases first this time ***/ + // No write bank hook set + secvar_storage.write_bank = NULL; + memcpy(key, "meow", 4); // ascii + rc = secvar_enqueue(key, 4, data, data_size); + ASSERT(rc == OPAL_HARDWARE); + + // Set a stub bank writer, so the rest runs ok + secvar_storage.write_bank = temp_write_bank; + + // Parameter checks + // null key + rc = secvar_enqueue(NULL, 5, data, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // key is empty + memset(key, 0, sizeof(key)); + rc = secvar_enqueue(key, 5, data, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // keylen is zero + rc = secvar_enqueue(key, 0, data, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // keylen is excessive + rc = secvar_enqueue(key, 5000, data, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // null data + rc = secvar_enqueue(key, 5, NULL, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // data_size is excessive + rc = secvar_enqueue(key, 5, data, 50000); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // data_size is zero + rc = secvar_enqueue(key, 5, data, 0); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // secvar is disabled + secvar_enabled = 0; + rc = secvar_enqueue(key, 5, data, data_size); + ASSERT(rc == OPAL_UNSUPPORTED); + secvar_enabled = 1; + + // secvar is not ready + secvar_ready = 0; + rc = secvar_enqueue(key, 5, data, data_size); + ASSERT(rc == OPAL_RESOURCE); + secvar_ready = 1; + + + /*** Good cases ***/ + // TODO: add data? + memcpy(key, "test", 4); // ascii + rc = secvar_enqueue(key, 4, data, data_size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 1); + + memcpy(key, "f\0o\0o\0b\0a\0r\0", 6*2); // "unicode" + rc = secvar_enqueue(key, 6*2, data, data_size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 2); + + memcpy(key, "meep", 4); + rc = secvar_enqueue(key, 4, data, data_size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 3); // should not increase + + // Re-add the same variable + memcpy(key, "meep", 4); + rc = secvar_enqueue(key, 4, data, data_size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 3); // should not increase + node = list_tail(&update_bank, struct secvar_node, link); + ASSERT(!memcmp(node->var->key, key, 4)) // should be at end + + // Unstage the variable update + rc = secvar_enqueue(key, 4, NULL, 0); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 2); + + // Unstage a bogus variable update + rc = secvar_enqueue("nada", 4, NULL, 0); + ASSERT(rc == OPAL_EMPTY); + ASSERT(list_length(&update_bank) == 2); + + + // Empty the in-memory cache, and reload from "pnor" + // Removed to drop dependency on a storage backend + // Probably not actually necessary to test, that's the + // job of the storage backend tests + /* + clear_bank_list(&update_bank); + ASSERT(list_empty(&update_bank)); + secvar_storage.load_bank(&update_bank, SECVAR_UPDATE_BANK); + printf("list_length = %d\n", list_length(&update_bank)); + ASSERT(list_length(&update_bank) == 2); + + node = list_top(&update_bank, struct secvar_node, link); + ASSERT(node); + ASSERT(!memcmp(node->var->key, "test", 4)); + node = list_next(&update_bank, node, link); + ASSERT(node); + ASSERT(!memcmp(node->var->key, "f\0o\0o\0b\0a\0r\0", 6*2)); + */ + + /*** ONE more bad case... ***/ + + free(data); + + return 0; + +} diff --git a/libstb/secvar/test/secvar-test-getvar.c b/libstb/secvar/test/secvar-test-getvar.c new file mode 100644 index 00000000..eeedd61b --- /dev/null +++ b/libstb/secvar/test/secvar-test-getvar.c @@ -0,0 +1,109 @@ +/* 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. + */ +#include "secvar_api_test.c" + +const char *secvar_test_name = "getvar"; + +// Run tests on the less obvious features of secvar_get +// Includes: +// - Partial reads +// - Size queries (NULL buffer) +//int run_test_helper(uint64_t bank_enum) +int run_test(void) +{ + int64_t rc; + + uint64_t size = 4; + char *temp = zalloc(100); + char key[1024] = {0}; + + struct secvar_node *node = zalloc(sizeof(struct secvar_node)); + struct secvar *var = zalloc(sizeof(struct secvar) + 1024); // over-allocate for now, this should be rewritten + size_t data_size = sizeof("foobar"); + char *data = zalloc(data_size); + uint64_t key_len = 4; + memcpy(data, "foobar", data_size); + + memcpy(key, "test", 4); + + // List should be empty at start + rc = secvar_get(key, key_len, data, &data_size); + ASSERT(rc == OPAL_EMPTY); + ASSERT(list_length(&variable_bank) == 0); + + // Manually add variables, and check get_variable call + var->key_len = key_len; + memcpy(var->key, key, key_len); + var->data_size = data_size; + memcpy(var->data, data, data_size); + + node->var = var; + list_add_tail(&variable_bank, &node->link); + + ASSERT(list_length(&variable_bank) == 1); + + // TEST ONLY DATA + // Test actual variable get + size = data_size; + rc = secvar_get(key, key_len, temp, &size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(0 == memcmp("foobar", var->data, size)); + + // Test buffer too small + size = data_size / 2; + memset(temp, 0, 100); + rc = secvar_get(key, key_len, temp, &size); + ASSERT(rc == OPAL_PARTIAL); + + size = 0; + rc = secvar_get(key, key_len, temp, &size); + ASSERT(rc == OPAL_PARTIAL); + ASSERT(size == data_size); + + // Test size query w/ no data + size = 0; + rc = secvar_get(key, key_len, NULL, &size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(size == data_size); + + /**** Error/Bad param cases ****/ + // NULL key + rc = secvar_get(NULL, key_len, data, &data_size); + ASSERT(rc == OPAL_PARAMETER); + // zero key_len + rc = secvar_get(key, 0, data, &data_size); + ASSERT(rc == OPAL_PARAMETER); + // NULL size, valid data + rc = secvar_get(key, key_len, data, NULL); + ASSERT(rc == OPAL_PARAMETER); + + secvar_enabled = 0; + rc = secvar_get(key, key_len, data, &data_size); + ASSERT(rc == OPAL_UNSUPPORTED); + secvar_enabled = 1; + + secvar_ready = 0; + rc = secvar_get(key, key_len, data, &data_size); + ASSERT(rc == OPAL_RESOURCE); + secvar_ready = 1; + + list_del(&node->link); + + free(data); + free(temp); + + return 0; +} diff --git a/libstb/secvar/test/secvar-test-nextvar.c b/libstb/secvar/test/secvar-test-nextvar.c new file mode 100644 index 00000000..79859195 --- /dev/null +++ b/libstb/secvar/test/secvar-test-nextvar.c @@ -0,0 +1,132 @@ +/* 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. + */ +#include "secvar_api_test.c" + +const char *secvar_test_name = "nextvar"; + +int run_test(void) +{ + int64_t rc; + + struct secvar *tmpvar; + struct secvar_node *tmpnode; + + char key[1024] = {0}; + uint64_t key_len = 16; + + + // Load up the bank with some variables. + // If these fail, we have bigger issues. + ASSERT(list_length(&variable_bank) == 0); + tmpvar = zalloc(sizeof(struct secvar) + 6); + tmpnode = zalloc(sizeof(struct secvar_node)); + memcpy(tmpvar->key, "test1", 6); // ascii w/ null + tmpvar->key_len = 6; + tmpnode->var = tmpvar; + list_add_tail(&variable_bank, &tmpnode->link); + ASSERT(list_length(&variable_bank) == 1); + + tmpvar = zalloc(sizeof(struct secvar) + 5); + tmpnode = zalloc(sizeof(struct secvar_node)); + memcpy(tmpvar->key, "test2", 5); // ascii w/o null + tmpvar->key_len = 5; + tmpnode->var = tmpvar; + list_add_tail(&variable_bank, &tmpnode->link); + ASSERT(list_length(&variable_bank) == 2); + + tmpvar = zalloc(sizeof(struct secvar) + 5*2); + tmpnode = zalloc(sizeof(struct secvar_node)); + memcpy(tmpvar->key, L"test3", 5*2); // wide char "unicode" + tmpvar->key_len = 10; + tmpnode->var = tmpvar; + list_add_tail(&variable_bank, &tmpnode->link); + ASSERT(list_length(&variable_bank) == 3); + + // Test sequential nexts + // first item + memset(key, 0, sizeof(key)); + key_len = 0; + rc = secvar_get_next(key, &key_len, sizeof(key)); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(key_len == 6); + ASSERT(!memcmp(key, "test1", key_len)); + + // second item + rc = secvar_get_next(key, &key_len, sizeof(key)); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(key_len == 5); + ASSERT(!memcmp(key, "test2", key_len)); + + // last item + rc = secvar_get_next(key, &key_len, sizeof(key)); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(key_len == 5*2); + ASSERT(!memcmp(key, L"test3", key_len)); + + // end-of-list + rc = secvar_get_next(key, &key_len, sizeof(key)); + ASSERT(rc == OPAL_EMPTY); + + + memset(key, 0, sizeof(key)); + /*** Time for a break to test bad parameters ***/ + // null key + rc = secvar_get_next(NULL, &key_len, 1024); + ASSERT(rc == OPAL_PARAMETER); + // Size too small + key_len = 0; + rc = secvar_get_next(key, &key_len, 1); + ASSERT(rc == OPAL_PARTIAL); + ASSERT(key_len == 6); + // Supplied key length is larger than the buffer + key_len = 6; + rc = secvar_get_next(key, &key_len, 1); + ASSERT(rc == OPAL_PARAMETER); + + // NULL key_len pointer + rc = secvar_get_next(key, NULL, 1024); + ASSERT(rc == OPAL_PARAMETER); + + // NULL key_len pointer + key_len = ~0; + rc = secvar_get_next(key, &key_len, 1024); + ASSERT(rc == OPAL_PARAMETER); + + // zero key_len + key_len = 0; + rc = secvar_get_next(key, &key_len, 0); + ASSERT(rc == OPAL_PARAMETER); + + // Non-existing previous variable + key_len = 1024; + memcpy(key, L"foobar", 7*2); + rc = secvar_get_next(key, &key_len, 1024); + ASSERT(rc == OPAL_PARAMETER); + + secvar_enabled = 0; + rc = secvar_get_next(key, &key_len, 1024); + ASSERT(rc == OPAL_UNSUPPORTED); + secvar_enabled = 1; + + secvar_ready = 0; + rc = secvar_get_next(key, &key_len, 1024); + ASSERT(rc == OPAL_RESOURCE); + secvar_ready = 1; + + clear_bank_list(&variable_bank); + + return 0; +} diff --git a/libstb/secvar/test/secvar-test-void.c b/libstb/secvar/test/secvar-test-void.c new file mode 100644 index 00000000..45b8f449 --- /dev/null +++ b/libstb/secvar/test/secvar-test-void.c @@ -0,0 +1,24 @@ +/* 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. + */ +#include "secvar_api_test.c" + +const char *secvar_test_name = "void"; + +int run_test() +{ + // Do nothing... ensure testing framework is...working. + return 0; +} diff --git a/libstb/secvar/test/secvar_api_test.c b/libstb/secvar/test/secvar_api_test.c new file mode 100644 index 00000000..62137b01 --- /dev/null +++ b/libstb/secvar/test/secvar_api_test.c @@ -0,0 +1,91 @@ +/* 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. + */ +#include "secvar_common_test.c" + + +// Hack to include the code we actually want to test here... +#include "../secvar_api.c" +#include "../secvar_util.c" + +// Stuff from secvar_main that we need, but not enough to +// include that file +int secvar_enabled = 0; +int secvar_ready = 0; + + +/**** Helper wrappers, so the caller doesn't have to cast ****/ + +static int64_t secvar_get(const char *k_key, uint64_t k_key_len, void *k_data, uint64_t *k_data_size) +{ + return opal_secvar_get( k_key, + k_key_len, + k_data, + k_data_size); +} + +static int64_t secvar_get_next(char *k_key, uint64_t *k_key_len, uint64_t k_key_size) +{ + + return opal_secvar_get_next( k_key, + k_key_len, + k_key_size); +} + + + +static int64_t secvar_enqueue(const char *k_key, uint64_t k_key_len, void *k_data, uint64_t k_data_size) +{ + return opal_secvar_enqueue_update(k_key, + k_key_len, + k_data, + k_data_size); + +} + + + +// Entry point +// TODO: do some real argparsing +int main(int argc, char **argv) +{ + int ret; + + (void) secvar_get; + (void) secvar_get_next; + (void) secvar_enqueue; + (void) argc; + (void) argv; + + secvar_enabled = 1; + + list_head_init(&variable_bank); + list_head_init(&update_bank); + + secvar_ready = 1; + + printf("Running test '%s'...", secvar_test_name); + ret = run_test(); + if (ret) + printf(COLOR_RED "FAILED" COLOR_RESET "\n"); + else + printf(COLOR_GREEN "OK" COLOR_RESET "\n"); + + // Clean up for the test cases + clear_bank_list(&variable_bank); + clear_bank_list(&update_bank); + + return ret; +} diff --git a/libstb/secvar/test/secvar_common_test.c b/libstb/secvar/test/secvar_common_test.c new file mode 100644 index 00000000..e5bbffaf --- /dev/null +++ b/libstb/secvar/test/secvar_common_test.c @@ -0,0 +1,62 @@ +/* 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. + */ +#define SECBOOT_FILE "secboot.img" +#define SECBOOT_SIZE 128000 + +#include +#include +#include +#include +#include +#include + +// Force p9 +enum proc_gen proc_gen = proc_gen_p9; + +// Replace memalign with regular old malloc +#define memalign(a, b) malloc(b) +#define zalloc(a) calloc(1, a) + + + +struct list_head variable_bank; +struct list_head update_bank; + +struct secvar_storage_driver secvar_storage; + + +// For log file output instead of stdout +FILE *outfile; + +#ifndef NO_COLOR +#define COLOR_RED "\033[0;31m" +#define COLOR_GREEN "\033[1;32m" +#define COLOR_RESET "\033[0m" +#else +#define COLOR_RED "" +#define COLOR_GREEN "" +#define COLOR_RESET "" +#endif + +// Helper functions and macros to make test case writing easier + +// Semi-configurable assert, can use to jump to a clean up step on fail +#define ASSERT_POST(a,b) if(!(a)){fprintf(stdout, "Assert '%s' failed at %s:%d...", #a, __FILE__, __LINE__);b;} +#define ASSERT(a) ASSERT_POST(a, return 1) + +// To be defined by test case +int run_test(void); +const char *secvar_test_name;