From patchwork Thu Jan 24 23:07:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780209 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 3F94C1399 for ; Thu, 24 Jan 2019 23:07:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2D7B52F4EF for ; Thu, 24 Jan 2019 23:07:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 20EB22F525; Thu, 24 Jan 2019 23:07:14 +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 B79D42F4EF for ; Thu, 24 Jan 2019 23:07:13 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 9BE38211B85DE; Thu, 24 Jan 2019 15:07:13 -0800 (PST) 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 B0996211B81A5 for ; Thu, 24 Jan 2019 15:07:11 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="128686582" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga002.jf.intel.com with ESMTP; 24 Jan 2019 15:07:10 -0800 Subject: [PATCH v10 01/12] ndctl: add support for display security state From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:10 -0700 Message-ID: <154837123008.37086.76497287122377987.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Adding libndctl API call for retrieving security state for a DIMM and also adding support to ndctl list for displaying security state. Signed-off-by: Dave Jiang --- Documentation/ndctl/ndctl-list.txt | 8 ++++++++ ndctl/lib/dimm.c | 33 +++++++++++++++++++++++++++++++++ ndctl/lib/libndctl.sym | 1 + ndctl/libndctl.h | 11 +++++++++++ util/json.c | 17 +++++++++++++++++ 5 files changed, 70 insertions(+) diff --git a/Documentation/ndctl/ndctl-list.txt b/Documentation/ndctl/ndctl-list.txt index e24c8f40..bdd69add 100644 --- a/Documentation/ndctl/ndctl-list.txt +++ b/Documentation/ndctl/ndctl-list.txt @@ -98,6 +98,14 @@ include::xable-region-options.txt[] -D:: --dimms:: Include dimm info in the listing +[verse] +{ + "dev":"nmem0", + "id":"cdab-0a-07e0-ffffffff", + "handle":0, + "phys_id":0, + "security:":"disabled" +} -H:: --health:: diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index 11a7efe9..712223fc 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -598,3 +598,36 @@ NDCTL_EXPORT unsigned long ndctl_dimm_get_available_labels( return strtoul(buf, NULL, 0); } + +NDCTL_EXPORT enum ndctl_security_state ndctl_dimm_get_security( + struct ndctl_dimm *dimm) +{ + struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm); + char *path = dimm->dimm_buf; + int len = dimm->buf_len; + char buf[64]; + int rc; + + if (snprintf(path, len, "%s/security", dimm->dimm_path) >= len) { + err(ctx, "%s: buffer too small!\n", + ndctl_dimm_get_devname(dimm)); + return NDCTL_SECURITY_INVALID; + } + + rc = sysfs_read_attr(ctx, path, buf); + if (rc < 0) + return NDCTL_SECURITY_INVALID; + + if (strcmp(buf, "disabled") == 0) + return NDCTL_SECURITY_DISABLED; + else if (strcmp(buf, "unlocked") == 0) + return NDCTL_SECURITY_UNLOCKED; + else if (strcmp(buf, "locked") == 0) + return NDCTL_SECURITY_LOCKED; + else if (strcmp(buf, "frozen") == 0) + return NDCTL_SECURITY_FROZEN; + else if (strcmp(buf, "overwrite") == 0) + return NDCTL_SECURITY_OVERWRITE; + + return NDCTL_SECURITY_INVALID; +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 275db92e..0888c824 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -390,4 +390,5 @@ LIBNDCTL_19 { global: ndctl_cmd_xlat_firmware_status; ndctl_cmd_submit_xlat; + ndctl_dimm_get_security; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index e55a5932..e228c64f 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -684,6 +684,17 @@ int ndctl_dimm_fw_update_supported(struct ndctl_dimm *dimm); int ndctl_cmd_xlat_firmware_status(struct ndctl_cmd *cmd); int ndctl_cmd_submit_xlat(struct ndctl_cmd *cmd); +enum ndctl_security_state { + NDCTL_SECURITY_INVALID = -1, + NDCTL_SECURITY_DISABLED = 0, + NDCTL_SECURITY_UNLOCKED, + NDCTL_SECURITY_LOCKED, + NDCTL_SECURITY_FROZEN, + NDCTL_SECURITY_OVERWRITE, +}; + +enum ndctl_security_state ndctl_dimm_get_security(struct ndctl_dimm *dimm); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/util/json.c b/util/json.c index 5c3424e2..9dc420ce 100644 --- a/util/json.c +++ b/util/json.c @@ -164,6 +164,7 @@ struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm, unsigned int handle = ndctl_dimm_get_handle(dimm); unsigned short phys_id = ndctl_dimm_get_phys_id(dimm); struct json_object *jobj; + enum ndctl_security_state sstate; if (!jdimm) return NULL; @@ -243,6 +244,22 @@ struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm, json_object_object_add(jdimm, "flag_smart_event", jobj); } + sstate = ndctl_dimm_get_security(dimm); + if (sstate == NDCTL_SECURITY_DISABLED) + jobj = json_object_new_string("disabled"); + else if (sstate == NDCTL_SECURITY_UNLOCKED) + jobj = json_object_new_string("unlocked"); + else if (sstate == NDCTL_SECURITY_LOCKED) + jobj = json_object_new_string("locked"); + else if (sstate == NDCTL_SECURITY_FROZEN) + jobj = json_object_new_string("frozen"); + else if (sstate == NDCTL_SECURITY_OVERWRITE) + jobj = json_object_new_string("overwrite"); + else + jobj = NULL; + if (jobj) + json_object_object_add(jdimm, "security", jobj); + return jdimm; err: json_object_put(jdimm); From patchwork Thu Jan 24 23:07:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780211 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 50ECA1399 for ; Thu, 24 Jan 2019 23:07:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 381252F4EF for ; Thu, 24 Jan 2019 23:07:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 293612F525; Thu, 24 Jan 2019 23:07:20 +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 C2A5A2F4EF for ; Thu, 24 Jan 2019 23:07:18 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id B9DC6211B85E7; Thu, 24 Jan 2019 15:07:18 -0800 (PST) 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 D003C211B85E6 for ; Thu, 24 Jan 2019 15:07:16 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:16 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="128686610" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga002.jf.intel.com with ESMTP; 24 Jan 2019 15:07:15 -0800 Subject: [PATCH v10 02/12] ndctl: add passphrase update to ndctl From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:15 -0700 Message-ID: <154837123565.37086.2456954752128201392.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add API call for triggering sysfs knob to update the security for a DIMM in libndctl. Also add the ndctl "update-passphrase" to trigger the operation. Signed-off-by: Dave Jiang --- Documentation/ndctl/Makefile.am | 5 Documentation/ndctl/ndctl-setup-passphrase.txt | 47 ++ Documentation/ndctl/ndctl-update-passphrase.txt | 51 +++ configure.ac | 17 + ndctl.spec.in | 2 ndctl/Makefile.am | 5 ndctl/builtin.h | 2 ndctl/dimm.c | 83 ++++ ndctl/lib/Makefile.am | 4 ndctl/lib/dimm.c | 24 + ndctl/lib/libndctl.sym | 1 ndctl/libndctl.h | 9 ndctl/ndctl.c | 2 ndctl/util/keys.c | 460 +++++++++++++++++++++++ ndctl/util/keys.h | 29 + 15 files changed, 729 insertions(+), 12 deletions(-) create mode 100644 Documentation/ndctl/ndctl-setup-passphrase.txt create mode 100644 Documentation/ndctl/ndctl-update-passphrase.txt create mode 100644 ndctl/util/keys.c create mode 100644 ndctl/util/keys.h diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am index 7e17f206..79b12f8b 100644 --- a/Documentation/ndctl/Makefile.am +++ b/Documentation/ndctl/Makefile.am @@ -47,7 +47,9 @@ man1_MANS = \ ndctl-inject-smart.1 \ ndctl-update-firmware.1 \ ndctl-list.1 \ - ndctl-monitor.1 + ndctl-monitor.1 \ + ndctl-setup-passphrase.1 \ + ndctl-update-passphrase.1 CLEANFILES = $(man1_MANS) @@ -56,6 +58,7 @@ attrs.adoc: $(srcdir)/Makefile.am $(AM_V_GEN) cat <<- EOF >$@ :ndctl_monitorconfdir: $(ndctl_monitorconfdir) :ndctl_monitorconf: $(ndctl_monitorconf) + :ndctl_keysdir: $(ndctl_keysdir) EOF XML_DEPS = \ diff --git a/Documentation/ndctl/ndctl-setup-passphrase.txt b/Documentation/ndctl/ndctl-setup-passphrase.txt new file mode 100644 index 00000000..1594f110 --- /dev/null +++ b/Documentation/ndctl/ndctl-setup-passphrase.txt @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 + +include::attrs.adoc[] + +ndctl-setup-passphrase(1) +========================= + +NAME +---- +ndctl-setup-passphrase - setup and enable the security passphrase for an NVDIMM + +SYNOPSIS +-------- +[verse] +'ndctl setup-passphrase' [..] -k [] + +DESCRIPTION +----------- +Enable the security passphrase for one or more NVDIMMs. + +Prerequisite for command to succeed: +1. The master key has already been loaded into the user key ring. +2. ndctl install-encrypt-key has been executed successfully. + +The encrypted key blobs will be created by ndctl in {ndctl_keysdir} directory +with the file name of "nvdimm__.blob". + +The command will fail if the nvdimm key is already in the user key ring and/or +the key blob already resides in {ndctl_keysdir}. + +OPTIONS +------- +:: +include::xable-dimm-options.txt[] + +-k:: +--key_handle=:: + The encryption key (master) key handle, used for sealing the DIMM + encrypted keys. The format is :. + i.e. trusted:nvdimm-master + This key is expected to be loaded in the kernel's user keyring. + +-v:: +--verbose:: + Emit debug messages for the namespace check process. + +include::../copyright.txt[] diff --git a/Documentation/ndctl/ndctl-update-passphrase.txt b/Documentation/ndctl/ndctl-update-passphrase.txt new file mode 100644 index 00000000..05573968 --- /dev/null +++ b/Documentation/ndctl/ndctl-update-passphrase.txt @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 + +include::attrs.adoc[] + +ndctl-update-passphrase(1) +========================== + +NAME +---- +ndctl-update-passphrase - update the security passphrase for an NVDIMM + +SYNOPSIS +-------- +[verse] +'ndctl update-passphrase' [..] [] + +DESCRIPTION +----------- +Update the security passphrase for one or more NVDIMMs. +Prerequisite for command to succeed: +1. The master key has already been loaded into the user key ring. +2. ndctl install-encrypt-key has been executed successfully. +3. setup-passphrase has successfully been executed previously on the NVDIMM + or NVDIMM has been successfully unlocked by the kernel. + +The updated key blobs will be created by ndctl in {ndctl_keysdir} directory +with the file name of "nvdimm__.blob". + +OPTIONS +------- +:: +include::xable-dimm-options.txt[] + +-k:: +--key_handle=:: + The new encryption key (master) key handle, used for sealing the DIMM + encrypted keys. The format is :. + i.e. trusted:nvdimm-master + This key is expected to be loaded in the kernel's user keyring. + This parameter is optional. If none provided, ndctl will determine + the current key handle from the encrypted key for the NVDIMM. + +-v:: +--verbose:: + Emit debug messages for the namespace check process. + +include::../copyright.txt[] + +SEE ALSO: +--------- +linkndctl:ndctl-setup-passphrase[1] diff --git a/configure.ac b/configure.ac index 5b4f1fc8..b08ddaf1 100644 --- a/configure.ac +++ b/configure.ac @@ -164,6 +164,23 @@ daxctl_modprobe_data=daxctl.conf AC_SUBST([daxctl_modprobe_datadir]) AC_SUBST([daxctl_modprobe_data]) +AC_ARG_WITH([keyutils], + AS_HELP_STRING([--with-keyutils], + [Enable keyutils functionality (security). @<:@default=yes@:>@]), [], [with_keyutils=yes]) + +if test "x$with_keyutils" = "xyes"; then + AC_CHECK_HEADERS([keyutils.h],,[ + AC_MSG_ERROR([keyutils.h not found, consider installing + keyutils-libs-devel.]) + ]) +fi +AS_IF([test "x$with_keyutils" = "xyes"], + [AC_DEFINE([ENABLE_KEYUTILS], [1], [Enable keyutils support])]) +AM_CONDITIONAL([ENABLE_KEYUTILS], [test "x$with_keyutils" = "xyes"]) + +ndctl_keysdir=${sysconfdir}/ndctl/keys +AC_SUBST([ndctl_keysdir]) + my_CFLAGS="\ -Wall \ -Wchar-subscripts \ diff --git a/ndctl.spec.in b/ndctl.spec.in index bc65a471..c075a0a0 100644 --- a/ndctl.spec.in +++ b/ndctl.spec.in @@ -21,6 +21,7 @@ BuildRequires: pkgconfig(uuid) BuildRequires: pkgconfig(json-c) BuildRequires: pkgconfig(bash-completion) BuildRequires: pkgconfig(systemd) +BuildRequires: keyutils-libs-devel %description Utility library for managing the "libnvdimm" subsystem. The "libnvdimm" @@ -118,6 +119,7 @@ make check %{_mandir}/man1/ndctl* %{bashcompdir}/ %{_unitdir}/ndctl-monitor.service +%{_sysconfdir}/ndctl/keys/ %config(noreplace) %{_sysconfdir}/ndctl/monitor.conf diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am index c7c1ac6e..28b4e09b 100644 --- a/ndctl/Makefile.am +++ b/ndctl/Makefile.am @@ -8,6 +8,7 @@ config.h: $(srcdir)/Makefile.am $(AM_V_GEN) echo "/* Autogenerated by ndctl/Makefile.am */" >$@ && \ echo '#define NDCTL_CONF_FILE \ "$(ndctl_monitorconfdir)/$(ndctl_monitorconf)"' >>$@ + $(AM_V_GEN) echo '#define NDCTL_KEYS_DIR "$(ndctl_keysdir)"' >>$@ ndctl_SOURCES = ndctl.c \ bus.c \ @@ -25,6 +26,10 @@ ndctl_SOURCES = ndctl.c \ inject-smart.c \ monitor.c +if ENABLE_KEYUTILS +ndctl_SOURCES += util/keys.c +endif + if ENABLE_DESTRUCTIVE ndctl_SOURCES += ../test/blk_namespaces.c \ ../test/pmem_namespaces.c diff --git a/ndctl/builtin.h b/ndctl/builtin.h index 17300df0..231fda25 100644 --- a/ndctl/builtin.h +++ b/ndctl/builtin.h @@ -32,4 +32,6 @@ int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx); #endif int cmd_update_firmware(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_inject_smart(int argc, const char **argv, struct ndctl_ctx *ctx); +int cmd_passphrase_setup(int argc, const char **argv, struct ndctl_ctx *ctx); +int cmd_passphrase_update(int argc, const char **argv, struct ndctl_ctx *ctx); #endif /* _NDCTL_BUILTIN_H_ */ diff --git a/ndctl/dimm.c b/ndctl/dimm.c index c717beeb..88319b31 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -31,6 +31,7 @@ #include #include #include +#include struct action_context { struct json_object *jdimms; @@ -40,6 +41,19 @@ struct action_context { struct update_context update; }; +static struct parameters { + const char *bus; + const char *outfile; + const char *infile; + const char *labelversion; + const char *kek; + bool force; + bool json; + bool verbose; +} param = { + .labelversion = "1.1", +}; + static int action_disable(struct ndctl_dimm *dimm, struct action_context *actx) { if (ndctl_dimm_is_active(dimm)) { @@ -824,17 +838,32 @@ static int action_update(struct ndctl_dimm *dimm, struct action_context *actx) return rc; } -static struct parameters { - const char *bus; - const char *outfile; - const char *infile; - const char *labelversion; - bool force; - bool json; - bool verbose; -} param = { - .labelversion = "1.1", -}; +static int action_passphrase_setup(struct ndctl_dimm *dimm, + struct action_context *actx) +{ + if (ndctl_dimm_get_security(dimm) < 0) { + error("%s: security operation not supported\n", + ndctl_dimm_get_devname(dimm)); + return -EOPNOTSUPP; + } + + if (!param.kek) + return -EINVAL; + + return ndctl_dimm_setup_key(dimm, param.kek); +} + +static int action_passphrase_update(struct ndctl_dimm *dimm, + struct action_context *actx) +{ + if (ndctl_dimm_get_security(dimm) < 0) { + error("%s: security operation not supported\n", + ndctl_dimm_get_devname(dimm)); + return -EOPNOTSUPP; + } + + return ndctl_dimm_update_key(dimm, param.kek); +} static int __action_init(struct ndctl_dimm *dimm, enum ndctl_namespace_version version, int chk_only) @@ -925,6 +954,10 @@ OPT_BOOLEAN('f', "force", ¶m.force, \ OPT_STRING('V', "label-version", ¶m.labelversion, "version-number", \ "namespace label specification version (default: 1.1)") +#define KEY_OPTIONS() \ +OPT_STRING('k', "key-handle", ¶m.kek, "key-handle", \ + "master encryption key handle") + static const struct option read_options[] = { BASE_OPTIONS(), READ_OPTIONS(), @@ -954,6 +987,12 @@ static const struct option init_options[] = { OPT_END(), }; +static const struct option key_options[] = { + BASE_OPTIONS(), + KEY_OPTIONS(), + OPT_END(), +}; + static int dimm_action(int argc, const char **argv, struct ndctl_ctx *ctx, int (*action)(struct ndctl_dimm *dimm, struct action_context *actx), const struct option *options, const char *usage) @@ -1181,3 +1220,25 @@ int cmd_update_firmware(int argc, const char **argv, struct ndctl_ctx *ctx) count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } + +int cmd_passphrase_update(int argc, const char **argv, struct ndctl_ctx *ctx) +{ + int count = dimm_action(argc, argv, ctx, action_passphrase_update, + key_options, + "ndctl update-passphrase [..] []"); + + fprintf(stderr, "passphrase updated for %d nmem%s.\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_passphrase_setup(int argc, const char **argv, struct ndctl_ctx *ctx) +{ + int count = dimm_action(argc, argv, ctx, action_passphrase_setup, + key_options, + "ndctl setup-passphrase [..] []"); + + fprintf(stderr, "passphrase enabled for %d nmem%s.\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} diff --git a/ndctl/lib/Makefile.am b/ndctl/lib/Makefile.am index 77970399..99eaae0d 100644 --- a/ndctl/lib/Makefile.am +++ b/ndctl/lib/Makefile.am @@ -30,6 +30,10 @@ libndctl_la_LIBADD =\ $(UUID_LIBS) \ $(KMOD_LIBS) +if ENABLE_KEYUTILS +libndctl_la_LIBADD += -lkeyutils +endif + EXTRA_DIST += libndctl.sym libndctl_la_LDFLAGS = $(AM_LDFLAGS) \ diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index 712223fc..72b6f66c 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -631,3 +631,27 @@ NDCTL_EXPORT enum ndctl_security_state ndctl_dimm_get_security( return NDCTL_SECURITY_INVALID; } + +static int write_security(struct ndctl_dimm *dimm, const char *cmd) +{ + struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm); + char *path = dimm->dimm_buf; + int len = dimm->buf_len; + + if (snprintf(path, len, "%s/security", dimm->dimm_path) >= len) { + err(ctx, "%s: buffer too small!\n", + ndctl_dimm_get_devname(dimm)); + return -ERANGE; + } + + return sysfs_write_attr(ctx, path, cmd); +} + +NDCTL_EXPORT int ndctl_dimm_update_passphrase(struct ndctl_dimm *dimm, + long ckey, long nkey) +{ + char buf[SYSFS_ATTR_SIZE]; + + sprintf(buf, "update %ld %ld\n", ckey, nkey); + return write_security(dimm, buf); +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 0888c824..88557710 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -391,4 +391,5 @@ global: ndctl_cmd_xlat_firmware_status; ndctl_cmd_submit_xlat; ndctl_dimm_get_security; + ndctl_dimm_update_passphrase; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index e228c64f..85c1537a 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -684,6 +684,10 @@ int ndctl_dimm_fw_update_supported(struct ndctl_dimm *dimm); int ndctl_cmd_xlat_firmware_status(struct ndctl_cmd *cmd); int ndctl_cmd_submit_xlat(struct ndctl_cmd *cmd); +#define ND_PASSPHRASE_SIZE 32 +#define ND_KEY_DESC_LEN 22 +#define ND_KEY_DESC_PREFIX 7 + enum ndctl_security_state { NDCTL_SECURITY_INVALID = -1, NDCTL_SECURITY_DISABLED = 0, @@ -694,6 +698,11 @@ enum ndctl_security_state { }; enum ndctl_security_state ndctl_dimm_get_security(struct ndctl_dimm *dimm); +int ndctl_dimm_update_passphrase(struct ndctl_dimm *dimm, + long ckey, long nkey); + +#define ND_KEY_DESC_SIZE 128 +#define ND_KEY_CMD_SIZE 128 #ifdef __cplusplus } /* extern "C" */ diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c index b01594e0..5cb5fa4f 100644 --- a/ndctl/ndctl.c +++ b/ndctl/ndctl.c @@ -88,6 +88,8 @@ static struct cmd_struct commands[] = { { "inject-smart", { cmd_inject_smart } }, { "wait-scrub", { cmd_wait_scrub } }, { "start-scrub", { cmd_start_scrub } }, + { "setup-passphrase", { cmd_passphrase_setup } }, + { "update-passphrase", { cmd_passphrase_update } }, { "list", { cmd_list } }, { "monitor", { cmd_monitor } }, { "help", { cmd_help } }, diff --git a/ndctl/util/keys.c b/ndctl/util/keys.c new file mode 100644 index 00000000..1592ff09 --- /dev/null +++ b/ndctl/util/keys.c @@ -0,0 +1,460 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2018 Intel Corporation. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int get_key_path(struct ndctl_dimm *dimm, char *path, + enum ndctl_key_type key_type) +{ + char hostname[HOST_NAME_MAX]; + int rc; + + rc = gethostname(hostname, HOST_NAME_MAX); + if (rc < 0) { + fprintf(stderr, "gethostname: %s\n", strerror(errno)); + return -errno; + } + + if (key_type == ND_USER_OLD_KEY) { + rc = sprintf(path, "%s/nvdimmold_%s_%s.blob", + NDCTL_KEYS_DIR, + ndctl_dimm_get_unique_id(dimm), + hostname); + } else { + rc = sprintf(path, "%s/nvdimm_%s_%s.blob", + NDCTL_KEYS_DIR, + ndctl_dimm_get_unique_id(dimm), + hostname); + } + + if (rc < 0) { + fprintf(stderr, "error setting path: %s\n", strerror(errno)); + return -errno; + } + + return 0; +} + +static int get_key_desc(struct ndctl_dimm *dimm, char *desc, + enum ndctl_key_type key_type) +{ + int rc; + + if (key_type == ND_USER_OLD_KEY) + rc = sprintf(desc, "nvdimm-old:%s", + ndctl_dimm_get_unique_id(dimm)); + else + rc = sprintf(desc, "nvdimm:%s", + ndctl_dimm_get_unique_id(dimm)); + + if (rc < 0) { + fprintf(stderr, "error setting key description: %s\n", + strerror(errno)); + return -errno; + } + + return 0; +} + +static char *load_key_blob(const char *path, int *size) +{ + struct stat st; + FILE *bfile = NULL; + ssize_t read; + int rc; + char *blob, *pl; + char prefix[] = "load "; + + rc = stat(path, &st); + if (rc < 0) { + fprintf(stderr, "stat: %s\n", strerror(errno)); + return NULL; + } + if ((st.st_mode & S_IFMT) != S_IFREG) { + fprintf(stderr, "%s not a regular file\n", path); + return NULL; + } + + if (st.st_size == 0 || st.st_size > 4096) { + fprintf(stderr, "Invalid blob file size\n"); + return NULL; + } + + *size = st.st_size + sizeof(prefix) - 1; + blob = malloc(*size); + if (!blob) { + fprintf(stderr, "Unable to allocate memory for blob\n"); + return NULL; + } + + bfile = fopen(path, "r"); + if (!bfile) { + fprintf(stderr, "Unable to open %s: %s\n", path, strerror(errno)); + free(blob); + return NULL; + } + + memcpy(blob, prefix, sizeof(prefix) - 1); + pl = blob + sizeof(prefix) - 1; + read = fread(pl, st.st_size, 1, bfile); + if (read < 0) { + fprintf(stderr, "Failed to read from blob file: %s\n", + strerror(errno)); + free(blob); + fclose(bfile); + return NULL; + } + + fclose(bfile); + return blob; +} + +static key_serial_t dimm_check_key(struct ndctl_dimm *dimm, + enum ndctl_key_type key_type) +{ + char desc[ND_KEY_DESC_SIZE]; + int rc; + + rc = get_key_desc(dimm, desc, key_type); + if (rc < 0) + return rc; + + return keyctl_search(KEY_SPEC_USER_KEYRING, "encrypted", desc, 0); +} + +static key_serial_t dimm_create_key(struct ndctl_dimm *dimm, + const char *kek) +{ + char desc[ND_KEY_DESC_SIZE]; + char path[PATH_MAX]; + char cmd[ND_KEY_CMD_SIZE]; + key_serial_t key; + void *buffer; + int rc; + ssize_t size; + FILE *fp; + ssize_t wrote; + struct stat st; + + if (ndctl_dimm_is_active(dimm)) { + fprintf(stderr, "regions active on %s, op failed\n", + ndctl_dimm_get_devname(dimm)); + return -EBUSY; + } + + rc = get_key_desc(dimm, desc, ND_USER_KEY); + if (rc < 0) + return rc; + + /* make sure it's not already in the key ring */ + key = keyctl_search(KEY_SPEC_USER_KEYRING, "encrypted", desc, 0); + if (key > 0) { + fprintf(stderr, "Error: key already present in user keyring\n"); + return -EEXIST; + } + + rc = get_key_path(dimm, path, ND_USER_KEY); + if (rc < 0) + return rc; + + rc = stat(path, &st); + if (rc == 0) { + fprintf(stderr, "%s already exists!\n", path); + return -EEXIST; + } + + rc = sprintf(cmd, "new enc32 %s 32", kek); + if (rc < 0) { + fprintf(stderr, "sprintf: %s\n", strerror(errno)); + return -errno; + } + + key = add_key("encrypted", desc, cmd, strlen(cmd), + KEY_SPEC_USER_KEYRING); + if (key < 0) { + fprintf(stderr, "add_key failed: %s\n", strerror(errno)); + return -errno; + } + + size = keyctl_read_alloc(key, &buffer); + if (size < 0) { + fprintf(stderr, "keyctl_read_alloc failed: %s\n", strerror(errno)); + keyctl_unlink(key, KEY_SPEC_USER_KEYRING); + return rc; + } + + fp = fopen(path, "w"); + if (!fp) { + rc = -errno; + fprintf(stderr, "Unable to open file %s: %s\n", + path, strerror(errno)); + free(buffer); + return rc; + } + + wrote = fwrite(buffer, 1, size, fp); + if (wrote != size) { + if (wrote == -1) + rc = -errno; + else + rc = -EIO; + fprintf(stderr, "Failed to write to %s: %s\n", + path, strerror(-rc)); + free(buffer); + return rc; + } + + fclose(fp); + free(buffer); + return key; +} + +static key_serial_t dimm_load_key(struct ndctl_dimm *dimm, + enum ndctl_key_type key_type) +{ + key_serial_t key; + char desc[ND_KEY_DESC_SIZE]; + char path[PATH_MAX]; + int rc; + char *blob; + int size; + + if (ndctl_dimm_is_active(dimm)) { + fprintf(stderr, "regions active on %s, op failed\n", + ndctl_dimm_get_devname(dimm)); + return -EBUSY; + } + + rc = get_key_desc(dimm, desc, key_type); + if (rc < 0) + return rc; + + rc = get_key_path(dimm, path, key_type); + if (rc < 0) + return rc; + + blob = load_key_blob(path, &size); + if (!blob) + return -ENOMEM; + + key = add_key("encrypted", desc, blob, size, KEY_SPEC_USER_KEYRING); + free(blob); + if (key < 0) { + fprintf(stderr, "add_key failed: %s\n", strerror(errno)); + return -errno; + } + + return key; +} + +/* + * The function will check to see if the existing key is there and remove + * from user key ring if it is. Rename the existing key blob to old key + * blob, and then attempt to inject the key as old key into the user key + * ring. + */ +static key_serial_t move_key_to_old(struct ndctl_dimm *dimm) +{ + int rc; + key_serial_t key; + char old_path[PATH_MAX]; + char new_path[PATH_MAX]; + + if (ndctl_dimm_is_active(dimm)) { + fprintf(stderr, "regions active on %s, op failed\n", + ndctl_dimm_get_devname(dimm)); + return -EBUSY; + } + + key = dimm_check_key(dimm, ND_USER_KEY); + if (key > 0) + keyctl_unlink(key, KEY_SPEC_USER_KEYRING); + + rc = get_key_path(dimm, old_path, ND_USER_KEY); + if (rc < 0) + return rc; + + rc = get_key_path(dimm, new_path, ND_USER_OLD_KEY); + if (rc < 0) + return rc; + + rc = rename(old_path, new_path); + if (rc < 0) { + fprintf(stderr, "rename failed from %s to %s: %s\n", + old_path, new_path, strerror(errno)); + return -errno; + } + + return dimm_load_key(dimm, ND_USER_OLD_KEY); +} + +static int dimm_remove_key(struct ndctl_dimm *dimm, + enum ndctl_key_type key_type) +{ + key_serial_t key; + char path[PATH_MAX]; + int rc; + + key = dimm_check_key(dimm, key_type); + if (key > 0) + keyctl_unlink(key, KEY_SPEC_USER_KEYRING); + + rc = get_key_path(dimm, path, key_type); + if (rc < 0) + return rc; + + rc = unlink(path); + if (rc < 0) { + fprintf(stderr, "delete file %s failed: %s\n", + path, strerror(errno)); + return -errno; + } + + return 0; +} + +static int verify_kek(struct ndctl_dimm *dimm, const char *kek) +{ + char *type, *desc, *key_handle; + key_serial_t key; + + key_handle = strdup(kek); + if (!key_handle) + return -ENOMEM; + + type = strtok(key_handle, ":"); + if (!type) { + fprintf(stderr, "No key type found for kek handle\n"); + return -EINVAL; + } + + if (strcmp(type, "trusted") != 0 && + strcmp(type, "user") != 0) { + fprintf(stderr, "No such key type: %s", type); + return -EINVAL; + } + + desc = strtok(NULL, ":"); + if (!desc) { + fprintf(stderr, "No description found for kek handle\n"); + return -EINVAL; + } + + key = keyctl_search(KEY_SPEC_USER_KEYRING, type, desc, 0); + if (key < 0) { + fprintf(stderr, "No key encryption key found\n"); + return key; + } + + free(key_handle); + return 0; +} + +int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek) +{ + key_serial_t key; + int rc; + + rc = verify_kek(dimm, kek); + if (rc < 0) + return rc; + + key = dimm_create_key(dimm, kek); + if (key < 0) + return key; + + rc = ndctl_dimm_update_passphrase(dimm, 0, key); + if (rc < 0) { + dimm_remove_key(dimm, ND_USER_KEY); + return rc; + } + + return 0; +} + +static char *get_current_kek(struct ndctl_dimm *dimm) +{ + key_serial_t key; + char *key_buf; + long rc; + char *type, *desc; + + key = dimm_check_key(dimm, ND_USER_KEY); + if (key < 0) + return NULL; + + rc = keyctl_read_alloc(key, (void **)&key_buf); + if (rc < 0) + return NULL; + + rc = sscanf(key_buf, "%ms %ms", &type, &desc); + if (rc < 0) + return NULL; + + free(key_buf); + free(type); + + return desc; +} + +int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek) +{ + int rc; + key_serial_t old_key, new_key; + char *current_kek = NULL; + + if (kek) { + rc = verify_kek(dimm, kek); + if (rc < 0) + return rc; + } else { /* find current kek */ + current_kek = get_current_kek(dimm); + if (!current_kek) + return -ENOKEY; + } + + /* + * 1. check if current key is loaded and remove + * 2. move current key blob to old key blob + * 3. load old key blob + * 4. trigger change key with old and new key + * 5. remove old key + * 6. remove old key blob + */ + old_key = move_key_to_old(dimm); + if (old_key < 0) + return old_key; + + new_key = dimm_create_key(dimm, current_kek ? current_kek : kek); + free(current_kek); + /* need to create new key here */ + if (new_key < 0) { + new_key = dimm_load_key(dimm, ND_USER_KEY); + if (new_key < 0) + return new_key; + } + + rc = ndctl_dimm_update_passphrase(dimm, old_key, new_key); + if (rc < 0) + return rc; + + rc = dimm_remove_key(dimm, ND_USER_OLD_KEY); + if (rc < 0) + return rc; + + return 0; +} diff --git a/ndctl/util/keys.h b/ndctl/util/keys.h new file mode 100644 index 00000000..2cebdf0c --- /dev/null +++ b/ndctl/util/keys.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2019 Intel Corporation. All rights reserved. */ + +#ifndef _NDCTL_UTIL_KEYS_H_ +#define _NDCTL_UTIL_KEYS_H_ + +enum ndctl_key_type { + ND_USER_KEY, + ND_USER_OLD_KEY, +}; + +#ifdef ENABLE_KEYUTILS +int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek); +int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek); +#else +static inline int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, + const char *kek) +{ + return -EOPNOTSUPP; +} + +static inline int ndctl_dimm_update_key(struct ndctl_dimm *dimm, + const char *kek) +{ + return -EOPNOTSUPP; +} +#endif /* ENABLE_KEYUTILS */ + +#endif From patchwork Thu Jan 24 23:07:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780213 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 8924E13BF for ; Thu, 24 Jan 2019 23:07:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 75EFF2F4EF for ; Thu, 24 Jan 2019 23:07:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6A0192F525; Thu, 24 Jan 2019 23:07:24 +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 DACDA2F4EF for ; Thu, 24 Jan 2019 23:07:23 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id D1655211B85E5; Thu, 24 Jan 2019 15:07:23 -0800 (PST) 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 46CB9211B81B1 for ; Thu, 24 Jan 2019 15:07:22 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:21 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="121107544" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga003.jf.intel.com with ESMTP; 24 Jan 2019 15:07:21 -0800 Subject: [PATCH v10 03/12] ndctl: add disable security support From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:21 -0700 Message-ID: <154837124124.37086.11776825409363769095.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support for disable security to libndctl and also command line option of "disable-passphrase" for ndctl. This provides a way to disable security on the nvdimm. Signed-off-by: Dave Jiang --- Documentation/ndctl/Makefile.am | 3 ++- Documentation/ndctl/ndctl-remove-passphrase.txt | 26 ++++++++++++++++++++++ ndctl/builtin.h | 1 + ndctl/dimm.c | 23 ++++++++++++++++++++ ndctl/lib/dimm.c | 9 ++++++++ ndctl/lib/libndctl.sym | 1 + ndctl/libndctl.h | 1 + ndctl/ndctl.c | 1 + ndctl/util/keys.c | 27 +++++++++++++++++++++++ ndctl/util/keys.h | 6 +++++ 10 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 Documentation/ndctl/ndctl-remove-passphrase.txt diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am index 79b12f8b..3b543216 100644 --- a/Documentation/ndctl/Makefile.am +++ b/Documentation/ndctl/Makefile.am @@ -49,7 +49,8 @@ man1_MANS = \ ndctl-list.1 \ ndctl-monitor.1 \ ndctl-setup-passphrase.1 \ - ndctl-update-passphrase.1 + ndctl-update-passphrase.1 \ + ndctl-remove-passphrase.1 CLEANFILES = $(man1_MANS) diff --git a/Documentation/ndctl/ndctl-remove-passphrase.txt b/Documentation/ndctl/ndctl-remove-passphrase.txt new file mode 100644 index 00000000..17ff905b --- /dev/null +++ b/Documentation/ndctl/ndctl-remove-passphrase.txt @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 + +ndctl-remove-passphrase(1) +=========================== + +NAME +---- +ndctl-remove-passphrase - Stop a DIMM from locking at power-loss and requiring a passphrase to access media + +SYNOPSIS +-------- +[verse] +'ndctl remove-passphrase' [..] [] + +DESCRIPTION +----------- +Search the user key ring for the associated NVDIMM key. If not found, +attempt to load the key blob. After disabling the passphrase successfully, +remove the key and the key blob. + +OPTIONS +------- +:: +include::xable-dimm-options.txt[] + +include::../copyright.txt[] diff --git a/ndctl/builtin.h b/ndctl/builtin.h index 231fda25..9deb175b 100644 --- a/ndctl/builtin.h +++ b/ndctl/builtin.h @@ -34,4 +34,5 @@ int cmd_update_firmware(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_inject_smart(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_passphrase_setup(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_passphrase_update(int argc, const char **argv, struct ndctl_ctx *ctx); +int cmd_passphrase_remove(int argc, const char **argv, struct ndctl_ctx *ctx); #endif /* _NDCTL_BUILTIN_H_ */ diff --git a/ndctl/dimm.c b/ndctl/dimm.c index 88319b31..045f9408 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -865,6 +865,18 @@ static int action_passphrase_update(struct ndctl_dimm *dimm, return ndctl_dimm_update_key(dimm, param.kek); } +static int action_passphrase_remove(struct ndctl_dimm *dimm, + struct action_context *actx) +{ + if (ndctl_dimm_get_security(dimm) < 0) { + error("%s: security operation not supported\n", + ndctl_dimm_get_devname(dimm)); + return -EOPNOTSUPP; + } + + return ndctl_dimm_remove_key(dimm); +} + static int __action_init(struct ndctl_dimm *dimm, enum ndctl_namespace_version version, int chk_only) { @@ -1242,3 +1254,14 @@ int cmd_passphrase_setup(int argc, const char **argv, struct ndctl_ctx *ctx) count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } + +int cmd_passphrase_remove(int argc, const char **argv, void *ctx) +{ + int count = dimm_action(argc, argv, ctx, action_passphrase_remove, + base_options, + "ndctl remove-passphrase [..] []"); + + fprintf(stderr, "passphrase removed for %d nmem%s.\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index 72b6f66c..a944c9af 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -655,3 +655,12 @@ NDCTL_EXPORT int ndctl_dimm_update_passphrase(struct ndctl_dimm *dimm, sprintf(buf, "update %ld %ld\n", ckey, nkey); return write_security(dimm, buf); } + +NDCTL_EXPORT int ndctl_dimm_disable_passphrase(struct ndctl_dimm *dimm, + long key) +{ + char buf[SYSFS_ATTR_SIZE]; + + sprintf(buf, "disable %ld\n", key); + return write_security(dimm, buf); +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 88557710..79b7f9e1 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -392,4 +392,5 @@ global: ndctl_cmd_submit_xlat; ndctl_dimm_get_security; ndctl_dimm_update_passphrase; + ndctl_dimm_disable_passphrase; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index 85c1537a..0253abf5 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -700,6 +700,7 @@ enum ndctl_security_state { enum ndctl_security_state ndctl_dimm_get_security(struct ndctl_dimm *dimm); int ndctl_dimm_update_passphrase(struct ndctl_dimm *dimm, long ckey, long nkey); +int ndctl_dimm_disable_passphrase(struct ndctl_dimm *dimm, long key); #define ND_KEY_DESC_SIZE 128 #define ND_KEY_CMD_SIZE 128 diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c index 5cb5fa4f..9f4ab234 100644 --- a/ndctl/ndctl.c +++ b/ndctl/ndctl.c @@ -90,6 +90,7 @@ static struct cmd_struct commands[] = { { "start-scrub", { cmd_start_scrub } }, { "setup-passphrase", { cmd_passphrase_setup } }, { "update-passphrase", { cmd_passphrase_update } }, + { "remove-passphrase", { cmd_passphrase_remove } }, { "list", { cmd_list } }, { "monitor", { cmd_monitor } }, { "help", { cmd_help } }, diff --git a/ndctl/util/keys.c b/ndctl/util/keys.c index 1592ff09..daf8e418 100644 --- a/ndctl/util/keys.c +++ b/ndctl/util/keys.c @@ -458,3 +458,30 @@ int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek) return 0; } + +int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) +{ + key_serial_t key; + int rc; + + key = dimm_check_key(dimm, false); + if (key < 0) { + key = dimm_load_key(dimm, false); + if (key < 0) { + fprintf(stderr, "Unable to load key\n"); + return -ENOKEY; + } + } + + rc = ndctl_dimm_disable_passphrase(dimm, key); + if (rc < 0) { + fprintf(stderr, "Failed to disable security for %s\n", + ndctl_dimm_get_devname(dimm)); + return rc; + } + + rc = dimm_remove_key(dimm, false); + if (rc < 0) + fprintf(stderr, "Unable to cleanup key.\n"); + return 0; +} diff --git a/ndctl/util/keys.h b/ndctl/util/keys.h index 2cebdf0c..1ea428ef 100644 --- a/ndctl/util/keys.h +++ b/ndctl/util/keys.h @@ -12,6 +12,7 @@ enum ndctl_key_type { #ifdef ENABLE_KEYUTILS int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek); int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek); +int ndctl_dimm_remove_key(struct ndctl_dimm *dimm); #else static inline int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek) @@ -24,6 +25,11 @@ static inline int ndctl_dimm_update_key(struct ndctl_dimm *dimm, { return -EOPNOTSUPP; } + +static inline int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) +{ + return -EOPNOTSUPP; +} #endif /* ENABLE_KEYUTILS */ #endif From patchwork Thu Jan 24 23:07:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780215 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 9AE6313BF for ; Thu, 24 Jan 2019 23:07:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 870722F53C for ; Thu, 24 Jan 2019 23:07:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7AEE92F53E; Thu, 24 Jan 2019 23:07:29 +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 090542F53C for ; Thu, 24 Jan 2019 23:07:29 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id F3EB3211B85ED; Thu, 24 Jan 2019 15:07:28 -0800 (PST) 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 E0AF7211B81A5 for ; Thu, 24 Jan 2019 15:07:27 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:27 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="112451001" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga008.jf.intel.com with ESMTP; 24 Jan 2019 15:07:26 -0800 Subject: [PATCH v10 04/12] ndctl: add support for freeze security From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:26 -0700 Message-ID: <154837124676.37086.14569414098343817192.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support for freeze security to libndctl and also command line option of "freeze-security" for ndctl. This will lock the ability to make changes to the NVDIMM security. Signed-off-by: Dave Jiang --- Documentation/ndctl/Makefile.am | 3 + Documentation/ndctl/ndctl-freeze-security.txt | 58 +++++++++++++++++++++++++ ndctl/builtin.h | 1 ndctl/dimm.c | 28 ++++++++++++ ndctl/lib/dimm.c | 5 ++ ndctl/lib/libndctl.sym | 1 ndctl/libndctl.h | 1 ndctl/ndctl.c | 1 8 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 Documentation/ndctl/ndctl-freeze-security.txt diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am index 3b543216..0327726b 100644 --- a/Documentation/ndctl/Makefile.am +++ b/Documentation/ndctl/Makefile.am @@ -50,7 +50,8 @@ man1_MANS = \ ndctl-monitor.1 \ ndctl-setup-passphrase.1 \ ndctl-update-passphrase.1 \ - ndctl-remove-passphrase.1 + ndctl-remove-passphrase.1 \ + ndctl-freeze-security.1 CLEANFILES = $(man1_MANS) diff --git a/Documentation/ndctl/ndctl-freeze-security.txt b/Documentation/ndctl/ndctl-freeze-security.txt new file mode 100644 index 00000000..d14b8a39 --- /dev/null +++ b/Documentation/ndctl/ndctl-freeze-security.txt @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 + +ndctl-freeze-security(1) +======================== + +NAME +---- +ndctl-freeze-security - Set the given DIMM(s) to reject future security operations + +SYNOPSIS +-------- +[verse] +'ndctl freeze-security' [..] [] + +DESCRIPTION +----------- +Prevent any further security operations on the given DIMMs until the +next reboot. This is used in scenarios where the administrator has +taken all expected security actions for the current boot and wants the +DIMM to enforce / lock the current state. + +EXAMPLES +-------- + +[verse] +ndctl list -d nmem0 +[ + { + "dev":"nmem0", + "id":"cdab-0a-07e0-ffffffff", + "handle":0, + "phys_id":0, + "security":"unlocked" + } +] + +[verse] +ndctl freeze-security nmem0 +security freezed 1 nmem. + +[verse] +ndctl list -d nmem0 +[ + { + "dev":"nmem0", + "id":"cdab-0a-07e0-ffffffff", + "handle":0, + "phys_id":0, + "security":"frozen" + } +] + +OPTIONS +------- +:: +include::xable-dimm-options.txt[] + +include::../copyright.txt[] diff --git a/ndctl/builtin.h b/ndctl/builtin.h index 9deb175b..0f567b9b 100644 --- a/ndctl/builtin.h +++ b/ndctl/builtin.h @@ -35,4 +35,5 @@ int cmd_inject_smart(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_passphrase_setup(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_passphrase_update(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_passphrase_remove(int argc, const char **argv, struct ndctl_ctx *ctx); +int cmd_freeze_security(int argc, const char **argv, struct ndctl_ctx *ctx); #endif /* _NDCTL_BUILTIN_H_ */ diff --git a/ndctl/dimm.c b/ndctl/dimm.c index 045f9408..7105c539 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -877,6 +877,24 @@ static int action_passphrase_remove(struct ndctl_dimm *dimm, return ndctl_dimm_remove_key(dimm); } +static int action_security_freeze(struct ndctl_dimm *dimm, + struct action_context *actx) +{ + int rc; + + if (ndctl_dimm_get_security(dimm) < 0) { + error("%s: security operation not supported\n", + ndctl_dimm_get_devname(dimm)); + return -EOPNOTSUPP; + } + + rc = ndctl_dimm_freeze_security(dimm); + if (rc < 0) + error("Failed to freeze security for %s\n", + ndctl_dimm_get_devname(dimm)); + return rc; +} + static int __action_init(struct ndctl_dimm *dimm, enum ndctl_namespace_version version, int chk_only) { @@ -1265,3 +1283,13 @@ int cmd_passphrase_remove(int argc, const char **argv, void *ctx) count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } + +int cmd_freeze_security(int argc, const char **argv, void *ctx) +{ + int count = dimm_action(argc, argv, ctx, action_security_freeze, base_options, + "ndctl freeze-security [..] []"); + + fprintf(stderr, "security freezed %d nmem%s.\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index a944c9af..0a7eaaef 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -664,3 +664,8 @@ NDCTL_EXPORT int ndctl_dimm_disable_passphrase(struct ndctl_dimm *dimm, sprintf(buf, "disable %ld\n", key); return write_security(dimm, buf); } + +NDCTL_EXPORT int ndctl_dimm_freeze_security(struct ndctl_dimm *dimm) +{ + return write_security(dimm, "freeze"); +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 79b7f9e1..d882939c 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -393,4 +393,5 @@ global: ndctl_dimm_get_security; ndctl_dimm_update_passphrase; ndctl_dimm_disable_passphrase; + ndctl_dimm_freeze_security; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index 0253abf5..7afbca58 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -701,6 +701,7 @@ enum ndctl_security_state ndctl_dimm_get_security(struct ndctl_dimm *dimm); int ndctl_dimm_update_passphrase(struct ndctl_dimm *dimm, long ckey, long nkey); int ndctl_dimm_disable_passphrase(struct ndctl_dimm *dimm, long key); +int ndctl_dimm_freeze_security(struct ndctl_dimm *dimm); #define ND_KEY_DESC_SIZE 128 #define ND_KEY_CMD_SIZE 128 diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c index 9f4ab234..07903981 100644 --- a/ndctl/ndctl.c +++ b/ndctl/ndctl.c @@ -91,6 +91,7 @@ static struct cmd_struct commands[] = { { "setup-passphrase", { cmd_passphrase_setup } }, { "update-passphrase", { cmd_passphrase_update } }, { "remove-passphrase", { cmd_passphrase_remove } }, + { "freeze-security", { cmd_freeze_security } }, { "list", { cmd_list } }, { "monitor", { cmd_monitor } }, { "help", { cmd_help } }, From patchwork Thu Jan 24 23:07:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780217 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 CB8FD1399 for ; Thu, 24 Jan 2019 23:07:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B94F92F53C for ; Thu, 24 Jan 2019 23:07:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ADC0A2F552; Thu, 24 Jan 2019 23:07:34 +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 1F47C2F53C for ; Thu, 24 Jan 2019 23:07:34 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 16592211B85DC; Thu, 24 Jan 2019 15:07:34 -0800 (PST) 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.65; helo=mga03.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) (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 ADB11211B81A5 for ; Thu, 24 Jan 2019 15:07:33 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="313295557" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga006.fm.intel.com with ESMTP; 24 Jan 2019 15:07:32 -0800 Subject: [PATCH v10 05/12] ndctl: add support for sanitize dimm From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:32 -0700 Message-ID: <154837125227.37086.9954775396836100763.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support to secure erase to libndctl and also command line option of "sanitize-dimm" for ndctl. This will initiate the request to crypto erase a DIMM. Signed-off-by: Dave Jiang --- Documentation/ndctl/Makefile.am | 3 + Documentation/ndctl/ndctl-sanitize-dimm.txt | 34 +++++++++++++++ ndctl/builtin.h | 1 ndctl/dimm.c | 29 +++++++++++++ ndctl/lib/dimm.c | 8 ++++ ndctl/lib/libndctl.sym | 1 ndctl/libndctl.h | 1 ndctl/ndctl.c | 1 ndctl/util/keys.c | 61 +++++++++++++++++++++++++-- ndctl/util/keys.h | 6 +++ 10 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 Documentation/ndctl/ndctl-sanitize-dimm.txt diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am index 0327726b..fa4a1263 100644 --- a/Documentation/ndctl/Makefile.am +++ b/Documentation/ndctl/Makefile.am @@ -51,7 +51,8 @@ man1_MANS = \ ndctl-setup-passphrase.1 \ ndctl-update-passphrase.1 \ ndctl-remove-passphrase.1 \ - ndctl-freeze-security.1 + ndctl-freeze-security.1 \ + ndctl-sanitize-dimm.1 CLEANFILES = $(man1_MANS) diff --git a/Documentation/ndctl/ndctl-sanitize-dimm.txt b/Documentation/ndctl/ndctl-sanitize-dimm.txt new file mode 100644 index 00000000..633498ef --- /dev/null +++ b/Documentation/ndctl/ndctl-sanitize-dimm.txt @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 + +ndctl-sanitize-dimm(1) +====================== + +NAME +---- +ndctl-sanitize-dimm - Perform a cryptographic destruction of the contents of the given NVDIMM(s). + +SYNOPSIS +-------- +[verse] +'ndctl sanitize-dimm' [..] [] + +DESCRIPTION +----------- +Search the user key ring for the associated NVDIMM. If not found, +attempt to load the key blob from the default location. The sanitize +operation scrambles the data and info-blocks, but it does not touch +the namespace labels. The user should expect namespaces to revert to raw mode +after the region is next enabled following the operation. Security is disabled +for the dimm after operation and ndctl will remove the key from the key ring +and delete the associated key blob file. + +OPTIONS +------- +:: +include::xable-dimm-options.txt[] + +include::../copyright.txt[] + +SEE ALSO +-------- +https://trustedcomputinggroup.org/wp-content/uploads/TCG_SWG_SIIS_Version_1_07_Revision_1_00.pdf [Trusted Computing Group Storage Interface Interactions Specification] diff --git a/ndctl/builtin.h b/ndctl/builtin.h index 0f567b9b..a474ec1a 100644 --- a/ndctl/builtin.h +++ b/ndctl/builtin.h @@ -36,4 +36,5 @@ int cmd_passphrase_setup(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_passphrase_update(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_passphrase_remove(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_freeze_security(int argc, const char **argv, struct ndctl_ctx *ctx); +int cmd_sanitize_dimm(int argc, const char **argv, struct ndctl_ctx *ctx); #endif /* _NDCTL_BUILTIN_H_ */ diff --git a/ndctl/dimm.c b/ndctl/dimm.c index 7105c539..e7872f52 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -895,6 +895,24 @@ static int action_security_freeze(struct ndctl_dimm *dimm, return rc; } +static int action_sanitize_dimm(struct ndctl_dimm *dimm, + struct action_context *actx) +{ + int rc; + + if (ndctl_dimm_get_security(dimm) < 0) { + error("%s: security operation not supported\n", + ndctl_dimm_get_devname(dimm)); + return -EOPNOTSUPP; + } + + rc = ndctl_dimm_secure_erase_key(dimm); + if (rc < 0) + return rc; + + return 0; +} + static int __action_init(struct ndctl_dimm *dimm, enum ndctl_namespace_version version, int chk_only) { @@ -1293,3 +1311,14 @@ int cmd_freeze_security(int argc, const char **argv, void *ctx) count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } + +int cmd_sanitize_dimm(int argc, const char **argv, void *ctx) +{ + int count = dimm_action(argc, argv, ctx, action_sanitize_dimm, + base_options, + "ndctl sanitize-dimm [..] []"); + + fprintf(stderr, "sanitized %d nmem%s.\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index 0a7eaaef..50650738 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -669,3 +669,11 @@ NDCTL_EXPORT int ndctl_dimm_freeze_security(struct ndctl_dimm *dimm) { return write_security(dimm, "freeze"); } + +NDCTL_EXPORT int ndctl_dimm_secure_erase(struct ndctl_dimm *dimm, long key) +{ + char buf[SYSFS_ATTR_SIZE]; + + sprintf(buf, "erase %ld\n", key); + return write_security(dimm, buf); +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index d882939c..dd2dc747 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -394,4 +394,5 @@ global: ndctl_dimm_update_passphrase; ndctl_dimm_disable_passphrase; ndctl_dimm_freeze_security; + ndctl_dimm_secure_erase; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index 7afbca58..83e52b76 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -702,6 +702,7 @@ int ndctl_dimm_update_passphrase(struct ndctl_dimm *dimm, long ckey, long nkey); int ndctl_dimm_disable_passphrase(struct ndctl_dimm *dimm, long key); int ndctl_dimm_freeze_security(struct ndctl_dimm *dimm); +int ndctl_dimm_secure_erase(struct ndctl_dimm *dimm, long key); #define ND_KEY_DESC_SIZE 128 #define ND_KEY_CMD_SIZE 128 diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c index 07903981..0274e9b7 100644 --- a/ndctl/ndctl.c +++ b/ndctl/ndctl.c @@ -92,6 +92,7 @@ static struct cmd_struct commands[] = { { "update-passphrase", { cmd_passphrase_update } }, { "remove-passphrase", { cmd_passphrase_remove } }, { "freeze-security", { cmd_freeze_security } }, + { "sanitize-dimm", { cmd_sanitize_dimm } }, { "list", { cmd_list } }, { "monitor", { cmd_monitor } }, { "help", { cmd_help } }, diff --git a/ndctl/util/keys.c b/ndctl/util/keys.c index daf8e418..4e0ac607 100644 --- a/ndctl/util/keys.c +++ b/ndctl/util/keys.c @@ -459,10 +459,9 @@ int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek) return 0; } -int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) +static key_serial_t check_dimm_key(struct ndctl_dimm *dimm) { key_serial_t key; - int rc; key = dimm_check_key(dimm, false); if (key < 0) { @@ -473,15 +472,67 @@ int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) } } - rc = ndctl_dimm_disable_passphrase(dimm, key); + return key; +} + +static int run_key_op(struct ndctl_dimm *dimm, + key_serial_t key, + int (*run_op)(struct ndctl_dimm *, long), const char *name) +{ + int rc; + + rc = run_op(dimm, key); if (rc < 0) { - fprintf(stderr, "Failed to disable security for %s\n", + fprintf(stderr, "Failed %s for %s\n", name, ndctl_dimm_get_devname(dimm)); return rc; } + return 0; +} + +static int discard_key(struct ndctl_dimm *dimm) +{ + int rc; + rc = dimm_remove_key(dimm, false); - if (rc < 0) + if (rc < 0) { fprintf(stderr, "Unable to cleanup key.\n"); + return rc; + } return 0; } + +int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) +{ + key_serial_t key; + int rc; + + key = check_dimm_key(dimm); + if (key < 0) + return key; + + rc = run_key_op(dimm, key, ndctl_dimm_disable_passphrase, + "remove passphrase"); + if (rc < 0) + return rc; + + return discard_key(dimm); +} + +int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm) +{ + key_serial_t key; + int rc; + + key = check_dimm_key(dimm); + if (key < 0) + return key; + + rc = run_key_op(dimm, key, ndctl_dimm_secure_erase, + "crypto erase"); + if (rc < 0) + return rc; + + return discard_key(dimm); +} diff --git a/ndctl/util/keys.h b/ndctl/util/keys.h index 1ea428ef..9b60d678 100644 --- a/ndctl/util/keys.h +++ b/ndctl/util/keys.h @@ -13,6 +13,7 @@ enum ndctl_key_type { int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek); int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek); int ndctl_dimm_remove_key(struct ndctl_dimm *dimm); +int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm); #else static inline int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek) @@ -30,6 +31,11 @@ static inline int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) { return -EOPNOTSUPP; } + +static inline int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm) +{ + return -EOPNOTSUPP; +} #endif /* ENABLE_KEYUTILS */ #endif From patchwork Thu Jan 24 23:07:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780219 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 D1CD813BF for ; Thu, 24 Jan 2019 23:07:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BEB802F53C for ; Thu, 24 Jan 2019 23:07:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B30E02F552; Thu, 24 Jan 2019 23:07:39 +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 385192F53C for ; Thu, 24 Jan 2019 23:07:39 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 2EDFA211B85E0; Thu, 24 Jan 2019 15:07:39 -0800 (PST) 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.65; helo=mga03.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) (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 93D0E211B81A5 for ; Thu, 24 Jan 2019 15:07:38 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:38 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="141104152" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga001.fm.intel.com with ESMTP; 24 Jan 2019 15:07:38 -0800 Subject: [PATCH v10 06/12] ndctl: add unit test for security ops (minus overwrite) From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:37 -0700 Message-ID: <154837125793.37086.1862844997973456756.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add unit test for security enable, disable, update, erase, unlock, and freeze. Signed-off-by: Dave Jiang --- test/Makefile.am | 4 + test/security.sh | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100755 test/security.sh diff --git a/test/Makefile.am b/test/Makefile.am index ebdd23f6..42009c31 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -27,6 +27,10 @@ TESTS =\ max_available_extent_ns.sh \ pfn-meta-errors.sh +if ENABLE_KEYUTILS +TESTS += security.sh +endif + check_PROGRAMS =\ libndctl \ dsm-fail \ diff --git a/test/security.sh b/test/security.sh new file mode 100755 index 00000000..38b21183 --- /dev/null +++ b/test/security.sh @@ -0,0 +1,222 @@ +#!/bin/bash -Ex +# SPDX-License-Identifier: GPL-2.0 +# Copyright(c) 2018 Intel Corporation. All rights reserved. + +rc=77 +dev="" +id="" +keypath="/etc/ndctl/keys" +masterkey="nvdimm-master-test" +masterpath="$keypath/$masterkey" + +. ./common + +trap 'err $LINENO' ERR + +setup() +{ + $NDCTL disable-region -b "$NFIT_TEST_BUS0" all +} + +detect() +{ + dev="$($NDCTL list -b "$NFIT_TEST_BUS0" -D | jq -r .[0].dev)" + [ -n "$dev" ] || err "$LINENO" + id="$($NDCTL list -b "$NFIT_TEST_BUS0" -D | jq -r .[0].id)" + [ -n "$id" ] || err "$LINENO" +} + +setup_keys() +{ + if [ ! -d "$keypath" ]; then + mkdir -p "$keypath" + fi + + dd if=/dev/urandom bs=1 count=32 2>/dev/null | keyctl padd user "$masterkey" @u + keyctl pipe "$(keyctl search @u user $masterkey)" > "$masterpath" +} + +test_cleanup() +{ + if keyctl search @u encrypted nvdimm:"$id"; then + keyctl unlink "$(keyctl search @u encrypted nvdimm:"$id")" + fi + + if keyctl search @u user "$masterkey"; then + keyctl unlink "$(keyctl search @u user $masterkey)" + fi + + if [ -f "$keypath"/nvdimm_"$id"_"$(hostname)".blob ]; then + rm -f "$keypath"/nvdimm_"$id"_"$(hostname)".blob + fi + + if [ -f $masterpath ]; then + rm -f "$masterpath" + fi + + rm -f "$keypath"/"$NFIT_TEST_BUS0".kek +} + +lock_dimm() +{ + $NDCTL disable-dimm "$dev" + # convert nmemX --> test_dimmY + # for now this is the only user of such a conversion so we can leave it + # inline once a subsequent user arrives we can refactor this to a + # helper in test/common: + # get_test_dimm_path "nfit_test.0" "nmem3" + handle="$(ndctl list -b "$NFIT_TEST_BUS0" -d "$dev" -i | jq -r .[].dimms[0].handle)" + test_dimm_path="" + for test_dimm in /sys/devices/platform/"$NFIT_TEST_BUS0"/nfit_test_dimm/test_dimm*; do + td_handle_file="$test_dimm/handle" + test -e "$td_handle_file" || continue + td_handle="$(cat "$td_handle_file")" + if [[ "$td_handle" -eq "$handle" ]]; then + test_dimm_path="$test_dimm" + break + fi + done + test -d "$test_dimm_path" + + # now lock the dimm + echo 1 > "${test_dimm_path}/lock_dimm" + sstate="$(get_security_state)" + if [ "$sstate" != "locked" ]; then + echo "Incorrect security state: $sstate expected: locked" + err "$LINENO" + fi +} + +get_security_state() +{ + $NDCTL list -i -b "$NFIT_TEST_BUS0" -d "$dev" | jq -r .[].dimms[0].security +} + +setup_passphrase() +{ + $NDCTL setup-passphrase "$dev" -k user:"$masterkey" + sstate="$(get_security_state)" + if [ "$sstate" != "unlocked" ]; then + echo "Incorrect security state: $sstate expected: unlocked" + err "$LINENO" + fi +} + +remove_passphrase() +{ + $NDCTL remove-passphrase "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "disabled" ]; then + echo "Incorrect security state: $sstate expected: disabled" + err "$LINENO" + fi +} + +erase_security() +{ + $NDCTL sanitize-dimm -c "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "disabled" ]; then + echo "Incorrect security state: $sstate expected: disabled" + err "$LINENO" + fi +} + +update_security() +{ + $NDCTL update-passphrase "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "unlocked" ]; then + echo "Incorrect security state: $sstate expected: unlocked" + err "$LINENO" + fi +} + +freeze_security() +{ + $NDCTL freeze-security "$dev" +} + +test_1_security_setup_and_remove() +{ + setup_passphrase + remove_passphrase +} + +test_2_security_setup_and_update() +{ + setup_passphrase + update_security + remove_passphrase +} + +test_3_security_setup_and_erase() +{ + setup_passphrase + erase_security +} + +test_4_security_unlock() +{ + setup_passphrase + lock_dimm + $NDCTL enable-dimm "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "unlocked" ]; then + echo "Incorrect security state: $sstate expected: unlocked" + err "$LINENO" + fi + $NDCTL disable-region -b "$NFIT_TEST_BUS0" all + remove_passphrase +} + +# this should always be the last test. with security frozen, nfit_test must +# be removed and is no longer usable +test_5_security_freeze() +{ + setup_passphrase + freeze_security + sstate="$(get_security_state)" + if [ "$sstate" != "frozen" ]; then + echo "Incorrect security state: $sstate expected: frozen" + err "$LINENO" + fi + $NDCTL remove-passphrase "$dev" && { echo "remove succeed after frozen"; } + sstate="$(get_security_state)" + echo "$sstate" + if [ "$sstate" != "frozen" ]; then + echo "Incorrect security state: $sstate expected: frozen" + err "$LINENO" + fi +} + +check_min_kver "5.0" || do_skip "may lack security handling" +uid="$(keyctl show | grep -Eo "_uid.[0-9]+" | head -1 | cut -d. -f2-)" +if [ "$uid" -ne 0 ]; then + do_skip "run as root or with a sudo login shell for test to work" +fi + +modprobe nfit_test +setup +check_prereq "keyctl" +rc=1 +detect +test_cleanup +setup_keys +echo "Test 1, security setup and remove" +test_1_security_setup_and_remove +echo "Test 2, security setup, update, and remove" +test_2_security_setup_and_update +echo "Test 3, security setup and erase" +test_3_security_setup_and_erase +echo "Test 4, unlock dimm" +test_4_security_unlock + +# Freeze should always be run last because it locks security state and require +# nfit_test module unload. +echo "Test 5, freeze security" +test_5_security_freeze + +test_cleanup +_cleanup +exit 0 From patchwork Thu Jan 24 23:07:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780221 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 5519B13BF for ; Thu, 24 Jan 2019 23:07:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4077A2F53C for ; Thu, 24 Jan 2019 23:07:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 348C92F552; Thu, 24 Jan 2019 23:07:46 +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 4F4A82F53E for ; Thu, 24 Jan 2019 23:07:45 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 46076211B85EF; Thu, 24 Jan 2019 15:07:45 -0800 (PST) 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 5E23B211B81A5 for ; Thu, 24 Jan 2019 15:07:44 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:44 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="119273795" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga008.fm.intel.com with ESMTP; 24 Jan 2019 15:07:43 -0800 Subject: [PATCH v10 07/12] ndctl: add modprobe conf file and load-keys ndctl command From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:43 -0700 Message-ID: <154837126335.37086.2736147926414652351.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add load-keys command to ndctl. This will attempt to load the master key and the related encrypted keys for nvdimms. Also add reference config file for modprobe.d in order to call ndctl load-keys and inject keys associated with the nvdimms into the kernel user ring for unlock. Signed-off-by: Dave Jiang --- Documentation/ndctl/Makefile.am | 3 Documentation/ndctl/ndctl-load-keys.txt | 45 +++++ Makefile.am | 4 contrib/nvdimm-security.conf | 1 ndctl.spec.in | 1 ndctl/Makefile.am | 3 ndctl/builtin.h | 1 ndctl/load-keys.c | 256 +++++++++++++++++++++++++++++++ ndctl/ndctl.c | 1 ndctl/util/keys.c | 65 +++++--- ndctl/util/keys.h | 7 + test/security.sh | 2 12 files changed, 363 insertions(+), 26 deletions(-) create mode 100644 Documentation/ndctl/ndctl-load-keys.txt create mode 100644 contrib/nvdimm-security.conf create mode 100644 ndctl/load-keys.c diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am index fa4a1263..f64619b0 100644 --- a/Documentation/ndctl/Makefile.am +++ b/Documentation/ndctl/Makefile.am @@ -52,7 +52,8 @@ man1_MANS = \ ndctl-update-passphrase.1 \ ndctl-remove-passphrase.1 \ ndctl-freeze-security.1 \ - ndctl-sanitize-dimm.1 + ndctl-sanitize-dimm.1 \ + ndctl-load-keys.1 CLEANFILES = $(man1_MANS) diff --git a/Documentation/ndctl/ndctl-load-keys.txt b/Documentation/ndctl/ndctl-load-keys.txt new file mode 100644 index 00000000..d0221c4c --- /dev/null +++ b/Documentation/ndctl/ndctl-load-keys.txt @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 + +include::attrs.adoc[] + +ndctl-load-keys(1) +================== + +NAME +---- +ndctl-load-keys - load encrypted keys with security passphrases for NVDIMM + +SYNOPSIS +-------- +[verse] +'ndctl load-keys' [] + +DESCRIPTION +----------- +Provide a command to load the master key and the nvdimm encrypted keys for +NVDIMM security operations. This command is expected to be called during +initialization and before the libnvdimm kernel module is loaded. This works +in conjunction with the provided module config file. + +NOTE: All nvdimm keys files are expected to be in format of: +nvdimm__hostname +The char '_' is used to deliminate the components in the file name. The char +'_' can be used for any purpose starting with the hostname component and after. + +This command is typically never called directly by a user. It is only run via +modprobe during early init. + +OPTIONS +------- +-p:: +--key-path=:: + Path to where key related files reside. This parameter is optional + and the default is set to {ndctl_keysdir}. + +-t:: +--tpm-handle=:: + Provide the TPM handle (should be a string such as 0x81000001) can + be optional if the key path contains a file called tpm.handle which + has the handle. + +include::../copyright.txt[] diff --git a/Makefile.am b/Makefile.am index e0c463a3..df8797ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,6 +42,10 @@ bashcompletiondir = $(BASH_COMPLETION_DIR) dist_bashcompletion_DATA = contrib/ndctl endif +modprobe_file = contrib/nvdimm-security.conf +modprobedir = $(sysconfdir)/modprobe.d/ +modprobe_DATA = $(modprobe_file) + noinst_LIBRARIES = libccan.a libccan_a_SOURCES = \ ccan/str/str.h \ diff --git a/contrib/nvdimm-security.conf b/contrib/nvdimm-security.conf new file mode 100644 index 00000000..e2bb7c0a --- /dev/null +++ b/contrib/nvdimm-security.conf @@ -0,0 +1 @@ +install libnvdimm /usr/bin/ndctl load-keys ; /sbin/modprobe --ignore-install libnvdimm $CMDLINE_OPTS diff --git a/ndctl.spec.in b/ndctl.spec.in index c075a0a0..0c8d6b40 100644 --- a/ndctl.spec.in +++ b/ndctl.spec.in @@ -120,6 +120,7 @@ make check %{bashcompdir}/ %{_unitdir}/ndctl-monitor.service %{_sysconfdir}/ndctl/keys/ +%{_sysconfdir}/modprobe.d/nvdimm-security.conf %config(noreplace) %{_sysconfdir}/ndctl/monitor.conf diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am index 28b4e09b..cd3312ba 100644 --- a/ndctl/Makefile.am +++ b/ndctl/Makefile.am @@ -27,7 +27,8 @@ ndctl_SOURCES = ndctl.c \ monitor.c if ENABLE_KEYUTILS -ndctl_SOURCES += util/keys.c +ndctl_SOURCES += util/keys.c \ + load-keys.c endif if ENABLE_DESTRUCTIVE diff --git a/ndctl/builtin.h b/ndctl/builtin.h index a474ec1a..733f41a5 100644 --- a/ndctl/builtin.h +++ b/ndctl/builtin.h @@ -37,4 +37,5 @@ int cmd_passphrase_update(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_passphrase_remove(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_freeze_security(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_sanitize_dimm(int argc, const char **argv, struct ndctl_ctx *ctx); +int cmd_load_keys(int argc, const char **argv, struct ndctl_ctx *ctx); #endif /* _NDCTL_BUILTIN_H_ */ diff --git a/ndctl/load-keys.c b/ndctl/load-keys.c new file mode 100644 index 00000000..184fa2dd --- /dev/null +++ b/ndctl/load-keys.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2019 Intel Corporation. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct parameters { + const char *key_path; + const char *tpm_handle; +} param; + +enum key_type { + KEY_USER = 0, + KEY_TRUSTED, +}; + +static const char *key_names[] = {"user", "trusted"}; + +static struct loadkeys { + enum key_type key_type; + DIR *dir; + int dirfd; +} loadkey_ctx; + +static int load_master_key(struct loadkeys *lk_ctx, const char *keypath) +{ + key_serial_t key; + char *blob; + int size, rc; + char path[PATH_MAX]; + + rc = sprintf(path, "%s/nvdimm-master.blob", keypath); + if (rc < 0) + return -errno; + + if (param.tpm_handle) + lk_ctx->key_type = KEY_TRUSTED; + else + lk_ctx->key_type = KEY_USER; + + key = keyctl_search(KEY_SPEC_USER_KEYRING, + key_names[lk_ctx->key_type], "nvdimm-master", 0); + if (key > 0) /* check to see if key already loaded */ + return 0; + + if (key < 0 && errno != ENOKEY) { + fprintf(stderr, "keyctl_search() failed: %s\n", + strerror(errno)); + return -errno; + } + + blob = ndctl_load_key_blob(path, &size, param.tpm_handle, -1); + if (!blob) + return -ENOMEM; + + key = add_key(key_names[lk_ctx->key_type], "nvdimm-master", + blob, size, KEY_SPEC_USER_KEYRING); + free(blob); + if (key < 0) { + fprintf(stderr, "add_key failed: %s\n", strerror(errno)); + return -errno; + } + + printf("nvdimm master key loaded.\n"); + + return 0; +} + +static int load_dimm_keys(struct loadkeys *lk_ctx) +{ + int rc; + struct dirent *dent; + char *fname, *id, *blob; + char desc[ND_KEY_DESC_SIZE]; + int size, count = 0; + key_serial_t key; + + while ((dent = readdir(lk_ctx->dir)) != NULL) { + if (dent->d_type != DT_REG) + continue; + + fname = strdup(dent->d_name); + if (!fname) { + fprintf(stderr, "Unable to strdup %s\n", + dent->d_name); + return -ENOMEM; + } + + /* + * We want to pick up the second member of the file name + * as the nvdimm id. + */ + id = strtok(fname, "_"); + if (!id) + continue; + if (strcmp(id, "nvdimm") != 0) + continue; + id = strtok(NULL, "_"); + if (!id) + continue; + + blob = ndctl_load_key_blob(dent->d_name, &size, NULL, + lk_ctx->dirfd); + if (!blob) { + free(fname); + continue; + } + + rc = sprintf(desc, "nvdimm:%s", id); + if (rc < 0) { + free(fname); + free(blob); + continue; + } + + key = add_key("encrypted", desc, blob, size, + KEY_SPEC_USER_KEYRING); + if (key < 0) + fprintf(stderr, "add_key failed: %s\n", + strerror(errno)); + else + count++; + free(fname); + free(blob); + } + + printf("%d nvdimm keys loaded\n", count); + + return 0; +} + +static int check_tpm_handle(struct loadkeys *lk_ctx) +{ + int fd, rc; + FILE *fs; + char *buf; + + fd = openat(lk_ctx->dirfd, "tpm.handle", O_RDONLY); + if (fd < 0) + return -errno; + + fs = fdopen(fd, "r"); + if (!fs) { + fprintf(stderr, "Failed to open file stream: %s\n", + strerror(errno)); + return -errno; + } + + rc = fscanf(fs, "%ms", &buf); + if (rc < 0) { + rc = -errno; + fprintf(stderr, "Failed to read file: %s\n", strerror(errno)); + fclose(fs); + return rc; + } + + param.tpm_handle = buf; + fclose(fs); + return 0; +} + +static int load_keys(struct loadkeys *lk_ctx, const char *keypath, + const char *tpmhandle) +{ + int rc; + + rc = chdir(keypath); + if (rc < 0) { + rc = -errno; + fprintf(stderr, "Change current work dir to %s failed: %s\n", + param.key_path, strerror(errno)); + rc = -errno; + goto erropen; + } + + lk_ctx->dir = opendir(param.key_path); + if (!lk_ctx->dir) { + fprintf(stderr, "Unable to open dir %s: %s\n", + param.key_path, strerror(errno)); + rc = -errno; + goto erropen; + } + + lk_ctx->dirfd = open(param.key_path, O_DIRECTORY); + if (lk_ctx->dirfd < 0) { + fprintf(stderr, "Unable to open dir %s: %s\n", + param.key_path, strerror(errno)); + rc = -errno; + goto erropen; + } + + if (!tpmhandle) { + rc = check_tpm_handle(lk_ctx); + if (rc < 0) { + rc = -errno; + goto erropen; + } + } + + rc = load_master_key(lk_ctx, param.key_path); + if (rc < 0) + goto out; + + rc = load_dimm_keys(lk_ctx); + if (rc < 0) + goto out; + + out: + close(lk_ctx->dirfd); + erropen: + closedir(lk_ctx->dir); + return rc; +} + +int cmd_load_keys(int argc, const char **argv, struct ndctl_ctx *ctx) +{ + const struct option options[] = { + OPT_FILENAME('p', "key-path", ¶m.key_path, "key-path", + "override the default key path"), + OPT_STRING('t', "tpm-handle", ¶m.tpm_handle, "tpm-handle", + "TPM handle for trusted key"), + OPT_END(), + }; + const char *const u[] = { + "ndctl load-keys []", + NULL + }; + int i; + + argc = parse_options(argc, argv, options, u, 0); + for (i = 0; i < argc; i++) + error("unknown parameter \"%s\"\n", argv[i]); + if (argc) + usage_with_options(u, options); + + if (!param.key_path) + param.key_path = strdup(NDCTL_KEYS_DIR); + + return load_keys(&loadkey_ctx, param.key_path, param.tpm_handle); +} diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c index 0274e9b7..041f66be 100644 --- a/ndctl/ndctl.c +++ b/ndctl/ndctl.c @@ -93,6 +93,7 @@ static struct cmd_struct commands[] = { { "remove-passphrase", { cmd_passphrase_remove } }, { "freeze-security", { cmd_freeze_security } }, { "sanitize-dimm", { cmd_sanitize_dimm } }, + { "load-keys", { cmd_load_keys } }, { "list", { cmd_list } }, { "monitor", { cmd_monitor } }, { "help", { cmd_help } }, diff --git a/ndctl/util/keys.c b/ndctl/util/keys.c index 4e0ac607..6f3d0830 100644 --- a/ndctl/util/keys.c +++ b/ndctl/util/keys.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -70,16 +71,23 @@ static int get_key_desc(struct ndctl_dimm *dimm, char *desc, return 0; } -static char *load_key_blob(const char *path, int *size) +char *ndctl_load_key_blob(const char *path, int *size, const char *postfix, + int dirfd) { struct stat st; - FILE *bfile = NULL; - ssize_t read; - int rc; - char *blob, *pl; + ssize_t read_bytes = 0; + int rc, fd; + char *blob, *pl, *rdptr; char prefix[] = "load "; - rc = stat(path, &st); + fd = openat(dirfd, path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "failed to open file %s: %s\n", + path, strerror(errno)); + return NULL; + } + + rc = fstat(fd, &st); if (rc < 0) { fprintf(stderr, "stat: %s\n", strerror(errno)); return NULL; @@ -95,31 +103,44 @@ static char *load_key_blob(const char *path, int *size) } *size = st.st_size + sizeof(prefix) - 1; + /* + * We need to increment postfix and space. + * "keyhandle=" is 10 bytes, plus null termination. + */ + if (postfix) + *size += strlen(postfix) + 10 + 1; blob = malloc(*size); if (!blob) { fprintf(stderr, "Unable to allocate memory for blob\n"); return NULL; } - bfile = fopen(path, "r"); - if (!bfile) { - fprintf(stderr, "Unable to open %s: %s\n", path, strerror(errno)); - free(blob); - return NULL; - } - memcpy(blob, prefix, sizeof(prefix) - 1); pl = blob + sizeof(prefix) - 1; - read = fread(pl, st.st_size, 1, bfile); - if (read < 0) { - fprintf(stderr, "Failed to read from blob file: %s\n", - strerror(errno)); - free(blob); - fclose(bfile); - return NULL; + + rdptr = pl; + do { + rc = read(fd, rdptr, st.st_size - read_bytes); + if (rc < 0) { + fprintf(stderr, "Failed to read from blob file: %s\n", + strerror(errno)); + free(blob); + close(fd); + return NULL; + } + read_bytes += rc; + rdptr += rc; + } while (read_bytes != st.st_size); + + close(fd); + + if (postfix) { + pl += read_bytes; + *pl = ' '; + pl++; + rc = sprintf(pl, "keyhandle=%s", postfix); } - fclose(bfile); return blob; } @@ -247,7 +268,7 @@ static key_serial_t dimm_load_key(struct ndctl_dimm *dimm, if (rc < 0) return rc; - blob = load_key_blob(path, &size); + blob = ndctl_load_key_blob(path, &size, NULL, -1); if (!blob) return -ENOMEM; diff --git a/ndctl/util/keys.h b/ndctl/util/keys.h index 9b60d678..86bd2270 100644 --- a/ndctl/util/keys.h +++ b/ndctl/util/keys.h @@ -10,11 +10,18 @@ enum ndctl_key_type { }; #ifdef ENABLE_KEYUTILS +char *ndctl_load_key_blob(const char *path, int *size, const char *postfix, + int dirfd); int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek); int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek); int ndctl_dimm_remove_key(struct ndctl_dimm *dimm); int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm); #else +char *ndctl_load_key_blob(const char *path, int *size, const char *postfix, + int dirfd) +{ + return NULL; +} static inline int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek) { diff --git a/test/security.sh b/test/security.sh index 38b21183..abe948d5 100755 --- a/test/security.sh +++ b/test/security.sh @@ -53,8 +53,6 @@ test_cleanup() if [ -f $masterpath ]; then rm -f "$masterpath" fi - - rm -f "$keypath"/"$NFIT_TEST_BUS0".kek } lock_dimm() From patchwork Thu Jan 24 23:07:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780225 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 51BC91399 for ; Thu, 24 Jan 2019 23:08:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3C41F2F53C for ; Thu, 24 Jan 2019 23:08:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2DD382F55B; Thu, 24 Jan 2019 23:08:02 +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 73C402F53C for ; Thu, 24 Jan 2019 23:08:01 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 66DCD211B85E8; Thu, 24 Jan 2019 15:07:56 -0800 (PST) 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.115; helo=mga14.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) (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 51E5C211B81A5 for ; Thu, 24 Jan 2019 15:07:55 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:54 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="128373258" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by FMSMGA003.fm.intel.com with ESMTP; 24 Jan 2019 15:07:51 -0800 Subject: [PATCH v10 08/12] ndctl: add overwrite operation support From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:48 -0700 Message-ID: <154837126880.37086.14119056413058289612.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add support for overwrite to libndctl. The operation will be triggered by the sanitize-dimm command with -o switch. This will initiate the request to wipe the entire nvdimm. Success return of the command only indicate overwrite has started and does not indicate completion of overwrite. Signed-off-by: Dave Jiang --- Documentation/ndctl/ndctl-sanitize-dimm.txt | 26 +++++++++++---- ndctl/dimm.c | 46 +++++++++++++++++++++++---- ndctl/lib/dimm.c | 8 +++++ ndctl/lib/libndctl.sym | 1 + ndctl/libndctl.h | 1 + ndctl/util/keys.c | 33 ++++++++++++++++--- ndctl/util/keys.h | 6 ++++ 7 files changed, 101 insertions(+), 20 deletions(-) diff --git a/Documentation/ndctl/ndctl-sanitize-dimm.txt b/Documentation/ndctl/ndctl-sanitize-dimm.txt index 633498ef..b0b1ae21 100644 --- a/Documentation/ndctl/ndctl-sanitize-dimm.txt +++ b/Documentation/ndctl/ndctl-sanitize-dimm.txt @@ -5,7 +5,7 @@ ndctl-sanitize-dimm(1) NAME ---- -ndctl-sanitize-dimm - Perform a cryptographic destruction of the contents of the given NVDIMM(s). +ndctl-sanitize-dimm - Perform a cryptographic destruction or overwrite of the contents of the given NVDIMM(s). SYNOPSIS -------- @@ -14,19 +14,29 @@ SYNOPSIS DESCRIPTION ----------- -Search the user key ring for the associated NVDIMM. If not found, -attempt to load the key blob from the default location. The sanitize -operation scrambles the data and info-blocks, but it does not touch -the namespace labels. The user should expect namespaces to revert to raw mode -after the region is next enabled following the operation. Security is disabled -for the dimm after operation and ndctl will remove the key from the key ring -and delete the associated key blob file. +Two different sanitize methods are supported. One is the crypto-erase, which +is the default method, and the other is overwrite the NVDIMM. ndctl will +search the user key ring for the associated NVDIMM. If not found, +attempt to load the key blob from the default location. +Security is disabled for the dimm after operation and ndctl will remove +the key from the key ring and delete the associated key blob file. OPTIONS ------- :: include::xable-dimm-options.txt[] +-c:: +--crypto-erase:: + Replace the media encryption key causing all existing data to read as + cipher text with the new key. This does not change label data. + The user should expect namespaces to revert to raw mode + after the region is next enabled following the operation. + +-o:: +--ovewrite:: + Wipe the entire DIMM, including label data. Can take significant time. + include::../copyright.txt[] SEE ALSO diff --git a/ndctl/dimm.c b/ndctl/dimm.c index e7872f52..da940843 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -47,6 +47,8 @@ static struct parameters { const char *infile; const char *labelversion; const char *kek; + bool crypto_erase; + bool overwrite; bool force; bool json; bool verbose; @@ -906,9 +908,26 @@ static int action_sanitize_dimm(struct ndctl_dimm *dimm, return -EOPNOTSUPP; } - rc = ndctl_dimm_secure_erase_key(dimm); - if (rc < 0) - return rc; + /* + * Setting crypto erase to be default. The other method will be + * overwrite. + */ + if (!param.crypto_erase && !param.overwrite) { + param.crypto_erase = true; + printf("No santize method passed in, default to crypto-erase\n"); + } + + if (param.crypto_erase) { + rc = ndctl_dimm_secure_erase_key(dimm); + if (rc < 0) + return rc; + } + + if (param.overwrite) { + rc = ndctl_dimm_overwrite_key(dimm); + if (rc < 0) + return rc; + } return 0; } @@ -1006,6 +1025,12 @@ OPT_STRING('V', "label-version", ¶m.labelversion, "version-number", \ OPT_STRING('k', "key-handle", ¶m.kek, "key-handle", \ "master encryption key handle") +#define SANITIZE_OPTIONS() \ +OPT_BOOLEAN('c', "crypto-erase", ¶m.crypto_erase, \ + "crypto erase a dimm"), \ +OPT_BOOLEAN('o', "overwrite", ¶m.overwrite, \ + "overwrite a dimm") + static const struct option read_options[] = { BASE_OPTIONS(), READ_OPTIONS(), @@ -1038,6 +1063,11 @@ static const struct option init_options[] = { static const struct option key_options[] = { BASE_OPTIONS(), KEY_OPTIONS(), +}; + +static const struct option sanitize_options[] = { + BASE_OPTIONS(), + SANITIZE_OPTIONS(), OPT_END(), }; @@ -1315,10 +1345,14 @@ int cmd_freeze_security(int argc, const char **argv, void *ctx) int cmd_sanitize_dimm(int argc, const char **argv, void *ctx) { int count = dimm_action(argc, argv, ctx, action_sanitize_dimm, - base_options, + sanitize_options, "ndctl sanitize-dimm [..] []"); - fprintf(stderr, "sanitized %d nmem%s.\n", count >= 0 ? count : 0, - count > 1 ? "s" : ""); + if (param.overwrite) + fprintf(stderr, "overwrite issued for %d nmem%s.\n", + count >= 0 ? count : 0, count > 1 ? "s" : ""); + else + fprintf(stderr, "sanitized %d nmem%s.\n", + count >= 0 ? count : 0, count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index 50650738..d7b70ebf 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -677,3 +677,11 @@ NDCTL_EXPORT int ndctl_dimm_secure_erase(struct ndctl_dimm *dimm, long key) sprintf(buf, "erase %ld\n", key); return write_security(dimm, buf); } + +NDCTL_EXPORT int ndctl_dimm_overwrite(struct ndctl_dimm *dimm, long key) +{ + char buf[SYSFS_ATTR_SIZE]; + + sprintf(buf, "overwrite %ld\n", key); + return write_security(dimm, buf); +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index dd2dc747..732c621e 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -395,4 +395,5 @@ global: ndctl_dimm_disable_passphrase; ndctl_dimm_freeze_security; ndctl_dimm_secure_erase; + ndctl_dimm_overwrite; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index 83e52b76..b191ad4a 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -703,6 +703,7 @@ int ndctl_dimm_update_passphrase(struct ndctl_dimm *dimm, int ndctl_dimm_disable_passphrase(struct ndctl_dimm *dimm, long key); int ndctl_dimm_freeze_security(struct ndctl_dimm *dimm); int ndctl_dimm_secure_erase(struct ndctl_dimm *dimm, long key); +int ndctl_dimm_overwrite(struct ndctl_dimm *dimm, long key); #define ND_KEY_DESC_SIZE 128 #define ND_KEY_CMD_SIZE 128 diff --git a/ndctl/util/keys.c b/ndctl/util/keys.c index 6f3d0830..2f0d8861 100644 --- a/ndctl/util/keys.c +++ b/ndctl/util/keys.c @@ -480,19 +480,19 @@ int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek) return 0; } -static key_serial_t check_dimm_key(struct ndctl_dimm *dimm) +static key_serial_t check_dimm_key(struct ndctl_dimm *dimm, bool need_key) { key_serial_t key; key = dimm_check_key(dimm, false); if (key < 0) { key = dimm_load_key(dimm, false); - if (key < 0) { + if (key < 0 && need_key) { fprintf(stderr, "Unable to load key\n"); return -ENOKEY; - } + } else + key = 0; } - return key; } @@ -521,6 +521,7 @@ static int discard_key(struct ndctl_dimm *dimm) fprintf(stderr, "Unable to cleanup key.\n"); return rc; } + return 0; } @@ -529,7 +530,7 @@ int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) key_serial_t key; int rc; - key = check_dimm_key(dimm); + key = check_dimm_key(dimm, true); if (key < 0) return key; @@ -546,7 +547,7 @@ int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm) key_serial_t key; int rc; - key = check_dimm_key(dimm); + key = check_dimm_key(dimm, true); if (key < 0) return key; @@ -557,3 +558,23 @@ int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm) return discard_key(dimm); } + +int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm) +{ + key_serial_t key; + int rc; + + key = check_dimm_key(dimm, false); + if (key < 0) + return key; + + rc = run_key_op(dimm, key, ndctl_dimm_overwrite, + "overwrite"); + if (rc < 0) + return rc; + + if (key > 0) + return discard_key(dimm); + + return 0; +} diff --git a/ndctl/util/keys.h b/ndctl/util/keys.h index 86bd2270..bdb9d6d7 100644 --- a/ndctl/util/keys.h +++ b/ndctl/util/keys.h @@ -16,6 +16,7 @@ int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek); int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek); int ndctl_dimm_remove_key(struct ndctl_dimm *dimm); int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm); +int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm); #else char *ndctl_load_key_blob(const char *path, int *size, const char *postfix, int dirfd) @@ -43,6 +44,11 @@ static inline int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm) { return -EOPNOTSUPP; } + +static inline int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm) +{ + return -EOPNOTSUPP; +} #endif /* ENABLE_KEYUTILS */ #endif From patchwork Thu Jan 24 23:07:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780223 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 79D711399 for ; Thu, 24 Jan 2019 23:08:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5EF272F53C for ; Thu, 24 Jan 2019 23:08:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4EA3D2F552; Thu, 24 Jan 2019 23:08:00 +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 8AA7F2F53C for ; Thu, 24 Jan 2019 23:07:59 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 815FE211B85EB; Thu, 24 Jan 2019 15:07:59 -0800 (PST) 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.88; helo=mga01.intel.com; envelope-from=dave.jiang@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) (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 2A029211B81A5 for ; Thu, 24 Jan 2019 15:07:58 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:07:57 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="138564379" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga004.fm.intel.com with ESMTP; 24 Jan 2019 15:07:57 -0800 Subject: [PATCH v10 09/12] ndctl: add wait-overwrite support From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:07:57 -0700 Message-ID: <154837127722.37086.14094509373956136731.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add a blocking 'wait-overwrite' command to ndctl to let a user wait for an overwrite operation on a dimm to complete. Signed-off-by: Dave Jiang --- Documentation/ndctl/Makefile.am | 3 + Documentation/ndctl/ndctl-wait-overwrite.txt | 31 ++++++++++ ndctl/builtin.h | 1 ndctl/dimm.c | 27 +++++++++ ndctl/lib/dimm.c | 78 ++++++++++++++++++++++++++ ndctl/lib/libndctl.sym | 1 ndctl/libndctl.h | 1 ndctl/ndctl.c | 1 8 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 Documentation/ndctl/ndctl-wait-overwrite.txt diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am index f64619b0..2593dbdc 100644 --- a/Documentation/ndctl/Makefile.am +++ b/Documentation/ndctl/Makefile.am @@ -53,7 +53,8 @@ man1_MANS = \ ndctl-remove-passphrase.1 \ ndctl-freeze-security.1 \ ndctl-sanitize-dimm.1 \ - ndctl-load-keys.1 + ndctl-load-keys.1 \ + ndctl-wait-overwrite.1 CLEANFILES = $(man1_MANS) diff --git a/Documentation/ndctl/ndctl-wait-overwrite.txt b/Documentation/ndctl/ndctl-wait-overwrite.txt new file mode 100644 index 00000000..5d4c72ef --- /dev/null +++ b/Documentation/ndctl/ndctl-wait-overwrite.txt @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 + +ndctl-wait-overwrite(1) +======================= + +NAME +---- +ndctl-wait-overwrite - wait for nvdimm overwrite operation to complete + +SYNOPSIS +-------- +[verse] +'ndctl wait-overwrite' [] + +DESCRIPTION +----------- +The kernel provides a POLL(2) capable sysfs file ('security') to indicate +the state of overwrite. The 'ndctl wait-overwrite' operation waits for +a change in the state of the 'security' file across all specified dimms. + +OPTIONS +------- +-v:: +--verbose:: + Emit debug messages for the overwrite wait process + +include::../copyright.txt[] + +SEE ALSO +-------- +linkndctl:ndctl-sanitize-dimm[1] diff --git a/ndctl/builtin.h b/ndctl/builtin.h index 733f41a5..60c3623f 100644 --- a/ndctl/builtin.h +++ b/ndctl/builtin.h @@ -38,4 +38,5 @@ int cmd_passphrase_remove(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_freeze_security(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_sanitize_dimm(int argc, const char **argv, struct ndctl_ctx *ctx); int cmd_load_keys(int argc, const char **argv, struct ndctl_ctx *ctx); +int cmd_wait_overwrite(int argc, const char **argv, struct ndctl_ctx *ctx); #endif /* _NDCTL_BUILTIN_H_ */ diff --git a/ndctl/dimm.c b/ndctl/dimm.c index da940843..fb16e9c8 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -932,6 +932,24 @@ static int action_sanitize_dimm(struct ndctl_dimm *dimm, return 0; } +static int action_wait_overwrite(struct ndctl_dimm *dimm, + struct action_context *actx) +{ + int rc; + + if (ndctl_dimm_get_security(dimm) < 0) { + error("%s: security operation not supported\n", + ndctl_dimm_get_devname(dimm)); + return -EOPNOTSUPP; + } + + rc = ndctl_dimm_wait_overwrite(dimm); + if (rc == 1) + printf("%s: overwrite completed.\n", + ndctl_dimm_get_devname(dimm)); + return rc; +} + static int __action_init(struct ndctl_dimm *dimm, enum ndctl_namespace_version version, int chk_only) { @@ -1356,3 +1374,12 @@ int cmd_sanitize_dimm(int argc, const char **argv, void *ctx) count >= 0 ? count : 0, count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } + +int cmd_wait_overwrite(int argc, const char **argv, void *ctx) +{ + int count = dimm_action(argc, argv, ctx, action_wait_overwrite, + base_options, + "ndctl wait-overwrite [..] []"); + + return count >= 0 ? 0 : EXIT_FAILURE; +} diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index d7b70ebf..150e337a 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "private.h" static const char NSINDEX_SIGNATURE[] = "NAMESPACE_INDEX\0"; @@ -685,3 +686,80 @@ NDCTL_EXPORT int ndctl_dimm_overwrite(struct ndctl_dimm *dimm, long key) sprintf(buf, "overwrite %ld\n", key); return write_security(dimm, buf); } + +NDCTL_EXPORT int ndctl_dimm_wait_overwrite(struct ndctl_dimm *dimm) +{ + struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm); + struct pollfd fds; + char buf[SYSFS_ATTR_SIZE]; + int fd = 0, rc; + char *path = dimm->dimm_buf; + int len = dimm->buf_len; + + if (snprintf(path, len, "%s/security", dimm->dimm_path) >= len) { + err(ctx, "%s: buffer too small!\n", + ndctl_dimm_get_devname(dimm)); + return -ERANGE; + } + + fd = open(path, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + rc = -errno; + err(ctx, "open: %s\n", strerror(errno)); + return rc; + } + memset(&fds, 0, sizeof(fds)); + fds.fd = fd; + + rc = sysfs_read_attr(ctx, path, buf); + if (rc < 0) { + rc = -EOPNOTSUPP; + goto out; + } + /* skipping if we aren't in overwrite state */ + if (strcmp(buf, "overwrite") != 0) { + rc = 0; + goto out; + } + + for (;;) { + rc = sysfs_read_attr(ctx, path, buf); + if (rc < 0) { + rc = -EOPNOTSUPP; + break; + } + + if (strcmp(buf, "overwrite") == 0) { + rc = poll(&fds, 1, -1); + if (rc < 0) { + rc = -errno; + err(ctx, "poll error: %s\n", strerror(errno)); + break; + } + dbg(ctx, "poll wake: revents: %d\n", fds.revents); + if (pread(fd, buf, 1, 0) == -1) { + rc = -errno; + break; + } + fds.revents = 0; + } else { + if (strcmp(buf, "disabled") == 0) + rc = 1; + break; + } + } + + if (rc == 1) + dbg(ctx, "%s: overwrite complete\n", + ndctl_dimm_get_devname(dimm)); + else if (rc == 0) + dbg(ctx, "%s: ovewrite skipped\n", + ndctl_dimm_get_devname(dimm)); + else + dbg(ctx, "%s: overwrite error waiting for complete\n", + ndctl_dimm_get_devname(dimm)); + + out: + close(fd); + return rc; +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 732c621e..7bd4ba59 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -396,4 +396,5 @@ global: ndctl_dimm_freeze_security; ndctl_dimm_secure_erase; ndctl_dimm_overwrite; + ndctl_dimm_wait_overwrite; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index b191ad4a..f767d637 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -704,6 +704,7 @@ int ndctl_dimm_disable_passphrase(struct ndctl_dimm *dimm, long key); int ndctl_dimm_freeze_security(struct ndctl_dimm *dimm); int ndctl_dimm_secure_erase(struct ndctl_dimm *dimm, long key); int ndctl_dimm_overwrite(struct ndctl_dimm *dimm, long key); +int ndctl_dimm_wait_overwrite(struct ndctl_dimm *dimm); #define ND_KEY_DESC_SIZE 128 #define ND_KEY_CMD_SIZE 128 diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c index 041f66be..04bf56d6 100644 --- a/ndctl/ndctl.c +++ b/ndctl/ndctl.c @@ -94,6 +94,7 @@ static struct cmd_struct commands[] = { { "freeze-security", { cmd_freeze_security } }, { "sanitize-dimm", { cmd_sanitize_dimm } }, { "load-keys", { cmd_load_keys } }, + { "wait-overwrite", { cmd_wait_overwrite } }, { "list", { cmd_list } }, { "monitor", { cmd_monitor } }, { "help", { cmd_help } }, From patchwork Thu Jan 24 23:08:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780227 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 8F24113BF for ; Thu, 24 Jan 2019 23:08:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7B9192F552 for ; Thu, 24 Jan 2019 23:08:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6F6112F560; Thu, 24 Jan 2019 23:08:06 +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 A3D102F552 for ; Thu, 24 Jan 2019 23:08:05 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 99F11211B85F3; Thu, 24 Jan 2019 15:08:05 -0800 (PST) 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 BE8EB211B81A5 for ; Thu, 24 Jan 2019 15:08:03 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:08:03 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="119273842" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by fmsmga008.fm.intel.com with ESMTP; 24 Jan 2019 15:08:03 -0800 Subject: [PATCH v10 10/12] ndctl: master phassphrase management support From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:08:02 -0700 Message-ID: <154837128293.37086.5932470737495070880.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Adding master passphrase enabling and update to ndctl. This is a new feature from Intel DSM v1.8. Signed-off-by: Dave Jiang --- Documentation/ndctl/ndctl-setup-passphrase.txt | 5 + Documentation/ndctl/ndctl-update-passphrase.txt | 6 + ndctl/dimm.c | 13 ++- ndctl/lib/dimm.c | 9 ++ ndctl/lib/libndctl.sym | 1 ndctl/libndctl.h | 2 ndctl/util/keys.c | 117 +++++++++++++++++------ ndctl/util/keys.h | 12 ++ 8 files changed, 129 insertions(+), 36 deletions(-) diff --git a/Documentation/ndctl/ndctl-setup-passphrase.txt b/Documentation/ndctl/ndctl-setup-passphrase.txt index 1594f110..613e17a1 100644 --- a/Documentation/ndctl/ndctl-setup-passphrase.txt +++ b/Documentation/ndctl/ndctl-setup-passphrase.txt @@ -40,6 +40,11 @@ include::xable-dimm-options.txt[] i.e. trusted:nvdimm-master This key is expected to be loaded in the kernel's user keyring. +-m:: +--master-passphrase:: + Indicates that we are managing the master passphrase instead of the + user passphrase. + -v:: --verbose:: Emit debug messages for the namespace check process. diff --git a/Documentation/ndctl/ndctl-update-passphrase.txt b/Documentation/ndctl/ndctl-update-passphrase.txt index 05573968..8b5fc812 100644 --- a/Documentation/ndctl/ndctl-update-passphrase.txt +++ b/Documentation/ndctl/ndctl-update-passphrase.txt @@ -40,10 +40,14 @@ include::xable-dimm-options.txt[] This parameter is optional. If none provided, ndctl will determine the current key handle from the encrypted key for the NVDIMM. +-m:: +--master-passphrase:: + Parameter to indicate that we are managing the master passphrase + instead of the user passphrase. + -v:: --verbose:: Emit debug messages for the namespace check process. - include::../copyright.txt[] SEE ALSO: diff --git a/ndctl/dimm.c b/ndctl/dimm.c index fb16e9c8..c5c4a6cb 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -49,6 +49,7 @@ static struct parameters { const char *kek; bool crypto_erase; bool overwrite; + bool master_pass; bool force; bool json; bool verbose; @@ -852,7 +853,8 @@ static int action_passphrase_setup(struct ndctl_dimm *dimm, if (!param.kek) return -EINVAL; - return ndctl_dimm_setup_key(dimm, param.kek); + return ndctl_dimm_setup_key(dimm, param.kek, + param.master_pass ? ND_MASTER_KEY : ND_USER_KEY); } static int action_passphrase_update(struct ndctl_dimm *dimm, @@ -864,7 +866,8 @@ static int action_passphrase_update(struct ndctl_dimm *dimm, return -EOPNOTSUPP; } - return ndctl_dimm_update_key(dimm, param.kek); + return ndctl_dimm_update_key(dimm, param.kek, + param.master_pass ? ND_MASTER_KEY : ND_USER_KEY); } static int action_passphrase_remove(struct ndctl_dimm *dimm, @@ -1049,6 +1052,10 @@ OPT_BOOLEAN('c', "crypto-erase", ¶m.crypto_erase, \ OPT_BOOLEAN('o', "overwrite", ¶m.overwrite, \ "overwrite a dimm") +#define MASTER_OPTIONS() \ +OPT_BOOLEAN('m', "master-passphrase", ¶m.master_pass, \ + "use master passphrase") + static const struct option read_options[] = { BASE_OPTIONS(), READ_OPTIONS(), @@ -1081,11 +1088,13 @@ static const struct option init_options[] = { static const struct option key_options[] = { BASE_OPTIONS(), KEY_OPTIONS(), + MASTER_OPTIONS(), }; static const struct option sanitize_options[] = { BASE_OPTIONS(), SANITIZE_OPTIONS(), + MASTER_OPTIONS(), OPT_END(), }; diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index 150e337a..5c65d171 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -763,3 +763,12 @@ NDCTL_EXPORT int ndctl_dimm_wait_overwrite(struct ndctl_dimm *dimm) close(fd); return rc; } + +NDCTL_EXPORT int ndctl_dimm_update_master_passphrase(struct ndctl_dimm *dimm, + long ckey, long nkey) +{ + char buf[SYSFS_ATTR_SIZE]; + + sprintf(buf, "master_update %ld %ld\n", ckey, nkey); + return write_security(dimm, buf); +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 7bd4ba59..c9e530ba 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -397,4 +397,5 @@ global: ndctl_dimm_secure_erase; ndctl_dimm_overwrite; ndctl_dimm_wait_overwrite; + ndctl_dimm_update_master_passphrase; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index f767d637..893e92e4 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -705,6 +705,8 @@ int ndctl_dimm_freeze_security(struct ndctl_dimm *dimm); int ndctl_dimm_secure_erase(struct ndctl_dimm *dimm, long key); int ndctl_dimm_overwrite(struct ndctl_dimm *dimm, long key); int ndctl_dimm_wait_overwrite(struct ndctl_dimm *dimm); +int ndctl_dimm_update_master_passphrase(struct ndctl_dimm *dimm, + long ckey, long nkey); #define ND_KEY_DESC_SIZE 128 #define ND_KEY_CMD_SIZE 128 diff --git a/ndctl/util/keys.c b/ndctl/util/keys.c index 2f0d8861..44ad0391 100644 --- a/ndctl/util/keys.c +++ b/ndctl/util/keys.c @@ -30,16 +30,33 @@ static int get_key_path(struct ndctl_dimm *dimm, char *path, return -errno; } - if (key_type == ND_USER_OLD_KEY) { - rc = sprintf(path, "%s/nvdimmold_%s_%s.blob", + switch (key_type) { + case ND_USER_OLD_KEY: + rc = sprintf(path, "%s/nvdimm-old_%s_%s.blob", NDCTL_KEYS_DIR, ndctl_dimm_get_unique_id(dimm), hostname); - } else { + break; + case ND_USER_KEY: rc = sprintf(path, "%s/nvdimm_%s_%s.blob", NDCTL_KEYS_DIR, ndctl_dimm_get_unique_id(dimm), hostname); + break; + case ND_MASTER_OLD_KEY: + rc = sprintf(path, "%s/nvdimm-master-old_%s_%s.blob", + NDCTL_KEYS_DIR, + ndctl_dimm_get_unique_id(dimm), + hostname); + break; + case ND_MASTER_KEY: + rc = sprintf(path, "%s/nvdimm-master_%s_%s.blob", + NDCTL_KEYS_DIR, + ndctl_dimm_get_unique_id(dimm), + hostname); + break; + default: + return -EINVAL; } if (rc < 0) { @@ -55,12 +72,26 @@ static int get_key_desc(struct ndctl_dimm *dimm, char *desc, { int rc; - if (key_type == ND_USER_OLD_KEY) + switch (key_type) { + case ND_USER_OLD_KEY: rc = sprintf(desc, "nvdimm-old:%s", ndctl_dimm_get_unique_id(dimm)); - else + break; + case ND_USER_KEY: rc = sprintf(desc, "nvdimm:%s", ndctl_dimm_get_unique_id(dimm)); + break; + case ND_MASTER_OLD_KEY: + rc = sprintf(desc, "nvdimm-master-old:%s", + ndctl_dimm_get_unique_id(dimm)); + break; + case ND_MASTER_KEY: + rc = sprintf(desc, "nvdimm-master:%s", + ndctl_dimm_get_unique_id(dimm)); + break; + default: + return -EINVAL; + } if (rc < 0) { fprintf(stderr, "error setting key description: %s\n", @@ -158,7 +189,7 @@ static key_serial_t dimm_check_key(struct ndctl_dimm *dimm, } static key_serial_t dimm_create_key(struct ndctl_dimm *dimm, - const char *kek) + const char *kek, enum ndctl_key_type key_type) { char desc[ND_KEY_DESC_SIZE]; char path[PATH_MAX]; @@ -177,7 +208,7 @@ static key_serial_t dimm_create_key(struct ndctl_dimm *dimm, return -EBUSY; } - rc = get_key_desc(dimm, desc, ND_USER_KEY); + rc = get_key_desc(dimm, desc, key_type); if (rc < 0) return rc; @@ -188,7 +219,7 @@ static key_serial_t dimm_create_key(struct ndctl_dimm *dimm, return -EEXIST; } - rc = get_key_path(dimm, path, ND_USER_KEY); + rc = get_key_path(dimm, path, key_type); if (rc < 0) return rc; @@ -288,12 +319,14 @@ static key_serial_t dimm_load_key(struct ndctl_dimm *dimm, * blob, and then attempt to inject the key as old key into the user key * ring. */ -static key_serial_t move_key_to_old(struct ndctl_dimm *dimm) +static key_serial_t move_key_to_old(struct ndctl_dimm *dimm, + enum ndctl_key_type key_type) { int rc; key_serial_t key; char old_path[PATH_MAX]; char new_path[PATH_MAX]; + enum ndctl_key_type okey_type; if (ndctl_dimm_is_active(dimm)) { fprintf(stderr, "regions active on %s, op failed\n", @@ -301,15 +334,22 @@ static key_serial_t move_key_to_old(struct ndctl_dimm *dimm) return -EBUSY; } - key = dimm_check_key(dimm, ND_USER_KEY); + key = dimm_check_key(dimm, key_type); if (key > 0) keyctl_unlink(key, KEY_SPEC_USER_KEYRING); - rc = get_key_path(dimm, old_path, ND_USER_KEY); + if (key_type == ND_USER_KEY) + okey_type = ND_USER_OLD_KEY; + else if (key_type == ND_MASTER_KEY) + okey_type = ND_MASTER_OLD_KEY; + else + return -EINVAL; + + rc = get_key_path(dimm, old_path, key_type); if (rc < 0) return rc; - rc = get_key_path(dimm, new_path, ND_USER_OLD_KEY); + rc = get_key_path(dimm, new_path, okey_type); if (rc < 0) return rc; @@ -320,7 +360,7 @@ static key_serial_t move_key_to_old(struct ndctl_dimm *dimm) return -errno; } - return dimm_load_key(dimm, ND_USER_OLD_KEY); + return dimm_load_key(dimm, okey_type); } static int dimm_remove_key(struct ndctl_dimm *dimm, @@ -385,7 +425,8 @@ static int verify_kek(struct ndctl_dimm *dimm, const char *kek) return 0; } -int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek) +int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek, + enum ndctl_key_type key_type) { key_serial_t key; int rc; @@ -394,27 +435,31 @@ int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek) if (rc < 0) return rc; - key = dimm_create_key(dimm, kek); + key = dimm_create_key(dimm, kek, key_type); if (key < 0) return key; - rc = ndctl_dimm_update_passphrase(dimm, 0, key); + if (key_type == ND_MASTER_KEY) + rc = ndctl_dimm_update_master_passphrase(dimm, 0, key); + else + rc = ndctl_dimm_update_passphrase(dimm, 0, key); if (rc < 0) { - dimm_remove_key(dimm, ND_USER_KEY); + dimm_remove_key(dimm, key_type); return rc; } return 0; } -static char *get_current_kek(struct ndctl_dimm *dimm) +static char *get_current_kek(struct ndctl_dimm *dimm, + enum ndctl_key_type key_type) { key_serial_t key; char *key_buf; long rc; char *type, *desc; - key = dimm_check_key(dimm, ND_USER_KEY); + key = dimm_check_key(dimm, key_type); if (key < 0) return NULL; @@ -432,22 +477,31 @@ static char *get_current_kek(struct ndctl_dimm *dimm) return desc; } -int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek) +int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek, + enum ndctl_key_type key_type) { int rc; key_serial_t old_key, new_key; char *current_kek = NULL; + enum ndctl_key_type okey_type; if (kek) { rc = verify_kek(dimm, kek); if (rc < 0) return rc; } else { /* find current kek */ - current_kek = get_current_kek(dimm); + current_kek = get_current_kek(dimm, key_type); if (!current_kek) return -ENOKEY; } + if (key_type == ND_USER_KEY) + okey_type = ND_USER_OLD_KEY; + else if (key_type == ND_MASTER_KEY) + okey_type = ND_MASTER_OLD_KEY; + else + return -EINVAL; + /* * 1. check if current key is loaded and remove * 2. move current key blob to old key blob @@ -456,24 +510,29 @@ int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek) * 5. remove old key * 6. remove old key blob */ - old_key = move_key_to_old(dimm); + old_key = move_key_to_old(dimm, key_type); if (old_key < 0) return old_key; - new_key = dimm_create_key(dimm, current_kek ? current_kek : kek); + new_key = dimm_create_key(dimm, current_kek ? current_kek : kek, + key_type); free(current_kek); /* need to create new key here */ if (new_key < 0) { - new_key = dimm_load_key(dimm, ND_USER_KEY); + new_key = dimm_load_key(dimm, key_type); if (new_key < 0) return new_key; } - rc = ndctl_dimm_update_passphrase(dimm, old_key, new_key); + if (key_type == ND_MASTER_KEY) + rc = ndctl_dimm_update_master_passphrase(dimm, + old_key, new_key); + else + rc = ndctl_dimm_update_passphrase(dimm, old_key, new_key); if (rc < 0) return rc; - rc = dimm_remove_key(dimm, ND_USER_OLD_KEY); + rc = dimm_remove_key(dimm, okey_type); if (rc < 0) return rc; @@ -484,9 +543,9 @@ static key_serial_t check_dimm_key(struct ndctl_dimm *dimm, bool need_key) { key_serial_t key; - key = dimm_check_key(dimm, false); + key = dimm_check_key(dimm, ND_USER_KEY); if (key < 0) { - key = dimm_load_key(dimm, false); + key = dimm_load_key(dimm, ND_USER_KEY); if (key < 0 && need_key) { fprintf(stderr, "Unable to load key\n"); return -ENOKEY; @@ -516,7 +575,7 @@ static int discard_key(struct ndctl_dimm *dimm) { int rc; - rc = dimm_remove_key(dimm, false); + rc = dimm_remove_key(dimm, ND_USER_KEY); if (rc < 0) { fprintf(stderr, "Unable to cleanup key.\n"); return rc; diff --git a/ndctl/util/keys.h b/ndctl/util/keys.h index bdb9d6d7..e445902d 100644 --- a/ndctl/util/keys.h +++ b/ndctl/util/keys.h @@ -7,13 +7,17 @@ enum ndctl_key_type { ND_USER_KEY, ND_USER_OLD_KEY, + ND_MASTER_KEY, + ND_MASTER_OLD_KEY, }; #ifdef ENABLE_KEYUTILS char *ndctl_load_key_blob(const char *path, int *size, const char *postfix, int dirfd); -int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek); -int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek); +int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek, + enum ndctl_key_type key_type); +int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek, + enum ndctl_key_type key_type); int ndctl_dimm_remove_key(struct ndctl_dimm *dimm); int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm); int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm); @@ -24,13 +28,13 @@ char *ndctl_load_key_blob(const char *path, int *size, const char *postfix, return NULL; } static inline int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, - const char *kek) + const char *kek, enum ndctl_key_type key_type) { return -EOPNOTSUPP; } static inline int ndctl_dimm_update_key(struct ndctl_dimm *dimm, - const char *kek) + const char *kek, enum ndctl_key_type key_type) { return -EOPNOTSUPP; } From patchwork Thu Jan 24 23:08:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780229 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 7871013BF for ; Thu, 24 Jan 2019 23:08:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 672DE2F552 for ; Thu, 24 Jan 2019 23:08:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5B9AF2F655; Thu, 24 Jan 2019 23:08:12 +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 C39032F552 for ; Thu, 24 Jan 2019 23:08:11 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id BAB6A211BA442; Thu, 24 Jan 2019 15:08:11 -0800 (PST) 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 D2AD0211B85EE for ; Thu, 24 Jan 2019 15:08:09 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:08:09 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="128686774" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by orsmga002.jf.intel.com with ESMTP; 24 Jan 2019 15:08:08 -0800 Subject: [PATCH v10 11/12] ndctl: add master secure erase support From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:08:08 -0700 Message-ID: <154837128868.37086.9305797391638685075.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Intel DSM v1.8 introduced the concept of master passphrase and allowing nvdimm to be secure erased via the master passphrase in addition to the user passphrase. Add ndctl support to provide master passphrase secure erase. Signed-off-by: Dave Jiang --- Documentation/ndctl/ndctl-sanitize-dimm.txt | 6 +++++ ndctl/dimm.c | 13 ++++++++++- ndctl/lib/dimm.c | 9 ++++++++ ndctl/lib/libndctl.sym | 1 + ndctl/libndctl.h | 1 + ndctl/util/keys.c | 31 ++++++++++++++++++--------- ndctl/util/keys.h | 6 +++-- 7 files changed, 53 insertions(+), 14 deletions(-) diff --git a/Documentation/ndctl/ndctl-sanitize-dimm.txt b/Documentation/ndctl/ndctl-sanitize-dimm.txt index b0b1ae21..78e1eb37 100644 --- a/Documentation/ndctl/ndctl-sanitize-dimm.txt +++ b/Documentation/ndctl/ndctl-sanitize-dimm.txt @@ -37,6 +37,12 @@ include::xable-dimm-options.txt[] --ovewrite:: Wipe the entire DIMM, including label data. Can take significant time. +-M:: +--master_passphrase:: + Parameter to indicate that we are managing the master passphrase + instead of the user passphrase. This only is applicable to the + crypto-erase option. + include::../copyright.txt[] SEE ALSO diff --git a/ndctl/dimm.c b/ndctl/dimm.c index c5c4a6cb..d4e2090f 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -911,6 +911,12 @@ static int action_sanitize_dimm(struct ndctl_dimm *dimm, return -EOPNOTSUPP; } + if (param.overwrite && param.master_pass) { + error("%s: overwrite does not support master passphrase\n", + ndctl_dimm_get_devname(dimm)); + return -EINVAL; + } + /* * Setting crypto erase to be default. The other method will be * overwrite. @@ -921,7 +927,8 @@ static int action_sanitize_dimm(struct ndctl_dimm *dimm, } if (param.crypto_erase) { - rc = ndctl_dimm_secure_erase_key(dimm); + rc = ndctl_dimm_secure_erase_key(dimm, param.master_pass ? + ND_MASTER_KEY : ND_USER_KEY); if (rc < 0) return rc; } @@ -1050,7 +1057,9 @@ OPT_STRING('k', "key-handle", ¶m.kek, "key-handle", \ OPT_BOOLEAN('c', "crypto-erase", ¶m.crypto_erase, \ "crypto erase a dimm"), \ OPT_BOOLEAN('o', "overwrite", ¶m.overwrite, \ - "overwrite a dimm") + "overwrite a dimm"), \ +OPT_BOOLEAN('M', "master-passphrase", ¶m.master_pass, \ + "use master passphrase") #define MASTER_OPTIONS() \ OPT_BOOLEAN('m', "master-passphrase", ¶m.master_pass, \ diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c index 5c65d171..0a4ca797 100644 --- a/ndctl/lib/dimm.c +++ b/ndctl/lib/dimm.c @@ -772,3 +772,12 @@ NDCTL_EXPORT int ndctl_dimm_update_master_passphrase(struct ndctl_dimm *dimm, sprintf(buf, "master_update %ld %ld\n", ckey, nkey); return write_security(dimm, buf); } + +NDCTL_EXPORT int ndctl_dimm_master_secure_erase(struct ndctl_dimm *dimm, + long key) +{ + char buf[SYSFS_ATTR_SIZE]; + + sprintf(buf, "master_erase %ld\n", key); + return write_security(dimm, buf); +} diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index c9e530ba..014da63a 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -398,4 +398,5 @@ global: ndctl_dimm_overwrite; ndctl_dimm_wait_overwrite; ndctl_dimm_update_master_passphrase; + ndctl_dimm_master_secure_erase; } LIBNDCTL_18; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index 893e92e4..d220aa3d 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -707,6 +707,7 @@ int ndctl_dimm_overwrite(struct ndctl_dimm *dimm, long key); int ndctl_dimm_wait_overwrite(struct ndctl_dimm *dimm); int ndctl_dimm_update_master_passphrase(struct ndctl_dimm *dimm, long ckey, long nkey); +int ndctl_dimm_master_secure_erase(struct ndctl_dimm *dimm, long key); #define ND_KEY_DESC_SIZE 128 #define ND_KEY_CMD_SIZE 128 diff --git a/ndctl/util/keys.c b/ndctl/util/keys.c index 44ad0391..85818c07 100644 --- a/ndctl/util/keys.c +++ b/ndctl/util/keys.c @@ -539,13 +539,14 @@ int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek, return 0; } -static key_serial_t check_dimm_key(struct ndctl_dimm *dimm, bool need_key) +static key_serial_t check_dimm_key(struct ndctl_dimm *dimm, bool need_key, + enum ndctl_key_type key_type) { key_serial_t key; - key = dimm_check_key(dimm, ND_USER_KEY); + key = dimm_check_key(dimm, key_type); if (key < 0) { - key = dimm_load_key(dimm, ND_USER_KEY); + key = dimm_load_key(dimm, key_type); if (key < 0 && need_key) { fprintf(stderr, "Unable to load key\n"); return -ENOKEY; @@ -589,7 +590,7 @@ int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) key_serial_t key; int rc; - key = check_dimm_key(dimm, true); + key = check_dimm_key(dimm, true, ND_USER_KEY); if (key < 0) return key; @@ -601,21 +602,31 @@ int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) return discard_key(dimm); } -int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm) +int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm, + enum ndctl_key_type key_type) { key_serial_t key; int rc; - key = check_dimm_key(dimm, true); + key = check_dimm_key(dimm, true, key_type); if (key < 0) return key; - rc = run_key_op(dimm, key, ndctl_dimm_secure_erase, - "crypto erase"); + if (key_type == ND_MASTER_KEY) + rc = run_key_op(dimm, key, ndctl_dimm_master_secure_erase, + "master crypto erase"); + else if (key_type == ND_USER_KEY) + rc = run_key_op(dimm, key, ndctl_dimm_secure_erase, + "crypto erase"); + else + rc = -EINVAL; if (rc < 0) return rc; - return discard_key(dimm); + if (key_type == ND_USER_KEY) + return discard_key(dimm); + + return 0; } int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm) @@ -623,7 +634,7 @@ int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm) key_serial_t key; int rc; - key = check_dimm_key(dimm, false); + key = check_dimm_key(dimm, false, ND_USER_KEY); if (key < 0) return key; diff --git a/ndctl/util/keys.h b/ndctl/util/keys.h index e445902d..c4d57eae 100644 --- a/ndctl/util/keys.h +++ b/ndctl/util/keys.h @@ -19,7 +19,8 @@ int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek, int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek, enum ndctl_key_type key_type); int ndctl_dimm_remove_key(struct ndctl_dimm *dimm); -int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm); +int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm, + enum ndctl_key_type key_type); int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm); #else char *ndctl_load_key_blob(const char *path, int *size, const char *postfix, @@ -44,7 +45,8 @@ static inline int ndctl_dimm_remove_key(struct ndctl_dimm *dimm) return -EOPNOTSUPP; } -static inline int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm) +static inline int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm, + enum ndctl_key_type key_type); { return -EOPNOTSUPP; } From patchwork Thu Jan 24 23:08:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 10780231 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 B54041399 for ; Thu, 24 Jan 2019 23:08:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A29892F552 for ; Thu, 24 Jan 2019 23:08:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 96DF12F655; Thu, 24 Jan 2019 23:08:17 +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 DBF422F552 for ; Thu, 24 Jan 2019 23:08:16 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id D19EC211B85EE; Thu, 24 Jan 2019 15:08:16 -0800 (PST) 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 89FBB211B81A5 for ; Thu, 24 Jan 2019 15:08:15 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jan 2019 15:08:15 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,518,1539673200"; d="scan'208";a="128373318" Received: from djiang5-desk3.ch.intel.com ([143.182.136.93]) by FMSMGA003.fm.intel.com with ESMTP; 24 Jan 2019 15:08:14 -0800 Subject: [PATCH v10 12/12] ndctl: documentation for security and key management From: Dave Jiang To: vishal.l.verma@intel.com, dan.j.williams@intel.com Date: Thu, 24 Jan 2019 16:08:14 -0700 Message-ID: <154837129419.37086.7272462682866063370.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <154837084784.37086.4597479371733088393.stgit@djiang5-desk3.ch.intel.com> References: <154837084784.37086.4597479371733088393.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: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Add a "Theory of Operation" section describing the Intel DSM operations to the relevant man pages. Signed-off-by: Dave Jiang --- Documentation/ndctl/intel-nvdimm-security.txt | 141 +++++++++++++++++++++++ Documentation/ndctl/ndctl-freeze-security.txt | 2 Documentation/ndctl/ndctl-remove-passphrase.txt | 2 Documentation/ndctl/ndctl-sanitize-dimm.txt | 2 Documentation/ndctl/ndctl-setup-passphrase.txt | 2 Documentation/ndctl/ndctl-update-passphrase.txt | 3 6 files changed, 152 insertions(+) create mode 100644 Documentation/ndctl/intel-nvdimm-security.txt diff --git a/Documentation/ndctl/intel-nvdimm-security.txt b/Documentation/ndctl/intel-nvdimm-security.txt new file mode 100644 index 00000000..dc114df9 --- /dev/null +++ b/Documentation/ndctl/intel-nvdimm-security.txt @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 + +include::attrs.adoc[] + +THEORY OF OPERATOIN +------------------- +With the introduction of Intel Device Specific Methods (DSM) specification +v1.7 and v1.8 [1], security DSMs were introduced. The operations supported by +ndctl are enable passhprase, update passphrase, disable security, +freeze security, secure (crypto) erase, overwrite, master passphrase enable, +master passphrase update, and master passphrase secure (crypto) erase. +The 'unlock' DSM is not supported by ndctl, that is left for the kernel to +manage with some assistance from userspace. + +The security management for nvdimm is composed of two parts. The front end +utilizes the Linux key management framework (trusted and encrypted keys [2]). +It uses the keyutils on the user side and Linux key management APIs in +the kernel. The backend takes the decrypted payload of the key and passes the +plaintext payload to the nvdimm for processing. + +Unlike typical DSMs, the security DSMs are managed through the 'security' +sysfs attribute under the dimm devices rather than an ioctl call by libndctl. +The relevant key id is written to the 'security' attribute and the kernel will +pull that key from the kernel's user key ring for processing. + +The entire security process starts with a master key that is used to seal the +encrypted keys that are used to protect the passphrase for each nvdimm. We +recommend using the *system* master key from the Trusted Platform +Module (TPM), but a master key generated by the TPM can also +be used. For testing purposes a user key with randomized payload can +also be served as a master key. See [2] for details. To perform any security +operations, it is expected that at the minimum the master key is already +in the kernel's user keyring as shown in example below: + +> keyctl show +Session Keyring + 736023423 --alswrv 0 0 keyring: _ses + 675104189 --alswrv 0 65534 \_ keyring: _uid.0 + 680187394 --alswrv 0 0 \_ trusted: nvdimm-master + +Except for 'overwrite', all operations expect the relevant regions associated +with the nvdimm are disabled before proceeding. For 'overwrite', in addition +to the regions, the dimm itself is expected to be disabled. + +The following sections describe specifics of each security features. + +UNLOCK +------ +Unlock is performed by the kernel, however a preparation step must happen +before the unlock DSM can be issued by the kernel. The expectation is that +during initramfs, a setup script is called before the libnvdimm module is +loaded by modprobe. This script script will inject the master key and the +related encrypted keys into the kernel's user key ring. A reference modprobe +config file and a setup script have been provided by ndctl. During the 'probe' +of the nvdimm driver, it will: +1. First, check the security state of the device and see if the DIMM is locked +2. Request the associated encrypted key from the kernel's user key ring. +3. Finally, create the unlock DSM, copy the decrypted payload into the DSM + passphrase field, and issue the DSM to unlock the DIMM. + +If the DIMM is already unlocked, the kernel will attempt to revalidate the key. +This can be overriden with a kernel module parameter. If we fail to revalidate +the key, the kernel will freeze the security and disallow any further security +configuration changes. + +SETUP USER PASSPHRASE +---------------------- +To setup the user passphrase for a DIMM, it is expected that the master key +is already in the kernel's user key ring and the master key name is passed to +ndctl so it can do key management. An encrypted key with a 32 bytes payload +and encrypted key format 'enc32' is created and sealed by the master key. Be +aware that the passphrase is never provided by or visible to the user. +The decrypted payload for the encrypted key will be randomly generated by the +kernel and userspace does not have access to this decrypted payload. When the +encrypted key is created, a binary blob of the encrypted key is written to the +key blob storage directory ({ndctl_keysdir}). The user is responsible for +backing up the dimm key blobs to a secure location. When a key is successfully +loaded into the kernel's user key ring, the payload is decrypted +and can be accessed by the kernel. + +Key ids are written to the 'security' sysfs attribute with the command "update". +A key id of 0 is provided for the old key id. The kernel will see that the +update call is an enable call because the 0 old key id. A "passphrase update" +DSM is issued by the kernel with the old passphrase as 0s. + +UPDATE USER PASSPHRASE +---------------------- +The update user passphrase operation uses the same DSM command as enable user +passphrase. Most of the work is done on the key management side. The user will +provide a new master key name for the new passphrase key or use the existing +one. ndctl will use whatever master key name that is passed in. The following +operations are performed for update: +1. Remove the associated encrypted key from the kernel's user key ring. +2. Rename the key blob to old. +3. Load the now old key blob into kernel's user key ring with "old" name. +4. Create new encrypted key and seal with master key. +5. Generate new key blob. +6. Send DSM with old and new passphrase via the decrypted key payloads. +7. On success, remove old key from key ring and old key blob. + +REMOVE USER PASSPHRASE +----------------------- +The current key id is written to sysfs by ndctl. Upon successfully disabling +the passphrase, the key is removed from the kernel's user keyring, and the +associated key blob is deleted. + +CRYPTO (SECURE) ERASE +--------------------- +This operation is similar to passphrase-disable. The kernel will issue +WBINVD before and after the operation to ensure no data corruption from a stale +CPU cache. Use ndctl's sanitize-dimm command with the --crypto-erase option to +perform this operation. + +OVERWRITE +--------- +The overwrite operation wipes the entire nvdimm. The operation can take +a significant amount of time. Issuing a command is very similar to +"passphrase-disable" and "secure erase". However, when the command returns +successfully it just means overwrite has been successfully started. +The wait-overwrite command for ndctl can be used to wait on the nvdimms that +are performing overwrite until the operation is completed. Upon successful +completion of the operation, wbinvd will be issued by the kernel. +The "sanitize-dimm" command with the --overwrite option is used via ndctl. +If both --crypto-erase and --overwrite options are passed in, the crypt-erase +will be issued first before overwrite. + +SECURITY FREEZE +--------------- +This operation requires no key to succeed. ndctl will issue the DSM command +and upon completion, the security commands besides status query will be locked +out until the next boot. + +MASTER PASSPHRASE SETUP, UPDATE, and CRYPTO ERASE +----------------------------------------------------------- +These operations are similar to the user passphrase enable and update. The only +difference is that a different encrypted key is being used for the master +passphrase operations. Note that master passphrase has no relation to the +master key for encryption. + +[1] http://pmem.io/documents/NVDIMM_DSM_Interface-V1.8.pdf +[2] https://www.kernel.org/doc/Documentation/security/keys/trusted-encrypted.rst diff --git a/Documentation/ndctl/ndctl-freeze-security.txt b/Documentation/ndctl/ndctl-freeze-security.txt index d14b8a39..43ea81eb 100644 --- a/Documentation/ndctl/ndctl-freeze-security.txt +++ b/Documentation/ndctl/ndctl-freeze-security.txt @@ -55,4 +55,6 @@ OPTIONS :: include::xable-dimm-options.txt[] +include::intel-nvdimm-security.txt[] + include::../copyright.txt[] diff --git a/Documentation/ndctl/ndctl-remove-passphrase.txt b/Documentation/ndctl/ndctl-remove-passphrase.txt index 17ff905b..df83eaee 100644 --- a/Documentation/ndctl/ndctl-remove-passphrase.txt +++ b/Documentation/ndctl/ndctl-remove-passphrase.txt @@ -23,4 +23,6 @@ OPTIONS :: include::xable-dimm-options.txt[] +include::intel-nvdimm-security.txt[] + include::../copyright.txt[] diff --git a/Documentation/ndctl/ndctl-sanitize-dimm.txt b/Documentation/ndctl/ndctl-sanitize-dimm.txt index 78e1eb37..06ce06c8 100644 --- a/Documentation/ndctl/ndctl-sanitize-dimm.txt +++ b/Documentation/ndctl/ndctl-sanitize-dimm.txt @@ -43,6 +43,8 @@ include::xable-dimm-options.txt[] instead of the user passphrase. This only is applicable to the crypto-erase option. +include::intel-nvdimm-security.txt[] + include::../copyright.txt[] SEE ALSO diff --git a/Documentation/ndctl/ndctl-setup-passphrase.txt b/Documentation/ndctl/ndctl-setup-passphrase.txt index 613e17a1..76b55492 100644 --- a/Documentation/ndctl/ndctl-setup-passphrase.txt +++ b/Documentation/ndctl/ndctl-setup-passphrase.txt @@ -49,4 +49,6 @@ include::xable-dimm-options.txt[] --verbose:: Emit debug messages for the namespace check process. +include::intel-nvdimm-security.txt[] + include::../copyright.txt[] diff --git a/Documentation/ndctl/ndctl-update-passphrase.txt b/Documentation/ndctl/ndctl-update-passphrase.txt index 8b5fc812..2a43f2bb 100644 --- a/Documentation/ndctl/ndctl-update-passphrase.txt +++ b/Documentation/ndctl/ndctl-update-passphrase.txt @@ -48,6 +48,9 @@ include::xable-dimm-options.txt[] -v:: --verbose:: Emit debug messages for the namespace check process. + +include::intel-nvdimm-security.txt[] + include::../copyright.txt[] SEE ALSO: