aboutsummaryrefslogtreecommitdiff
path: root/drivers/nvdimm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nvdimm')
-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
4 files changed, 99 insertions, 82 deletions
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)
/* We are shutting down. Make state frozen artificially. */
nvdimm_bus_lock(dev);
- nvdimm->sec.state = NVDIMM_SECURITY_FROZEN;
+ set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags);
if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags))
dev_put = true;
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,
{
struct nvdimm *nvdimm = to_nvdimm(dev);
- switch (nvdimm->sec.state) {
- case NVDIMM_SECURITY_DISABLED:
+ if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
return sprintf(buf, "disabled\n");
- case NVDIMM_SECURITY_UNLOCKED:
+ if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags))
return sprintf(buf, "unlocked\n");
- case NVDIMM_SECURITY_LOCKED:
+ if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags))
return sprintf(buf, "locked\n");
- case NVDIMM_SECURITY_FROZEN:
- return sprintf(buf, "frozen\n");
- case NVDIMM_SECURITY_OVERWRITE:
+ if (test_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags))
return sprintf(buf, "overwrite\n");
- default:
- return -ENOTTY;
- }
-
return -ENOTTY;
}
+static ssize_t frozen_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+
+ return sprintf(buf, "%d\n", test_bit(NVDIMM_SECURITY_FROZEN,
+ &nvdimm->sec.flags));
+}
+static DEVICE_ATTR_RO(frozen);
+
#define OPS \
C( OP_FREEZE, "freeze", 1), \
C( OP_DISABLE, "disable", 2), \
@@ -501,6 +504,7 @@ static struct attribute *nvdimm_attributes[] = {
&dev_attr_commands.attr,
&dev_attr_available_slots.attr,
&dev_attr_security.attr,
+ &dev_attr_frozen.attr,
NULL,
};
@@ -509,17 +513,24 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n)
struct device *dev = container_of(kobj, typeof(*dev), kobj);
struct nvdimm *nvdimm = to_nvdimm(dev);
- if (a != &dev_attr_security.attr)
+ if (a != &dev_attr_security.attr && a != &dev_attr_frozen.attr)
return a->mode;
- if (nvdimm->sec.state < 0)
+ if (!nvdimm->sec.flags)
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->erase
- || nvdimm->sec.ops->overwrite)
+
+ if (a == &dev_attr_security.attr) {
+ /* Are there any state mutation ops (make writable)? */
+ if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable
+ || nvdimm->sec.ops->change_key
+ || nvdimm->sec.ops->erase
+ || nvdimm->sec.ops->overwrite)
+ return a->mode;
+ return 0444;
+ }
+
+ if (nvdimm->sec.ops->freeze)
return a->mode;
- return 0444;
+ return 0;
}
struct attribute_group nvdimm_attribute_group = {
@@ -569,8 +580,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
* attribute visibility.
*/
/* 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);
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
+ nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
nd_device_register(dev);
return nvdimm;
@@ -588,7 +599,7 @@ int nvdimm_security_setup_events(struct device *dev)
{
struct nvdimm *nvdimm = to_nvdimm(dev);
- if (nvdimm->sec.state < 0 || !nvdimm->sec.ops
+ if (!nvdimm->sec.flags || !nvdimm->sec.ops
|| !nvdimm->sec.ops->overwrite)
return 0;
nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security");
@@ -614,7 +625,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze)
return -EOPNOTSUPP;
- if (nvdimm->sec.state < 0)
+ if (!nvdimm->sec.flags)
return -EIO;
if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
@@ -623,7 +634,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
}
rc = nvdimm->sec.ops->freeze(nvdimm);
- nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER);
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return rc;
}
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 {
const char *dimm_id;
struct {
const struct nvdimm_security_ops *ops;
- enum nvdimm_security_state state;
- enum nvdimm_security_state ext_state;
+ unsigned long flags;
+ unsigned long ext_flags;
unsigned int overwrite_tmo;
struct kernfs_node *overwrite_state;
} sec;
struct delayed_work dwork;
};
-static inline enum nvdimm_security_state nvdimm_security_state(
+static inline unsigned long nvdimm_security_flags(
struct nvdimm *nvdimm, enum nvdimm_passphrase_type ptype)
{
+ u64 flags;
+ const u64 state_flags = 1UL << NVDIMM_SECURITY_DISABLED
+ | 1UL << NVDIMM_SECURITY_LOCKED
+ | 1UL << NVDIMM_SECURITY_UNLOCKED
+ | 1UL << NVDIMM_SECURITY_OVERWRITE;
+
if (!nvdimm->sec.ops)
- return -ENXIO;
+ return 0;
- return nvdimm->sec.ops->state(nvdimm, ptype);
+ flags = nvdimm->sec.ops->get_flags(nvdimm, ptype);
+ /* disabled, locked, unlocked, and overwrite are mutually exclusive */
+ dev_WARN_ONCE(&nvdimm->dev, hweight64(flags & state_flags) > 1,
+ "reported invalid security state: %#llx\n",
+ (unsigned long long) flags);
+ return flags;
}
int nvdimm_security_freeze(struct nvdimm *nvdimm);
#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)
}
nvdimm_put_key(key);
- nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER);
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return 0;
}
@@ -174,7 +174,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock
- || nvdimm->sec.state < 0)
+ || !nvdimm->sec.flags)
return -EIO;
if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
@@ -189,7 +189,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
* 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 (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags)) {
if (!key_revalidate)
return 0;
@@ -202,7 +202,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_USER);
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return rc;
}
@@ -217,6 +217,24 @@ int nvdimm_security_unlock(struct device *dev)
return rc;
}
+static int check_security_state(struct nvdimm *nvdimm)
+{
+ struct device *dev = &nvdimm->dev;
+
+ if (test_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags)) {
+ dev_dbg(dev, "Incorrect security state: %#lx\n",
+ nvdimm->sec.flags);
+ return -EIO;
+ }
+
+ if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
+ dev_dbg(dev, "Security operation in progress.\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
{
struct device *dev = &nvdimm->dev;
@@ -229,19 +247,12 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable
- || nvdimm->sec.state < 0)
+ || !nvdimm->sec.flags)
return -EOPNOTSUPP;
- if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) {
- dev_dbg(dev, "Incorrect security state: %d\n",
- nvdimm->sec.state);
- return -EIO;
- }
-
- if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
- dev_dbg(dev, "Security operation in progress.\n");
- return -EBUSY;
- }
+ rc = check_security_state(nvdimm);
+ if (rc)
+ return rc;
data = nvdimm_get_user_key_payload(nvdimm, keyid,
NVDIMM_BASE_KEY, &key);
@@ -253,7 +264,7 @@ 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_USER);
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return rc;
}
@@ -271,14 +282,12 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key
- || nvdimm->sec.state < 0)
+ || !nvdimm->sec.flags)
return -EOPNOTSUPP;
- if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) {
- dev_dbg(dev, "Incorrect security state: %d\n",
- nvdimm->sec.state);
- return -EIO;
- }
+ rc = check_security_state(nvdimm);
+ if (rc)
+ return rc;
data = nvdimm_get_user_key_payload(nvdimm, keyid,
NVDIMM_BASE_KEY, &key);
@@ -301,10 +310,10 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
nvdimm_put_key(newkey);
nvdimm_put_key(key);
if (pass_type == NVDIMM_MASTER)
- nvdimm->sec.ext_state = nvdimm_security_state(nvdimm,
+ nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm,
NVDIMM_MASTER);
else
- nvdimm->sec.state = nvdimm_security_state(nvdimm,
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm,
NVDIMM_USER);
return rc;
}
@@ -322,7 +331,7 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid,
lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase
- || nvdimm->sec.state < 0)
+ || !nvdimm->sec.flags)
return -EOPNOTSUPP;
if (atomic_read(&nvdimm->busy)) {
@@ -330,18 +339,11 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid,
return -EBUSY;
}
- if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) {
- dev_dbg(dev, "Incorrect security state: %d\n",
- nvdimm->sec.state);
- return -EIO;
- }
-
- if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
- dev_dbg(dev, "Security operation in progress.\n");
- return -EBUSY;
- }
+ rc = check_security_state(nvdimm);
+ if (rc)
+ return rc;
- if (nvdimm->sec.ext_state != NVDIMM_SECURITY_UNLOCKED
+ if (!test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.ext_flags)
&& pass_type == NVDIMM_MASTER) {
dev_dbg(dev,
"Attempt to secure erase in wrong master state.\n");
@@ -359,7 +361,7 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid,
rc == 0 ? "success" : "fail");
nvdimm_put_key(key);
- nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER);
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return rc;
}
@@ -375,7 +377,7 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite
- || nvdimm->sec.state < 0)
+ || !nvdimm->sec.flags)
return -EOPNOTSUPP;
if (atomic_read(&nvdimm->busy)) {
@@ -388,16 +390,9 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
return -EINVAL;
}
- if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) {
- dev_dbg(dev, "Incorrect security state: %d\n",
- nvdimm->sec.state);
- return -EIO;
- }
-
- if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
- dev_dbg(dev, "Security operation in progress.\n");
- return -EBUSY;
- }
+ rc = check_security_state(nvdimm);
+ if (rc)
+ return rc;
data = nvdimm_get_user_key_payload(nvdimm, keyid,
NVDIMM_BASE_KEY, &key);
@@ -412,7 +407,7 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
if (rc == 0) {
set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
set_bit(NDD_WORK_PENDING, &nvdimm->flags);
- nvdimm->sec.state = NVDIMM_SECURITY_OVERWRITE;
+ set_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags);
/*
* Make sure we don't lose device while doing overwrite
* query.
@@ -443,7 +438,7 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm)
tmo = nvdimm->sec.overwrite_tmo;
if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite
- || nvdimm->sec.state < 0)
+ || !nvdimm->sec.flags)
return;
rc = nvdimm->sec.ops->query_overwrite(nvdimm);
@@ -467,8 +462,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_USER);
- nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER);
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
+ nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
}
void nvdimm_security_overwrite_query(struct work_struct *work)