diff options
-rw-r--r-- | drivers/acpi/nfit/intel.c | 59 | ||||
-rw-r--r-- | drivers/nvdimm/bus.c | 2 | ||||
-rw-r--r-- | drivers/nvdimm/dimm_devs.c | 59 | ||||
-rw-r--r-- | drivers/nvdimm/nd-core.h | 21 | ||||
-rw-r--r-- | drivers/nvdimm/security.c | 99 | ||||
-rw-r--r-- | include/linux/libnvdimm.h | 9 | ||||
-rw-r--r-- | tools/testing/nvdimm/dimm_devs.c | 19 |
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 | ||
10 | static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, | 10 | static 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 | ||
72 | static int intel_security_freeze(struct nvdimm *nvdimm) | 77 | static int intel_security_freeze(struct nvdimm *nvdimm) |
@@ -371,7 +376,7 @@ static void nvdimm_invalidate_cache(void) | |||
371 | #endif | 376 | #endif |
372 | 377 | ||
373 | static const struct nvdimm_security_ops __intel_security_ops = { | 378 | static 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 | ||
386 | static 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 | } | ||
394 | static 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 | ||
525 | struct attribute_group nvdimm_attribute_group = { | 536 | struct 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 | ||
50 | static inline enum nvdimm_security_state nvdimm_security_state( | 50 | static 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 | } |
58 | int nvdimm_security_freeze(struct nvdimm *nvdimm); | 69 | int 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 | ||
220 | static 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 | |||
220 | int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | 238 | int 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 | ||
474 | void nvdimm_security_overwrite_query(struct work_struct *work) | 469 | void 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 | ||
163 | enum 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 | */ | ||
167 | enum 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 | ||
184 | struct nvdimm_security_ops { | 187 | struct 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 | |||