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);