Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6cb2e9ee authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+32 −27
Original line number Diff line number Diff line
@@ -7,10 +7,11 @@
#include "intel.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)
{
	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
	unsigned long security_flags = 0;
	struct {
		struct nd_cmd_pkg pkg;
		struct nd_intel_get_security_state cmd;
@@ -27,7 +28,7 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm,
	int rc;

	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.
@@ -35,38 +36,42 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm,
	 * until the overwrite DSM completes.
	 */
	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);
	if (rc < 0)
		return rc;
	if (nd_cmd.cmd.status)
		return -EIO;
	if (rc < 0 || nd_cmd.cmd.status) {
		pr_err("%s: security state retrieval failed (%d:%#x)\n",
				nvdimm_name(nvdimm), rc, nd_cmd.cmd.status);
		return 0;
	}

	/* check and see if security is enabled and locked */
	if (ptype == NVDIMM_MASTER) {
		if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED)
			return NVDIMM_SECURITY_UNLOCKED;
		else if (nd_cmd.cmd.extended_state &
				ND_INTEL_SEC_ESTATE_PLIMIT)
			return NVDIMM_SECURITY_FROZEN;
	} else {
			set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
		else
			set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
		if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_PLIMIT)
			set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
		return security_flags;
	}

	if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED)
			return -ENXIO;
		else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) {
		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)
				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;
			set_bit(NVDIMM_SECURITY_LOCKED, &security_flags);
		else
				return NVDIMM_SECURITY_UNLOCKED;
		}
	}
			set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
	} else
		set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);

	/* this should cover master security disabled as well */
	return NVDIMM_SECURITY_DISABLED;
	return security_flags;
}

static int intel_security_freeze(struct nvdimm *nvdimm)
@@ -371,7 +376,7 @@ static void nvdimm_invalidate_cache(void)
#endif

static const struct nvdimm_security_ops __intel_security_ops = {
	.state = intel_security_state,
	.get_flags = intel_security_flags,
	.freeze = intel_security_freeze,
	.change_key = intel_security_change_key,
	.disable = intel_security_disable,
+4 −6
Original line number Diff line number Diff line
@@ -95,10 +95,9 @@ static int nvdimm_bus_probe(struct device *dev)
	rc = nd_drv->probe(dev);
	debug_nvdimm_unlock(dev);

	if (rc == 0)
		nd_region_probe_success(nvdimm_bus, dev);
	else
		nd_region_disable(nvdimm_bus, dev);
	if ((rc == 0 || rc == -EOPNOTSUPP) &&
			dev->parent && is_nd_region(dev->parent))
		nd_region_advance_seeds(to_nd_region(dev->parent), dev);
	nvdimm_bus_probe_end(nvdimm_bus);

	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)
		rc = nd_drv->remove(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_name(dev), rc);
@@ -400,7 +398,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);
+31 −103
Original line number Diff line number Diff line
@@ -372,106 +372,26 @@ __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;
}

#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

static ssize_t __security_store(struct device *dev, const char *buf, size_t len)
static ssize_t frozen_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	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 -EBUSY;

	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;
	return sprintf(buf, "%d\n", test_bit(NVDIMM_SECURITY_FROZEN,
				&nvdimm->sec.flags));
}
static DEVICE_ATTR_RO(frozen);

static ssize_t security_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t len)
@@ -487,7 +407,7 @@ static ssize_t security_store(struct device *dev,
	nd_device_lock(dev);
	nvdimm_bus_lock(dev);
	wait_nvdimm_bus_probe_idle(dev);
	rc = __security_store(dev, buf, len);
	rc = nvdimm_security_store(dev, buf, len);
	nvdimm_bus_unlock(dev);
	nd_device_unlock(dev);

@@ -501,6 +421,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,11 +430,13 @@ 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 (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
@@ -522,6 +445,11 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n)
		return 0444;
	}

	if (nvdimm->sec.ops->freeze)
		return a->mode;
	return 0;
}

struct attribute_group nvdimm_attribute_group = {
	.attrs = nvdimm_attributes,
	.is_visible = nvdimm_visible,
@@ -569,8 +497,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 +516,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 +542,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 +551,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;
}
+0 −5
Original line number Diff line number Diff line
@@ -353,11 +353,6 @@ static bool slot_valid(struct nvdimm_drvdata *ndd,
	if (slot != __le32_to_cpu(nd_label->slot))
		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 */
	if (namespace_label_has(ndd, checksum)) {
		u64 sum, sum_save;
+31 −9
Original line number Diff line number Diff line
@@ -1006,10 +1006,10 @@ static ssize_t __size_store(struct device *dev, unsigned long long val)
		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) {
		dev_dbg(dev, "%llu is not %dK aligned\n", val,
				(SZ_4K * nd_region->ndr_mappings) / SZ_1K);
		dev_dbg(dev, "%llu is not %ldK aligned\n", val,
				(PAGE_SIZE * nd_region->ndr_mappings) / SZ_1K);
		return -EINVAL;
	}

@@ -2462,6 +2462,27 @@ static struct device **create_namespaces(struct nd_region *nd_region)
	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)
{
	int i;
@@ -2519,16 +2540,17 @@ static int init_active_labels(struct nd_region *nd_region)
			mutex_unlock(&nd_mapping->lock);
		}

		if (j >= count)
			continue;
		if (j < count)
			break;
	}

		mutex_lock(&nd_mapping->lock);
		nd_mapping_free_labels(nd_mapping);
		mutex_unlock(&nd_mapping->lock);
	if (i < nd_region->ndr_mappings) {
		deactivate_labels(nd_region);
		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)
Loading