From patchwork Wed Sep 26 20:46:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616777 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D4E1814BD for ; Wed, 26 Sep 2018 20:46:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BBDC52B6CF for ; Wed, 26 Sep 2018 20:46:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AD6AF2B76E; Wed, 26 Sep 2018 20:46:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 29CB52B6CF for ; Wed, 26 Sep 2018 20:46:51 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id BA0BE211597FB; Wed, 26 Sep 2018 13:46:50 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.43; helo=mga05.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 53582211597F3 for ; Wed, 26 Sep 2018 13:46:50 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:46:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="73129337" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga007.fm.intel.com with ESMTP; 26 Sep 2018 13:46:49 -0700 Subject: [PATCH v10 01/12] nfit: add support for Intel DSM 1.7 commands From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:46:49 -0700 Message-ID: <153799480953.71621.8040473699184943509.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add command definition for security commands defined in Intel DSM specification v1.7. This includes "get security state", "set passphrase", "unlock unit", "freeze lock", "secure erase", "ovewrite", and "overwrite query". Since we are adding a lot of Intel definitions, moving the relevant bits to its own header. Also, we don't want those commands to be issued from user space through ioctls. Reason being some of the security commands require kernel involvement to flush all CPU caches that can't be done in userspace and the result can cause system crash. So blocking security commands in the ioctl path. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- drivers/acpi/nfit/core.c | 28 ++++++++++++++++++- drivers/acpi/nfit/intel.h | 67 +++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/nfit/nfit.h | 17 +++++++++++ drivers/nvdimm/bus.c | 2 + include/linux/libnvdimm.h | 2 + 5 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 drivers/acpi/nfit/intel.h diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index b072cfc5f20e..4f3b89dc9238 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -24,6 +24,7 @@ #include #include #include +#include "intel.h" #include "nfit.h" /* @@ -377,6 +378,14 @@ static u8 nfit_dsm_revid(unsigned family, unsigned func) [NVDIMM_INTEL_QUERY_FWUPDATE] = 2, [NVDIMM_INTEL_SET_THRESHOLD] = 2, [NVDIMM_INTEL_INJECT_ERROR] = 2, + [NVDIMM_INTEL_GET_SECURITY_STATE] = 2, + [NVDIMM_INTEL_SET_PASSPHRASE] = 2, + [NVDIMM_INTEL_DISABLE_PASSPHRASE] = 2, + [NVDIMM_INTEL_UNLOCK_UNIT] = 2, + [NVDIMM_INTEL_FREEZE_LOCK] = 2, + [NVDIMM_INTEL_SECURE_ERASE] = 2, + [NVDIMM_INTEL_OVERWRITE] = 2, + [NVDIMM_INTEL_QUERY_OVERWRITE] = 2, }, }; u8 id; @@ -3229,7 +3238,7 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) return 0; } -static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, +static int __acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd) { struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); @@ -3251,6 +3260,23 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, return 0; } +/* prevent security commands from being issued via ioctl */ +static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, + struct nvdimm *nvdimm, unsigned int cmd, void *buf) +{ + struct nd_cmd_pkg *call_pkg = buf; + unsigned int func; + + if (nvdimm && cmd == ND_CMD_CALL && + call_pkg->nd_family == NVDIMM_FAMILY_INTEL) { + func = call_pkg->nd_command; + if ((1 << func) & NVDIMM_INTEL_SECURITY_CMDMASK) + return -EOPNOTSUPP; + } + + return __acpi_nfit_clear_to_send(nd_desc, nvdimm, cmd); +} + int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags) { struct device *dev = acpi_desc->dev; diff --git a/drivers/acpi/nfit/intel.h b/drivers/acpi/nfit/intel.h new file mode 100644 index 000000000000..a6f8f4bc8ebb --- /dev/null +++ b/drivers/acpi/nfit/intel.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2018 Intel Corporation. All rights reserved. */ +/* + * Intel specific definitions for NVDIMM Firmware Interface Table - NFIT + */ +#ifndef _NFIT_INTEL_H_ +#define _NFIT_INTEL_H_ + +#ifdef CONFIG_X86 + +#define ND_INTEL_STATUS_SIZE 4 +#define ND_INTEL_PASSPHRASE_SIZE 32 + +#define ND_INTEL_STATUS_RETRY 5 +#define ND_INTEL_STATUS_NOT_READY 9 +#define ND_INTEL_STATUS_INVALID_STATE 10 +#define ND_INTEL_STATUS_INVALID_PASS 11 + +#define ND_INTEL_SEC_STATE_ENABLED 0x02 +#define ND_INTEL_SEC_STATE_LOCKED 0x04 +#define ND_INTEL_SEC_STATE_FROZEN 0x08 +#define ND_INTEL_SEC_STATE_PLIMIT 0x10 +#define ND_INTEL_SEC_STATE_UNSUPPORTED 0x20 + +struct nd_intel_get_security_state { + u32 status; + u32 reserved; + u8 state; + u8 reserved1[3]; +} __packed; + +struct nd_intel_set_passphrase { + u8 old_pass[ND_INTEL_PASSPHRASE_SIZE]; + u8 new_pass[ND_INTEL_PASSPHRASE_SIZE]; + u32 status; +} __packed; + +struct nd_intel_unlock_unit { + u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; + u32 status; +} __packed; + +struct nd_intel_disable_passphrase { + u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; + u32 status; +} __packed; + +struct nd_intel_freeze_lock { + u32 status; +} __packed; + +struct nd_intel_secure_erase { + u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; + u32 status; +} __packed; + +struct nd_intel_overwrite { + u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; + u32 status; +} __packed; + +struct nd_intel_query_overwrite { + u32 status; +} __packed; +#endif /* CONFIG_X86 */ + +#endif diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index d1274ea2d251..1c4e26dd6425 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -60,14 +60,29 @@ enum nvdimm_family_cmds { NVDIMM_INTEL_QUERY_FWUPDATE = 16, NVDIMM_INTEL_SET_THRESHOLD = 17, NVDIMM_INTEL_INJECT_ERROR = 18, + NVDIMM_INTEL_GET_SECURITY_STATE = 19, + NVDIMM_INTEL_SET_PASSPHRASE = 20, + NVDIMM_INTEL_DISABLE_PASSPHRASE = 21, + NVDIMM_INTEL_UNLOCK_UNIT = 22, + NVDIMM_INTEL_FREEZE_LOCK = 23, + NVDIMM_INTEL_SECURE_ERASE = 24, + NVDIMM_INTEL_OVERWRITE = 25, + NVDIMM_INTEL_QUERY_OVERWRITE = 26, }; +#define NVDIMM_INTEL_SECURITY_CMDMASK \ +(1 << NVDIMM_INTEL_GET_SECURITY_STATE | 1 << NVDIMM_INTEL_SET_PASSPHRASE \ +| 1 << NVDIMM_INTEL_DISABLE_PASSPHRASE | 1 << NVDIMM_INTEL_UNLOCK_UNIT \ +| 1 << NVDIMM_INTEL_FREEZE_LOCK | 1 << NVDIMM_INTEL_SECURE_ERASE \ +| 1 << NVDIMM_INTEL_OVERWRITE | 1 << NVDIMM_INTEL_QUERY_OVERWRITE) + #define NVDIMM_INTEL_CMDMASK \ (NVDIMM_STANDARD_CMDMASK | 1 << NVDIMM_INTEL_GET_MODES \ | 1 << NVDIMM_INTEL_GET_FWINFO | 1 << NVDIMM_INTEL_START_FWUPDATE \ | 1 << NVDIMM_INTEL_SEND_FWUPDATE | 1 << NVDIMM_INTEL_FINISH_FWUPDATE \ | 1 << NVDIMM_INTEL_QUERY_FWUPDATE | 1 << NVDIMM_INTEL_SET_THRESHOLD \ - | 1 << NVDIMM_INTEL_INJECT_ERROR | 1 << NVDIMM_INTEL_LATCH_SHUTDOWN) + | 1 << NVDIMM_INTEL_INJECT_ERROR | 1 << NVDIMM_INTEL_LATCH_SHUTDOWN \ + | NVDIMM_INTEL_SECURITY_CMDMASK) enum nfit_uuids { /* for simplicity alias the uuid index with the family id */ diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 8aae6dcc839f..51113eeb6076 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -894,7 +894,7 @@ static int nd_cmd_clear_to_send(struct nvdimm_bus *nvdimm_bus, /* ask the bus provider if it would like to block this request */ if (nd_desc->clear_to_send) { - int rc = nd_desc->clear_to_send(nd_desc, nvdimm, cmd); + int rc = nd_desc->clear_to_send(nd_desc, nvdimm, cmd, data); if (rc) return rc; diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 097072c5a852..472171af7f60 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -87,7 +87,7 @@ struct nvdimm_bus_descriptor { ndctl_fn ndctl; int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc); int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc, - struct nvdimm *nvdimm, unsigned int cmd); + struct nvdimm *nvdimm, unsigned int cmd, void *data); }; struct nd_cmd_desc { From patchwork Wed Sep 26 20:46:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616799 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 92F4A15A6 for ; Wed, 26 Sep 2018 20:50:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 80A812B7EE for ; Wed, 26 Sep 2018 20:50:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 751152B7F2; Wed, 26 Sep 2018 20:50:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 18ED22B7EE for ; Wed, 26 Sep 2018 20:50:23 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 0F204211597F6; Wed, 26 Sep 2018 13:50:23 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.20; helo=mga02.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 32E3921157426 for ; Wed, 26 Sep 2018 13:50:22 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:50:21 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="73944190" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga008.fm.intel.com with ESMTP; 26 Sep 2018 13:46:55 -0700 Subject: [PATCH v10 02/12] libnvdimm: create keyring to store security keys From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:46:55 -0700 Message-ID: <153799481498.71621.12671693381009469035.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Prepping the libnvdimm to support security management by adding a keyring in order to provide passphrase management through the kernel key management APIs. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- drivers/nvdimm/Kconfig | 1 + drivers/nvdimm/core.c | 7 ++++++- drivers/nvdimm/dimm_devs.c | 29 ++++++++++++++++++++++++++++- drivers/nvdimm/nd-core.h | 1 + include/linux/libnvdimm.h | 3 +++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 9d36473dc2a2..830a7a5342e1 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -3,6 +3,7 @@ menuconfig LIBNVDIMM depends on PHYS_ADDR_T_64BIT depends on HAS_IOMEM depends on BLK_DEV + depends on KEYS help Generic support for non-volatile memory devices including ACPI-6-NFIT defined resources. On platforms that define an diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index acce050856a8..3cd33d5c7cf0 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c @@ -437,9 +437,12 @@ static __init int libnvdimm_init(void) { int rc; - rc = nvdimm_bus_init(); + rc = nvdimm_devs_init(); if (rc) return rc; + rc = nvdimm_bus_init(); + if (rc) + goto err_bus; rc = nvdimm_init(); if (rc) goto err_dimm; @@ -454,6 +457,8 @@ static __init int libnvdimm_init(void) nvdimm_exit(); err_dimm: nvdimm_bus_exit(); + err_bus: + nvdimm_devs_exit(); return rc; } diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 863cabc35215..d058078a82aa 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -18,12 +18,15 @@ #include #include #include +#include +#include #include "nd-core.h" #include "label.h" #include "pmem.h" #include "nd.h" static DEFINE_IDA(dimm_ida); +static struct key *nvdimm_keyring; /* * Retrieve bus and dimm handle and return if this bus supports @@ -699,7 +702,31 @@ int nvdimm_bus_check_dimm_count(struct nvdimm_bus *nvdimm_bus, int dimm_count) } EXPORT_SYMBOL_GPL(nvdimm_bus_check_dimm_count); -void __exit nvdimm_devs_exit(void) +static int nvdimm_register_keyring(void) { + nvdimm_keyring = keyring_alloc(".nvdimm", + GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(), + (KEY_POS_ALL & ~KEY_POS_SETATTR), + KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); + if (IS_ERR(nvdimm_keyring)) + return PTR_ERR(nvdimm_keyring); + + return 0; +} + +static void nvdimm_unregister_keyring(void) +{ + key_put(nvdimm_keyring); + key_revoke(nvdimm_keyring); +} + +int __init nvdimm_devs_init(void) +{ + return nvdimm_register_keyring(); +} + +void nvdimm_devs_exit(void) +{ + nvdimm_unregister_keyring(); ida_destroy(&dimm_ida); } diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index ac68072fb8cd..711eaf055455 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -76,6 +76,7 @@ static inline bool is_memory(struct device *dev) struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev); int __init nvdimm_bus_init(void); void nvdimm_bus_exit(void); +int nvdimm_devs_init(void); void nvdimm_devs_exit(void); void nd_region_devs_exit(void); void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev); diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 472171af7f60..51084043915c 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -155,6 +155,9 @@ static inline struct nd_blk_region_desc *to_blk_region_desc( } +#define NVDIMM_PASSPHRASE_LEN 32 +#define NVDIMM_KEY_DESC_LEN 22 + void badrange_init(struct badrange *badrange); int badrange_add(struct badrange *badrange, u64 addr, u64 length); void badrange_forget(struct badrange *badrange, phys_addr_t start, From patchwork Wed Sep 26 20:47:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616781 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8005A15A6 for ; Wed, 26 Sep 2018 20:47:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 721022B6CF for ; Wed, 26 Sep 2018 20:47:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 663E42B76E; Wed, 26 Sep 2018 20:47:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id EEFE02B6CF for ; Wed, 26 Sep 2018 20:47:02 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id E5710211597FC; Wed, 26 Sep 2018 13:47:02 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.126; helo=mga18.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 60BE0211597F3 for ; Wed, 26 Sep 2018 13:47:01 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:47:01 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="83509422" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by FMSMGA003.fm.intel.com with ESMTP; 26 Sep 2018 13:47:00 -0700 Subject: [PATCH v10 03/12] nfit/libnvdimm: store dimm id as a member to struct nvdimm From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:00 -0700 Message-ID: <153799482041.71621.7125674719664645338.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP The generated dimm id is needed for the sysfs attribute as well as being used as the identifier/description for the security key. Since it's constant and should never change, store it as a member of struct nvdimm. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- drivers/acpi/nfit/core.c | 29 +++++++++++++++++------------ drivers/acpi/nfit/nfit.h | 3 +++ drivers/nvdimm/dimm_devs.c | 4 +++- drivers/nvdimm/nd-core.h | 1 + include/linux/libnvdimm.h | 2 +- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 4f3b89dc9238..94755a4b6327 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1572,18 +1572,10 @@ static DEVICE_ATTR_RO(flags); static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); - if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID) - return sprintf(buf, "%04x-%02x-%04x-%08x\n", - be16_to_cpu(dcr->vendor_id), - dcr->manufacturing_location, - be16_to_cpu(dcr->manufacturing_date), - be32_to_cpu(dcr->serial_number)); - else - return sprintf(buf, "%04x-%08x\n", - be16_to_cpu(dcr->vendor_id), - be32_to_cpu(dcr->serial_number)); + return sprintf(buf, "%s\n", nfit_mem->id); } static DEVICE_ATTR_RO(id); @@ -1712,10 +1704,23 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, const guid_t *guid; int i; int family = -1; + struct acpi_nfit_control_region *dcr = nfit_mem->dcr; /* nfit test assumes 1:1 relationship between commands and dsms */ nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en; nfit_mem->family = NVDIMM_FAMILY_INTEL; + + if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID) + sprintf(nfit_mem->id, "%04x-%02x-%04x-%08x", + be16_to_cpu(dcr->vendor_id), + dcr->manufacturing_location, + be16_to_cpu(dcr->manufacturing_date), + be32_to_cpu(dcr->serial_number)); + else + sprintf(nfit_mem->id, "%04x-%08x", + be16_to_cpu(dcr->vendor_id), + be32_to_cpu(dcr->serial_number)); + adev = to_acpi_dev(acpi_desc); if (!adev) return 0; @@ -1899,7 +1904,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem, acpi_nfit_dimm_attribute_groups, flags, cmd_mask, flush ? flush->hint_count : 0, - nfit_mem->flush_wpq); + nfit_mem->flush_wpq, &nfit_mem->id[0]); if (!nvdimm) return -ENOMEM; diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index 1c4e26dd6425..36c8695a3d27 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -174,6 +174,8 @@ struct nfit_memdev { struct acpi_nfit_memory_map memdev[0]; }; +#define NFIT_DIMM_ID_LEN 22 + /* assembled tables for a given dimm/memory-device */ struct nfit_mem { struct nvdimm *nvdimm; @@ -196,6 +198,7 @@ struct nfit_mem { int family; bool has_lsr; bool has_lsw; + char id[NFIT_DIMM_ID_LEN+1]; }; struct acpi_nfit_desc { diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index d058078a82aa..f414ed346215 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -401,7 +401,7 @@ EXPORT_SYMBOL_GPL(nvdimm_attribute_group); struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, const struct attribute_group **groups, unsigned long flags, unsigned long cmd_mask, int num_flush, - struct resource *flush_wpq) + struct resource *flush_wpq, const char *dimm_id) { struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL); struct device *dev; @@ -414,6 +414,8 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, kfree(nvdimm); return NULL; } + + nvdimm->dimm_id = dimm_id; nvdimm->provider_data = provider_data; nvdimm->flags = flags; nvdimm->cmd_mask = cmd_mask; diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 711eaf055455..8f377682a3ac 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -42,6 +42,7 @@ struct nvdimm { atomic_t busy; int id, num_flush; struct resource *flush_wpq; + const char *dimm_id; }; /** diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 51084043915c..3c1f18fdf76f 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -181,7 +181,7 @@ void *nvdimm_provider_data(struct nvdimm *nvdimm); struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, const struct attribute_group **groups, unsigned long flags, unsigned long cmd_mask, int num_flush, - struct resource *flush_wpq); + struct resource *flush_wpq, const char *dimm_id); const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, From patchwork Wed Sep 26 20:47:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616789 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C2FDC14BD for ; Wed, 26 Sep 2018 20:47:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B3F492B6CF for ; Wed, 26 Sep 2018 20:47:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A7E0A2B76E; Wed, 26 Sep 2018 20:47:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 62BA42B6CF for ; Wed, 26 Sep 2018 20:47:41 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 5A05E211597FF; Wed, 26 Sep 2018 13:47:41 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.120; helo=mga04.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 63C19211597FB for ; Wed, 26 Sep 2018 13:47:39 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:47:39 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="93993956" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga001.jf.intel.com with ESMTP; 26 Sep 2018 13:47:06 -0700 Subject: [PATCH v10 04/12] keys: export lookup_user_key to external users From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:06 -0700 Message-ID: <153799482596.71621.1758872314488292531.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Export lookup_user_key() symbol in order to allow nvdimm passphrase update to retrieve user injected keys. Signed-off-by: Dave Jiang Acked-by: David Howells --- include/linux/key.h | 3 +++ security/keys/internal.h | 2 -- security/keys/process_keys.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/key.h b/include/linux/key.h index e58ee10f6e58..7099985e35a9 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -346,6 +346,9 @@ static inline key_serial_t key_serial(const struct key *key) extern void key_set_timeout(struct key *, unsigned); +extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, + key_perm_t perm); + /* * The permissions required on a key that we're looking up. */ diff --git a/security/keys/internal.h b/security/keys/internal.h index 9f8208dc0e55..9968b21a76dd 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -158,8 +158,6 @@ extern struct key *request_key_and_link(struct key_type *type, extern bool lookup_user_key_possessed(const struct key *key, const struct key_match_data *match_data); -extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, - key_perm_t perm); #define KEY_LOOKUP_CREATE 0x01 #define KEY_LOOKUP_PARTIAL 0x02 #define KEY_LOOKUP_FOR_UNLINK 0x04 diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index d5b25e535d3a..ec4fd4531224 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -755,6 +755,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, put_cred(ctx.cred); goto try_again; } +EXPORT_SYMBOL(lookup_user_key); /* * Join the named keyring as the session keyring if possible else attempt to From patchwork Wed Sep 26 20:47:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616783 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1448714BD for ; Wed, 26 Sep 2018 20:47:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 00F5E2B6CF for ; Wed, 26 Sep 2018 20:47:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E7A372B76E; Wed, 26 Sep 2018 20:47:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 130692B6CF for ; Wed, 26 Sep 2018 20:47:16 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 09FDD21159801; Wed, 26 Sep 2018 13:47:16 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.93; helo=mga11.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 481C3211597F3 for ; Wed, 26 Sep 2018 13:47:14 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:47:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="77536599" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga006.jf.intel.com with ESMTP; 26 Sep 2018 13:47:12 -0700 Subject: [PATCH v10 05/12] nfit/libnvdimm: add unlock of nvdimm support for Intel DIMMs From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:12 -0700 Message-ID: <153799483234.71621.9184634994174583985.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support to allow query the security status of the Intel nvdimms and also unlock the dimm via the kernel key management APIs. The passphrase is expected to be pulled from userspace through keyutils. Moving the Intel related bits to its own source file as well. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- drivers/acpi/nfit/Makefile | 1 drivers/acpi/nfit/core.c | 3 + drivers/acpi/nfit/intel.c | 152 ++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/nfit/intel.h | 15 ++++ drivers/nvdimm/dimm.c | 7 ++ drivers/nvdimm/dimm_devs.c | 121 +++++++++++++++++++++++++++++++++++ drivers/nvdimm/nd-core.h | 4 + drivers/nvdimm/nd.h | 2 + include/linux/libnvdimm.h | 24 +++++++ include/uapi/linux/ndctl.h | 6 ++ 10 files changed, 332 insertions(+), 3 deletions(-) create mode 100644 drivers/acpi/nfit/intel.c diff --git a/drivers/acpi/nfit/Makefile b/drivers/acpi/nfit/Makefile index a407e769f103..443c7ef4e6a6 100644 --- a/drivers/acpi/nfit/Makefile +++ b/drivers/acpi/nfit/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_ACPI_NFIT) := nfit.o nfit-y := core.o +nfit-$(CONFIG_X86) += intel.o nfit-$(CONFIG_X86_MCE) += mce.o diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 94755a4b6327..e5f7c664a7c8 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1904,7 +1904,8 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem, acpi_nfit_dimm_attribute_groups, flags, cmd_mask, flush ? flush->hint_count : 0, - nfit_mem->flush_wpq, &nfit_mem->id[0]); + nfit_mem->flush_wpq, &nfit_mem->id[0], + acpi_nfit_get_security_ops(nfit_mem->family)); if (!nvdimm) return -ENOMEM; diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c new file mode 100644 index 000000000000..4bfc1c1da339 --- /dev/null +++ b/drivers/acpi/nfit/intel.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2018 Intel Corporation. All rights reserved. */ +/* + * Intel specific NFIT ops + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "intel.h" +#include "nfit.h" + +static int intel_dimm_security_unlock(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, const struct nvdimm_key_data *nkey) +{ + struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); + int cmd_rc, rc = 0; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_unlock_unit cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_UNLOCK_UNIT, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + }, + .cmd = { + .status = 0, + }, + }; + + if (!test_bit(NVDIMM_INTEL_UNLOCK_UNIT, &nfit_mem->dsm_mask)) + return -ENOTTY; + + memcpy(nd_cmd.cmd.passphrase, nkey->data, + sizeof(nd_cmd.cmd.passphrase)); + rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_CALL, &nd_cmd, + sizeof(nd_cmd), &cmd_rc); + if (rc < 0) + goto out; + if (cmd_rc < 0) { + rc = cmd_rc; + goto out; + } + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_INVALID_PASS: + rc = -EINVAL; + goto out; + case ND_INTEL_STATUS_INVALID_STATE: + default: + rc = -ENXIO; + goto out; + } + + /* + * TODO: define a cross arch wbinvd when/if NVDIMM_FAMILY_INTEL + * support arrives on another arch. + */ + /* DIMM unlocked, invalidate all CPU caches before we read it */ + wbinvd_on_all_cpus(); + + out: + return rc; +} + +static int intel_dimm_security_state(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, enum nvdimm_security_state *state) +{ + struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); + int cmd_rc, rc = 0; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_get_security_state cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_GET_SECURITY_STATE, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = 0, + .nd_size_out = + sizeof(struct nd_intel_get_security_state), + .nd_fw_size = + sizeof(struct nd_intel_get_security_state), + }, + .cmd = { + .status = 0, + .state = 0, + }, + }; + + if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask)) { + *state = NVDIMM_SECURITY_UNSUPPORTED; + return 0; + } + + *state = NVDIMM_SECURITY_DISABLED; + rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_CALL, &nd_cmd, + sizeof(nd_cmd), &cmd_rc); + if (rc < 0) + goto out; + if (cmd_rc < 0) { + rc = cmd_rc; + goto out; + } + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_RETRY: + rc = -EAGAIN; + goto out; + case ND_INTEL_STATUS_NOT_READY: + default: + rc = -ENXIO; + goto out; + } + + /* check and see if security is enabled and locked */ + if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) + *state = NVDIMM_SECURITY_UNSUPPORTED; + else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) { + if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED) + *state = NVDIMM_SECURITY_LOCKED; + else + *state = NVDIMM_SECURITY_UNLOCKED; + } else + *state = NVDIMM_SECURITY_DISABLED; + + out: + if (rc < 0) + *state = NVDIMM_SECURITY_INVALID; + return rc; +} + +const struct nvdimm_security_ops intel_security_ops = { + .state = intel_dimm_security_state, + .unlock = intel_dimm_security_unlock, +}; diff --git a/drivers/acpi/nfit/intel.h b/drivers/acpi/nfit/intel.h index a6f8f4bc8ebb..f9ac718776ca 100644 --- a/drivers/acpi/nfit/intel.h +++ b/drivers/acpi/nfit/intel.h @@ -8,6 +8,8 @@ #ifdef CONFIG_X86 +extern const struct nvdimm_security_ops intel_security_ops; + #define ND_INTEL_STATUS_SIZE 4 #define ND_INTEL_PASSPHRASE_SIZE 32 @@ -64,4 +66,17 @@ struct nd_intel_query_overwrite { } __packed; #endif /* CONFIG_X86 */ +static inline const struct nvdimm_security_ops * +acpi_nfit_get_security_ops(int family) +{ + switch (family) { +#ifdef CONFIG_X86 + case NVDIMM_FAMILY_INTEL: + return &intel_security_ops; +#endif + default: + return NULL; + } +} + #endif diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 6c8fb7590838..b6381ddbd6c1 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -51,6 +51,13 @@ static int nvdimm_probe(struct device *dev) get_device(dev); kref_init(&ndd->kref); + nvdimm_security_get_state(dev); + + /* unlock DIMM here before touch label */ + rc = nvdimm_security_unlock_dimm(dev); + if (rc < 0) + dev_warn(dev, "failed to unlock dimm %s\n", dev_name(dev)); + /* * EACCES failures reading the namespace label-area-properties * are interpreted as the DIMM capacity being locked but the diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index f414ed346215..e7f4c8a2b242 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "nd-core.h" #include "label.h" #include "pmem.h" @@ -28,6 +29,122 @@ static DEFINE_IDA(dimm_ida); static struct key *nvdimm_keyring; +/* + * Find key in kernel keyring + */ +static struct key *nvdimm_get_key(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + + if (!nvdimm->key) + return NULL; + + if (key_validate(nvdimm->key) < 0) + return NULL; + + key_get(nvdimm->key); + + dev_dbg(dev, "%s: key found: %d\n", __func__, + key_serial(nvdimm->key)); + return nvdimm->key; +} + +/* + * Retrieve kernel key for DIMM and request from user space if necessary. + */ +static struct key *nvdimm_request_key(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct key *key = NULL; + char desc[NVDIMM_KEY_DESC_LEN + sizeof(NVDIMM_PREFIX)]; + + sprintf(desc, "%s%s", NVDIMM_PREFIX, nvdimm->dimm_id); + key = request_key(&key_type_logon, desc, desc); + if (IS_ERR(key)) + key = NULL; + + return key; +} + +static int nvdimm_check_key_len(unsigned short len) +{ + if (len == NVDIMM_PASSPHRASE_LEN) + return 0; + + return -EINVAL; +} + +int nvdimm_security_get_state(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + + if (!nvdimm->security_ops) + return 0; + + return nvdimm->security_ops->state(nvdimm_bus, nvdimm, + &nvdimm->state); +} + +int nvdimm_security_unlock_dimm(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key; + struct user_key_payload *payload; + int rc; + bool cached_key = false; + + if (!nvdimm->security_ops) + return 0; + + if (nvdimm->state == NVDIMM_SECURITY_UNLOCKED || + nvdimm->state == NVDIMM_SECURITY_UNSUPPORTED || + nvdimm->state == NVDIMM_SECURITY_DISABLED) + return 0; + + key = nvdimm_get_key(dev); + if (!key) + key = nvdimm_request_key(dev); + else + cached_key = true; + if (!key) + return -ENXIO; + + if (!cached_key) { + rc = nvdimm_check_key_len(key->datalen); + if (rc < 0) { + key_put(key); + return rc; + } + } + + dev_dbg(dev, "%s: key: %#x\n", __func__, key_serial(key)); + down_read(&key->sem); + payload = key->payload.data[0]; + rc = nvdimm->security_ops->unlock(nvdimm_bus, nvdimm, + (const void *)payload->data); + up_read(&key->sem); + + if (rc == 0) { + if (!cached_key) { + key_link(nvdimm_keyring, key); + nvdimm->key = key; + } + nvdimm->state = NVDIMM_SECURITY_UNLOCKED; + dev_dbg(dev, "DIMM %s unlocked\n", dev_name(dev)); + } else { + key_unlink(nvdimm_keyring, key); + key_invalidate(key); + nvdimm->key = NULL; + dev_warn(dev, "Failed to unlock dimm: %s\n", dev_name(dev)); + } + + key_put(key); + nvdimm_security_get_state(dev); + return rc; +} + /* * Retrieve bus and dimm handle and return if this bus supports * get_config_data commands @@ -401,7 +518,8 @@ EXPORT_SYMBOL_GPL(nvdimm_attribute_group); struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, const struct attribute_group **groups, unsigned long flags, unsigned long cmd_mask, int num_flush, - struct resource *flush_wpq, const char *dimm_id) + struct resource *flush_wpq, const char *dimm_id, + const struct nvdimm_security_ops *sec_ops) { struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL); struct device *dev; @@ -416,6 +534,7 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, } nvdimm->dimm_id = dimm_id; + nvdimm->security_ops = sec_ops; nvdimm->provider_data = provider_data; nvdimm->flags = flags; nvdimm->cmd_mask = cmd_mask; diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 8f377682a3ac..3833b725b4f9 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -18,6 +18,7 @@ #include #include #include +#include extern struct list_head nvdimm_bus_list; extern struct mutex nvdimm_bus_list_mutex; @@ -43,6 +44,9 @@ struct nvdimm { int id, num_flush; struct resource *flush_wpq; const char *dimm_id; + const struct nvdimm_security_ops *security_ops; + enum nvdimm_security_state state; + struct key *key; }; /** diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 98317e7ce5b5..e6490b191076 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -423,4 +423,6 @@ static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector, resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk); const u8 *nd_dev_to_uuid(struct device *dev); bool pmem_should_map_pages(struct device *dev); +int nvdimm_security_unlock_dimm(struct device *dev); +int nvdimm_security_get_state(struct device *dev); #endif /* __ND_H__ */ diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 3c1f18fdf76f..257ff2637ce1 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -155,9 +155,30 @@ static inline struct nd_blk_region_desc *to_blk_region_desc( } +enum nvdimm_security_state { + NVDIMM_SECURITY_INVALID = 0, + NVDIMM_SECURITY_DISABLED, + NVDIMM_SECURITY_UNLOCKED, + NVDIMM_SECURITY_LOCKED, + NVDIMM_SECURITY_UNSUPPORTED, +}; + #define NVDIMM_PASSPHRASE_LEN 32 #define NVDIMM_KEY_DESC_LEN 22 +struct nvdimm_key_data { + u8 data[NVDIMM_PASSPHRASE_LEN]; +}; + +struct nvdimm_security_ops { + int (*state)(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, + enum nvdimm_security_state *state); + int (*unlock)(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, + const struct nvdimm_key_data *nkey); +}; + void badrange_init(struct badrange *badrange); int badrange_add(struct badrange *badrange, u64 addr, u64 length); void badrange_forget(struct badrange *badrange, phys_addr_t start, @@ -181,7 +202,8 @@ void *nvdimm_provider_data(struct nvdimm *nvdimm); struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, const struct attribute_group **groups, unsigned long flags, unsigned long cmd_mask, int num_flush, - struct resource *flush_wpq, const char *dimm_id); + struct resource *flush_wpq, const char *dimm_id, + const struct nvdimm_security_ops *sec_ops); const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index 7e27070b9440..dd48a2b5aa3d 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -257,4 +257,10 @@ struct nd_cmd_pkg { #define ND_IOCTL_CALL _IOWR(ND_IOCTL, ND_CMD_CALL,\ struct nd_cmd_pkg) +/* + * The key payload description for nvdimm logon key is: + * + */ +static const char NVDIMM_PREFIX[] = "nvdimm:"; + #endif /* __NDCTL_H__ */ From patchwork Wed Sep 26 20:47:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616797 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B33C515A6 for ; Wed, 26 Sep 2018 20:49:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A2E042B76F for ; Wed, 26 Sep 2018 20:49:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 970022B7CC; Wed, 26 Sep 2018 20:49:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E22CD2B76F for ; Wed, 26 Sep 2018 20:49:10 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id D8880211597F6; Wed, 26 Sep 2018 13:49:10 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.43; helo=mga05.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 8759421157426 for ; Wed, 26 Sep 2018 13:49:09 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:49:09 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="76461568" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga008.jf.intel.com with ESMTP; 26 Sep 2018 13:47:18 -0700 Subject: [PATCH v10 06/12] nfit/libnvdimm: add set passphrase support for Intel nvdimms From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:18 -0700 Message-ID: <153799483810.71621.11639561453544624699.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support for setting and/or updating passphrase on the Intel nvdimms. The passphrase is pulled from userspace through the kernel key management. We trigger the update via writing "update " to the sysfs attribute "security". If no exists (for enabling security) then a 0 should be used. The state of the security can also be read via the "security" attribute. libnvdimm will generically support the key_change API call. Signed-off-by: Dave Jiang --- drivers/acpi/nfit/intel.c | 68 ++++++++++++ drivers/nvdimm/dimm_devs.c | 248 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/libnvdimm.h | 5 + 3 files changed, 321 insertions(+) diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index 4bfc1c1da339..314eae7e02d7 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -18,6 +18,73 @@ #include "intel.h" #include "nfit.h" +/* + * The update passphrase takes the old passphrase and the new passphrase + * and send those to the nvdimm. The nvdimm will verify the old + * passphrase and then update it with the new passphrase if pending + * verification. The function will pass in a zeroed passphrase field + * if the old passphrase is NULL. This typically happens when we are + * enabling security from the disabled state. + */ +static int intel_dimm_security_update_passphrase( + struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, + const struct nvdimm_key_data *old_data, + const struct nvdimm_key_data *new_data) +{ + struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); + int cmd_rc, rc = 0; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_set_passphrase cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_SET_PASSPHRASE, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = ND_INTEL_PASSPHRASE_SIZE * 2, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + }, + .cmd = { + .status = 0, + }, + }; + + if (!test_bit(NVDIMM_INTEL_SET_PASSPHRASE, &nfit_mem->dsm_mask)) + return -ENOTTY; + + if (old_data) + memcpy(nd_cmd.cmd.old_pass, old_data->data, + sizeof(nd_cmd.cmd.old_pass)); + else + memset(nd_cmd.cmd.old_pass, 0, sizeof(nd_cmd.cmd.old_pass)); + memcpy(nd_cmd.cmd.new_pass, new_data->data, + sizeof(nd_cmd.cmd.new_pass)); + rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_CALL, &nd_cmd, + sizeof(nd_cmd), &cmd_rc); + if (rc < 0) + goto out; + if (cmd_rc < 0) { + rc = cmd_rc; + goto out; + } + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_INVALID_PASS: + rc = -EINVAL; + goto out; + case ND_INTEL_STATUS_INVALID_STATE: + default: + rc = -ENXIO; + goto out; + } + + out: + return rc; +} + static int intel_dimm_security_unlock(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, const struct nvdimm_key_data *nkey) { @@ -149,4 +216,5 @@ static int intel_dimm_security_state(struct nvdimm_bus *nvdimm_bus, const struct nvdimm_security_ops intel_security_ops = { .state = intel_dimm_security_state, .unlock = intel_dimm_security_unlock, + .change_key = intel_dimm_security_update_passphrase, }; diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index e7f4c8a2b242..becbe670b572 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "nd-core.h" #include "label.h" @@ -49,6 +50,58 @@ static struct key *nvdimm_get_key(struct device *dev) return nvdimm->key; } +/* + * Replacing the user key with a kernel key. The function expects that + * we hold the sem for the key passed in. The function will release that + * sem when done process. We will also hold the sem for the valid new key + * returned. + */ +static struct key *nvdimm_replace_key(struct key *key) +{ + struct key *new_key; + struct user_key_payload *payload; + int rc; + + new_key = key_alloc(&key_type_logon, key->description, + GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(), + KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL); + if (IS_ERR(new_key)) + return NULL; + + payload = key->payload.data[0]; + rc = key_instantiate_and_link(new_key, payload->data, + payload->datalen, NULL, NULL); + up_read(&key->sem); + if (rc < 0) { + key_put(new_key); + return NULL; + } + + key_put(key); + + down_read(&new_key->sem); + return new_key; +} + +/* + * Retrieve user injected key + */ +static struct key *nvdimm_lookup_user_key(struct device *dev, + key_serial_t id) +{ + key_ref_t keyref; + struct key *key; + + keyref = lookup_user_key(id, 0, 0); + if (IS_ERR(keyref)) + return NULL; + + key = key_ref_to_ptr(keyref); + dev_dbg(dev, "%s: key found: %d\n", __func__, key_serial(key)); + + return key; +} + /* * Retrieve kernel key for DIMM and request from user space if necessary. */ @@ -66,6 +119,49 @@ static struct key *nvdimm_request_key(struct device *dev) return key; } +struct key *nvdimm_get_and_verify_key(struct device *dev, + unsigned int user_key_id) +{ + struct key *user_key, *key; + struct user_key_payload *upayload, *payload; + int rc = 0; + + key = nvdimm_get_key(dev); + /* we don't have a cached key */ + if (!key) { + dev_dbg(dev, "No cached kernel key\n"); + return NULL; + } + + user_key = nvdimm_lookup_user_key(dev, user_key_id); + if (!user_key) { + dev_dbg(dev, "Old user key lookup failed\n"); + rc = -EINVAL; + goto out; + } + + down_read(&key->sem); + payload = key->payload.data[0]; + down_read(&user_key->sem); + upayload = user_key->payload.data[0]; + + if (memcmp(payload->data, upayload->data, + NVDIMM_PASSPHRASE_LEN) != 0) { + rc = -EINVAL; + dev_warn(dev, "Supplied old user key fails check.\n"); + } + + up_read(&user_key->sem); + key_put(user_key); + up_read(&key->sem); + +out: + key_put(key); + if (rc < 0) + key = ERR_PTR(rc); + return key; +} + static int nvdimm_check_key_len(unsigned short len) { if (len == NVDIMM_PASSPHRASE_LEN) @@ -145,6 +241,103 @@ int nvdimm_security_unlock_dimm(struct device *dev) return rc; } +static int nvdimm_security_change_key(struct device *dev, + unsigned int old_keyid, unsigned int new_keyid) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key, *old_key; + int rc; + void *old_data = NULL, *new_data; + bool update = false; + struct user_key_payload *payload, *old_payload; + + if (!nvdimm->security_ops) + return -EOPNOTSUPP; + + if (nvdimm->state == NVDIMM_SECURITY_FROZEN) + return -EBUSY; + + /* look for a key from keyring if exists and remove */ + old_key = nvdimm_get_and_verify_key(dev, old_keyid); + if (IS_ERR(old_key)) + return PTR_ERR(old_key); + if (old_key) { + dev_dbg(dev, "%s: old key: %#x\n", + __func__, key_serial(old_key)); + update = true; + } + + /* request new key from userspace */ + key = nvdimm_lookup_user_key(dev, new_keyid); + if (!key) { + dev_dbg(dev, "%s: failed to acquire new key\n", __func__); + rc = -ENXIO; + goto out; + } + + dev_dbg(dev, "%s: new key: %#x\n", __func__, key_serial(key)); + + down_read(&key->sem); + payload = key->payload.data[0]; + rc = nvdimm_check_key_len(payload->datalen); + if (rc < 0) { + up_read(&key->sem); + goto out; + } + + /* we need to check description as well */ + + if (!update) + key = nvdimm_replace_key(key); + + /* + * We don't need to release key->sem here because nvdimm_repalce_key + * will. + */ + if (!key) + goto out; + + payload = key->payload.data[0]; + + if (old_key) { + down_read(&old_key->sem); + old_payload = old_key->payload.data[0]; + old_data = old_payload->data; + } + + new_data = payload->data; + + rc = nvdimm->security_ops->change_key(nvdimm_bus, nvdimm, old_data, + new_data); + /* copy new payload to old payload */ + if (rc == 0) { + if (update) + key_update(make_key_ref(old_key, 1), new_data, + old_key->datalen); + } else + dev_warn(dev, "key update failed\n"); + if (old_key) + up_read(&old_key->sem); + up_read(&key->sem); + + if (!update) { + if (rc == 0) { + key_link(nvdimm_keyring, key); + nvdimm->key = key; + } else + key_invalidate(key); + } + nvdimm_security_get_state(dev); + + out: + if (old_key) + key_put(old_key); + if (key) + key_put(key); + return rc; +} + /* * Retrieve bus and dimm handle and return if this bus supports * get_config_data commands @@ -502,11 +695,66 @@ static ssize_t available_slots_show(struct device *dev, } static DEVICE_ATTR_RO(available_slots); +static ssize_t security_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + + switch (nvdimm->state) { + case NVDIMM_SECURITY_DISABLED: + return sprintf(buf, "disabled\n"); + case NVDIMM_SECURITY_UNLOCKED: + return sprintf(buf, "unlocked\n"); + case NVDIMM_SECURITY_LOCKED: + return sprintf(buf, "locked\n"); + case NVDIMM_SECURITY_FROZEN: + return sprintf(buf, "frozen\n"); + case NVDIMM_SECURITY_UNSUPPORTED: + default: + return sprintf(buf, "unsupported\n"); + } + + return -ENOTTY; +} + +#define SEC_CMD_SIZE 128 +static ssize_t security_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) + +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + ssize_t rc = -EINVAL; + unsigned int new_key = 0, old_key = 0; + char cmd[SEC_CMD_SIZE]; + + if (len > SEC_CMD_SIZE) + return -EINVAL; + + wait_nvdimm_bus_probe_idle(&nvdimm_bus->dev); + if (atomic_read(&nvdimm->busy)) + return -EBUSY; + + sscanf(buf, "%s %u %u", cmd, &old_key, &new_key); + if (sysfs_streq(cmd, "update")) { + dev_dbg(dev, "update %u %u\n", old_key, new_key); + rc = nvdimm_security_change_key(dev, old_key, new_key); + } else + return -EINVAL; + + if (rc == 0) + rc = len; + + return rc; +} +static DEVICE_ATTR_RW(security); + static struct attribute *nvdimm_attributes[] = { &dev_attr_state.attr, &dev_attr_flags.attr, &dev_attr_commands.attr, &dev_attr_available_slots.attr, + &dev_attr_security.attr, NULL, }; diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 257ff2637ce1..bd6a413164ee 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -160,6 +160,7 @@ enum nvdimm_security_state { NVDIMM_SECURITY_DISABLED, NVDIMM_SECURITY_UNLOCKED, NVDIMM_SECURITY_LOCKED, + NVDIMM_SECURITY_FROZEN, NVDIMM_SECURITY_UNSUPPORTED, }; @@ -177,6 +178,10 @@ struct nvdimm_security_ops { int (*unlock)(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, const struct nvdimm_key_data *nkey); + int (*change_key)(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, + const struct nvdimm_key_data *old_data, + const struct nvdimm_key_data *new_data); }; void badrange_init(struct badrange *badrange); From patchwork Wed Sep 26 20:47:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616785 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CA72B15A6 for ; Wed, 26 Sep 2018 20:47:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BB8082B6CF for ; Wed, 26 Sep 2018 20:47:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AF45F2B76F; Wed, 26 Sep 2018 20:47:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4491F2B6CF for ; Wed, 26 Sep 2018 20:47:26 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 2ACB5211597F6; Wed, 26 Sep 2018 13:47:26 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.24; helo=mga09.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id BF89021157426 for ; Wed, 26 Sep 2018 13:47:24 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:47:24 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="76178607" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga007.jf.intel.com with ESMTP; 26 Sep 2018 13:47:24 -0700 Subject: [PATCH v10 07/12] nfit/libnvdimm: add disable passphrase support to Intel nvdimm. From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:23 -0700 Message-ID: <153799484384.71621.15520725169719507042.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support to disable passphrase (security) for the Intel nvdimm. The passphrase used for disabling is pulled from userspace via the kernel key management. The action is triggered by writing "disable " to the sysfs attribute "security". libnvdimm will support the generic disable API call. The kernel will verify the passphrase of the user key against the cached kernel key. If no kernel key exists, then the user key will be tried for the op. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- drivers/acpi/nfit/intel.c | 53 ++++++++++++++++++++++++++++++++++++++++++ drivers/nvdimm/dimm_devs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/libnvdimm.h | 3 ++ 3 files changed, 111 insertions(+) diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index 314eae7e02d7..21d30222371f 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -18,6 +18,58 @@ #include "intel.h" #include "nfit.h" +static int intel_dimm_security_disable(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, const struct nvdimm_key_data *nkey) +{ + struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); + int cmd_rc, rc = 0; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_disable_passphrase cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + }, + .cmd = { + .status = 0, + }, + }; + + if (!test_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, &nfit_mem->dsm_mask)) + return -ENOTTY; + + memcpy(nd_cmd.cmd.passphrase, nkey->data, + sizeof(nd_cmd.cmd.passphrase)); + rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_CALL, &nd_cmd, + sizeof(nd_cmd), &cmd_rc); + if (rc < 0) + goto out; + if (cmd_rc < 0) { + rc = cmd_rc; + goto out; + } + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_INVALID_PASS: + rc = -EINVAL; + goto out; + case ND_INTEL_STATUS_INVALID_STATE: + default: + rc = -ENXIO; + goto out; + } + + out: + return rc; +} + /* * The update passphrase takes the old passphrase and the new passphrase * and send those to the nvdimm. The nvdimm will verify the old @@ -217,4 +269,5 @@ const struct nvdimm_security_ops intel_security_ops = { .state = intel_dimm_security_state, .unlock = intel_dimm_security_unlock, .change_key = intel_dimm_security_update_passphrase, + .disable = intel_dimm_security_disable, }; diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index becbe670b572..f2d627201f5e 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -160,6 +160,7 @@ struct key *nvdimm_get_and_verify_key(struct device *dev, if (rc < 0) key = ERR_PTR(rc); return key; + } static int nvdimm_check_key_len(unsigned short len) @@ -182,6 +183,57 @@ int nvdimm_security_get_state(struct device *dev) &nvdimm->state); } +static int nvdimm_security_disable(struct device *dev, unsigned int keyid) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key; + int rc; + struct user_key_payload *payload; + bool is_userkey = false; + + if (!nvdimm->security_ops) + return -EOPNOTSUPP; + + if (nvdimm->state == NVDIMM_SECURITY_UNSUPPORTED) + return -EOPNOTSUPP; + + /* look for a key from keyring if exists and remove */ + key = nvdimm_get_and_verify_key(dev, old_keyid); + if (IS_ERR(old_key)) + return PTR_ERR(old_key); + if (!key) { + /* get old user key */ + key = nvdimm_lookup_user_key(dev, keyid); + if (!key) + return -ENOKEY; + is_userkey = true; + } + + down_read(&key->sem); + payload = key->payload.data[0]; + + rc = nvdimm->security_ops->disable(nvdimm_bus, nvdimm, + (void *)payload->data); + up_read(&key->sem); + if (rc < 0) { + dev_warn(dev, "unlock failed\n"); + goto out; + } + + /* If we succeed then remove the key */ + if (!is_userkey) { + key_unlink(nvdimm_keyring, key); + key_invalidate(key); + nvdimm->key = NULL; + } + + out: + key_put(key); + nvdimm_security_get_state(dev); + return rc; +} + int nvdimm_security_unlock_dimm(struct device *dev) { struct nvdimm *nvdimm = to_nvdimm(dev); @@ -739,6 +791,9 @@ static ssize_t security_store(struct device *dev, if (sysfs_streq(cmd, "update")) { dev_dbg(dev, "update %u %u\n", old_key, new_key); rc = nvdimm_security_change_key(dev, old_key, new_key); + } else if (sysfs_streq(cmd, "disable")) { + dev_dbg(dev, "disable %u\n", old_key); + rc = nvdimm_security_disable(dev, old_key); } else return -EINVAL; diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index bd6a413164ee..c60ab4b238f3 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -182,6 +182,9 @@ struct nvdimm_security_ops { struct nvdimm *nvdimm, const struct nvdimm_key_data *old_data, const struct nvdimm_key_data *new_data); + int (*disable)(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, + const struct nvdimm_key_data *nkey); }; void badrange_init(struct badrange *badrange); From patchwork Wed Sep 26 20:47:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616791 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 04E1315A6 for ; Wed, 26 Sep 2018 20:47:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E8EF02B6CF for ; Wed, 26 Sep 2018 20:47:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DCF6F2B76E; Wed, 26 Sep 2018 20:47:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 7AB202B6CF for ; Wed, 26 Sep 2018 20:47:42 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 713CE21159803; Wed, 26 Sep 2018 13:47:42 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.43; helo=mga05.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 11138211597F3 for ; Wed, 26 Sep 2018 13:47:41 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:47:40 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="236194174" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga004.jf.intel.com with ESMTP; 26 Sep 2018 13:47:29 -0700 Subject: [PATCH v10 08/12] nfit/libnvdimm: add freeze security support to Intel nvdimm From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:29 -0700 Message-ID: <153799484954.71621.11164359745920758602.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support for freeze security on Intel nvdimm. This locks out any changes to security for the DIMM unless a reboot is done. This is triggered by writing "freeze" to the "security" sysfs attribute. libnvdimm will support the generic freeze_lock API call. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- drivers/acpi/nfit/intel.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ drivers/nvdimm/dimm_devs.c | 29 ++++++++++++++++++++++--- include/linux/libnvdimm.h | 2 ++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index 21d30222371f..ba886f1f5399 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -18,6 +18,53 @@ #include "intel.h" #include "nfit.h" +static int intel_dimm_security_freeze_lock(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm) +{ + struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); + int cmd_rc, rc = 0; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_freeze_lock cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_FREEZE_LOCK, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = 0, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + }, + .cmd = { + .status = 0, + }, + }; + + if (!test_bit(NVDIMM_INTEL_FREEZE_LOCK, &nfit_mem->dsm_mask)) + return -ENOTTY; + + rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_CALL, &nd_cmd, + sizeof(nd_cmd), &cmd_rc); + if (rc < 0) + goto out; + if (cmd_rc < 0) { + rc = cmd_rc; + goto out; + } + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_INVALID_STATE: + default: + rc = -ENXIO; + goto out; + } + + out: + return rc; +} + static int intel_dimm_security_disable(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, const struct nvdimm_key_data *nkey) { @@ -254,6 +301,9 @@ static int intel_dimm_security_state(struct nvdimm_bus *nvdimm_bus, else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) { if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED) *state = NVDIMM_SECURITY_LOCKED; + else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN || + nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT) + *state = NVDIMM_SECURITY_FROZEN; else *state = NVDIMM_SECURITY_UNLOCKED; } else @@ -270,4 +320,5 @@ const struct nvdimm_security_ops intel_security_ops = { .unlock = intel_dimm_security_unlock, .change_key = intel_dimm_security_update_passphrase, .disable = intel_dimm_security_disable, + .freeze_lock = intel_dimm_security_freeze_lock, }; diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index f2d627201f5e..75a3f841a7ce 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -183,6 +183,26 @@ int nvdimm_security_get_state(struct device *dev) &nvdimm->state); } +static int nvdimm_security_freeze_lock(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + int rc; + + if (!nvdimm->security_ops) + return -EOPNOTSUPP; + + if (nvdimm->state == NVDIMM_SECURITY_UNSUPPORTED) + return -EOPNOTSUPP; + + rc = nvdimm->security_ops->freeze_lock(nvdimm_bus, nvdimm); + if (rc < 0) + return rc; + + nvdimm_security_get_state(dev); + return 0; +} + static int nvdimm_security_disable(struct device *dev, unsigned int keyid) { struct nvdimm *nvdimm = to_nvdimm(dev); @@ -199,9 +219,9 @@ static int nvdimm_security_disable(struct device *dev, unsigned int keyid) return -EOPNOTSUPP; /* look for a key from keyring if exists and remove */ - key = nvdimm_get_and_verify_key(dev, old_keyid); - if (IS_ERR(old_key)) - return PTR_ERR(old_key); + key = nvdimm_get_and_verify_key(dev, keyid); + if (IS_ERR(key)) + return PTR_ERR(key); if (!key) { /* get old user key */ key = nvdimm_lookup_user_key(dev, keyid); @@ -794,6 +814,9 @@ static ssize_t security_store(struct device *dev, } else if (sysfs_streq(cmd, "disable")) { dev_dbg(dev, "disable %u\n", old_key); rc = nvdimm_security_disable(dev, old_key); + } else if (sysfs_streq(buf, "freeze")) { + dev_dbg(dev, "freeze\n"); + rc = nvdimm_security_freeze_lock(dev); } else return -EINVAL; diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index c60ab4b238f3..bcab42caa948 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -185,6 +185,8 @@ struct nvdimm_security_ops { int (*disable)(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, const struct nvdimm_key_data *nkey); + int (*freeze_lock)(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm); }; void badrange_init(struct badrange *badrange); From patchwork Wed Sep 26 20:47:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616787 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D516815A6 for ; Wed, 26 Sep 2018 20:47:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C541A2B6CF for ; Wed, 26 Sep 2018 20:47:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B91952B76E; Wed, 26 Sep 2018 20:47:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4A8132B6CF for ; Wed, 26 Sep 2018 20:47:37 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 41400211597FE; Wed, 26 Sep 2018 13:47:37 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.31; helo=mga06.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 1866D21157426 for ; Wed, 26 Sep 2018 13:47:36 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:47:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="266969952" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga006.fm.intel.com with ESMTP; 26 Sep 2018 13:47:35 -0700 Subject: [PATCH v10 09/12] nfit/libnvdimm: add support for issue secure erase DSM to Intel nvdimm From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:35 -0700 Message-ID: <153799485526.71621.18168202531797718675.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support to issue a secure erase DSM to the Intel nvdimm. The required passphrase is acquired from userspace through the kernel key management. To trigger the action, "erase " is written to the "security" sysfs attribute. libnvdimm will support the erase generic API call. The user key provided will be verified against the cached kernel key. If no kernel key exists, then the user key will be attempted for the operation. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- drivers/acpi/nfit/intel.c | 58 ++++++++++++++++++++++++++++++++++ drivers/nvdimm/dimm_devs.c | 74 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/libnvdimm.h | 3 ++ 3 files changed, 135 insertions(+) diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index ba886f1f5399..419a7d54d4e8 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -18,6 +18,63 @@ #include "intel.h" #include "nfit.h" +static int intel_dimm_security_erase(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, const struct nvdimm_key_data *nkey) +{ + struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); + int cmd_rc, rc = 0; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_secure_erase cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_SECURE_ERASE, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + }, + .cmd = { + .status = 0, + }, + }; + + if (!test_bit(NVDIMM_INTEL_SECURE_ERASE, &nfit_mem->dsm_mask)) + return -ENOTTY; + + /* flush all cache before we erase DIMM */ + wbinvd_on_all_cpus(); + memcpy(nd_cmd.cmd.passphrase, nkey->data, + sizeof(nd_cmd.cmd.passphrase)); + rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_CALL, &nd_cmd, + sizeof(nd_cmd), &cmd_rc); + if (rc < 0) + goto out; + if (cmd_rc < 0) { + rc = cmd_rc; + goto out; + } + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_INVALID_PASS: + rc = -EINVAL; + goto out; + case ND_INTEL_STATUS_INVALID_STATE: + default: + rc = -ENXIO; + goto out; + } + + /* DIMM erased, invalidate all CPU caches before we read it */ + wbinvd_on_all_cpus(); + + out: + return rc; +} + static int intel_dimm_security_freeze_lock(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm) { @@ -321,4 +378,5 @@ const struct nvdimm_security_ops intel_security_ops = { .change_key = intel_dimm_security_update_passphrase, .disable = intel_dimm_security_disable, .freeze_lock = intel_dimm_security_freeze_lock, + .erase = intel_dimm_security_erase, }; diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 75a3f841a7ce..752149c9450c 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -183,6 +183,77 @@ int nvdimm_security_get_state(struct device *dev) &nvdimm->state); } +static int nvdimm_security_erase(struct device *dev, unsigned int keyid) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key; + struct user_key_payload *payload; + int rc = 0; + bool is_userkey = false; + + if (!nvdimm->security_ops) + return -EOPNOTSUPP; + + nvdimm_bus_lock(&nvdimm_bus->dev); + if (atomic_read(&nvdimm->busy)) { + dev_warn(dev, "Unable to secure erase while DIMM active.\n"); + rc = -EBUSY; + goto out; + } + + if (dev_get_drvdata(dev)) { + dev_warn(dev, "Unable to secure erase while DIMM enabled.\n"); + rc = -EBUSY; + goto out; + } + + if (nvdimm->state == NVDIMM_SECURITY_UNSUPPORTED) { + dev_warn(dev, "Attempt to secure erase in wrong state.\n"); + rc = -EOPNOTSUPP; + goto out; + } + + /* look for a key from keyring if exists and remove */ + key = nvdimm_get_and_verify_key(dev, keyid); + if (IS_ERR(key)) { + dev_dbg(dev, "Unable to get and verify key\n"); + rc = PTR_ERR(key); + goto out; + } + if (!key) { + dev_dbg(dev, "No cached key found\n"); + /* get old user key */ + key = nvdimm_lookup_user_key(dev, keyid); + if (!key) { + dev_dbg(dev, "Unable to retrieve user key: %d\n", + keyid); + rc = -ENOKEY; + goto out; + } + is_userkey = true; + } + + down_read(&key->sem); + payload = key->payload.data[0]; + rc = nvdimm->security_ops->erase(nvdimm_bus, nvdimm, + (void *)payload->data); + up_read(&key->sem); + /* remove key since secure erase kills the passphrase */ + + if (!is_userkey) { + key_unlink(nvdimm_keyring, key); + key_invalidate(key); + nvdimm->key = NULL; + } + key_put(key); + + out: + nvdimm_bus_unlock(&nvdimm_bus->dev); + nvdimm_security_get_state(dev); + return rc; +} + static int nvdimm_security_freeze_lock(struct device *dev) { struct nvdimm *nvdimm = to_nvdimm(dev); @@ -817,6 +888,9 @@ static ssize_t security_store(struct device *dev, } else if (sysfs_streq(buf, "freeze")) { dev_dbg(dev, "freeze\n"); rc = nvdimm_security_freeze_lock(dev); + } else if (sysfs_streq(cmd, "erase")) { + dev_dbg(dev, "erase %u\n", old_key); + rc = nvdimm_security_erase(dev, old_key); } else return -EINVAL; diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index bcab42caa948..0d85e092a6dd 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -187,6 +187,9 @@ struct nvdimm_security_ops { const struct nvdimm_key_data *nkey); int (*freeze_lock)(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm); + int (*erase)(struct nvdimm_bus *nvdimm_bus, + struct nvdimm *nvdimm, + const struct nvdimm_key_data *nkey); }; void badrange_init(struct badrange *badrange); From patchwork Wed Sep 26 20:47:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616793 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1411015A6 for ; Wed, 26 Sep 2018 20:47:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 04B5B2B6CF for ; Wed, 26 Sep 2018 20:47:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ED2342B76E; Wed, 26 Sep 2018 20:47:43 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9335B2B6CF for ; Wed, 26 Sep 2018 20:47:43 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 89BD821959CB2; Wed, 26 Sep 2018 13:47:43 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.20; helo=mga02.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D121C211597F3 for ; Wed, 26 Sep 2018 13:47:41 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:47:41 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="93532886" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga001.fm.intel.com with ESMTP; 26 Sep 2018 13:47:41 -0700 Subject: [PATCH v10 10/12] nfit_test: add context to dimm_dev for nfit_test From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:40 -0700 Message-ID: <153799486070.71621.11412880339298606423.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP In order to access the nfit_test context via sideband sysfs knobs, the dimm_dev needs to be more than struct device in order to point back to struct nfit_test. Wrapping the original struct device with a struct nfit_dimm_dev and saving the nfit_test as private driver data. Also changing the nfit_mem to be a member of struct nfit_dimm_dev instead of saving as private driver data of that device. This is in preparation for adding security DSM support and allowing the locking of DIMMs for testing via sideband. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 41 +++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index cffc2c5a778d..1d62222a10da 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -172,6 +172,11 @@ struct nfit_test_fw { u64 end_time; }; +struct nfit_dimm_dev { + struct device dev; + struct nfit_mem *nfit_mem; +}; + struct nfit_test { struct acpi_nfit_desc acpi_desc; struct platform_device pdev; @@ -203,7 +208,7 @@ struct nfit_test { unsigned long deadline; spinlock_t lock; } ars_state; - struct device *dimm_dev[NUM_DCR]; + struct nfit_dimm_dev dimm_dev[NUM_DCR]; struct nd_intel_smart *smart; struct nd_intel_smart_threshold *smart_threshold; struct badrange badrange; @@ -1018,7 +1023,8 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, &t->smart_threshold[i - t->dcr_idx], &t->smart[i - t->dcr_idx], - &t->pdev.dev, t->dimm_dev[i]); + &t->pdev.dev, + &t->dimm_dev[i].dev); break; case ND_INTEL_SMART_INJECT: rc = nfit_test_cmd_smart_inject(buf, @@ -1026,7 +1032,8 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, &t->smart_threshold[i - t->dcr_idx], &t->smart[i - t->dcr_idx], - &t->pdev.dev, t->dimm_dev[i]); + &t->pdev.dev, + &t->dimm_dev[i].dev); break; default: return -ENOTTY; @@ -1224,8 +1231,7 @@ static void put_dimms(void *data) int i; for (i = 0; i < t->num_dcr; i++) - if (t->dimm_dev[i]) - device_unregister(t->dimm_dev[i]); + device_unregister(&t->dimm_dev[i].dev); } static struct class *nfit_test_dimm; @@ -1327,19 +1333,27 @@ static const struct attribute_group *nfit_test_dimm_attribute_groups[] = { NULL, }; +static void dimm_dev_release(struct device *dev) +{ +} + static int nfit_test_dimm_init(struct nfit_test *t) { - int i; + int i, rc; if (devm_add_action_or_reset(&t->pdev.dev, put_dimms, t)) return -ENOMEM; for (i = 0; i < t->num_dcr; i++) { - t->dimm_dev[i] = device_create_with_groups(nfit_test_dimm, - &t->pdev.dev, 0, NULL, - nfit_test_dimm_attribute_groups, - "test_dimm%d", i + t->dcr_idx); - if (!t->dimm_dev[i]) - return -ENOMEM; + t->dimm_dev[i].dev.parent = &t->pdev.dev; + dev_set_name(&t->dimm_dev[i].dev, "test_dimm%d", + i + t->dcr_idx); + t->dimm_dev[i].dev.class = nfit_test_dimm; + t->dimm_dev[i].dev.groups = nfit_test_dimm_attribute_groups; + t->dimm_dev[i].dev.release = dimm_dev_release; + rc = device_register(&t->dimm_dev[i].dev); + if (rc < 0) + return rc; + dev_set_drvdata(&t->dimm_dev[i].dev, t); } return 0; } @@ -2680,8 +2694,7 @@ static int nfit_test_probe(struct platform_device *pdev) for (i = 0; i < NUM_DCR; i++) if (nfit_handle == handle[i]) - dev_set_drvdata(nfit_test->dimm_dev[i], - nfit_mem); + nfit_test->dimm_dev[i].nfit_mem = nfit_mem; } mutex_unlock(&acpi_desc->init_mutex); From patchwork Wed Sep 26 20:47:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616801 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E251915A6 for ; Wed, 26 Sep 2018 20:50:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D27692B7EE for ; Wed, 26 Sep 2018 20:50:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C60EF2B7F5; Wed, 26 Sep 2018 20:50:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 319252B7EE for ; Wed, 26 Sep 2018 20:50:37 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 2866B211597FB; Wed, 26 Sep 2018 13:50:37 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.20; helo=mga02.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D367021157426 for ; Wed, 26 Sep 2018 13:50:35 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:50:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="92171558" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga004.fm.intel.com with ESMTP; 26 Sep 2018 13:47:46 -0700 Subject: [PATCH v10 11/12] nfit_test: add test support for Intel nvdimm security DSMs From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:46 -0700 Message-ID: <153799486626.71621.17207195693882049901.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add nfit_test support for DSM functions "Get Security State", "Set Passphrase", "Disable Passphrase", "Unlock Unit", "Freeze Lock", and "Secure Erase" for the fake DIMMs. Also adding a sysfs knob in order to put the DIMMs in "locked" state. The order of testing DIMM unlocking would be. 1a. Disable DIMM X. 1b. Set Passphrase to DIMM X. 2. Write to /sys/devices/platform/nfit_test.0/nfit_test_dimm/test_dimmX/lock_dimm 3. Renable DIMM X 4. Check DIMM X state via sysfs "security" attribute for nmemX. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams --- tools/testing/nvdimm/Kbuild | 1 tools/testing/nvdimm/test/nfit.c | 186 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 0392153a0009..a13670d3b389 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -36,6 +36,7 @@ obj-$(CONFIG_DEV_DAX) += device_dax.o obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o nfit-y := $(ACPI_SRC)/core.o +nfit-$(CONFIG_X86) += $(ACPI_SRC)/intel.o nfit-$(CONFIG_X86_MCE) += $(ACPI_SRC)/mce.o nfit-y += acpi_nfit_test.o nfit-y += config_check.o diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 1d62222a10da..61ad16beef6d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "nfit_test.h" @@ -177,6 +178,11 @@ struct nfit_dimm_dev { struct nfit_mem *nfit_mem; }; +struct nfit_test_sec { + u8 state; + u8 passphrase[32]; +}; + struct nfit_test { struct acpi_nfit_desc acpi_desc; struct platform_device pdev; @@ -214,6 +220,7 @@ struct nfit_test { struct badrange badrange; struct work_struct work; struct nfit_test_fw *fw; + struct nfit_test_sec *sec; }; static struct workqueue_struct *nfit_wq; @@ -936,6 +943,138 @@ static int override_return_code(int dimm, unsigned int func, int rc) return rc; } +static int nd_intel_test_cmd_security_status(struct nfit_test *t, + struct nd_intel_get_security_state *nd_cmd, + unsigned int buf_len, int idx) +{ + struct device *dev = &t->pdev.dev; + struct nfit_test_sec *sec = &t->sec[idx]; + + nd_cmd->status = 0; + nd_cmd->state = sec->state; + dev_dbg(dev, "security state (%#x) returned\n", nd_cmd->state); + + return 0; +} + +static int nd_intel_test_cmd_unlock_unit(struct nfit_test *t, + struct nd_intel_unlock_unit *nd_cmd, + unsigned int buf_len, int idx) +{ + struct device *dev = &t->pdev.dev; + struct nfit_test_sec *sec = &t->sec[idx]; + + if (!(sec->state & ND_INTEL_SEC_STATE_LOCKED) || + (sec->state & ND_INTEL_SEC_STATE_FROZEN)) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; + dev_dbg(dev, "unlock unit: invalid state: %#x\n", + sec->state); + } else if (memcmp(nd_cmd->passphrase, sec->passphrase, + ND_INTEL_PASSPHRASE_SIZE) != 0) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; + dev_dbg(dev, "unlock unit: invalid passphrase\n"); + } else { + nd_cmd->status = 0; + sec->state = ND_INTEL_SEC_STATE_ENABLED; + dev_dbg(dev, "Unit unlocked\n"); + } + + dev_dbg(dev, "unlocking status returned: %#x\n", nd_cmd->status); + return 0; +} + +static int nd_intel_test_cmd_set_pass(struct nfit_test *t, + struct nd_intel_set_passphrase *nd_cmd, + unsigned int buf_len, int idx) +{ + struct device *dev = &t->pdev.dev; + struct nfit_test_sec *sec = &t->sec[idx]; + + if (sec->state & ND_INTEL_SEC_STATE_FROZEN) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; + dev_dbg(dev, "set passphrase: wrong security state\n"); + } else if (memcmp(nd_cmd->old_pass, sec->passphrase, + ND_INTEL_PASSPHRASE_SIZE) != 0) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; + dev_dbg(dev, "set passphrase: wrong passphrase\n"); + } else { + memcpy(sec->passphrase, nd_cmd->new_pass, + ND_INTEL_PASSPHRASE_SIZE); + sec->state |= ND_INTEL_SEC_STATE_ENABLED; + nd_cmd->status = 0; + dev_dbg(dev, "passphrase updated\n"); + } + + return 0; +} + +static int nd_intel_test_cmd_freeze_lock(struct nfit_test *t, + struct nd_intel_freeze_lock *nd_cmd, + unsigned int buf_len, int idx) +{ + struct device *dev = &t->pdev.dev; + struct nfit_test_sec *sec = &t->sec[idx]; + + if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED)) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; + dev_dbg(dev, "freeze lock: wrong security state\n"); + } else { + sec->state |= ND_INTEL_SEC_STATE_FROZEN; + nd_cmd->status = 0; + dev_dbg(dev, "security frozen\n"); + } + + return 0; +} + +static int nd_intel_test_cmd_disable_pass(struct nfit_test *t, + struct nd_intel_disable_passphrase *nd_cmd, + unsigned int buf_len, int idx) +{ + struct device *dev = &t->pdev.dev; + struct nfit_test_sec *sec = &t->sec[idx]; + + if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED) || + (sec->state & ND_INTEL_SEC_STATE_FROZEN)) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; + dev_dbg(dev, "disable passphrase: wrong security state\n"); + } else if (memcmp(nd_cmd->passphrase, sec->passphrase, + ND_INTEL_PASSPHRASE_SIZE) != 0) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; + dev_dbg(dev, "disable passphrase: wrong passphrase\n"); + } else { + memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE); + sec->state = 0; + dev_dbg(dev, "disable passphrase: done\n"); + } + + return 0; +} + +static int nd_intel_test_cmd_secure_erase(struct nfit_test *t, + struct nd_intel_secure_erase *nd_cmd, + unsigned int buf_len, int idx) +{ + struct device *dev = &t->pdev.dev; + struct nfit_test_sec *sec = &t->sec[idx]; + + if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED) || + (sec->state & ND_INTEL_SEC_STATE_FROZEN)) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; + dev_dbg(dev, "secure erase: wrong security state\n"); + } else if (memcmp(nd_cmd->passphrase, sec->passphrase, + ND_INTEL_PASSPHRASE_SIZE) != 0) { + nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; + dev_dbg(dev, "secure erase: wrong passphrase\n"); + } else { + memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE); + sec->state = 0; + dev_dbg(dev, "secure erase: done\n"); + } + + return 0; +} + static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) { int i; @@ -983,6 +1122,30 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, return i; switch (func) { + case NVDIMM_INTEL_GET_SECURITY_STATE: + rc = nd_intel_test_cmd_security_status(t, + buf, buf_len, i - t->dcr_idx); + break; + case NVDIMM_INTEL_UNLOCK_UNIT: + rc = nd_intel_test_cmd_unlock_unit(t, + buf, buf_len, i - t->dcr_idx); + break; + case NVDIMM_INTEL_SET_PASSPHRASE: + rc = nd_intel_test_cmd_set_pass(t, + buf, buf_len, i - t->dcr_idx); + break; + case NVDIMM_INTEL_DISABLE_PASSPHRASE: + rc = nd_intel_test_cmd_disable_pass(t, + buf, buf_len, i - t->dcr_idx); + break; + case NVDIMM_INTEL_FREEZE_LOCK: + rc = nd_intel_test_cmd_freeze_lock(t, + buf, buf_len, i - t->dcr_idx); + break; + case NVDIMM_INTEL_SECURE_ERASE: + rc = nd_intel_test_cmd_secure_erase(t, + buf, buf_len, i - t->dcr_idx); + break; case ND_INTEL_ENABLE_LSS_STATUS: rc = nd_intel_test_cmd_set_lss_status(t, buf, buf_len); @@ -1317,10 +1480,23 @@ static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute * } static DEVICE_ATTR_RW(fail_cmd_code); +static ssize_t lock_dimm_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int dimm = dimm_name_to_id(dev); + struct nfit_test *t = dev_get_drvdata(dev); + struct nfit_test_sec *sec = &t->sec[dimm]; + + sec->state = ND_INTEL_SEC_STATE_ENABLED | ND_INTEL_SEC_STATE_LOCKED; + return size; +} +static DEVICE_ATTR_WO(lock_dimm); + static struct attribute *nfit_test_dimm_attributes[] = { &dev_attr_fail_cmd.attr, &dev_attr_fail_cmd_code.attr, &dev_attr_handle.attr, + &dev_attr_lock_dimm.attr, NULL, }; @@ -2207,6 +2383,14 @@ static void nfit_test0_setup(struct nfit_test *t) set_bit(ND_INTEL_FW_FINISH_UPDATE, &acpi_desc->dimm_cmd_force_en); set_bit(ND_INTEL_FW_FINISH_QUERY, &acpi_desc->dimm_cmd_force_en); set_bit(ND_INTEL_ENABLE_LSS_STATUS, &acpi_desc->dimm_cmd_force_en); + set_bit(NVDIMM_INTEL_GET_SECURITY_STATE, + &acpi_desc->dimm_cmd_force_en); + set_bit(NVDIMM_INTEL_SET_PASSPHRASE, &acpi_desc->dimm_cmd_force_en); + set_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, + &acpi_desc->dimm_cmd_force_en); + set_bit(NVDIMM_INTEL_UNLOCK_UNIT, &acpi_desc->dimm_cmd_force_en); + set_bit(NVDIMM_INTEL_FREEZE_LOCK, &acpi_desc->dimm_cmd_force_en); + set_bit(NVDIMM_INTEL_SECURE_ERASE, &acpi_desc->dimm_cmd_force_en); } static void nfit_test1_setup(struct nfit_test *t) @@ -2626,6 +2810,8 @@ static int nfit_test_probe(struct platform_device *pdev) GFP_KERNEL); nfit_test->fw = devm_kcalloc(dev, num, sizeof(struct nfit_test_fw), GFP_KERNEL); + nfit_test->sec = devm_kcalloc(dev, num, + sizeof(struct nfit_test_sec), GFP_KERNEL); if (nfit_test->dimm && nfit_test->dimm_dma && nfit_test->label && nfit_test->label_dma && nfit_test->dcr && nfit_test->dcr_dma && nfit_test->flush From patchwork Wed Sep 26 20:47:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10616795 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4969E14BD for ; Wed, 26 Sep 2018 20:47:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3928A2B6CF for ; Wed, 26 Sep 2018 20:47:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2CD6B2B76E; Wed, 26 Sep 2018 20:47:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id B64E42B6CF for ; Wed, 26 Sep 2018 20:47:53 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id ACBE5211597FC; Wed, 26 Sep 2018 13:47:53 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.31; helo=mga06.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 6A55B211597F3 for ; Wed, 26 Sep 2018 13:47:52 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Sep 2018 13:47:52 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,307,1534834800"; d="scan'208";a="265994478" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga005.fm.intel.com with ESMTP; 26 Sep 2018 13:47:51 -0700 Subject: [PATCH v10 12/12] libnvdimm: add documentation for nvdimm security support From: Dave Jiang To: dan.j.williams@intel.com Date: Wed, 26 Sep 2018 13:47:51 -0700 Message-ID: <153799487169.71621.5218226610050907633.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> References: <153799466529.71621.10728628542331983376.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alison.schofield@intel.com, keescook@chromium.org, linux-nvdimm@lists.01.org, ebiggers3@gmail.com, dhowells@redhat.com, keyrings@vger.kernel.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add theory of operation for the security support that's going into libnvdimm. Signed-off-by: Dave Jiang --- Documentation/nvdimm/security.txt | 99 +++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 Documentation/nvdimm/security.txt diff --git a/Documentation/nvdimm/security.txt b/Documentation/nvdimm/security.txt new file mode 100644 index 000000000000..50cbb6cb96a1 --- /dev/null +++ b/Documentation/nvdimm/security.txt @@ -0,0 +1,99 @@ +NVDIMM SECURITY +=============== + +1. Introduction +--------------- + +With the introduction of Intel DSM v1.7 specification [1], security DSMs are +introduced. The spec added the following security DSMs: "get security state", +"set passphrase", "disable passphrase", "unlock unit", "freeze lock", +"secure erase", and "overwrite". A security_ops data structure has been +added to struct dimm in order to support the security operations and generic +APIs are exposed to allow vendor neutral operations. + +2. Sysfs Interface +------------------ +The "security" sysfs attribute is provided in the nvdimm sysfs directory. For +example: +/sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/nmem0/security + +The "show" function of that attribute will display the security state for +that DIMM. The following states are available: disabled, unlocked, locked, +frozen, and unsupported. + +The "store" function takes several commands when the attribute is written to +in order to support some of the security functionalities: +update - enable security. Add or update current key. +disable - disable enabled security and remove key. +freeze - freeze changing of security states. +erase - generate new ecryption key for DIMM and crypto-scrambles + all existing user data. + +3. Key Management +----------------- + +The key is associted to the payload by the DIMM id. For example: +# cat /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/nmem0/nfit/id +8089-a2-1740-00000133 +The DIMM id would be provided along with the key payload (passphrase) to +the kernel. + +The security keys are managed on the basis of a single key per DIMM. The +key "passphrase" is expected to be 32bytes long or padded to 32bytes. This is +similar to the ATA security specification [2]. A key is initially acquired +via the request_key() kernel API call and retrieved from userspace. It is up to +the user to provide an upcall application to retrieve the key in whatever +fashion meets their security requirements. + +A nvdimm user logon key has the description format of: +nvdimm: + +4. Unlocking +------------ +When the DIMMs are being enumerated by the kernel, the kernel will attempt to +retrieve the key from its keyring. If that fails, it will attempt to +acquire the key from the userspace upcall function. This is the only time +a locked DIMM can be unlocked. Once unlocked, the DIMM will remain unlocked +until reboot. + +5. Update +--------- +When doing an update, it is expected that the new key with the 64bit payload of +format described above is added via the keyutils API or utility. The update +command written to the sysfs attribute will be with the format: +update + +It is expected that a user logon key has been injected via keyutils to provide +the payload for the update operation. The kernel will take the new user key, +attempt the update operation with the nvdimm, and replace the existing key's +payload with the new passphrase. + +If there is no old key id due to a security enabling, then a 0 should be +passed in. If a nvdimm has an existing passphrase, then an "old" key should +be injected with a key description that does not have the "nvdimm:" prefix. + +6. Freeze +--------- +The freeze operation does not require any keys. The security config can be +frozen by a user with root privelege. + +7. Disable +---------- +The security disable command format is: +disable + +An "old" key with the passphrase payload that is tied to the nvdimm should be +injected with a key description that does not have the "nvdimm:" prefix and +its keyid should be passed in via sysfs. + +8. Secure Erase +--------------- +The command format for doing a secure erase is: +erase + +An "old" key with the passphrase payload that is tied to the nvdimm should be +injected with a key description that does not have the "nvdimm:" prefix and +its keyid should be passed in via sysfs. + +[1]: http://pmem.io/documents/NVDIMM_DSM_Interface-V1.7.pdf +[2]: http://www.t13.org/documents/UploadedDocuments/docs2006/e05179r4-ACS-SecurityClarifications.pdf