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

Commit 37833fb7 authored by Dave Jiang's avatar Dave Jiang Committed by Dan Williams
Browse files

acpi/nfit, libnvdimm: Add freeze security support to Intel nvdimm



Add support for freeze security on Intel nvdimm. This locks out any
changes to security for the DIMM until a hard reset of the DIMM is
performed. This is triggered by writing "freeze" to the generic
nvdimm/nmemX "security" sysfs attribute.

Signed-off-by: default avatarDave Jiang <dave.jiang@intel.com>
Co-developed-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent f2989396
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -48,7 +48,35 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm)
	return NVDIMM_SECURITY_DISABLED;
}

static int intel_security_freeze(struct nvdimm *nvdimm)
{
	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
	struct {
		struct nd_cmd_pkg pkg;
		struct nd_intel_freeze_lock cmd;
	} nd_cmd = {
		.pkg = {
			.nd_command = NVDIMM_INTEL_FREEZE_LOCK,
			.nd_family = NVDIMM_FAMILY_INTEL,
			.nd_size_out = ND_INTEL_STATUS_SIZE,
			.nd_fw_size = ND_INTEL_STATUS_SIZE,
		},
	};
	int rc;

	if (!test_bit(NVDIMM_INTEL_FREEZE_LOCK, &nfit_mem->dsm_mask))
		return -ENOTTY;

	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;
	return 0;
}

static const struct nvdimm_security_ops __intel_security_ops = {
	.state = intel_security_state,
	.freeze = intel_security_freeze,
};
const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops;
+64 −2
Original line number Diff line number Diff line
@@ -390,7 +390,48 @@ static ssize_t security_show(struct device *dev,

	return -ENOTTY;
}
static DEVICE_ATTR_RO(security);

static ssize_t __security_store(struct device *dev, const char *buf, size_t len)
{
	struct nvdimm *nvdimm = to_nvdimm(dev);
	ssize_t rc;

	if (atomic_read(&nvdimm->busy))
		return -EBUSY;

	if (sysfs_streq(buf, "freeze")) {
		dev_dbg(dev, "freeze\n");
		rc = nvdimm_security_freeze(nvdimm);
	} else
		return -EINVAL;

	if (rc == 0)
		rc = len;
	return rc;

}

static ssize_t security_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t len)

{
	ssize_t rc;

	/*
	 * Require all userspace triggered security management to be
	 * done while probing is idle and the DIMM is not in active use
	 * in any region.
	 */
	device_lock(dev);
	nvdimm_bus_lock(dev);
	wait_nvdimm_bus_probe_idle(dev);
	rc = __security_store(dev, buf, len);
	nvdimm_bus_unlock(dev);
	device_unlock(dev);

	return rc;
}
static DEVICE_ATTR_RW(security);

static struct attribute *nvdimm_attributes[] = {
	&dev_attr_state.attr,
@@ -410,7 +451,10 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n)
		return a->mode;
	if (nvdimm->sec.state < 0)
		return 0;
	/* Are there any state mutation ops? */
	if (nvdimm->sec.ops->freeze)
		return a->mode;
	return 0444;
}

struct attribute_group nvdimm_attribute_group = {
@@ -462,6 +506,24 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
}
EXPORT_SYMBOL_GPL(__nvdimm_create);

int nvdimm_security_freeze(struct nvdimm *nvdimm)
{
	int rc;

	WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm->dev));

	if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze)
		return -EOPNOTSUPP;

	if (nvdimm->sec.state < 0)
		return -EIO;

	rc = nvdimm->sec.ops->freeze(nvdimm);
	nvdimm->sec.state = nvdimm_security_state(nvdimm);

	return rc;
}

int alias_dpa_busy(struct device *dev, void *data)
{
	resource_size_t map_end, blk_start, new;
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ static inline enum nvdimm_security_state nvdimm_security_state(

	return nvdimm->sec.ops->state(nvdimm);
}
int nvdimm_security_freeze(struct nvdimm *nvdimm);

/**
 * struct blk_alloc_info - tracking info for BLK dpa scanning
+1 −0
Original line number Diff line number Diff line
@@ -165,6 +165,7 @@ enum nvdimm_security_state {

struct nvdimm_security_ops {
	enum nvdimm_security_state (*state)(struct nvdimm *nvdimm);
	int (*freeze)(struct nvdimm *nvdimm);
};

void badrange_init(struct badrange *badrange);