aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nvdimm
diff options
context:
space:
mode:
authorDave Jiang <dave.jiang@intel.com>2018-12-07 16:02:12 -0500
committerDan Williams <dan.j.williams@intel.com>2018-12-21 15:44:41 -0500
commit64e77c8c047fb91ea8c7800c1238108a72f0bf9c (patch)
tree59aef33ac371f18b005319560addc9c9c85dea9b /drivers/nvdimm
parentd2a4ac73f56a5d0709d28b41fec8d15e4500f8f1 (diff)
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 <keyid>" is written to the "security" sysfs attribute. Signed-off-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/nvdimm')
-rw-r--r--drivers/nvdimm/dimm_devs.c9
-rw-r--r--drivers/nvdimm/nd-core.h5
-rw-r--r--drivers/nvdimm/security.c41
3 files changed, 53 insertions, 2 deletions
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,
394#define OPS \ 394#define OPS \
395 C( OP_FREEZE, "freeze", 1), \ 395 C( OP_FREEZE, "freeze", 1), \
396 C( OP_DISABLE, "disable", 2), \ 396 C( OP_DISABLE, "disable", 2), \
397 C( OP_UPDATE, "update", 3) 397 C( OP_UPDATE, "update", 3), \
398 C( OP_ERASE, "erase", 2)
398#undef C 399#undef C
399#define C(a, b, c) a 400#define C(a, b, c) a
400enum nvdimmsec_op_ids { OPS }; 401enum nvdimmsec_op_ids { OPS };
@@ -448,6 +449,9 @@ static ssize_t __security_store(struct device *dev, const char *buf, size_t len)
448 } else if (i == OP_UPDATE) { 449 } else if (i == OP_UPDATE) {
449 dev_dbg(dev, "update %u %u\n", key, newkey); 450 dev_dbg(dev, "update %u %u\n", key, newkey);
450 rc = nvdimm_security_update(nvdimm, key, newkey); 451 rc = nvdimm_security_update(nvdimm, key, newkey);
452 } else if (i == OP_ERASE) {
453 dev_dbg(dev, "erase %u\n", key);
454 rc = nvdimm_security_erase(nvdimm, key);
451 } else 455 } else
452 return -EINVAL; 456 return -EINVAL;
453 457
@@ -498,7 +502,8 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n)
498 return 0; 502 return 0;
499 /* Are there any state mutation ops? */ 503 /* Are there any state mutation ops? */
500 if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable 504 if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable
501 || nvdimm->sec.ops->change_key) 505 || nvdimm->sec.ops->change_key
506 || nvdimm->sec.ops->erase)
502 return a->mode; 507 return a->mode;
503 return 0444; 508 return 0444;
504} 509}
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);
61int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); 61int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid);
62int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, 62int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
63 unsigned int new_keyid); 63 unsigned int new_keyid);
64int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid);
64#else 65#else
65static inline int nvdimm_security_disable(struct nvdimm *nvdimm, 66static inline int nvdimm_security_disable(struct nvdimm *nvdimm,
66 unsigned int keyid) 67 unsigned int keyid)
@@ -72,6 +73,10 @@ static inline int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int key
72{ 73{
73 return -EOPNOTSUPP; 74 return -EOPNOTSUPP;
74} 75}
76static inline int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid)
77{
78 return -EOPNOTSUPP;
79}
75#endif 80#endif
76 81
77/** 82/**
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)
33 33
34static void nvdimm_put_key(struct key *key) 34static void nvdimm_put_key(struct key *key)
35{ 35{
36 if (!key)
37 return;
38
36 up_read(&key->sem); 39 up_read(&key->sem);
37 key_put(key); 40 key_put(key);
38} 41}
@@ -259,3 +262,41 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
259 nvdimm->sec.state = nvdimm_security_state(nvdimm); 262 nvdimm->sec.state = nvdimm_security_state(nvdimm);
260 return rc; 263 return rc;
261} 264}
265
266int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid)
267{
268 struct device *dev = &nvdimm->dev;
269 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
270 struct key *key;
271 int rc;
272
273 /* The bus lock should be held at the top level of the call stack */
274 lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
275
276 if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase
277 || nvdimm->sec.state < 0)
278 return -EOPNOTSUPP;
279
280 if (atomic_read(&nvdimm->busy)) {
281 dev_warn(dev, "Unable to secure erase while DIMM active.\n");
282 return -EBUSY;
283 }
284
285 if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) {
286 dev_warn(dev, "Incorrect security state: %d\n",
287 nvdimm->sec.state);
288 return -EIO;
289 }
290
291 key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY);
292 if (!key)
293 return -ENOKEY;
294
295 rc = nvdimm->sec.ops->erase(nvdimm, key_data(key));
296 dev_dbg(dev, "key: %d erase: %s\n", key_serial(key),
297 rc == 0 ? "success" : "fail");
298
299 nvdimm_put_key(key);
300 nvdimm->sec.state = nvdimm_security_state(nvdimm);
301 return rc;
302}