@@ -557,6 +557,12 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
if (nvdimm->sec.state < 0)
return -EIO;
+ rc = nvdimm_security_check_busy(nvdimm);
+ if (rc < 0) {
+ dev_warn(&nvdimm->dev, "Security operation in progress.\n");
+ return rc;
+ }
+
rc = nvdimm->sec.ops->freeze(nvdimm);
nvdimm->sec.state = nvdimm_security_state(nvdimm);
@@ -61,6 +61,22 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid);
int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid,
unsigned int new_keyid);
int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid);
+static inline int nvdimm_security_check_busy(struct nvdimm *nvdimm)
+{
+ if (test_bit(NDD_SECURITY_BUSY, &nvdimm->flags))
+ return -EBUSY;
+ return 0;
+}
+
+static inline void nvdimm_set_security_busy(struct nvdimm *nvdimm)
+{
+ set_bit(NDD_SECURITY_BUSY, &nvdimm->flags);
+}
+
+static inline void nvdimm_clear_security_busy(struct nvdimm *nvdimm)
+{
+ clear_bit(NDD_SECURITY_BUSY, &nvdimm->flags);
+}
/**
* struct blk_alloc_info - tracking info for BLK dpa scanning
@@ -78,6 +78,13 @@ int nd_region_activate(struct nd_region *nd_region)
for (i = 0; i < nd_region->ndr_mappings; i++) {
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
struct nvdimm *nvdimm = nd_mapping->nvdimm;
+ int rc;
+
+ rc = nvdimm_security_check_busy(nvdimm);
+ if (rc) {
+ nvdimm_bus_unlock(&nd_region->dev);
+ return rc;
+ }
/* at least one null hint slot per-dimm for the "no-hint" case */
flush_data_size += sizeof(void *);
@@ -143,6 +143,12 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
|| nvdimm->sec.state < 0)
return -EIO;
+ rc = nvdimm_security_check_busy(nvdimm);
+ if (rc < 0) {
+ dev_warn(dev, "Security operation in progress.\n");
+ return rc;
+ }
+
/*
* If the pre-OS has unlocked the DIMM, attempt to send the key
* from request_key() to the hardware for verification. Failure
@@ -203,6 +209,12 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
return -EIO;
}
+ rc = nvdimm_security_check_busy(nvdimm);
+ if (rc < 0) {
+ dev_warn(dev, "Security operation in progress.\n");
+ return rc;
+ }
+
key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY);
if (!key)
return -ENOKEY;
@@ -288,6 +300,12 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid)
return -EIO;
}
+ rc = nvdimm_security_check_busy(nvdimm);
+ if (rc < 0) {
+ dev_warn(dev, "Security operation in progress.\n");
+ return rc;
+ }
+
key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY);
if (!key)
return -ENOKEY;
@@ -38,6 +38,8 @@ enum {
NDD_UNARMED = 1,
/* locked memory devices should not be accessed */
NDD_LOCKED = 2,
+ /* memory under security wipes should not be accessed */
+ NDD_SECURITY_BUSY = 3,
/* need to set a limit somewhere, but yes, this is likely overkill */
ND_IOCTL_MAX_BUFLEN = SZ_4M,
Adding a flag for nvdimm->flags to support erase functions. While it's ok to hold the nvdimm_bus lock for secure erase due to minimal time to execute the command, overwrite requires a significantly longer time and makes this impossible. The flag will block any drivers from being loaded and DIMMs being probed. Signed-off-by: Dave Jiang <dave.jiang@intel.com> --- drivers/nvdimm/dimm_devs.c | 6 ++++++ drivers/nvdimm/nd-core.h | 16 ++++++++++++++++ drivers/nvdimm/region_devs.c | 7 +++++++ drivers/nvdimm/security.c | 18 ++++++++++++++++++ include/linux/libnvdimm.h | 2 ++ 5 files changed, 49 insertions(+)