Commit 6cb2e9ee authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'libnvdimm-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm

Pull libnvdimm updates from Dan Williams:
 "Some reworks to better support nvdimms on powerpc and an nvdimm
  security interface update:

   - Rework the nvdimm core to accommodate architectures with different
     page sizes and ones that can change supported huge page sizes at
     boot time rather than a compile time constant.

   - Introduce a distinct 'frozen' attribute for the nvdimm security
     state since it is independent of the locked state.

   - Miscellaneous fixups"

* tag 'libnvdimm-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm:
  libnvdimm: Use PAGE_SIZE instead of SZ_4K for align check
  libnvdimm/label: Remove the dpa align check
  libnvdimm/pfn_dev: Add page size and struct page size to pfn superblock
  libnvdimm/pfn_dev: Add a build check to make sure we notice when struct page size change
  libnvdimm/pmem: Advance namespace seed for specific probe errors
  libnvdimm/region: Rewrite _probe_success() to _advance_seeds()
  libnvdimm/security: Consolidate 'security' operations
  libnvdimm/security: Tighten scope of nvdimm->busy vs security operations
  libnvdimm/security: Introduce a 'frozen' attribute
  libnvdimm, region: Use struct_size() in kzalloc()
  tools/testing/nvdimm: Fix fallthrough warning
  libnvdimm/of_pmem: Provide a unique name for bus provider
parents 10fd7178 5b26db95
...@@ -7,10 +7,11 @@ ...@@ -7,10 +7,11 @@
#include "intel.h" #include "intel.h"
#include "nfit.h" #include "nfit.h"
static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, static unsigned long intel_security_flags(struct nvdimm *nvdimm,
enum nvdimm_passphrase_type ptype) enum nvdimm_passphrase_type ptype)
{ {
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
unsigned long security_flags = 0;
struct { struct {
struct nd_cmd_pkg pkg; struct nd_cmd_pkg pkg;
struct nd_intel_get_security_state cmd; struct nd_intel_get_security_state cmd;
...@@ -27,7 +28,7 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, ...@@ -27,7 +28,7 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm,
int rc; int rc;
if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask)) if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask))
return -ENXIO; return 0;
/* /*
* Short circuit the state retrieval while we are doing overwrite. * 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,38 +36,42 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm,
* until the overwrite DSM completes. * until the overwrite DSM completes.
*/ */
if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER) if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER)
return NVDIMM_SECURITY_OVERWRITE; return BIT(NVDIMM_SECURITY_OVERWRITE);
rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
if (rc < 0) if (rc < 0 || nd_cmd.cmd.status) {
return rc; pr_err("%s: security state retrieval failed (%d:%#x)\n",
if (nd_cmd.cmd.status) nvdimm_name(nvdimm), rc, nd_cmd.cmd.status);
return -EIO; return 0;
}
/* check and see if security is enabled and locked */ /* check and see if security is enabled and locked */
if (ptype == NVDIMM_MASTER) { if (ptype == NVDIMM_MASTER) {
if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED) if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED)
return NVDIMM_SECURITY_UNLOCKED; set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
else if (nd_cmd.cmd.extended_state & else
ND_INTEL_SEC_ESTATE_PLIMIT) set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
return NVDIMM_SECURITY_FROZEN; if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_PLIMIT)
} else { set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) return security_flags;
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 */ if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED)
return NVDIMM_SECURITY_DISABLED; return 0;
if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) {
if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN ||
nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT)
set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED)
set_bit(NVDIMM_SECURITY_LOCKED, &security_flags);
else
set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
} else
set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
return security_flags;
} }
static int intel_security_freeze(struct nvdimm *nvdimm) static int intel_security_freeze(struct nvdimm *nvdimm)
...@@ -371,7 +376,7 @@ static void nvdimm_invalidate_cache(void) ...@@ -371,7 +376,7 @@ static void nvdimm_invalidate_cache(void)
#endif #endif
static const struct nvdimm_security_ops __intel_security_ops = { static const struct nvdimm_security_ops __intel_security_ops = {
.state = intel_security_state, .get_flags = intel_security_flags,
.freeze = intel_security_freeze, .freeze = intel_security_freeze,
.change_key = intel_security_change_key, .change_key = intel_security_change_key,
.disable = intel_security_disable, .disable = intel_security_disable,
......
...@@ -95,10 +95,9 @@ static int nvdimm_bus_probe(struct device *dev) ...@@ -95,10 +95,9 @@ static int nvdimm_bus_probe(struct device *dev)
rc = nd_drv->probe(dev); rc = nd_drv->probe(dev);
debug_nvdimm_unlock(dev); debug_nvdimm_unlock(dev);
if (rc == 0) if ((rc == 0 || rc == -EOPNOTSUPP) &&
nd_region_probe_success(nvdimm_bus, dev); dev->parent && is_nd_region(dev->parent))
else nd_region_advance_seeds(to_nd_region(dev->parent), dev);
nd_region_disable(nvdimm_bus, dev);
nvdimm_bus_probe_end(nvdimm_bus); nvdimm_bus_probe_end(nvdimm_bus);
dev_dbg(&nvdimm_bus->dev, "END: %s.probe(%s) = %d\n", dev->driver->name, dev_dbg(&nvdimm_bus->dev, "END: %s.probe(%s) = %d\n", dev->driver->name,
...@@ -121,7 +120,6 @@ static int nvdimm_bus_remove(struct device *dev) ...@@ -121,7 +120,6 @@ static int nvdimm_bus_remove(struct device *dev)
rc = nd_drv->remove(dev); rc = nd_drv->remove(dev);
debug_nvdimm_unlock(dev); debug_nvdimm_unlock(dev);
} }
nd_region_disable(nvdimm_bus, dev);
dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name, dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name,
dev_name(dev), rc); dev_name(dev), rc);
...@@ -400,7 +398,7 @@ static int child_unregister(struct device *dev, void *data) ...@@ -400,7 +398,7 @@ static int child_unregister(struct device *dev, void *data)
/* We are shutting down. Make state frozen artificially. */ /* We are shutting down. Make state frozen artificially. */
nvdimm_bus_lock(dev); 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)) if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags))
dev_put = true; dev_put = true;
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
......
...@@ -372,106 +372,26 @@ __weak ssize_t security_show(struct device *dev, ...@@ -372,106 +372,26 @@ __weak ssize_t security_show(struct device *dev,
{ {
struct nvdimm *nvdimm = to_nvdimm(dev); struct nvdimm *nvdimm = to_nvdimm(dev);
switch (nvdimm->sec.state) { if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
case NVDIMM_SECURITY_DISABLED:
return sprintf(buf, "disabled\n"); return sprintf(buf, "disabled\n");
case NVDIMM_SECURITY_UNLOCKED: if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags))
return sprintf(buf, "unlocked\n"); return sprintf(buf, "unlocked\n");
case NVDIMM_SECURITY_LOCKED: if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags))
return sprintf(buf, "locked\n"); return sprintf(buf, "locked\n");
case NVDIMM_SECURITY_FROZEN: if (test_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags))
return sprintf(buf, "frozen\n");
case NVDIMM_SECURITY_OVERWRITE:
return sprintf(buf, "overwrite\n"); return sprintf(buf, "overwrite\n");
default:
return -ENOTTY;
}
return -ENOTTY; return -ENOTTY;
} }
#define OPS \ static ssize_t frozen_show(struct device *dev,
C( OP_FREEZE, "freeze", 1), \ struct device_attribute *attr, char *buf)
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 };
#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); 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 sprintf(buf, "%d\n", test_bit(NVDIMM_SECURITY_FROZEN,
return -EBUSY; &nvdimm->sec.flags));
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 if (i == OP_UPDATE) {
dev_dbg(dev, "update %u %u\n", 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, 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;
if (rc == 0)
rc = len;
return rc;
} }
static DEVICE_ATTR_RO(frozen);
static ssize_t security_store(struct device *dev, static ssize_t security_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len) struct device_attribute *attr, const char *buf, size_t len)
...@@ -487,7 +407,7 @@ static ssize_t security_store(struct device *dev, ...@@ -487,7 +407,7 @@ static ssize_t security_store(struct device *dev,
nd_device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
rc = __security_store(dev, buf, len); rc = nvdimm_security_store(dev, buf, len);
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
nd_device_unlock(dev); nd_device_unlock(dev);
...@@ -501,6 +421,7 @@ static struct attribute *nvdimm_attributes[] = { ...@@ -501,6 +421,7 @@ static struct attribute *nvdimm_attributes[] = {
&dev_attr_commands.attr, &dev_attr_commands.attr,
&dev_attr_available_slots.attr, &dev_attr_available_slots.attr,
&dev_attr_security.attr, &dev_attr_security.attr,
&dev_attr_frozen.attr,
NULL, NULL,
}; };
...@@ -509,17 +430,24 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n) ...@@ -509,17 +430,24 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n)
struct device *dev = container_of(kobj, typeof(*dev), kobj); struct device *dev = container_of(kobj, typeof(*dev), kobj);
struct nvdimm *nvdimm = to_nvdimm(dev); 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; return a->mode;
if (nvdimm->sec.state < 0) if (!nvdimm->sec.flags)
return 0; return 0;
/* Are there any state mutation ops? */
if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable if (a == &dev_attr_security.attr) {
|| nvdimm->sec.ops->change_key /* Are there any state mutation ops (make writable)? */
|| nvdimm->sec.ops->erase if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable
|| nvdimm->sec.ops->overwrite) || 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 a->mode;
return 0444; return 0;
} }
struct attribute_group nvdimm_attribute_group = { struct attribute_group nvdimm_attribute_group = {
...@@ -569,8 +497,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, ...@@ -569,8 +497,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
* attribute visibility. * attribute visibility.
*/ */
/* get security state and extended (master) state */ /* get security state and extended (master) state */
nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
nd_device_register(dev); nd_device_register(dev);
return nvdimm; return nvdimm;
...@@ -588,7 +516,7 @@ int nvdimm_security_setup_events(struct device *dev) ...@@ -588,7 +516,7 @@ int nvdimm_security_setup_events(struct device *dev)
{ {
struct nvdimm *nvdimm = to_nvdimm(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) || !nvdimm->sec.ops->overwrite)
return 0; return 0;
nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security"); nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security");
...@@ -614,7 +542,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm) ...@@ -614,7 +542,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze) if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (nvdimm->sec.state < 0) if (!nvdimm->sec.flags)
return -EIO; return -EIO;
if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
...@@ -623,7 +551,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm) ...@@ -623,7 +551,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
} }
rc = nvdimm->sec.ops->freeze(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; return rc;
} }
......
...@@ -353,11 +353,6 @@ static bool slot_valid(struct nvdimm_drvdata *ndd, ...@@ -353,11 +353,6 @@ static bool slot_valid(struct nvdimm_drvdata *ndd,
if (slot != __le32_to_cpu(nd_label->slot)) if (slot != __le32_to_cpu(nd_label->slot))
return false; return false;
/* check that DPA allocations are page aligned */
if ((__le64_to_cpu(nd_label->dpa)
| __le64_to_cpu(nd_label->rawsize)) % SZ_4K)
return false;
/* check checksum */ /* check checksum */
if (namespace_label_has(ndd, checksum)) { if (namespace_label_has(ndd, checksum)) {
u64 sum, sum_save; u64 sum, sum_save;
......
...@@ -1006,10 +1006,10 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) ...@@ -1006,10 +1006,10 @@ static ssize_t __size_store(struct device *dev, unsigned long long val)
return -ENXIO; return -ENXIO;
} }
div_u64_rem(val, SZ_4K * nd_region->ndr_mappings, &remainder); div_u64_rem(val, PAGE_SIZE * nd_region->ndr_mappings, &remainder);
if (remainder) { if (remainder) {
dev_dbg(dev, "%llu is not %dK aligned\n", val, dev_dbg(dev, "%llu is not %ldK aligned\n", val,
(SZ_4K * nd_region->ndr_mappings) / SZ_1K); (PAGE_SIZE * nd_region->ndr_mappings) / SZ_1K);
return -EINVAL; return -EINVAL;
} }
...@@ -2462,6 +2462,27 @@ static struct device **create_namespaces(struct nd_region *nd_region) ...@@ -2462,6 +2462,27 @@ static struct device **create_namespaces(struct nd_region *nd_region)
return devs; return devs;
} }
static void deactivate_labels(void *region)
{
struct nd_region *nd_region = region;
int i;
for (i = 0; i < nd_region->ndr_mappings; i++) {
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
struct nvdimm_drvdata *ndd = nd_mapping->ndd;
struct nvdimm *nvdimm = nd_mapping->nvdimm;
mutex_lock(&nd_mapping->lock);
nd_mapping_free_labels(nd_mapping);
mutex_unlock(&nd_mapping->lock);
put_ndd(ndd);
nd_mapping->ndd = NULL;
if (ndd)
atomic_dec(&nvdimm->busy);
}
}
static int init_active_labels(struct nd_region *nd_region) static int init_active_labels(struct nd_region *nd_region)
{ {
int i; int i;
...@@ -2519,16 +2540,17 @@ static int init_active_labels(struct nd_region *nd_region) ...@@ -2519,16 +2540,17 @@ static int init_active_labels(struct nd_region *nd_region)
mutex_unlock(&nd_mapping->lock); mutex_unlock(&nd_mapping->lock);
} }
if (j >= count) if (j < count)
continue; break;
}
mutex_lock(&nd_mapping->lock); if (i < nd_region->ndr_mappings) {
nd_mapping_free_labels(nd_mapping); deactivate_labels(nd_region);
mutex_unlock(&nd_mapping->lock);
return -ENOMEM; return -ENOMEM;
} }
return 0; return devm_add_action_or_reset(&nd_region->dev, deactivate_labels,
nd_region);
} }
int nd_region_register_namespaces(struct nd_region *nd_region, int *err) int nd_region_register_namespaces(struct nd_region *nd_region, int *err)
......
...@@ -39,53 +39,40 @@ struct nvdimm { ...@@ -39,53 +39,40 @@ struct nvdimm {
const char *dimm_id; const char *dimm_id;
struct { struct {
const struct nvdimm_security_ops *ops; const struct nvdimm_security_ops *ops;
enum nvdimm_security_state state; unsigned long flags;
enum nvdimm_security_state ext_state; unsigned long ext_flags;
unsigned int overwrite_tmo; unsigned int overwrite_tmo;
struct kernfs_node *overwrite_state; struct kernfs_node *overwrite_state;
} sec; } sec;
struct delayed_work dwork; 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) 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) 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); int nvdimm_security_freeze(struct nvdimm *nvdimm);
#if IS_ENABLED(CONFIG_NVDIMM_KEYS) #if IS_ENABLED(CONFIG_NVDIMM_KEYS)
int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); ssize_t nvdimm_security_store(struct device *dev, const char *buf, size_t len);
int nvdimm_security_update(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); void nvdimm_security_overwrite_query(struct work_struct *work);
#else #else
static inline int nvdimm_security_disable(struct nvdimm *nvdimm, static inline ssize_t nvdimm_security_store(struct device *dev,
unsigned int keyid) const char *buf, size_t len)
{
return -EOPNOTSUPP;
}
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,
enum nvdimm_passphrase_type pass_type)
{
return -EOPNOTSUPP;
}
static inline int nvdimm_security_overwrite(struct nvdimm *nvdimm,
unsigned int keyid)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -128,13 +115,12 @@ int __init nvdimm_bus_init(void); ...@@ -128,13 +115,12 @@ int __init nvdimm_bus_init(void);
void nvdimm_bus_exit(void); void nvdimm_bus_exit(void);
void nvdimm_devs_exit(void); void nvdimm_devs_exit(void);
void nd_region_devs_exit(void); void nd_region_devs_exit(void);
void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev);
struct nd_region; struct nd_region;
void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev);
void nd_region_create_ns_seed(struct nd_region *nd_region); void nd_region_create_ns_seed(struct nd_region *nd_region);
void nd_region_create_btt_seed(struct nd_region *nd_region); void nd_region_create_btt_seed(struct nd_region *nd_region);
void nd_region_create_pfn_seed(struct nd_region *nd_region); void nd_region_create_pfn_seed(struct nd_region *nd_region);
void nd_region_create_dax_seed(struct nd_region *nd_region); void nd_region_create_dax_seed(struct nd_region *nd_region);
void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev);
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus); int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);
void nd_synchronize(void); void nd_synchronize(void);
......
...@@ -375,6 +375,10 @@ unsigned int pmem_sector_size(struct nd_namespace_common *ndns); ...@@ -375,6 +375,10 @@ unsigned int pmem_sector_size(struct nd_namespace_common *ndns);
void nvdimm_badblocks_populate(struct nd_region *nd_region, void nvdimm_badblocks_populate(struct nd_region *nd_region,
struct badblocks *bb, const struct resource *res); struct badblocks *bb, const struct resource *res);
#if IS_ENABLED(CONFIG_ND_CLAIM) #if IS_ENABLED(CONFIG_ND_CLAIM)
/* max struct page size independent of kernel config */
#define MAX_STRUCT_PAGE_SIZE 64
int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap); int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap);
int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio); int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio);
void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio); void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio);
......
...@@ -42,7 +42,7 @@ static int of_pmem_region_probe(struct platform_device *pdev) ...@@ -42,7 +42,7 @@ static int of_pmem_region_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
priv->bus_desc.attr_groups = bus_attr_groups; priv->bus_desc.attr_groups = bus_attr_groups;
priv->bus_desc.provider_name = "of_pmem"; priv->bus_desc.provider_name = kstrdup(pdev->name, GFP_KERNEL);
priv->bus_desc.module = THIS_MODULE; priv->bus_desc.module = THIS_MODULE;
priv->bus_desc.of_node = np; priv->bus_desc.of_node = np;
......
...@@ -29,7 +29,10 @@ struct nd_pfn_sb { ...@@ -29,7 +29,10 @@ struct nd_pfn_sb {
/* minor-version-2 record the base alignment of the mapping */ /* minor-version-2 record the base alignment of the mapping */
__le32 align; __le32 align;
/* minor-version-3 guarantee the padding and flags are zero */ /* minor-version-3 guarantee the padding and flags are zero */
u8 padding[4000]; /* minor-version-4 record the page size and struct page size */
__le32 page_size;
__le16 page_struct_size;
u8 padding[3994];
__le64 checksum; __le64 checksum;
}; };
......
...@@ -460,6 +460,11 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) ...@@ -460,6 +460,11 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
if (__le16_to_cpu(pfn_sb->version_minor) < 2) if (__le16_to_cpu(pfn_sb->version_minor) < 2)
pfn_sb->align = 0; pfn_sb->align = 0;
if (__le16_to_cpu(pfn_sb->version_minor) < 4) {
pfn_sb->page_struct_size = cpu_to_le16(64);
pfn_sb->page_size = cpu_to_le32(PAGE_SIZE);
}
switch (le32_to_cpu(pfn_sb->mode)) { switch (le32_to_cpu(pfn_sb->mode)) {
case PFN_MODE_RAM: case PFN_MODE_RAM:
case PFN_MODE_PMEM: case PFN_MODE_PMEM:
...@@ -475,6 +480,22 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) ...@@ -475,6 +480,22 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
align = 1UL << ilog2(offset); align = 1UL << ilog2(offset);
mode = le32_to_cpu(pfn_sb->mode); mode = le32_to_cpu(pfn_sb->mode);
if ((le32_to_cpu(pfn_sb->page_size) > PAGE_SIZE) &&
(mode == PFN_MODE_PMEM)) {
dev_err(&nd_pfn->dev,
"init failed, page size mismatch %d\n",
le32_to_cpu(pfn_sb->page_size));
return -EOPNOTSUPP;
}
if ((le16_to_cpu(pfn_sb->page_struct_size) < sizeof(struct page)) &&
(mode == PFN_MODE_PMEM)) {
dev_err(&nd_pfn->dev,
"init failed, struct page size mismatch %d\n",
le16_to_cpu(pfn_sb->page_struct_size));
return -EOPNOTSUPP;
}
if (!nd_pfn->uuid) { if (!nd_pfn->uuid) {
/* /*
* When probing a namepace via nd_pfn_probe() the uuid * When probing a namepace via nd_pfn_probe() the uuid
...@@ -703,8 +724,16 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) ...@@ -703,8 +724,16 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
* The altmap should be padded out to the block size used * The altmap should be padded out to the block size used
* when populating the vmemmap. This *should* be equal to * when populating the vmemmap. This *should* be equal to
* PMD_SIZE for most architectures. * PMD_SIZE for most architectures.
*
* Also make sure size of struct page is less than 64. We
* want to make sure we use large enough size here so that
* we don't have a dynamic reserve space depending on
* struct page size. But we also want to make sure we notice
* when we end up adding new elements to struct page.
*/ */
offset = ALIGN(start + SZ_8K + 64 * npfns, align) - start; BUILD_BUG_ON(sizeof(struct page) > MAX_STRUCT_PAGE_SIZE);
offset = ALIGN(start + SZ_8K + MAX_STRUCT_PAGE_SIZE * npfns, align)
- start;
} else if (nd_pfn->mode == PFN_MODE_RAM) } else if (nd_pfn->mode == PFN_MODE_RAM)
offset = ALIGN(start + SZ_8K, align) - start; offset = ALIGN(start + SZ_8K, align) - start;
else else
...@@ -724,9 +753,11 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) ...@@ -724,9 +753,11 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
memcpy(pfn_sb->uuid, nd_pfn->uuid, 16); memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16); memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
pfn_sb->version_major = cpu_to_le16(1); pfn_sb->version_major = cpu_to_le16(1);
pfn_sb->version_minor = cpu_to_le16(3); pfn_sb->version_minor = cpu_to_le16(4);
pfn_sb->end_trunc = cpu_to_le32(end_trunc); pfn_sb->end_trunc = cpu_to_le32(end_trunc);
pfn_sb->align = cpu_to_le32(nd_pfn->align); pfn_sb->align = cpu_to_le32(nd_pfn->align);
pfn_sb->page_struct_size = cpu_to_le16(MAX_STRUCT_PAGE_SIZE);
pfn_sb->page_size = cpu_to_le32(PAGE_SIZE);
checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb); checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
pfn_sb->checksum = cpu_to_le64(checksum); pfn_sb->checksum = cpu_to_le64(checksum);
......
...@@ -490,6 +490,7 @@ static int pmem_attach_disk(struct device *dev, ...@@ -490,6 +490,7 @@ static int pmem_attach_disk(struct device *dev,
static int nd_pmem_probe(struct device *dev) static int nd_pmem_probe(struct device *dev)
{ {
int ret;
struct nd_namespace_common *ndns; struct nd_namespace_common *ndns;
ndns = nvdimm_namespace_common_probe(dev); ndns = nvdimm_namespace_common_probe(dev);
...@@ -505,12 +506,32 @@ static int nd_pmem_probe(struct device *dev) ...@@ -505,12 +506,32 @@ static int nd_pmem_probe(struct device *dev)
if (is_nd_pfn(dev)) if (is_nd_pfn(dev))
return pmem_attach_disk(dev, ndns); return pmem_attach_disk(dev, ndns);
/* if we find a valid info-block we'll come back as that personality */ ret = nd_btt_probe(dev, ndns);
if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0 if (ret == 0)
|| nd_dax_probe(dev, ndns) == 0)
return -ENXIO; return -ENXIO;
/* ...otherwise we're just a raw pmem device */ /*
* We have two failure conditions here, there is no
* info reserver block or we found a valid info reserve block
* but failed to initialize the pfn superblock.
*
* For the first case consider namespace as a raw pmem namespace
* and attach a disk.
*
* For the latter, consider this a success and advance the namespace
* seed.
*/
ret = nd_pfn_probe(dev, ndns);
if (ret == 0)
return -ENXIO;
else if (ret == -EOPNOTSUPP)
return ret;
ret = nd_dax_probe(dev, ndns);
if (ret == 0)
return -ENXIO;
else if (ret == -EOPNOTSUPP)
return ret;
return pmem_attach_disk(dev, ndns); return pmem_attach_disk(dev, ndns);
} }
......
...@@ -715,85 +715,37 @@ void nd_mapping_free_labels(struct nd_mapping *nd_mapping) ...@@ -715,85 +715,37 @@ void nd_mapping_free_labels(struct nd_mapping *nd_mapping)
} }
/* /*
* Upon successful probe/remove, take/release a reference on the * When a namespace is activated create new seeds for the next
* associated interleave set (if present), and plant new btt + namespace * namespace, or namespace-personality to be configured.
* seeds. Also, on the removal of a BLK region, notify the provider to
* disable the region.
*/ */
static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus, void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev)
struct device *dev, bool probe)
{ {
struct nd_region *nd_region; nvdimm_bus_lock(dev);
if (nd_region->ns_seed == dev) {
if (!probe && is_nd_region(dev)) { nd_region_create_ns_seed(nd_region);
int i; } else if (is_nd_btt(dev)) {
nd_region = to_nd_region(dev);
for (i = 0; i < nd_region->ndr_mappings; i++) {
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
struct nvdimm_drvdata *ndd = nd_mapping->ndd;
struct nvdimm *nvdimm = nd_mapping->nvdimm;
mutex_lock(&nd_mapping->lock);
nd_mapping_free_labels(nd_mapping);
mutex_unlock(&nd_mapping->lock);
put_ndd(ndd);
nd_mapping->ndd = NULL;
if (ndd)
atomic_dec(&nvdimm->busy);
}
}
if (dev->parent && is_nd_region(dev->parent) && probe) {
nd_region = to_nd_region(dev->parent);
nvdimm_bus_lock(dev);
if (nd_region->ns_seed == dev)
nd_region_create_ns_seed(nd_region);
nvdimm_bus_unlock(dev);
}
if (is_nd_btt(dev) && probe) {
struct nd_btt *nd_btt = to_nd_btt(dev); struct nd_btt *nd_btt = to_nd_btt(dev);
nd_region = to_nd_region(dev->parent);
nvdimm_bus_lock(dev);
if (nd_region->btt_seed == dev) if (nd_region->btt_seed == dev)
nd_region_create_btt_seed(nd_region); nd_region_create_btt_seed(nd_region);
if (nd_region->ns_seed == &nd_btt->ndns->dev) if (nd_region->ns_seed == &nd_btt->ndns->dev)
nd_region_create_ns_seed(nd_region); nd_region_create_ns_seed(nd_region);
nvdimm_bus_unlock(dev); } else if (is_nd_pfn(dev)) {
}
if (is_nd_pfn(dev) && probe) {
struct nd_pfn *nd_pfn = to_nd_pfn(dev); struct nd_pfn *nd_pfn = to_nd_pfn(dev);
nd_region = to_nd_region(dev->parent);
nvdimm_bus_lock(dev);
if (nd_region->pfn_seed == dev) if (nd_region->pfn_seed == dev)
nd_region_create_pfn_seed(nd_region); nd_region_create_pfn_seed(nd_region);
if (nd_region->ns_seed == &nd_pfn->ndns->dev) if (nd_region->ns_seed == &nd_pfn->ndns->dev)
nd_region_create_ns_seed(nd_region); nd_region_create_ns_seed(nd_region);
nvdimm_bus_unlock(dev); } else if (is_nd_dax(dev)) {
}
if (is_nd_dax(dev) && probe) {
struct nd_dax *nd_dax = to_nd_dax(dev); struct nd_dax *nd_dax = to_nd_dax(dev);
nd_region = to_nd_region(dev->parent);
nvdimm_bus_lock(dev);
if (nd_region->dax_seed == dev) if (nd_region->dax_seed == dev)
nd_region_create_dax_seed(nd_region); nd_region_create_dax_seed(nd_region);
if (nd_region->ns_seed == &nd_dax->nd_pfn.ndns->dev) if (nd_region->ns_seed == &nd_dax->nd_pfn.ndns->dev)
nd_region_create_ns_seed(nd_region); nd_region_create_ns_seed(nd_region);
nvdimm_bus_unlock(dev);
} }
} nvdimm_bus_unlock(dev);
void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev)
{
nd_region_notify_driver_action(nvdimm_bus, dev, true);
}
void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev)
{
nd_region_notify_driver_action(nvdimm_bus, dev, false);
} }
static ssize_t mappingN(struct device *dev, char *buf, int n) static ssize_t mappingN(struct device *dev, char *buf, int n)
...@@ -992,10 +944,10 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, ...@@ -992,10 +944,10 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
struct nd_mapping_desc *mapping = &ndr_desc->mapping[i]; struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
struct nvdimm *nvdimm = mapping->nvdimm; struct nvdimm *nvdimm = mapping->nvdimm;
if ((mapping->start | mapping->size) % SZ_4K) { if ((mapping->start | mapping->size) % PAGE_SIZE) {
dev_err(&nvdimm_bus->dev, "%s: %s mapping%d is not 4K aligned\n", dev_err(&nvdimm_bus->dev,
caller, dev_name(&nvdimm->dev), i); "%s: %s mapping%d is not %ld aligned\n",
caller, dev_name(&nvdimm->dev), i, PAGE_SIZE);
return NULL; return NULL;
} }
...@@ -1025,10 +977,9 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, ...@@ -1025,10 +977,9 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
} }
region_buf = ndbr; region_buf = ndbr;
} else { } else {
nd_region = kzalloc(sizeof(struct nd_region) nd_region = kzalloc(struct_size(nd_region, mapping,
+ sizeof(struct nd_mapping) ndr_desc->num_mappings),
* ndr_desc->num_mappings, GFP_KERNEL);
GFP_KERNEL);
region_buf = nd_region; region_buf = nd_region;
} }
......
...@@ -158,7 +158,7 @@ static int nvdimm_key_revalidate(struct nvdimm *nvdimm) ...@@ -158,7 +158,7 @@ static int nvdimm_key_revalidate(struct nvdimm *nvdimm)
} }
nvdimm_put_key(key); nvdimm_put_key(key);
nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return 0; return 0;
} }
...@@ -174,7 +174,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) ...@@ -174,7 +174,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
lockdep_assert_held(&nvdimm_bus->reconfig_mutex); lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock
|| nvdimm->sec.state < 0) || !nvdimm->sec.flags)
return -EIO; return -EIO;
if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
...@@ -189,7 +189,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) ...@@ -189,7 +189,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
* freeze of the security configuration. I.e. if the OS does not * freeze of the security configuration. I.e. if the OS does not
* have the key, security is being managed pre-OS. * 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) if (!key_revalidate)
return 0; return 0;
...@@ -202,7 +202,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) ...@@ -202,7 +202,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
rc == 0 ? "success" : "fail"); rc == 0 ? "success" : "fail");
nvdimm_put_key(key); nvdimm_put_key(key);
nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return rc; return rc;
} }
...@@ -217,7 +217,25 @@ int nvdimm_security_unlock(struct device *dev) ...@@ -217,7 +217,25 @@ int nvdimm_security_unlock(struct device *dev)
return rc; return rc;
} }
int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) 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;
}
static int security_disable(struct nvdimm *nvdimm, unsigned int keyid)
{ {
struct device *dev = &nvdimm->dev; struct device *dev = &nvdimm->dev;
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
...@@ -229,19 +247,12 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) ...@@ -229,19 +247,12 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
lockdep_assert_held(&nvdimm_bus->reconfig_mutex); lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable
|| nvdimm->sec.state < 0) || !nvdimm->sec.flags)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { rc = check_security_state(nvdimm);
dev_dbg(dev, "Incorrect security state: %d\n", if (rc)
nvdimm->sec.state); return rc;
return -EIO;
}
if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
dev_dbg(dev, "Security operation in progress.\n");
return -EBUSY;
}
data = nvdimm_get_user_key_payload(nvdimm, keyid, data = nvdimm_get_user_key_payload(nvdimm, keyid,
NVDIMM_BASE_KEY, &key); NVDIMM_BASE_KEY, &key);
...@@ -253,11 +264,11 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) ...@@ -253,11 +264,11 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
rc == 0 ? "success" : "fail"); rc == 0 ? "success" : "fail");
nvdimm_put_key(key); nvdimm_put_key(key);
nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return rc; return rc;
} }
int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, static int security_update(struct nvdimm *nvdimm, unsigned int keyid,
unsigned int new_keyid, unsigned int new_keyid,
enum nvdimm_passphrase_type pass_type) enum nvdimm_passphrase_type pass_type)
{ {
...@@ -271,14 +282,12 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, ...@@ -271,14 +282,12 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
lockdep_assert_held(&nvdimm_bus->reconfig_mutex); lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key
|| nvdimm->sec.state < 0) || !nvdimm->sec.flags)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { rc = check_security_state(nvdimm);
dev_dbg(dev, "Incorrect security state: %d\n", if (rc)
nvdimm->sec.state); return rc;
return -EIO;
}
data = nvdimm_get_user_key_payload(nvdimm, keyid, data = nvdimm_get_user_key_payload(nvdimm, keyid,
NVDIMM_BASE_KEY, &key); NVDIMM_BASE_KEY, &key);
...@@ -301,15 +310,15 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, ...@@ -301,15 +310,15 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
nvdimm_put_key(newkey); nvdimm_put_key(newkey);
nvdimm_put_key(key); nvdimm_put_key(key);
if (pass_type == NVDIMM_MASTER) if (pass_type == NVDIMM_MASTER)
nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm,
NVDIMM_MASTER); NVDIMM_MASTER);
else else
nvdimm->sec.state = nvdimm_security_state(nvdimm, nvdimm->sec.flags = nvdimm_security_flags(nvdimm,
NVDIMM_USER); NVDIMM_USER);
return rc; return rc;
} }
int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, static int security_erase(struct nvdimm *nvdimm, unsigned int keyid,
enum nvdimm_passphrase_type pass_type) enum nvdimm_passphrase_type pass_type)
{ {
struct device *dev = &nvdimm->dev; struct device *dev = &nvdimm->dev;
...@@ -322,26 +331,14 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, ...@@ -322,26 +331,14 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid,
lockdep_assert_held(&nvdimm_bus->reconfig_mutex); lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase
|| nvdimm->sec.state < 0) || !nvdimm->sec.flags)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (atomic_read(&nvdimm->busy)) { rc = check_security_state(nvdimm);
dev_dbg(dev, "Unable to secure erase while DIMM active.\n"); if (rc)
return -EBUSY; return rc;
}
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;
}
if (nvdimm->sec.ext_state != NVDIMM_SECURITY_UNLOCKED if (!test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.ext_flags)
&& pass_type == NVDIMM_MASTER) { && pass_type == NVDIMM_MASTER) {
dev_dbg(dev, dev_dbg(dev,
"Attempt to secure erase in wrong master state.\n"); "Attempt to secure erase in wrong master state.\n");
...@@ -359,11 +356,11 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, ...@@ -359,11 +356,11 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid,
rc == 0 ? "success" : "fail"); rc == 0 ? "success" : "fail");
nvdimm_put_key(key); nvdimm_put_key(key);
nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
return rc; return rc;
} }
int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) static int security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
{ {
struct device *dev = &nvdimm->dev; struct device *dev = &nvdimm->dev;
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
...@@ -375,29 +372,17 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) ...@@ -375,29 +372,17 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
lockdep_assert_held(&nvdimm_bus->reconfig_mutex); lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite
|| nvdimm->sec.state < 0) || !nvdimm->sec.flags)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (atomic_read(&nvdimm->busy)) {
dev_dbg(dev, "Unable to overwrite while DIMM active.\n");
return -EBUSY;
}
if (dev->driver == NULL) { if (dev->driver == NULL) {
dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); dev_dbg(dev, "Unable to overwrite while DIMM active.\n");
return -EINVAL; return -EINVAL;
} }
if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { rc = check_security_state(nvdimm);
dev_dbg(dev, "Incorrect security state: %d\n", if (rc)
nvdimm->sec.state); return rc;
return -EIO;
}
if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
dev_dbg(dev, "Security operation in progress.\n");
return -EBUSY;
}
data = nvdimm_get_user_key_payload(nvdimm, keyid, data = nvdimm_get_user_key_payload(nvdimm, keyid,
NVDIMM_BASE_KEY, &key); NVDIMM_BASE_KEY, &key);
...@@ -412,7 +397,7 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) ...@@ -412,7 +397,7 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
if (rc == 0) { if (rc == 0) {
set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
set_bit(NDD_WORK_PENDING, &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 * Make sure we don't lose device while doing overwrite
* query. * query.
...@@ -443,7 +428,7 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) ...@@ -443,7 +428,7 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm)
tmo = nvdimm->sec.overwrite_tmo; tmo = nvdimm->sec.overwrite_tmo;
if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite
|| nvdimm->sec.state < 0) || !nvdimm->sec.flags)
return; return;
rc = nvdimm->sec.ops->query_overwrite(nvdimm); rc = nvdimm->sec.ops->query_overwrite(nvdimm);
...@@ -467,8 +452,8 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) ...@@ -467,8 +452,8 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm)
clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
clear_bit(NDD_WORK_PENDING, &nvdimm->flags); clear_bit(NDD_WORK_PENDING, &nvdimm->flags);
put_device(&nvdimm->dev); put_device(&nvdimm->dev);
nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
} }
void nvdimm_security_overwrite_query(struct work_struct *work) void nvdimm_security_overwrite_query(struct work_struct *work)
...@@ -480,3 +465,85 @@ void nvdimm_security_overwrite_query(struct work_struct *work) ...@@ -480,3 +465,85 @@ void nvdimm_security_overwrite_query(struct work_struct *work)
__nvdimm_security_overwrite_query(nvdimm); __nvdimm_security_overwrite_query(nvdimm);
nvdimm_bus_unlock(&nvdimm->dev); nvdimm_bus_unlock(&nvdimm->dev);
} }
#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 };
#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
ssize_t nvdimm_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;
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 = security_disable(nvdimm, key);
} else if (i == OP_UPDATE || i == OP_MASTER_UPDATE) {
dev_dbg(dev, "%s %u %u\n", ops[i].name, key, newkey);
rc = security_update(nvdimm, key, newkey, i == OP_UPDATE
? NVDIMM_USER : NVDIMM_MASTER);
} else if (i == OP_ERASE || i == OP_MASTER_ERASE) {
dev_dbg(dev, "%s %u\n", ops[i].name, key);
if (atomic_read(&nvdimm->busy)) {
dev_dbg(dev, "Unable to secure erase while DIMM active.\n");
return -EBUSY;
}
rc = security_erase(nvdimm, key, i == OP_ERASE
? NVDIMM_USER : NVDIMM_MASTER);
} else if (i == OP_OVERWRITE) {
dev_dbg(dev, "overwrite %u\n", key);
if (atomic_read(&nvdimm->busy)) {
dev_dbg(dev, "Unable to overwrite while DIMM active.\n");
return -EBUSY;
}
rc = security_overwrite(nvdimm, key);
} else
return -EINVAL;
if (rc == 0)
rc = len;
return rc;
}
...@@ -160,8 +160,11 @@ static inline struct nd_blk_region_desc *to_blk_region_desc( ...@@ -160,8 +160,11 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
} }
enum nvdimm_security_state { /*
NVDIMM_SECURITY_ERROR = -1, * Note that separate bits for locked + unlocked are defined so that
* 'flags == 0' corresponds to an error / not-supported state.
*/
enum nvdimm_security_bits {
NVDIMM_SECURITY_DISABLED, NVDIMM_SECURITY_DISABLED,
NVDIMM_SECURITY_UNLOCKED, NVDIMM_SECURITY_UNLOCKED,
NVDIMM_SECURITY_LOCKED, NVDIMM_SECURITY_LOCKED,
...@@ -182,7 +185,7 @@ enum nvdimm_passphrase_type { ...@@ -182,7 +185,7 @@ enum nvdimm_passphrase_type {
}; };
struct nvdimm_security_ops { struct nvdimm_security_ops {
enum nvdimm_security_state (*state)(struct nvdimm *nvdimm, unsigned long (*get_flags)(struct nvdimm *nvdimm,
enum nvdimm_passphrase_type pass_type); enum nvdimm_passphrase_type pass_type);
int (*freeze)(struct nvdimm *nvdimm); int (*freeze)(struct nvdimm *nvdimm);
int (*change_key)(struct nvdimm *nvdimm, int (*change_key)(struct nvdimm *nvdimm,
......
...@@ -18,24 +18,13 @@ ssize_t security_show(struct device *dev, ...@@ -18,24 +18,13 @@ ssize_t security_show(struct device *dev,
* For the test version we need to poll the "hardware" in order * For the test version we need to poll the "hardware" in order
* to get the updated status for unlock testing. * to get the updated status for unlock testing.
*/ */
nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER);
switch (nvdimm->sec.state) { if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
case NVDIMM_SECURITY_DISABLED:
return sprintf(buf, "disabled\n"); return sprintf(buf, "disabled\n");
case NVDIMM_SECURITY_UNLOCKED: if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags))
return sprintf(buf, "unlocked\n"); return sprintf(buf, "unlocked\n");
case NVDIMM_SECURITY_LOCKED: if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags))
return sprintf(buf, "locked\n"); return sprintf(buf, "locked\n");
case NVDIMM_SECURITY_FROZEN:
return sprintf(buf, "frozen\n");
case NVDIMM_SECURITY_OVERWRITE:
return sprintf(buf, "overwrite\n");
default:
return -ENOTTY;
}
return -ENOTTY; return -ENOTTY;
} }
...@@ -428,10 +428,9 @@ static int nd_intel_test_finish_query(struct nfit_test *t, ...@@ -428,10 +428,9 @@ static int nd_intel_test_finish_query(struct nfit_test *t,
dev_dbg(dev, "%s: still verifying\n", __func__); dev_dbg(dev, "%s: still verifying\n", __func__);
break; break;
} }
dev_dbg(dev, "%s: transition out verify\n", __func__); dev_dbg(dev, "%s: transition out verify\n", __func__);
fw->state = FW_STATE_UPDATED; fw->state = FW_STATE_UPDATED;
/* we are going to fall through if it's "done" */ /* fall through */
case FW_STATE_UPDATED: case FW_STATE_UPDATED:
nd_cmd->status = 0; nd_cmd->status = 0;
/* bogus test version */ /* bogus test version */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment