From 4c6926a23b76ea23403976290cd45a7a143f6500 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 6 Dec 2018 12:40:01 -0800 Subject: acpi/nfit, libnvdimm: Add unlock of nvdimm support for Intel DIMMs Add support to unlock the dimm via the kernel key management APIs. The passphrase is expected to be pulled from userspace through keyutils. The key management and sysfs attributes are libnvdimm generic. Encrypted keys are used to protect the nvdimm passphrase at rest. The master key can be a trusted-key sealed in a TPM, preferred, or an encrypted-key, more flexible, but more exposure to a potential attacker. Signed-off-by: Dave Jiang Co-developed-by: Dan Williams Reported-by: Randy Dunlap Signed-off-by: Dan Williams --- drivers/nvdimm/security.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 drivers/nvdimm/security.c (limited to 'drivers/nvdimm/security.c') diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c new file mode 100644 index 000000000000..51d77a67a9fb --- /dev/null +++ b/drivers/nvdimm/security.c @@ -0,0 +1,148 @@ +// 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 "nd-core.h" +#include "nd.h" + +static bool key_revalidate = true; +module_param(key_revalidate, bool, 0444); +MODULE_PARM_DESC(key_revalidate, "Require key validation at init."); + +static void *key_data(struct key *key) +{ + struct encrypted_key_payload *epayload = dereference_key_locked(key); + + lockdep_assert_held_read(&key->sem); + + return epayload->decrypted_data; +} + +static void nvdimm_put_key(struct key *key) +{ + up_read(&key->sem); + key_put(key); +} + +/* + * Retrieve kernel key for DIMM and request from user space if + * necessary. Returns a key held for read and must be put by + * nvdimm_put_key() before the usage goes out of scope. + */ +static struct key *nvdimm_request_key(struct nvdimm *nvdimm) +{ + struct key *key = NULL; + static const char NVDIMM_PREFIX[] = "nvdimm:"; + char desc[NVDIMM_KEY_DESC_LEN + sizeof(NVDIMM_PREFIX)]; + struct device *dev = &nvdimm->dev; + + sprintf(desc, "%s%s", NVDIMM_PREFIX, nvdimm->dimm_id); + key = request_key(&key_type_encrypted, desc, ""); + if (IS_ERR(key)) { + if (PTR_ERR(key) == -ENOKEY) + dev_warn(dev, "request_key() found no key\n"); + else + dev_warn(dev, "request_key() upcall failed\n"); + key = NULL; + } else { + struct encrypted_key_payload *epayload; + + down_read(&key->sem); + epayload = dereference_key_locked(key); + if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { + up_read(&key->sem); + key_put(key); + key = NULL; + } + } + + return key; +} + +static struct key *nvdimm_key_revalidate(struct nvdimm *nvdimm) +{ + struct key *key; + int rc; + + if (!nvdimm->sec.ops->change_key) + return NULL; + + key = nvdimm_request_key(nvdimm); + if (!key) + return NULL; + + /* + * Send the same key to the hardware as new and old key to + * verify that the key is good. + */ + rc = nvdimm->sec.ops->change_key(nvdimm, key_data(key), key_data(key)); + if (rc < 0) { + nvdimm_put_key(key); + key = NULL; + } + return key; +} + +static int __nvdimm_security_unlock(struct nvdimm *nvdimm) +{ + struct device *dev = &nvdimm->dev; + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key = NULL; + int rc; + + /* The bus lock should be held at the top level of the call stack */ + lockdep_assert_held(&nvdimm_bus->reconfig_mutex); + + if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock + || nvdimm->sec.state < 0) + return -EIO; + + /* + * If the pre-OS has unlocked the DIMM, attempt to send the key + * from request_key() to the hardware for verification. Failure + * to revalidate the key against the hardware results in a + * freeze of the security configuration. I.e. if the OS does not + * have the key, security is being managed pre-OS. + */ + if (nvdimm->sec.state == NVDIMM_SECURITY_UNLOCKED) { + if (!key_revalidate) + return 0; + + key = nvdimm_key_revalidate(nvdimm); + if (!key) + return nvdimm_security_freeze(nvdimm); + } else + key = nvdimm_request_key(nvdimm); + + if (!key) + return -ENOKEY; + + rc = nvdimm->sec.ops->unlock(nvdimm, key_data(key)); + dev_dbg(dev, "key: %d unlock: %s\n", key_serial(key), + rc == 0 ? "success" : "fail"); + + nvdimm_put_key(key); + nvdimm->sec.state = nvdimm_security_state(nvdimm); + return rc; +} + +int nvdimm_security_unlock(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + int rc; + + nvdimm_bus_lock(dev); + rc = __nvdimm_security_unlock(nvdimm); + nvdimm_bus_unlock(dev); + return rc; +} -- cgit v1.2.3-55-g7522 From 03b65b22ada8115a7a7bfdf0789f6a94adfd6070 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 7 Dec 2018 10:33:30 -0700 Subject: acpi/nfit, libnvdimm: Add disable passphrase support to Intel nvdimm. Add support to disable passphrase (security) for the Intel nvdimm. The passphrase used for disabling is pulled from an encrypted-key in the kernel user keyring. The action is triggered by writing "disable " to the sysfs attribute "security". Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/acpi/nfit/intel.c | 41 ++++++++++++++++++++++++++++++ drivers/nvdimm/dimm_devs.c | 47 +++++++++++++++++++++++++++++++--- drivers/nvdimm/nd-core.h | 9 +++++++ drivers/nvdimm/security.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/libnvdimm.h | 2 ++ 5 files changed, 159 insertions(+), 3 deletions(-) (limited to 'drivers/nvdimm/security.c') diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index 38f2cb364853..bb033b74bff0 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -163,6 +163,46 @@ static int intel_security_unlock(struct nvdimm *nvdimm, return 0; } +static int intel_security_disable(struct nvdimm *nvdimm, + const struct nvdimm_key_data *key_data) +{ + int rc; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_disable_passphrase cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + }, + }; + + if (!test_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, &nfit_mem->dsm_mask)) + return -ENOTTY; + + memcpy(nd_cmd.cmd.passphrase, key_data->data, + sizeof(nd_cmd.cmd.passphrase)); + rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); + if (rc < 0) + return rc; + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_INVALID_PASS: + return -EINVAL; + case ND_INTEL_STATUS_INVALID_STATE: + default: + return -ENXIO; + } + + return 0; +} + /* * TODO: define a cross arch wbinvd equivalent when/if * NVDIMM_FAMILY_INTEL command support arrives on another arch. @@ -183,6 +223,7 @@ static const struct nvdimm_security_ops __intel_security_ops = { .state = intel_security_state, .freeze = intel_security_freeze, .change_key = intel_security_change_key, + .disable = intel_security_disable, #ifdef CONFIG_X86 .unlock = intel_security_unlock, #endif diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 8e0bd2ce4dd0..7f42cc4e119b 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -391,24 +391,65 @@ static ssize_t security_show(struct device *dev, return -ENOTTY; } +#define OPS \ + C( OP_FREEZE, "freeze", 1), \ + C( OP_DISABLE, "disable", 2) +#undef C +#define C(a, b, c) a +enum nvdimmsec_op_ids { OPS }; +#undef C +#define C(a, b, c) { b, c } +static struct { + const char *name; + int args; +} ops[] = { OPS }; +#undef C + +#define SEC_CMD_SIZE 32 +#define KEY_ID_SIZE 10 + static ssize_t __security_store(struct device *dev, const char *buf, size_t len) { struct nvdimm *nvdimm = to_nvdimm(dev); ssize_t rc; + char cmd[SEC_CMD_SIZE+1], keystr[KEY_ID_SIZE+1], + nkeystr[KEY_ID_SIZE+1]; + unsigned int key, newkey; + int i; if (atomic_read(&nvdimm->busy)) return -EBUSY; - if (sysfs_streq(buf, "freeze")) { + rc = sscanf(buf, "%"__stringify(SEC_CMD_SIZE)"s" + " %"__stringify(KEY_ID_SIZE)"s" + " %"__stringify(KEY_ID_SIZE)"s", + cmd, keystr, nkeystr); + if (rc < 1) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(ops); i++) + if (sysfs_streq(cmd, ops[i].name)) + break; + if (i >= ARRAY_SIZE(ops)) + return -EINVAL; + if (ops[i].args > 1) + rc = kstrtouint(keystr, 0, &key); + if (rc >= 0 && ops[i].args > 2) + rc = kstrtouint(nkeystr, 0, &newkey); + if (rc < 0) + return rc; + + if (i == OP_FREEZE) { dev_dbg(dev, "freeze\n"); rc = nvdimm_security_freeze(nvdimm); + } else if (i == OP_DISABLE) { + dev_dbg(dev, "disable %u\n", key); + rc = nvdimm_security_disable(nvdimm, key); } else return -EINVAL; if (rc == 0) rc = len; return rc; - } static ssize_t security_store(struct device *dev, @@ -452,7 +493,7 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n) if (nvdimm->sec.state < 0) return 0; /* Are there any state mutation ops? */ - if (nvdimm->sec.ops->freeze) + if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable) return a->mode; return 0444; } diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 15eff40f55f6..d1351c0b1119 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -57,6 +57,15 @@ static inline enum nvdimm_security_state nvdimm_security_state( return nvdimm->sec.ops->state(nvdimm); } int nvdimm_security_freeze(struct nvdimm *nvdimm); +#if IS_ENABLED(CONFIG_NVDIMM_KEYS) +int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); +#else +static inline int nvdimm_security_disable(struct nvdimm *nvdimm, + unsigned int keyid) +{ + return -EOPNOTSUPP; +} +#endif /** * struct blk_alloc_info - tracking info for BLK dpa scanning diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index 51d77a67a9fb..647a99dd3182 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -69,6 +69,36 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) return key; } +static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, + key_serial_t id) +{ + key_ref_t keyref; + struct key *key; + struct encrypted_key_payload *epayload; + struct device *dev = &nvdimm->dev; + + keyref = lookup_user_key(id, 0, 0); + if (IS_ERR(keyref)) + return NULL; + + key = key_ref_to_ptr(keyref); + if (key->type != &key_type_encrypted) { + key_put(key); + return NULL; + } + dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key)); + + + down_read(&key->sem); + epayload = dereference_key_locked(key); + if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { + up_read(&key->sem); + key_put(key); + key = NULL; + } + return key; +} + static struct key *nvdimm_key_revalidate(struct nvdimm *nvdimm) { struct key *key; @@ -146,3 +176,36 @@ int nvdimm_security_unlock(struct device *dev) nvdimm_bus_unlock(dev); return rc; } + +int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) +{ + struct device *dev = &nvdimm->dev; + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key; + int rc; + + /* The bus lock should be held at the top level of the call stack */ + lockdep_assert_held(&nvdimm_bus->reconfig_mutex); + + if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable + || nvdimm->sec.state < 0) + return -EOPNOTSUPP; + + if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { + dev_warn(dev, "Incorrect security state: %d\n", + nvdimm->sec.state); + return -EIO; + } + + key = nvdimm_lookup_user_key(nvdimm, keyid); + if (!key) + return -ENOKEY; + + rc = nvdimm->sec.ops->disable(nvdimm, key_data(key)); + dev_dbg(dev, "key: %d disable: %s\n", key_serial(key), + rc == 0 ? "success" : "fail"); + + nvdimm_put_key(key); + nvdimm->sec.state = nvdimm_security_state(nvdimm); + return rc; +} diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 0f0ab276134e..d0afa115356e 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -178,6 +178,8 @@ struct nvdimm_security_ops { const struct nvdimm_key_data *new_data); int (*unlock)(struct nvdimm *nvdimm, const struct nvdimm_key_data *key_data); + int (*disable)(struct nvdimm *nvdimm, + const struct nvdimm_key_data *key_data); }; void badrange_init(struct badrange *badrange); -- cgit v1.2.3-55-g7522 From d2a4ac73f56a5d0709d28b41fec8d15e4500f8f1 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 7 Dec 2018 13:29:09 -0700 Subject: acpi/nfit, libnvdimm: Add enable/update passphrase support for Intel nvdimms Add support for enabling and updating passphrase on the Intel nvdimms. The passphrase is the an encrypted key in the kernel user keyring. We trigger the update via writing "update " to the sysfs attribute "security". If no exists (for enabling security) then a 0 should be used. Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/nvdimm/dimm_devs.c | 11 ++++++--- drivers/nvdimm/nd-core.h | 7 ++++++ drivers/nvdimm/security.c | 58 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 69 insertions(+), 7 deletions(-) (limited to 'drivers/nvdimm/security.c') diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 7f42cc4e119b..1cc3a6af3d0e 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -392,8 +392,9 @@ static ssize_t security_show(struct device *dev, } #define OPS \ - C( OP_FREEZE, "freeze", 1), \ - C( OP_DISABLE, "disable", 2) + C( OP_FREEZE, "freeze", 1), \ + C( OP_DISABLE, "disable", 2), \ + C( OP_UPDATE, "update", 3) #undef C #define C(a, b, c) a enum nvdimmsec_op_ids { OPS }; @@ -444,6 +445,9 @@ static ssize_t __security_store(struct device *dev, const char *buf, size_t len) } else if (i == OP_DISABLE) { dev_dbg(dev, "disable %u\n", key); rc = nvdimm_security_disable(nvdimm, key); + } else if (i == OP_UPDATE) { + dev_dbg(dev, "update %u %u\n", key, newkey); + rc = nvdimm_security_update(nvdimm, key, newkey); } else return -EINVAL; @@ -493,7 +497,8 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n) if (nvdimm->sec.state < 0) return 0; /* Are there any state mutation ops? */ - if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable) + if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable + || nvdimm->sec.ops->change_key) return a->mode; return 0444; } diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index d1351c0b1119..c2567f9ae07b 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -59,12 +59,19 @@ static inline enum nvdimm_security_state nvdimm_security_state( int nvdimm_security_freeze(struct nvdimm *nvdimm); #if IS_ENABLED(CONFIG_NVDIMM_KEYS) int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); +int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, + unsigned int new_keyid); #else static inline int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) { return -EOPNOTSUPP; } +static inline int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, + unsigned int new_keyid) +{ + return -EOPNOTSUPP; +} #endif /** diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index 647a99dd3182..df7f070e96fb 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -15,6 +15,9 @@ #include "nd-core.h" #include "nd.h" +#define NVDIMM_BASE_KEY 0 +#define NVDIMM_NEW_KEY 1 + static bool key_revalidate = true; module_param(key_revalidate, bool, 0444); MODULE_PARM_DESC(key_revalidate, "Require key validation at init."); @@ -70,7 +73,7 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) } static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, - key_serial_t id) + key_serial_t id, int subclass) { key_ref_t keyref; struct key *key; @@ -86,10 +89,10 @@ static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, key_put(key); return NULL; } - dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key)); + dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key)); - down_read(&key->sem); + down_read_nested(&key->sem, subclass); epayload = dereference_key_locked(key); if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { up_read(&key->sem); @@ -197,7 +200,7 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) return -EIO; } - key = nvdimm_lookup_user_key(nvdimm, keyid); + key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); if (!key) return -ENOKEY; @@ -209,3 +212,50 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) nvdimm->sec.state = nvdimm_security_state(nvdimm); return rc; } + +int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, + unsigned int new_keyid) +{ + struct device *dev = &nvdimm->dev; + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key, *newkey; + int rc; + + /* The bus lock should be held at the top level of the call stack */ + lockdep_assert_held(&nvdimm_bus->reconfig_mutex); + + if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key + || nvdimm->sec.state < 0) + return -EOPNOTSUPP; + + if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { + dev_warn(dev, "Incorrect security state: %d\n", + nvdimm->sec.state); + return -EIO; + } + + if (keyid == 0) + key = NULL; + else { + key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); + if (!key) + return -ENOKEY; + } + + newkey = nvdimm_lookup_user_key(nvdimm, new_keyid, NVDIMM_NEW_KEY); + if (!newkey) { + nvdimm_put_key(key); + return -ENOKEY; + } + + rc = nvdimm->sec.ops->change_key(nvdimm, key ? key_data(key) : NULL, + key_data(newkey)); + dev_dbg(dev, "key: %d %d update: %s\n", + key_serial(key), key_serial(newkey), + rc == 0 ? "success" : "fail"); + + nvdimm_put_key(newkey); + nvdimm_put_key(key); + nvdimm->sec.state = nvdimm_security_state(nvdimm); + return rc; +} -- cgit v1.2.3-55-g7522 From 64e77c8c047fb91ea8c7800c1238108a72f0bf9c Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 7 Dec 2018 14:02:12 -0700 Subject: acpi/nfit, libnvdimm: Add support for issue secure erase DSM to Intel nvdimm Add support to issue a secure erase DSM to the Intel nvdimm. The required passphrase is acquired from an encrypted key in the kernel user keyring. To trigger the action, "erase " is written to the "security" sysfs attribute. Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/acpi/nfit/intel.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/nvdimm/dimm_devs.c | 9 +++++++-- drivers/nvdimm/nd-core.h | 5 +++++ drivers/nvdimm/security.c | 41 ++++++++++++++++++++++++++++++++++++++++ include/linux/libnvdimm.h | 2 ++ 5 files changed, 102 insertions(+), 2 deletions(-) (limited to 'drivers/nvdimm/security.c') diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index bb033b74bff0..e0e04b730b4f 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -203,6 +203,52 @@ static int intel_security_disable(struct nvdimm *nvdimm, return 0; } +static int intel_security_erase(struct nvdimm *nvdimm, + const struct nvdimm_key_data *key) +{ + int rc; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_secure_erase cmd; + } nd_cmd = { + .pkg = { + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + .nd_command = NVDIMM_INTEL_SECURE_ERASE, + }, + }; + + if (!test_bit(NVDIMM_INTEL_SECURE_ERASE, &nfit_mem->dsm_mask)) + return -ENOTTY; + + /* flush all cache before we erase DIMM */ + nvdimm_invalidate_cache(); + memcpy(nd_cmd.cmd.passphrase, key->data, + sizeof(nd_cmd.cmd.passphrase)); + rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); + if (rc < 0) + return rc; + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_NOT_SUPPORTED: + return -EOPNOTSUPP; + case ND_INTEL_STATUS_INVALID_PASS: + return -EINVAL; + case ND_INTEL_STATUS_INVALID_STATE: + default: + return -ENXIO; + } + + /* DIMM erased, invalidate all CPU caches before we read it */ + nvdimm_invalidate_cache(); + return 0; +} + /* * TODO: define a cross arch wbinvd equivalent when/if * NVDIMM_FAMILY_INTEL command support arrives on another arch. @@ -226,6 +272,7 @@ static const struct nvdimm_security_ops __intel_security_ops = { .disable = intel_security_disable, #ifdef CONFIG_X86 .unlock = intel_security_unlock, + .erase = intel_security_erase, #endif }; diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 1cc3a6af3d0e..bc432b7c17b8 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -394,7 +394,8 @@ static ssize_t security_show(struct device *dev, #define OPS \ C( OP_FREEZE, "freeze", 1), \ C( OP_DISABLE, "disable", 2), \ - C( OP_UPDATE, "update", 3) + C( OP_UPDATE, "update", 3), \ + C( OP_ERASE, "erase", 2) #undef C #define C(a, b, c) a enum nvdimmsec_op_ids { OPS }; @@ -448,6 +449,9 @@ static ssize_t __security_store(struct device *dev, const char *buf, size_t len) } else if (i == OP_UPDATE) { dev_dbg(dev, "update %u %u\n", key, newkey); rc = nvdimm_security_update(nvdimm, key, newkey); + } else if (i == OP_ERASE) { + dev_dbg(dev, "erase %u\n", key); + rc = nvdimm_security_erase(nvdimm, key); } else return -EINVAL; @@ -498,7 +502,8 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n) return 0; /* Are there any state mutation ops? */ if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable - || nvdimm->sec.ops->change_key) + || nvdimm->sec.ops->change_key + || nvdimm->sec.ops->erase) return a->mode; return 0444; } diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index c2567f9ae07b..b4b633ccfbe9 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -61,6 +61,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm); int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, unsigned int new_keyid); +int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid); #else static inline int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) @@ -72,6 +73,10 @@ static inline int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int key { return -EOPNOTSUPP; } +static inline int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid) +{ + return -EOPNOTSUPP; +} #endif /** diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index df7f070e96fb..05677be3c0dd 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -33,6 +33,9 @@ static void *key_data(struct key *key) static void nvdimm_put_key(struct key *key) { + if (!key) + return; + up_read(&key->sem); key_put(key); } @@ -259,3 +262,41 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, nvdimm->sec.state = nvdimm_security_state(nvdimm); return rc; } + +int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid) +{ + struct device *dev = &nvdimm->dev; + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key; + int rc; + + /* The bus lock should be held at the top level of the call stack */ + lockdep_assert_held(&nvdimm_bus->reconfig_mutex); + + if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase + || nvdimm->sec.state < 0) + return -EOPNOTSUPP; + + if (atomic_read(&nvdimm->busy)) { + dev_warn(dev, "Unable to secure erase while DIMM active.\n"); + return -EBUSY; + } + + if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { + dev_warn(dev, "Incorrect security state: %d\n", + nvdimm->sec.state); + return -EIO; + } + + key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); + if (!key) + return -ENOKEY; + + rc = nvdimm->sec.ops->erase(nvdimm, key_data(key)); + dev_dbg(dev, "key: %d erase: %s\n", key_serial(key), + rc == 0 ? "success" : "fail"); + + nvdimm_put_key(key); + nvdimm->sec.state = nvdimm_security_state(nvdimm); + return rc; +} diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index d0afa115356e..9a6cb7067dc7 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -180,6 +180,8 @@ struct nvdimm_security_ops { const struct nvdimm_key_data *key_data); int (*disable)(struct nvdimm *nvdimm, const struct nvdimm_key_data *key_data); + int (*erase)(struct nvdimm *nvdimm, + const struct nvdimm_key_data *key_data); }; void badrange_init(struct badrange *badrange); -- cgit v1.2.3-55-g7522 From 7d988097c546187ada602cc9bccd0f03d473eb8f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 13 Dec 2018 15:36:18 -0700 Subject: acpi/nfit, libnvdimm/security: Add security DSM overwrite support Add support for the NVDIMM_FAMILY_INTEL "ovewrite" capability as described by the Intel DSM spec v1.7. This will allow triggering of overwrite on Intel NVDIMMs. The overwrite operation can take tens of minutes. When the overwrite DSM is issued successfully, the NVDIMMs will be unaccessible. The kernel will do backoff polling to detect when the overwrite process is completed. According to the DSM spec v1.7, the 128G NVDIMMs can take up to 15mins to perform overwrite and larger DIMMs will take longer. Given that overwrite puts the DIMM in an indeterminate state until it completes introduce the NDD_SECURITY_OVERWRITE flag to prevent other operations from executing when overwrite is happening. The NDD_WORK_PENDING flag is added to denote that there is a device reference on the nvdimm device for an async workqueue thread context. Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 5 ++ drivers/acpi/nfit/intel.c | 90 +++++++++++++++++++++++++++++ drivers/nvdimm/bus.c | 21 ++++++- drivers/nvdimm/dimm_devs.c | 32 ++++++++++- drivers/nvdimm/nd-core.h | 14 +++++ drivers/nvdimm/region_devs.c | 5 ++ drivers/nvdimm/security.c | 133 +++++++++++++++++++++++++++++++++++++++++++ include/linux/libnvdimm.h | 9 +++ 8 files changed, 304 insertions(+), 5 deletions(-) (limited to 'drivers/nvdimm/security.c') diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 41c261ab793e..ab57a3fe4511 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2045,6 +2045,11 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) if (!nvdimm) continue; + rc = nvdimm_security_setup_events(nvdimm); + if (rc < 0) + dev_warn(acpi_desc->dev, + "security event setup failed: %d\n", rc); + nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); if (nfit_kernfs) nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs, diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index e0e04b730b4f..82e805d4458a 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -28,6 +28,14 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm) if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask)) return -ENXIO; + /* + * Short circuit the state retrieval while we are doing overwrite. + * The DSM spec states that the security state is indeterminate + * until the overwrite DSM completes. + */ + if (nvdimm_in_overwrite(nvdimm)) + return NVDIMM_SECURITY_OVERWRITE; + rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); if (rc < 0) return rc; @@ -249,6 +257,86 @@ static int intel_security_erase(struct nvdimm *nvdimm, return 0; } +static int intel_security_query_overwrite(struct nvdimm *nvdimm) +{ + int rc; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_query_overwrite cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_QUERY_OVERWRITE, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + }, + }; + + if (!test_bit(NVDIMM_INTEL_QUERY_OVERWRITE, &nfit_mem->dsm_mask)) + return -ENOTTY; + + rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); + if (rc < 0) + return rc; + + switch (nd_cmd.cmd.status) { + case 0: + break; + case ND_INTEL_STATUS_OQUERY_INPROGRESS: + return -EBUSY; + default: + return -ENXIO; + } + + /* flush all cache before we make the nvdimms available */ + nvdimm_invalidate_cache(); + return 0; +} + +static int intel_security_overwrite(struct nvdimm *nvdimm, + const struct nvdimm_key_data *nkey) +{ + int rc; + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + struct { + struct nd_cmd_pkg pkg; + struct nd_intel_overwrite cmd; + } nd_cmd = { + .pkg = { + .nd_command = NVDIMM_INTEL_OVERWRITE, + .nd_family = NVDIMM_FAMILY_INTEL, + .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, + .nd_size_out = ND_INTEL_STATUS_SIZE, + .nd_fw_size = ND_INTEL_STATUS_SIZE, + }, + }; + + if (!test_bit(NVDIMM_INTEL_OVERWRITE, &nfit_mem->dsm_mask)) + return -ENOTTY; + + /* flush all cache before we erase DIMM */ + nvdimm_invalidate_cache(); + if (nkey) + memcpy(nd_cmd.cmd.passphrase, nkey->data, + sizeof(nd_cmd.cmd.passphrase)); + rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); + if (rc < 0) + return rc; + + switch (nd_cmd.cmd.status) { + case 0: + return 0; + case ND_INTEL_STATUS_OVERWRITE_UNSUPPORTED: + return -ENOTSUPP; + case ND_INTEL_STATUS_INVALID_PASS: + return -EINVAL; + case ND_INTEL_STATUS_INVALID_STATE: + default: + return -ENXIO; + } +} + /* * TODO: define a cross arch wbinvd equivalent when/if * NVDIMM_FAMILY_INTEL command support arrives on another arch. @@ -273,6 +361,8 @@ static const struct nvdimm_security_ops __intel_security_ops = { #ifdef CONFIG_X86 .unlock = intel_security_unlock, .erase = intel_security_erase, + .overwrite = intel_security_overwrite, + .query_overwrite = intel_security_query_overwrite, #endif }; diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index eae17d8ee539..adb01c1f92de 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -393,9 +393,24 @@ static int child_unregister(struct device *dev, void *data) * i.e. remove classless children */ if (dev->class) - /* pass */; - else - nd_device_unregister(dev, ND_SYNC); + return 0; + + if (is_nvdimm(dev)) { + struct nvdimm *nvdimm = to_nvdimm(dev); + bool dev_put = false; + + /* We are shutting down. Make state frozen artificially. */ + nvdimm_bus_lock(dev); + nvdimm->sec.state = NVDIMM_SECURITY_FROZEN; + if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags)) + dev_put = true; + nvdimm_bus_unlock(dev); + cancel_delayed_work_sync(&nvdimm->dwork); + if (dev_put) + put_device(dev); + } + nd_device_unregister(dev, ND_SYNC); + return 0; } diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index bc432b7c17b8..6affa270abd3 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -395,7 +395,8 @@ static ssize_t security_show(struct device *dev, C( OP_FREEZE, "freeze", 1), \ C( OP_DISABLE, "disable", 2), \ C( OP_UPDATE, "update", 3), \ - C( OP_ERASE, "erase", 2) + C( OP_ERASE, "erase", 2), \ + C( OP_OVERWRITE, "overwrite", 2) #undef C #define C(a, b, c) a enum nvdimmsec_op_ids { OPS }; @@ -452,6 +453,9 @@ static ssize_t __security_store(struct device *dev, const char *buf, size_t len) } else if (i == OP_ERASE) { dev_dbg(dev, "erase %u\n", key); rc = nvdimm_security_erase(nvdimm, key); + } else if (i == OP_OVERWRITE) { + dev_dbg(dev, "overwrite %u\n", key); + rc = nvdimm_security_overwrite(nvdimm, key); } else return -EINVAL; @@ -503,7 +507,8 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n) /* Are there any state mutation ops? */ if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable || nvdimm->sec.ops->change_key - || nvdimm->sec.ops->erase) + || nvdimm->sec.ops->erase + || nvdimm->sec.ops->overwrite) return a->mode; return 0444; } @@ -546,6 +551,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, dev->devt = MKDEV(nvdimm_major, nvdimm->id); dev->groups = groups; nvdimm->sec.ops = sec_ops; + nvdimm->sec.overwrite_tmo = 0; + INIT_DELAYED_WORK(&nvdimm->dwork, nvdimm_security_overwrite_query); /* * Security state must be initialized before device_add() for * attribute visibility. @@ -557,6 +564,22 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, } EXPORT_SYMBOL_GPL(__nvdimm_create); +int nvdimm_security_setup_events(struct nvdimm *nvdimm) +{ + nvdimm->sec.overwrite_state = sysfs_get_dirent(nvdimm->dev.kobj.sd, + "security"); + if (!nvdimm->sec.overwrite_state) + return -ENODEV; + return 0; +} +EXPORT_SYMBOL_GPL(nvdimm_security_setup_events); + +int nvdimm_in_overwrite(struct nvdimm *nvdimm) +{ + return test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); +} +EXPORT_SYMBOL_GPL(nvdimm_in_overwrite); + int nvdimm_security_freeze(struct nvdimm *nvdimm) { int rc; @@ -569,6 +592,11 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm) if (nvdimm->sec.state < 0) return -EIO; + if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { + dev_warn(&nvdimm->dev, "Overwrite operation in progress.\n"); + return -EBUSY; + } + rc = nvdimm->sec.ops->freeze(nvdimm); nvdimm->sec.state = nvdimm_security_state(nvdimm); diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index b4b633ccfbe9..952d688982d8 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -21,6 +21,7 @@ extern struct list_head nvdimm_bus_list; extern struct mutex nvdimm_bus_list_mutex; extern int nvdimm_major; +extern struct workqueue_struct *nvdimm_wq; struct nvdimm_bus { struct nvdimm_bus_descriptor *nd_desc; @@ -45,7 +46,10 @@ struct nvdimm { struct { const struct nvdimm_security_ops *ops; enum nvdimm_security_state state; + unsigned int overwrite_tmo; + struct kernfs_node *overwrite_state; } sec; + struct delayed_work dwork; }; static inline enum nvdimm_security_state nvdimm_security_state( @@ -62,6 +66,8 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, unsigned int new_keyid); int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid); +int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid); +void nvdimm_security_overwrite_query(struct work_struct *work); #else static inline int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) @@ -77,6 +83,14 @@ static inline int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyi { return -EOPNOTSUPP; } +static inline int nvdimm_security_overwrite(struct nvdimm *nvdimm, + unsigned int keyid) +{ + return -EOPNOTSUPP; +} +static inline void nvdimm_security_overwrite_query(struct work_struct *work) +{ +} #endif /** diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 174a418cb171..b4d8e4ed3020 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -79,6 +79,11 @@ int nd_region_activate(struct nd_region *nd_region) struct nd_mapping *nd_mapping = &nd_region->mapping[i]; struct nvdimm *nvdimm = nd_mapping->nvdimm; + if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { + nvdimm_bus_unlock(&nd_region->dev); + return -EBUSY; + } + /* at least one null hint slot per-dimm for the "no-hint" case */ flush_data_size += sizeof(void *); num_flush = min_not_zero(num_flush, nvdimm->num_flush); diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index 05677be3c0dd..5055979f89c4 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -143,6 +143,11 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) || nvdimm->sec.state < 0) return -EIO; + if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { + dev_warn(dev, "Security operation in progress.\n"); + return -EBUSY; + } + /* * If the pre-OS has unlocked the DIMM, attempt to send the key * from request_key() to the hardware for verification. Failure @@ -203,6 +208,11 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) return -EIO; } + if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { + dev_warn(dev, "Security operation in progress.\n"); + return -EBUSY; + } + key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); if (!key) return -ENOKEY; @@ -288,6 +298,11 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid) return -EIO; } + if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { + dev_warn(dev, "Security operation in progress.\n"); + return -EBUSY; + } + key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); if (!key) return -ENOKEY; @@ -300,3 +315,121 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid) nvdimm->sec.state = nvdimm_security_state(nvdimm); return rc; } + +int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) +{ + struct device *dev = &nvdimm->dev; + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct key *key; + int rc; + + /* The bus lock should be held at the top level of the call stack */ + lockdep_assert_held(&nvdimm_bus->reconfig_mutex); + + if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite + || nvdimm->sec.state < 0) + return -EOPNOTSUPP; + + if (atomic_read(&nvdimm->busy)) { + dev_warn(dev, "Unable to overwrite while DIMM active.\n"); + return -EBUSY; + } + + if (dev->driver == NULL) { + dev_warn(dev, "Unable to overwrite while DIMM active.\n"); + return -EINVAL; + } + + if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { + dev_warn(dev, "Incorrect security state: %d\n", + nvdimm->sec.state); + return -EIO; + } + + if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { + dev_warn(dev, "Security operation in progress.\n"); + return -EBUSY; + } + + if (keyid == 0) + key = NULL; + else { + key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); + if (!key) + return -ENOKEY; + } + + rc = nvdimm->sec.ops->overwrite(nvdimm, key ? key_data(key) : NULL); + dev_dbg(dev, "key: %d overwrite submission: %s\n", key_serial(key), + rc == 0 ? "success" : "fail"); + + nvdimm_put_key(key); + if (rc == 0) { + set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); + set_bit(NDD_WORK_PENDING, &nvdimm->flags); + nvdimm->sec.state = NVDIMM_SECURITY_OVERWRITE; + /* + * Make sure we don't lose device while doing overwrite + * query. + */ + get_device(dev); + queue_delayed_work(system_wq, &nvdimm->dwork, 0); + } + return rc; +} + +void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) +{ + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev); + int rc; + unsigned int tmo; + + /* The bus lock should be held at the top level of the call stack */ + lockdep_assert_held(&nvdimm_bus->reconfig_mutex); + + /* + * Abort and release device if we no longer have the overwrite + * flag set. It means the work has been canceled. + */ + if (!test_bit(NDD_WORK_PENDING, &nvdimm->flags)) + return; + + tmo = nvdimm->sec.overwrite_tmo; + + if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite + || nvdimm->sec.state < 0) + return; + + rc = nvdimm->sec.ops->query_overwrite(nvdimm); + if (rc == -EBUSY) { + + /* setup delayed work again */ + tmo += 10; + queue_delayed_work(system_wq, &nvdimm->dwork, tmo * HZ); + nvdimm->sec.overwrite_tmo = min(15U * 60U, tmo); + return; + } + + if (rc < 0) + dev_warn(&nvdimm->dev, "overwrite failed\n"); + else + dev_dbg(&nvdimm->dev, "overwrite completed\n"); + + if (nvdimm->sec.overwrite_state) + sysfs_notify_dirent(nvdimm->sec.overwrite_state); + nvdimm->sec.overwrite_tmo = 0; + clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); + clear_bit(NDD_WORK_PENDING, &nvdimm->flags); + put_device(&nvdimm->dev); + nvdimm->sec.state = nvdimm_security_state(nvdimm); +} + +void nvdimm_security_overwrite_query(struct work_struct *work) +{ + struct nvdimm *nvdimm = + container_of(work, typeof(*nvdimm), dwork.work); + + nvdimm_bus_lock(&nvdimm->dev); + __nvdimm_security_overwrite_query(nvdimm); + nvdimm_bus_unlock(&nvdimm->dev); +} diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 9a6cb7067dc7..d18885304020 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -38,6 +38,10 @@ enum { NDD_UNARMED = 1, /* locked memory devices should not be accessed */ NDD_LOCKED = 2, + /* memory under security wipes should not be accessed */ + NDD_SECURITY_OVERWRITE = 3, + /* tracking whether or not there is a pending device reference */ + NDD_WORK_PENDING = 4, /* need to set a limit somewhere, but yes, this is likely overkill */ ND_IOCTL_MAX_BUFLEN = SZ_4M, @@ -182,6 +186,9 @@ struct nvdimm_security_ops { const struct nvdimm_key_data *key_data); int (*erase)(struct nvdimm *nvdimm, const struct nvdimm_key_data *key_data); + int (*overwrite)(struct nvdimm *nvdimm, + const struct nvdimm_key_data *key_data); + int (*query_overwrite)(struct nvdimm *nvdimm); }; void badrange_init(struct badrange *badrange); @@ -219,6 +226,7 @@ static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, cmd_mask, num_flush, flush_wpq, NULL, NULL); } +int nvdimm_security_setup_events(struct nvdimm *nvdimm); const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, @@ -244,6 +252,7 @@ u64 nd_fletcher64(void *addr, size_t len, bool le); void nvdimm_flush(struct nd_region *nd_region); int nvdimm_has_flush(struct nd_region *nd_region); int nvdimm_has_cache(struct nd_region *nd_region); +int nvdimm_in_overwrite(struct nvdimm *nvdimm); static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) -- cgit v1.2.3-55-g7522 From 89fa9d8ea7bdfa841d19044485cec5f4171069e5 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 10 Dec 2018 10:53:22 -0700 Subject: acpi/nfit, libnvdimm/security: add Intel DSM 1.8 master passphrase support With Intel DSM 1.8 [1] two new security DSMs are introduced. Enable/update master passphrase and master secure erase. The master passphrase allows a secure erase to be performed without the user passphrase that is set on the NVDIMM. The commands of master_update and master_erase are added to the sysfs knob in order to initiate the DSMs. They are similar in opeartion mechanism compare to update and erase. [1]: http://pmem.io/documents/NVDIMM_DSM_Interface-V1.8.pdf Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 2 ++ drivers/acpi/nfit/intel.c | 53 +++++++++++++++++++++++++++++++--------------- drivers/nvdimm/dimm_devs.c | 34 ++++++++++++++++++++--------- drivers/nvdimm/nd-core.h | 21 ++++++++++++------ drivers/nvdimm/security.c | 43 ++++++++++++++++++++++++++----------- include/linux/libnvdimm.h | 14 +++++++++--- 6 files changed, 118 insertions(+), 49 deletions(-) (limited to 'drivers/nvdimm/security.c') diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index ab57a3fe4511..c246e71c5345 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -389,6 +389,8 @@ static u8 nfit_dsm_revid(unsigned family, unsigned func) [NVDIMM_INTEL_SECURE_ERASE] = 2, [NVDIMM_INTEL_OVERWRITE] = 2, [NVDIMM_INTEL_QUERY_OVERWRITE] = 2, + [NVDIMM_INTEL_SET_MASTER_PASSPHRASE] = 2, + [NVDIMM_INTEL_MASTER_SECURE_ERASE] = 2, }, }; u8 id; diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index 82e805d4458a..850b2927b4e7 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -7,7 +7,8 @@ #include "intel.h" #include "nfit.h" -static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm) +static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, + enum nvdimm_passphrase_type ptype) { struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); struct { @@ -33,7 +34,7 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm) * The DSM spec states that the security state is indeterminate * until the overwrite DSM completes. */ - if (nvdimm_in_overwrite(nvdimm)) + if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER) return NVDIMM_SECURITY_OVERWRITE; rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); @@ -43,17 +44,28 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm) return -EIO; /* check and see if security is enabled and locked */ - if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) - return -ENXIO; - else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) { - if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED) - return NVDIMM_SECURITY_LOCKED; - else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN || - nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT) - return NVDIMM_SECURITY_FROZEN; - else + if (ptype == NVDIMM_MASTER) { + if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED) return NVDIMM_SECURITY_UNLOCKED; + else if (nd_cmd.cmd.extended_state & + ND_INTEL_SEC_ESTATE_PLIMIT) + return NVDIMM_SECURITY_FROZEN; + } else { + if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) + return -ENXIO; + else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) { + if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED) + return NVDIMM_SECURITY_LOCKED; + else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN + || nd_cmd.cmd.state & + ND_INTEL_SEC_STATE_PLIMIT) + return NVDIMM_SECURITY_FROZEN; + else + return NVDIMM_SECURITY_UNLOCKED; + } } + + /* this should cover master security disabled as well */ return NVDIMM_SECURITY_DISABLED; } @@ -86,24 +98,28 @@ static int intel_security_freeze(struct nvdimm *nvdimm) static int intel_security_change_key(struct nvdimm *nvdimm, const struct nvdimm_key_data *old_data, - const struct nvdimm_key_data *new_data) + const struct nvdimm_key_data *new_data, + enum nvdimm_passphrase_type ptype) { struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + unsigned int cmd = ptype == NVDIMM_MASTER ? + NVDIMM_INTEL_SET_MASTER_PASSPHRASE : + NVDIMM_INTEL_SET_PASSPHRASE; struct { struct nd_cmd_pkg pkg; struct nd_intel_set_passphrase cmd; } nd_cmd = { .pkg = { - .nd_command = NVDIMM_INTEL_SET_PASSPHRASE, .nd_family = NVDIMM_FAMILY_INTEL, .nd_size_in = ND_INTEL_PASSPHRASE_SIZE * 2, .nd_size_out = ND_INTEL_STATUS_SIZE, .nd_fw_size = ND_INTEL_STATUS_SIZE, + .nd_command = cmd, }, }; int rc; - if (!test_bit(NVDIMM_INTEL_SET_PASSPHRASE, &nfit_mem->dsm_mask)) + if (!test_bit(cmd, &nfit_mem->dsm_mask)) return -ENOTTY; if (old_data) @@ -212,10 +228,13 @@ static int intel_security_disable(struct nvdimm *nvdimm, } static int intel_security_erase(struct nvdimm *nvdimm, - const struct nvdimm_key_data *key) + const struct nvdimm_key_data *key, + enum nvdimm_passphrase_type ptype) { int rc; struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + unsigned int cmd = ptype == NVDIMM_MASTER ? + NVDIMM_INTEL_MASTER_SECURE_ERASE : NVDIMM_INTEL_SECURE_ERASE; struct { struct nd_cmd_pkg pkg; struct nd_intel_secure_erase cmd; @@ -225,11 +244,11 @@ static int intel_security_erase(struct nvdimm *nvdimm, .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, .nd_size_out = ND_INTEL_STATUS_SIZE, .nd_fw_size = ND_INTEL_STATUS_SIZE, - .nd_command = NVDIMM_INTEL_SECURE_ERASE, + .nd_command = cmd, }, }; - if (!test_bit(NVDIMM_INTEL_SECURE_ERASE, &nfit_mem->dsm_mask)) + if (!test_bit(cmd, &nfit_mem->dsm_mask)) return -ENOTTY; /* flush all cache before we erase DIMM */ diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 6affa270abd3..bd3f156463b1 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -386,17 +386,21 @@ static ssize_t security_show(struct device *dev, return sprintf(buf, "frozen\n"); case NVDIMM_SECURITY_OVERWRITE: return sprintf(buf, "overwrite\n"); + default: + return -ENOTTY; } return -ENOTTY; } -#define OPS \ - C( OP_FREEZE, "freeze", 1), \ - C( OP_DISABLE, "disable", 2), \ - C( OP_UPDATE, "update", 3), \ - C( OP_ERASE, "erase", 2), \ - C( OP_OVERWRITE, "overwrite", 2) +#define OPS \ + C( OP_FREEZE, "freeze", 1), \ + C( OP_DISABLE, "disable", 2), \ + C( OP_UPDATE, "update", 3), \ + C( OP_ERASE, "erase", 2), \ + C( OP_OVERWRITE, "overwrite", 2), \ + C( OP_MASTER_UPDATE, "master_update", 3), \ + C( OP_MASTER_ERASE, "master_erase", 2) #undef C #define C(a, b, c) a enum nvdimmsec_op_ids { OPS }; @@ -449,13 +453,21 @@ static ssize_t __security_store(struct device *dev, const char *buf, size_t len) rc = nvdimm_security_disable(nvdimm, key); } else if (i == OP_UPDATE) { dev_dbg(dev, "update %u %u\n", key, newkey); - rc = nvdimm_security_update(nvdimm, key, newkey); + rc = nvdimm_security_update(nvdimm, key, newkey, NVDIMM_USER); } else if (i == OP_ERASE) { dev_dbg(dev, "erase %u\n", key); - rc = nvdimm_security_erase(nvdimm, key); + rc = nvdimm_security_erase(nvdimm, key, NVDIMM_USER); } else if (i == OP_OVERWRITE) { dev_dbg(dev, "overwrite %u\n", key); rc = nvdimm_security_overwrite(nvdimm, key); + } else if (i == OP_MASTER_UPDATE) { + dev_dbg(dev, "master_update %u %u\n", key, newkey); + rc = nvdimm_security_update(nvdimm, key, newkey, + NVDIMM_MASTER); + } else if (i == OP_MASTER_ERASE) { + dev_dbg(dev, "master_erase %u\n", key); + rc = nvdimm_security_erase(nvdimm, key, + NVDIMM_MASTER); } else return -EINVAL; @@ -557,7 +569,9 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, * Security state must be initialized before device_add() for * attribute visibility. */ - nvdimm->sec.state = nvdimm_security_state(nvdimm); + /* get security state and extended (master) state */ + nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); + nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); nd_device_register(dev); return nvdimm; @@ -598,7 +612,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm) } rc = nvdimm->sec.ops->freeze(nvdimm); - nvdimm->sec.state = nvdimm_security_state(nvdimm); + nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); return rc; } diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 952d688982d8..52d20d9f39f6 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -46,6 +46,7 @@ struct nvdimm { struct { const struct nvdimm_security_ops *ops; enum nvdimm_security_state state; + enum nvdimm_security_state ext_state; unsigned int overwrite_tmo; struct kernfs_node *overwrite_state; } sec; @@ -53,19 +54,21 @@ struct nvdimm { }; static inline enum nvdimm_security_state nvdimm_security_state( - struct nvdimm *nvdimm) + struct nvdimm *nvdimm, bool master) { if (!nvdimm->sec.ops) return -ENXIO; - return nvdimm->sec.ops->state(nvdimm); + return nvdimm->sec.ops->state(nvdimm, master); } int nvdimm_security_freeze(struct nvdimm *nvdimm); #if IS_ENABLED(CONFIG_NVDIMM_KEYS) int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, - unsigned int new_keyid); -int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid); + unsigned int new_keyid, + enum nvdimm_passphrase_type pass_type); +int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, + enum nvdimm_passphrase_type pass_type); int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid); void nvdimm_security_overwrite_query(struct work_struct *work); #else @@ -74,12 +77,16 @@ static inline int nvdimm_security_disable(struct nvdimm *nvdimm, { return -EOPNOTSUPP; } -static inline int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, - unsigned int new_keyid) +static inline int nvdimm_security_update(struct nvdimm *nvdimm, + unsigned int keyid, + unsigned int new_keyid, + enum nvdimm_passphrase_type pass_type) { return -EOPNOTSUPP; } -static inline int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid) +static inline int nvdimm_security_erase(struct nvdimm *nvdimm, + unsigned int keyid, + enum nvdimm_passphrase_type pass_type) { return -EOPNOTSUPP; } diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index 5055979f89c4..d9a39dc251e9 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -121,7 +121,8 @@ static struct key *nvdimm_key_revalidate(struct nvdimm *nvdimm) * Send the same key to the hardware as new and old key to * verify that the key is good. */ - rc = nvdimm->sec.ops->change_key(nvdimm, key_data(key), key_data(key)); + rc = nvdimm->sec.ops->change_key(nvdimm, key_data(key), + key_data(key), NVDIMM_USER); if (rc < 0) { nvdimm_put_key(key); key = NULL; @@ -173,7 +174,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) rc == 0 ? "success" : "fail"); nvdimm_put_key(key); - nvdimm->sec.state = nvdimm_security_state(nvdimm); + nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); return rc; } @@ -222,12 +223,13 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) rc == 0 ? "success" : "fail"); nvdimm_put_key(key); - nvdimm->sec.state = nvdimm_security_state(nvdimm); + nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); return rc; } int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, - unsigned int new_keyid) + unsigned int new_keyid, + enum nvdimm_passphrase_type pass_type) { struct device *dev = &nvdimm->dev; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); @@ -262,18 +264,25 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, } rc = nvdimm->sec.ops->change_key(nvdimm, key ? key_data(key) : NULL, - key_data(newkey)); - dev_dbg(dev, "key: %d %d update: %s\n", + key_data(newkey), pass_type); + dev_dbg(dev, "key: %d %d update%s: %s\n", key_serial(key), key_serial(newkey), + pass_type == NVDIMM_MASTER ? "(master)" : "(user)", rc == 0 ? "success" : "fail"); nvdimm_put_key(newkey); nvdimm_put_key(key); - nvdimm->sec.state = nvdimm_security_state(nvdimm); + if (pass_type == NVDIMM_MASTER) + nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, + NVDIMM_MASTER); + else + nvdimm->sec.state = nvdimm_security_state(nvdimm, + NVDIMM_USER); return rc; } -int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid) +int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, + enum nvdimm_passphrase_type pass_type) { struct device *dev = &nvdimm->dev; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); @@ -303,16 +312,24 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid) return -EBUSY; } + if (nvdimm->sec.ext_state != NVDIMM_SECURITY_UNLOCKED + && pass_type == NVDIMM_MASTER) { + dev_warn(dev, + "Attempt to secure erase in wrong master state.\n"); + return -EOPNOTSUPP; + } + key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); if (!key) return -ENOKEY; - rc = nvdimm->sec.ops->erase(nvdimm, key_data(key)); - dev_dbg(dev, "key: %d erase: %s\n", key_serial(key), + rc = nvdimm->sec.ops->erase(nvdimm, key_data(key), pass_type); + dev_dbg(dev, "key: %d erase%s: %s\n", key_serial(key), + pass_type == NVDIMM_MASTER ? "(master)" : "(user)", rc == 0 ? "success" : "fail"); nvdimm_put_key(key); - nvdimm->sec.state = nvdimm_security_state(nvdimm); + nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); return rc; } @@ -375,6 +392,7 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) get_device(dev); queue_delayed_work(system_wq, &nvdimm->dwork, 0); } + return rc; } @@ -421,7 +439,8 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); clear_bit(NDD_WORK_PENDING, &nvdimm->flags); put_device(&nvdimm->dev); - nvdimm->sec.state = nvdimm_security_state(nvdimm); + nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); + nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); } void nvdimm_security_overwrite_query(struct work_struct *work) diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index d18885304020..5440f11b0907 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -174,18 +174,26 @@ struct nvdimm_key_data { u8 data[NVDIMM_PASSPHRASE_LEN]; }; +enum nvdimm_passphrase_type { + NVDIMM_USER, + NVDIMM_MASTER, +}; + struct nvdimm_security_ops { - enum nvdimm_security_state (*state)(struct nvdimm *nvdimm); + enum nvdimm_security_state (*state)(struct nvdimm *nvdimm, + enum nvdimm_passphrase_type pass_type); int (*freeze)(struct nvdimm *nvdimm); int (*change_key)(struct nvdimm *nvdimm, const struct nvdimm_key_data *old_data, - const struct nvdimm_key_data *new_data); + const struct nvdimm_key_data *new_data, + enum nvdimm_passphrase_type pass_type); int (*unlock)(struct nvdimm *nvdimm, const struct nvdimm_key_data *key_data); int (*disable)(struct nvdimm *nvdimm, const struct nvdimm_key_data *key_data); int (*erase)(struct nvdimm *nvdimm, - const struct nvdimm_key_data *key_data); + const struct nvdimm_key_data *key_data, + enum nvdimm_passphrase_type pass_type); int (*overwrite)(struct nvdimm *nvdimm, const struct nvdimm_key_data *key_data); int (*query_overwrite)(struct nvdimm *nvdimm); -- cgit v1.2.3-55-g7522 From 37379cfc661e51607733f266d9f407b4f8aee16b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 22 Dec 2018 11:35:41 -0800 Subject: libnvdimm/security: Quiet security operations The security implementation is too chatty. For example, the common case is that security is not enabled / setup, and booting a qemu configuration currently yields: nvdimm nmem0: request_key() found no key nvdimm nmem0: failed to unlock dimm: -126 nvdimm nmem1: request_key() found no key nvdimm nmem1: failed to unlock dimm: -126 Convert all security related log messages to debug level. Cc: Dave Jiang Signed-off-by: Dan Williams --- drivers/nvdimm/dimm.c | 2 +- drivers/nvdimm/security.c | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/nvdimm/security.c') diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 1b3d9e7b2ffe..0cf58cabc9ed 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -62,7 +62,7 @@ static int nvdimm_probe(struct device *dev) */ rc = nvdimm_security_unlock(dev); if (rc < 0) - dev_err(dev, "failed to unlock dimm: %d\n", rc); + dev_dbg(dev, "failed to unlock dimm: %d\n", rc); /* diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index d9a39dc251e9..f8bb746a549f 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -56,9 +56,9 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) key = request_key(&key_type_encrypted, desc, ""); if (IS_ERR(key)) { if (PTR_ERR(key) == -ENOKEY) - dev_warn(dev, "request_key() found no key\n"); + dev_dbg(dev, "request_key() found no key\n"); else - dev_warn(dev, "request_key() upcall failed\n"); + dev_dbg(dev, "request_key() upcall failed\n"); key = NULL; } else { struct encrypted_key_payload *epayload; @@ -145,7 +145,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) return -EIO; if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { - dev_warn(dev, "Security operation in progress.\n"); + dev_dbg(dev, "Security operation in progress.\n"); return -EBUSY; } @@ -204,13 +204,13 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) return -EOPNOTSUPP; if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { - dev_warn(dev, "Incorrect security state: %d\n", + dev_dbg(dev, "Incorrect security state: %d\n", nvdimm->sec.state); return -EIO; } if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { - dev_warn(dev, "Security operation in progress.\n"); + dev_dbg(dev, "Security operation in progress.\n"); return -EBUSY; } @@ -244,7 +244,7 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, return -EOPNOTSUPP; if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { - dev_warn(dev, "Incorrect security state: %d\n", + dev_dbg(dev, "Incorrect security state: %d\n", nvdimm->sec.state); return -EIO; } @@ -297,24 +297,24 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, return -EOPNOTSUPP; if (atomic_read(&nvdimm->busy)) { - dev_warn(dev, "Unable to secure erase while DIMM active.\n"); + dev_dbg(dev, "Unable to secure erase while DIMM active.\n"); return -EBUSY; } if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { - dev_warn(dev, "Incorrect security state: %d\n", + dev_dbg(dev, "Incorrect security state: %d\n", nvdimm->sec.state); return -EIO; } if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { - dev_warn(dev, "Security operation in progress.\n"); + dev_dbg(dev, "Security operation in progress.\n"); return -EBUSY; } if (nvdimm->sec.ext_state != NVDIMM_SECURITY_UNLOCKED && pass_type == NVDIMM_MASTER) { - dev_warn(dev, + dev_dbg(dev, "Attempt to secure erase in wrong master state.\n"); return -EOPNOTSUPP; } @@ -348,23 +348,23 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) return -EOPNOTSUPP; if (atomic_read(&nvdimm->busy)) { - dev_warn(dev, "Unable to overwrite while DIMM active.\n"); + dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); return -EBUSY; } if (dev->driver == NULL) { - dev_warn(dev, "Unable to overwrite while DIMM active.\n"); + dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); return -EINVAL; } if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { - dev_warn(dev, "Incorrect security state: %d\n", + dev_dbg(dev, "Incorrect security state: %d\n", nvdimm->sec.state); return -EIO; } if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { - dev_warn(dev, "Security operation in progress.\n"); + dev_dbg(dev, "Security operation in progress.\n"); return -EBUSY; } @@ -429,7 +429,7 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) } if (rc < 0) - dev_warn(&nvdimm->dev, "overwrite failed\n"); + dev_dbg(&nvdimm->dev, "overwrite failed\n"); else dev_dbg(&nvdimm->dev, "overwrite completed\n"); -- cgit v1.2.3-55-g7522