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: Dave Jiang <dave.jiang@intel.com> Co-developed-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
f298939655
commit
37833fb798
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue