summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2019-08-26 20:54:54 -0400
committerDan Williams <dan.j.williams@intel.com>2019-08-29 16:49:13 -0400
commitd78c620a2e824d7b01a6e991208a8aa2c938cabe (patch)
treec37be9e345e45b7370fc4b0287472a478b790b7d
parent2b90cb223320a93b1be6c2616efe6f9ff14d8b28 (diff)
libnvdimm/security: Introduce a 'frozen' attribute
In the process of debugging a system with an NVDIMM that was failing to unlock it was found that the kernel is reporting 'locked' while the DIMM security interface is 'frozen'. Unfortunately the security state is tracked internally as an enum which prevents it from communicating the difference between 'locked' and 'locked + frozen'. It follows that the enum also prevents the kernel from communicating 'unlocked + frozen' which would be useful for debugging why security operations like 'change passphrase' are disabled. Ditch the security state enum for a set of flags and introduce a new sysfs attribute explicitly for the 'frozen' state. The regression risk is low because the 'frozen' state was already blocked behind the 'locked' state, but will need to revisit if there were cases where applications need 'frozen' to show up in the primary 'security' attribute. The expectation is that communicating 'frozen' is mostly a helper for debug and status monitoring. Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reported-by: Jeff Moyer <jmoyer@redhat.com> Reviewed-by: Jeff Moyer <jmoyer@redhat.com> Link: https://lore.kernel.org/r/156686729474.184120.5835135644278860826.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/acpi/nfit/intel.c59
-rw-r--r--drivers/nvdimm/bus.c2
-rw-r--r--drivers/nvdimm/dimm_devs.c59
-rw-r--r--drivers/nvdimm/nd-core.h21
-rw-r--r--drivers/nvdimm/security.c99
-rw-r--r--include/linux/libnvdimm.h9
-rw-r--r--tools/testing/nvdimm/dimm_devs.c19
7 files changed, 141 insertions, 127 deletions
diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c
index cddd0fcf622c..1113b679cd7b 100644
--- a/drivers/acpi/nfit/intel.c
+++ b/drivers/acpi/nfit/intel.c
@@ -7,10 +7,11 @@
7#include "intel.h" 7#include "intel.h"
8#include "nfit.h" 8#include "nfit.h"
9 9
10static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, 10static unsigned long intel_security_flags(struct nvdimm *nvdimm,
11 enum nvdimm_passphrase_type ptype) 11 enum nvdimm_passphrase_type ptype)
12{ 12{
13 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 13 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
14 unsigned long security_flags = 0;
14 struct { 15 struct {
15 struct nd_cmd_pkg pkg; 16 struct nd_cmd_pkg pkg;
16 struct nd_intel_get_security_state cmd; 17 struct nd_intel_get_security_state cmd;
@@ -27,7 +28,7 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm,
27 int rc; 28 int rc;
28 29
29 if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask)) 30 if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask))
30 return -ENXIO; 31 return 0;
31 32
32 /* 33 /*
33 * Short circuit the state retrieval while we are doing overwrite. 34 * Short circuit the state retrieval while we are doing overwrite.
@@ -35,38 +36,42 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm,
35 * until the overwrite DSM completes. 36 * until the overwrite DSM completes.
36 */ 37 */
37 if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER) 38 if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER)
38 return NVDIMM_SECURITY_OVERWRITE; 39 return BIT(NVDIMM_SECURITY_OVERWRITE);
39 40
40 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 41 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
41 if (rc < 0) 42 if (rc < 0 || nd_cmd.cmd.status) {
42 return rc; 43 pr_err("%s: security state retrieval failed (%d:%#x)\n",
43 if (nd_cmd.cmd.status) 44 nvdimm_name(nvdimm), rc, nd_cmd.cmd.status);
44 return -EIO; 45 return 0;
46 }
45 47
46 /* check and see if security is enabled and locked */ 48 /* check and see if security is enabled and locked */
47 if (ptype == NVDIMM_MASTER) { 49 if (ptype == NVDIMM_MASTER) {
48 if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED) 50 if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED)
49 return NVDIMM_SECURITY_UNLOCKED; 51 set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
50 else if (nd_cmd.cmd.extended_state & 52 else
51 ND_INTEL_SEC_ESTATE_PLIMIT) 53 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
52 return NVDIMM_SECURITY_FROZEN; 54 if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_PLIMIT)
53 } else { 55 set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
54 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) 56 return security_flags;
55 return -ENXIO;
56 else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) {
57 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED)
58 return NVDIMM_SECURITY_LOCKED;
59 else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN
60 || nd_cmd.cmd.state &
61 ND_INTEL_SEC_STATE_PLIMIT)
62 return NVDIMM_SECURITY_FROZEN;
63 else
64 return NVDIMM_SECURITY_UNLOCKED;
65 }
66 } 57 }
67 58
68 /* this should cover master security disabled as well */ 59 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED)
69 return NVDIMM_SECURITY_DISABLED; 60 return 0;
61
62 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) {
63 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN ||
64 nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT)
65 set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
66
67 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED)
68 set_bit(NVDIMM_SECURITY_LOCKED, &security_flags);
69 else
70 set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
71 } else
72 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
73
74 return security_flags;
70} 75}
71 76
72static int intel_security_freeze(struct nvdimm *nvdimm) 77static int intel_security_freeze(struct nvdimm *nvdimm)
@@ -371,7 +376,7 @@ static void nvdimm_invalidate_cache(void)
371#endif 376#endif
372 377
373static const struct nvdimm_security_ops __intel_security_ops = { 378static const struct nvdimm_security_ops __intel_security_ops = {
374 .state = intel_security_state, 379 .get_flags = intel_security_flags,
375 .freeze = intel_security_freeze, 380 .freeze = intel_security_freeze,
376 .change_key = intel_security_change_key, 381 .change_key = intel_security_change_key,
377 .disable = intel_security_disable, 382 .disable = intel_security_disable,
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 798c5c4aea9c..29479d3b01b0 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -400,7 +400,7 @@ static int child_unregister(struct device *dev, void *data)
400 400
401 /* We are shutting down. Make state frozen artificially. */ 401 /* We are shutting down. Make state frozen artificially. */
402 nvdimm_bus_lock(dev); 402 nvdimm_bus_lock(dev);
403 nvdimm->sec.state = NVDIMM_SECURITY_FROZEN; 403 set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags);
404 if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags)) 404 if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags))
405 dev_put = true; 405 dev_put = true;
406 nvdimm_bus_unlock(dev); 406 nvdimm_bus_unlock(dev);
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 29a065e769ea..53330625fe07 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -372,24 +372,27 @@ __weak ssize_t security_show(struct device *dev,
372{ 372{
373 struct nvdimm *nvdimm = to_nvdimm(dev); 373 struct nvdimm *nvdimm = to_nvdimm(dev);
374 374
375 switch (nvdimm->sec.state) { 375 if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
376 case NVDIMM_SECURITY_DISABLED:
377 return sprintf(buf, "disabled\n"); 376 return sprintf(buf, "disabled\n");
378 case NVDIMM_SECURITY_UNLOCKED: 377 if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags))
379 return sprintf(buf, "unlocked\n"); 378 return sprintf(buf, "unlocked\n");
380 case NVDIMM_SECURITY_LOCKED: 379 if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags))
381 return sprintf(buf, "locked\n"); 380 return sprintf(buf, "locked\n");
382 case NVDIMM_SECURITY_FROZEN: 381 if (test_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags))
383 return sprintf(buf, "frozen\n");
384 case NVDIMM_SECURITY_OVERWRITE:
385 return sprintf(buf, "overwrite\n"); 382 return sprintf(buf, "overwrite\n");
386 default:
387 return -ENOTTY;
388 }
389
390 return -ENOTTY; 383 return -ENOTTY;
391} 384}
392 385
386static ssize_t frozen_show(struct device *dev,
387 struct device_attribute *attr, char *buf)
388{
389 struct nvdimm *nvdimm = to_nvdimm(dev);
390
391 return sprintf(buf, "%d\n", test_bit(NVDIMM_SECURITY_FROZEN,
392 &nvdimm->sec.flags));
393}
394static DEVICE_ATTR_RO(frozen);
395
393#define OPS \ 396#define OPS \
394 C( OP_FREEZE, "freeze", 1), \ 397 C( OP_FREEZE, "freeze", 1), \
395 C( OP_DISABLE, "disable", 2), \ 398 C( OP_DISABLE, "disable", 2), \
@@ -501,6 +504,7 @@ static struct attribute *nvdimm_attributes[] = {
501 &dev_attr_commands.attr, 504 &dev_attr_commands.attr,
502 &dev_attr_available_slots.attr, 505 &dev_attr_available_slots.attr,
503 &dev_attr_security.attr, 506 &dev_attr_security.attr,
507 &dev_attr_frozen.attr,
504 NULL, 508 NULL,
505}; 509};
506 510
@@ -509,17 +513,24 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n)
509 struct device *dev = container_of(kobj, typeof(*dev), kobj); 513 struct device *dev = container_of(kobj, typeof(*dev), kobj);
510 struct nvdimm *nvdimm = to_nvdimm(dev); 514 struct nvdimm *nvdimm = to_nvdimm(dev);
511 515
512 if (a != &dev_attr_security.attr) 516 if (a != &dev_attr_security.attr && a != &dev_attr_frozen.attr)
513 return a->mode; 517 return a->mode;
514 if (nvdimm->sec.state < 0) 518 if (!nvdimm->sec.flags)
515 return 0; 519 return 0;
516 /* Are there any state mutation ops? */ 520
517 if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable 521 if (a == &dev_attr_security.attr) {
518 || nvdimm->sec.ops->change_key 522 /* Are there any state mutation ops (make writable)? */
519 || nvdimm->sec.ops->erase 523 if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable
520 || nvdimm->sec.ops->overwrite) 524 || nvdimm->sec.ops->change_key
525 || nvdimm->sec.ops->erase
526 || nvdimm->sec.ops->overwrite)
527 return a->mode;
528 return 0444;
529 }
530
531 if (nvdimm->sec.ops->freeze)
521 return a->mode; 532 return a->mode;
522 return 0444; 533 return 0;
523} 534}
524 535
525struct attribute_group nvdimm_attribute_group = { 536struct attribute_group nvdimm_attribute_group = {
@@ -569,8 +580,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
569 * attribute visibility. 580 * attribute visibility.
570 */ 581 */
571 /* get security state and extended (master) state */ 582 /* get security state and extended (master) state */
572 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 583 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
573 nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); 584 nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
574 nd_device_register(dev); 585 nd_device_register(dev);
575 586
576 return nvdimm; 587 return nvdimm;
@@ -588,7 +599,7 @@ int nvdimm_security_setup_events(struct device *dev)
588{ 599{
589 struct nvdimm *nvdimm = to_nvdimm(dev); 600 struct nvdimm *nvdimm = to_nvdimm(dev);
590 601
591 if (nvdimm->sec.state < 0 || !nvdimm->sec.ops 602 if (!nvdimm->sec.flags || !nvdimm->sec.ops
592 || !nvdimm->sec.ops->overwrite) 603 || !nvdimm->sec.ops->overwrite)
593 return 0; 604 return 0;
594 nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security"); 605 nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security");
@@ -614,7 +625,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
614 if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze) 625 if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze)
615 return -EOPNOTSUPP; 626 return -EOPNOTSUPP;
616 627
617 if (nvdimm->sec.state < 0) 628 if (!nvdimm->sec.flags)
618 return -EIO; 629 return -EIO;
619 630
620 if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { 631 if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
@@ -623,7 +634,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
623 } 634 }
624 635
625 rc = nvdimm->sec.ops->freeze(nvdimm); 636 rc = nvdimm->sec.ops->freeze(nvdimm);
626 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 637 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
627 638
628 return rc; 639 return rc;
629} 640}
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index 0ac52b6eb00e..da2bbfd56d9f 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -39,21 +39,32 @@ struct nvdimm {
39 const char *dimm_id; 39 const char *dimm_id;
40 struct { 40 struct {
41 const struct nvdimm_security_ops *ops; 41 const struct nvdimm_security_ops *ops;
42 enum nvdimm_security_state state; 42 unsigned long flags;
43 enum nvdimm_security_state ext_state; 43 unsigned long ext_flags;
44 unsigned int overwrite_tmo; 44 unsigned int overwrite_tmo;
45 struct kernfs_node *overwrite_state; 45 struct kernfs_node *overwrite_state;
46 } sec; 46 } sec;
47 struct delayed_work dwork; 47 struct delayed_work dwork;
48}; 48};
49 49
50static inline enum nvdimm_security_state nvdimm_security_state( 50static inline unsigned long nvdimm_security_flags(
51 struct nvdimm *nvdimm, enum nvdimm_passphrase_type ptype) 51 struct nvdimm *nvdimm, enum nvdimm_passphrase_type ptype)
52{ 52{
53 u64 flags;
54 const u64 state_flags = 1UL << NVDIMM_SECURITY_DISABLED
55 | 1UL << NVDIMM_SECURITY_LOCKED
56 | 1UL << NVDIMM_SECURITY_UNLOCKED
57 | 1UL << NVDIMM_SECURITY_OVERWRITE;
58
53 if (!nvdimm->sec.ops) 59 if (!nvdimm->sec.ops)
54 return -ENXIO; 60 return 0;
55 61
56 return nvdimm->sec.ops->state(nvdimm, ptype); 62 flags = nvdimm->sec.ops->get_flags(nvdimm, ptype);
63 /* disabled, locked, unlocked, and overwrite are mutually exclusive */
64 dev_WARN_ONCE(&nvdimm->dev, hweight64(flags & state_flags) > 1,
65 "reported invalid security state: %#llx\n",
66 (unsigned long long) flags);
67 return flags;
57} 68}
58int nvdimm_security_freeze(struct nvdimm *nvdimm); 69int nvdimm_security_freeze(struct nvdimm *nvdimm);
59#if IS_ENABLED(CONFIG_NVDIMM_KEYS) 70#if IS_ENABLED(CONFIG_NVDIMM_KEYS)
diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c
index a570f2263a42..5862d0eee9db 100644
--- a/drivers/nvdimm/security.c
+++ b/drivers/nvdimm/security.c
@@ -158,7 +158,7 @@ static int nvdimm_key_revalidate(struct nvdimm *nvdimm)
158 } 158 }
159 159
160 nvdimm_put_key(key); 160 nvdimm_put_key(key);
161 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 161 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
162 return 0; 162 return 0;
163} 163}
164 164
@@ -174,7 +174,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
174 lockdep_assert_held(&nvdimm_bus->reconfig_mutex); 174 lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
175 175
176 if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock 176 if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock
177 || nvdimm->sec.state < 0) 177 || !nvdimm->sec.flags)
178 return -EIO; 178 return -EIO;
179 179
180 if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { 180 if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
@@ -189,7 +189,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
189 * freeze of the security configuration. I.e. if the OS does not 189 * freeze of the security configuration. I.e. if the OS does not
190 * have the key, security is being managed pre-OS. 190 * have the key, security is being managed pre-OS.
191 */ 191 */
192 if (nvdimm->sec.state == NVDIMM_SECURITY_UNLOCKED) { 192 if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags)) {
193 if (!key_revalidate) 193 if (!key_revalidate)
194 return 0; 194 return 0;
195 195
@@ -202,7 +202,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
202 rc == 0 ? "success" : "fail"); 202 rc == 0 ? "success" : "fail");
203 203
204 nvdimm_put_key(key); 204 nvdimm_put_key(key);
205 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 205 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
206 return rc; 206 return rc;
207} 207}
208 208
@@ -217,6 +217,24 @@ int nvdimm_security_unlock(struct device *dev)
217 return rc; 217 return rc;
218} 218}
219 219
220static int check_security_state(struct nvdimm *nvdimm)
221{
222 struct device *dev = &nvdimm->dev;
223
224 if (test_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags)) {
225 dev_dbg(dev, "Incorrect security state: %#lx\n",
226 nvdimm->sec.flags);
227 return -EIO;
228 }
229
230 if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
231 dev_dbg(dev, "Security operation in progress.\n");
232 return -EBUSY;
233 }
234
235 return 0;
236}
237
220int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) 238int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
221{ 239{
222 struct device *dev = &nvdimm->dev; 240 struct device *dev = &nvdimm->dev;
@@ -229,19 +247,12 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
229 lockdep_assert_held(&nvdimm_bus->reconfig_mutex); 247 lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
230 248
231 if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable 249 if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable
232 || nvdimm->sec.state < 0) 250 || !nvdimm->sec.flags)
233 return -EOPNOTSUPP; 251 return -EOPNOTSUPP;
234 252
235 if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { 253 rc = check_security_state(nvdimm);
236 dev_dbg(dev, "Incorrect security state: %d\n", 254 if (rc)
237 nvdimm->sec.state); 255 return rc;
238 return -EIO;
239 }
240
241 if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
242 dev_dbg(dev, "Security operation in progress.\n");
243 return -EBUSY;
244 }
245 256
246 data = nvdimm_get_user_key_payload(nvdimm, keyid, 257 data = nvdimm_get_user_key_payload(nvdimm, keyid,
247 NVDIMM_BASE_KEY, &key); 258 NVDIMM_BASE_KEY, &key);
@@ -253,7 +264,7 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
253 rc == 0 ? "success" : "fail"); 264 rc == 0 ? "success" : "fail");
254 265
255 nvdimm_put_key(key); 266 nvdimm_put_key(key);
256 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 267 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
257 return rc; 268 return rc;
258} 269}
259 270
@@ -271,14 +282,12 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
271 lockdep_assert_held(&nvdimm_bus->reconfig_mutex); 282 lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
272 283
273 if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key 284 if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key
274 || nvdimm->sec.state < 0) 285 || !nvdimm->sec.flags)
275 return -EOPNOTSUPP; 286 return -EOPNOTSUPP;
276 287
277 if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { 288 rc = check_security_state(nvdimm);
278 dev_dbg(dev, "Incorrect security state: %d\n", 289 if (rc)
279 nvdimm->sec.state); 290 return rc;
280 return -EIO;
281 }
282 291
283 data = nvdimm_get_user_key_payload(nvdimm, keyid, 292 data = nvdimm_get_user_key_payload(nvdimm, keyid,
284 NVDIMM_BASE_KEY, &key); 293 NVDIMM_BASE_KEY, &key);
@@ -301,10 +310,10 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
301 nvdimm_put_key(newkey); 310 nvdimm_put_key(newkey);
302 nvdimm_put_key(key); 311 nvdimm_put_key(key);
303 if (pass_type == NVDIMM_MASTER) 312 if (pass_type == NVDIMM_MASTER)
304 nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, 313 nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm,
305 NVDIMM_MASTER); 314 NVDIMM_MASTER);
306 else 315 else
307 nvdimm->sec.state = nvdimm_security_state(nvdimm, 316 nvdimm->sec.flags = nvdimm_security_flags(nvdimm,
308 NVDIMM_USER); 317 NVDIMM_USER);
309 return rc; 318 return rc;
310} 319}
@@ -322,7 +331,7 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid,
322 lockdep_assert_held(&nvdimm_bus->reconfig_mutex); 331 lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
323 332
324 if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase 333 if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase
325 || nvdimm->sec.state < 0) 334 || !nvdimm->sec.flags)
326 return -EOPNOTSUPP; 335 return -EOPNOTSUPP;
327 336
328 if (atomic_read(&nvdimm->busy)) { 337 if (atomic_read(&nvdimm->busy)) {
@@ -330,18 +339,11 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid,
330 return -EBUSY; 339 return -EBUSY;
331 } 340 }
332 341
333 if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { 342 rc = check_security_state(nvdimm);
334 dev_dbg(dev, "Incorrect security state: %d\n", 343 if (rc)
335 nvdimm->sec.state); 344 return rc;
336 return -EIO;
337 }
338
339 if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
340 dev_dbg(dev, "Security operation in progress.\n");
341 return -EBUSY;
342 }
343 345
344 if (nvdimm->sec.ext_state != NVDIMM_SECURITY_UNLOCKED 346 if (!test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.ext_flags)
345 && pass_type == NVDIMM_MASTER) { 347 && pass_type == NVDIMM_MASTER) {
346 dev_dbg(dev, 348 dev_dbg(dev,
347 "Attempt to secure erase in wrong master state.\n"); 349 "Attempt to secure erase in wrong master state.\n");
@@ -359,7 +361,7 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid,
359 rc == 0 ? "success" : "fail"); 361 rc == 0 ? "success" : "fail");
360 362
361 nvdimm_put_key(key); 363 nvdimm_put_key(key);
362 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 364 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
363 return rc; 365 return rc;
364} 366}
365 367
@@ -375,7 +377,7 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
375 lockdep_assert_held(&nvdimm_bus->reconfig_mutex); 377 lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
376 378
377 if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite 379 if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite
378 || nvdimm->sec.state < 0) 380 || !nvdimm->sec.flags)
379 return -EOPNOTSUPP; 381 return -EOPNOTSUPP;
380 382
381 if (atomic_read(&nvdimm->busy)) { 383 if (atomic_read(&nvdimm->busy)) {
@@ -388,16 +390,9 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
388 return -EINVAL; 390 return -EINVAL;
389 } 391 }
390 392
391 if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { 393 rc = check_security_state(nvdimm);
392 dev_dbg(dev, "Incorrect security state: %d\n", 394 if (rc)
393 nvdimm->sec.state); 395 return rc;
394 return -EIO;
395 }
396
397 if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
398 dev_dbg(dev, "Security operation in progress.\n");
399 return -EBUSY;
400 }
401 396
402 data = nvdimm_get_user_key_payload(nvdimm, keyid, 397 data = nvdimm_get_user_key_payload(nvdimm, keyid,
403 NVDIMM_BASE_KEY, &key); 398 NVDIMM_BASE_KEY, &key);
@@ -412,7 +407,7 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
412 if (rc == 0) { 407 if (rc == 0) {
413 set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); 408 set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
414 set_bit(NDD_WORK_PENDING, &nvdimm->flags); 409 set_bit(NDD_WORK_PENDING, &nvdimm->flags);
415 nvdimm->sec.state = NVDIMM_SECURITY_OVERWRITE; 410 set_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags);
416 /* 411 /*
417 * Make sure we don't lose device while doing overwrite 412 * Make sure we don't lose device while doing overwrite
418 * query. 413 * query.
@@ -443,7 +438,7 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm)
443 tmo = nvdimm->sec.overwrite_tmo; 438 tmo = nvdimm->sec.overwrite_tmo;
444 439
445 if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite 440 if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite
446 || nvdimm->sec.state < 0) 441 || !nvdimm->sec.flags)
447 return; 442 return;
448 443
449 rc = nvdimm->sec.ops->query_overwrite(nvdimm); 444 rc = nvdimm->sec.ops->query_overwrite(nvdimm);
@@ -467,8 +462,8 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm)
467 clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); 462 clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
468 clear_bit(NDD_WORK_PENDING, &nvdimm->flags); 463 clear_bit(NDD_WORK_PENDING, &nvdimm->flags);
469 put_device(&nvdimm->dev); 464 put_device(&nvdimm->dev);
470 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 465 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
471 nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); 466 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
472} 467}
473 468
474void nvdimm_security_overwrite_query(struct work_struct *work) 469void nvdimm_security_overwrite_query(struct work_struct *work)
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 7a64b3ddb408..b6eddf912568 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -160,8 +160,11 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
160 160
161} 161}
162 162
163enum nvdimm_security_state { 163/*
164 NVDIMM_SECURITY_ERROR = -1, 164 * Note that separate bits for locked + unlocked are defined so that
165 * 'flags == 0' corresponds to an error / not-supported state.
166 */
167enum nvdimm_security_bits {
165 NVDIMM_SECURITY_DISABLED, 168 NVDIMM_SECURITY_DISABLED,
166 NVDIMM_SECURITY_UNLOCKED, 169 NVDIMM_SECURITY_UNLOCKED,
167 NVDIMM_SECURITY_LOCKED, 170 NVDIMM_SECURITY_LOCKED,
@@ -182,7 +185,7 @@ enum nvdimm_passphrase_type {
182}; 185};
183 186
184struct nvdimm_security_ops { 187struct nvdimm_security_ops {
185 enum nvdimm_security_state (*state)(struct nvdimm *nvdimm, 188 unsigned long (*get_flags)(struct nvdimm *nvdimm,
186 enum nvdimm_passphrase_type pass_type); 189 enum nvdimm_passphrase_type pass_type);
187 int (*freeze)(struct nvdimm *nvdimm); 190 int (*freeze)(struct nvdimm *nvdimm);
188 int (*change_key)(struct nvdimm *nvdimm, 191 int (*change_key)(struct nvdimm *nvdimm,
diff --git a/tools/testing/nvdimm/dimm_devs.c b/tools/testing/nvdimm/dimm_devs.c
index 2d4baf57822f..57bd27dedf1f 100644
--- a/tools/testing/nvdimm/dimm_devs.c
+++ b/tools/testing/nvdimm/dimm_devs.c
@@ -18,24 +18,13 @@ ssize_t security_show(struct device *dev,
18 * For the test version we need to poll the "hardware" in order 18 * For the test version we need to poll the "hardware" in order
19 * to get the updated status for unlock testing. 19 * to get the updated status for unlock testing.
20 */ 20 */
21 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 21 nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
22 nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER);
23 22
24 switch (nvdimm->sec.state) { 23 if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
25 case NVDIMM_SECURITY_DISABLED:
26 return sprintf(buf, "disabled\n"); 24 return sprintf(buf, "disabled\n");
27 case NVDIMM_SECURITY_UNLOCKED: 25 if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags))
28 return sprintf(buf, "unlocked\n"); 26 return sprintf(buf, "unlocked\n");
29 case NVDIMM_SECURITY_LOCKED: 27 if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags))
30 return sprintf(buf, "locked\n"); 28 return sprintf(buf, "locked\n");
31 case NVDIMM_SECURITY_FROZEN:
32 return sprintf(buf, "frozen\n");
33 case NVDIMM_SECURITY_OVERWRITE:
34 return sprintf(buf, "overwrite\n");
35 default:
36 return -ENOTTY;
37 }
38
39 return -ENOTTY; 29 return -ENOTTY;
40} 30}
41