Skip to content

Commit

Permalink
acpi/nfit, libnvdimm: Add freeze security support to Intel nvdimm
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
davejiang authored and djbw committed Dec 14, 2018
1 parent f298939 commit 37833fb
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 2 deletions.
28 changes: 28 additions & 0 deletions drivers/acpi/nfit/intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
66 changes: 64 additions & 2 deletions drivers/nvdimm/dimm_devs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
return a->mode;
/* Are there any state mutation ops? */
if (nvdimm->sec.ops->freeze)
return a->mode;
return 0444;
}

struct attribute_group nvdimm_attribute_group = {
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/nvdimm/nd-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/linux/libnvdimm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 37833fb

Please sign in to comment.