Message ID | 165791938847.2491387.8701829648751368015.stgit@djiang5-desk3.ch.intel.com |
---|---|
State | Superseded |
Headers | show |
Series | Introduce security commands for CXL pmem device | expand |
On Fri, 15 Jul 2022, Dave Jiang wrote: >Create callback function to support the nvdimm_security_ops() ->erase() >callback. Translate the operation to send "Passphrase Secure Erase" >security command for CXL memory device. > >When the mem device is secure erased, arch_invalidate_nvdimm_cache() is >called in order to invalidate all CPU caches before attempting to access >the mem device again. > >See CXL 2.0 spec section 8.2.9.5.6.6 for reference. So something like the below is what I picture for 8.2.9.5.5.2 (I'm still thinking about the background command polling semantics and corner cases for the overwrite/sanitize - also needed for scan media - so I haven't implemented 8.2.9.5.5.1, but should otherwise be straightforward). The use cases here would be: $> cxl sanitize --crypto-erase memN $> cxl sanitize --overwrite memN $> cxl sanitize --wait-overwrite memN While slightly out of the scope of this series, it still might be worth carrying as they are that unrelated unless there is something fundamentally with my approach. Thanks, Davidlohr -----<8---------------------------------------------------- [PATCH 16/15] cxl/mbox: Add "Secure Erase" security command support To properly support this feature, create a 'security' sysfs file that when read will list the current pmem security state, and when written to, perform the requested operation (only secure erase is currently supported). Signed-off-by: Davidlohr Bueso <dave@stgolabs.net> --- Documentation/ABI/testing/sysfs-bus-cxl | 13 +++++++ drivers/cxl/core/mbox.c | 44 +++++++++++++++++++++ drivers/cxl/core/memdev.c | 51 +++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 3 ++ 4 files changed, 111 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index 7c2b846521f3..ca5216b37bcf 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -52,6 +52,19 @@ Description: host PCI device for this memory device, emit the CPU node affinity for this device. +What: /sys/bus/cxl/devices/memX/security +Date: July, 2022 +KernelVersion: v5.21 +Contact: linux-cxl@vger.kernel.org +Description: + Reading this file will display the security state for that + device. The following states are available: disabled, frozen, + locked and unlocked. When writing to the file, the following + command(s) are supported: + erase - Secure Erase user data by changing the media encryption + keys for all user data areas of the device. This causes + all CPU caches to be flushed. + What: /sys/bus/cxl/devices/*/devtype Date: June, 2021 KernelVersion: v5.14 diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 54f434733b56..54b4aec615ee 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -787,6 +787,50 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds) } EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL); +/** + * cxl_mem_sanitize() - Send sanitation related commands to the device. + * @cxlds: The device data for the operation + * @cmd: The command opcode to send + * + * Return: 0 if the command was executed successfully, regardless of + * whether or not the actual security operation is done in the background. + * Upon error, return the result of the mailbox command or -EINVAL if + * security requirements are not met. + * + * See CXL 2.0 @8.2.9.5.5 Sanitize. + */ +int cxl_mem_sanitize(struct cxl_dev_state *cxlds, enum cxl_opcode cmd) +{ + int rc; + u32 sec_out; + + /* TODO: CXL_MBOX_OP_SECURE_SANITIZE */ + if (cmd != CXL_MBOX_OP_SECURE_ERASE) + return -EINVAL; + + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SECURITY_STATE, + NULL, 0, &sec_out, sizeof(sec_out)); + if (rc) + return rc; + /* + * Prior to using these commands, any security applied to + * the user data areas of the device shall be DISABLED (or + * UNLOCKED for secure erase case). + */ + if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET || + sec_out & CXL_PMEM_SEC_STATE_LOCKED) + return -EINVAL; + + rc = cxl_mbox_send_cmd(cxlds, cmd, NULL, 0, NULL, 0); + if (rc == 0) { + /* flush all CPU caches before we read it */ + flush_cache_all(); + } + + return rc; +} +EXPORT_SYMBOL_NS_GPL(cxl_mem_sanitize, CXL); + int cxl_mem_create_range_info(struct cxl_dev_state *cxlds) { int rc; diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index f7cdcd33504a..13563facfd62 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -106,12 +106,63 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(numa_node); +#define CXL_SEC_CMD_SIZE 32 + +static ssize_t security_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + u32 sec_out; + int rc; + + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SECURITY_STATE, + NULL, 0, &sec_out, sizeof(sec_out)); + if (rc) + return rc; + + if (!(sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)) + return sprintf(buf, "disabled\n"); + if (sec_out & CXL_PMEM_SEC_STATE_FROZEN) + return sprintf(buf, "frozen\n"); + if (sec_out & CXL_PMEM_SEC_STATE_LOCKED) + return sprintf(buf, "locked\n"); + else + return sprintf(buf, "unlocked\n"); +} + +static ssize_t security_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + char cmd[CXL_SEC_CMD_SIZE+1]; + ssize_t rc; + + rc = sscanf(buf, "%"__stringify(CXL_SEC_CMD_SIZE)"s", cmd); + if (rc < 1) + return -EINVAL; + + if (sysfs_streq(cmd, "erase")) { + dev_dbg(dev, "secure-erase\n"); + rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE); + } else + rc = -EINVAL; + + if (rc == 0) + rc = len; + return rc; +} +static DEVICE_ATTR_RW(security); + static struct attribute *cxl_memdev_attributes[] = { &dev_attr_serial.attr, &dev_attr_firmware_version.attr, &dev_attr_payload_max.attr, &dev_attr_label_storage_size.attr, &dev_attr_numa_node.attr, + &dev_attr_security.attr, NULL, }; diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index a375a69040d2..cd6650ff757f 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -250,6 +250,7 @@ enum cxl_opcode { CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS = 0x4303, CXL_MBOX_OP_SCAN_MEDIA = 0x4304, CXL_MBOX_OP_GET_SCAN_MEDIA = 0x4305, + CXL_MBOX_OP_SECURE_ERASE = 0x4401, CXL_MBOX_OP_GET_SECURITY_STATE = 0x4500, CXL_MBOX_OP_SET_PASSPHRASE = 0x4501, CXL_MBOX_OP_DISABLE_PASSPHRASE = 0x4502, @@ -348,6 +349,8 @@ struct cxl_mem_command { #define CXL_CMD_FLAG_FORCE_ENABLE BIT(0) }; +int cxl_mem_sanitize(struct cxl_dev_state *cxlds, enum cxl_opcode cmd); + #define CXL_PMEM_SEC_STATE_USER_PASS_SET 0x01 #define CXL_PMEM_SEC_STATE_MASTER_PASS_SET 0x02 #define CXL_PMEM_SEC_STATE_LOCKED 0x04
On 7/19/2022 11:17 PM, Davidlohr Bueso wrote: > On Fri, 15 Jul 2022, Dave Jiang wrote: > >> Create callback function to support the nvdimm_security_ops() ->erase() >> callback. Translate the operation to send "Passphrase Secure Erase" >> security command for CXL memory device. >> >> When the mem device is secure erased, arch_invalidate_nvdimm_cache() is >> called in order to invalidate all CPU caches before attempting to access >> the mem device again. >> >> See CXL 2.0 spec section 8.2.9.5.6.6 for reference. > > So something like the below is what I picture for 8.2.9.5.5.2 > (I'm still thinking about the background command polling semantics > and corner cases for the overwrite/sanitize - also needed for > scan media - so I haven't implemented 8.2.9.5.5.1, but should > otherwise be straightforward). > > The use cases here would be: > > $> cxl sanitize --crypto-erase memN > $> cxl sanitize --overwrite memN > $> cxl sanitize --wait-overwrite memN > > While slightly out of the scope of this series, it still might be > worth carrying as they are that unrelated unless there is something > fundamentally with my approach. Patch below is about what I had in mind for the secure erase command. Looks good to me. The only thing I think it needs is to make sure the mem devs are not "in use" before secure erase in addition to the security check that's already there below. I was planning on working on this after getting the current security commands series wrapped up. But if you are already developing this then I'll defer. Also here's the latest code that I'm still going through testing if you want to play with it. I still need to replace the x86 patch with your version. https://git.kernel.org/pub/scm/linux/kernel/git/djiang/linux.git/log/?h=cxl-security > > Thanks, > Davidlohr > > -----<8---------------------------------------------------- > [PATCH 16/15] cxl/mbox: Add "Secure Erase" security command support > > To properly support this feature, create a 'security' sysfs > file that when read will list the current pmem security state, > and when written to, perform the requested operation (only > secure erase is currently supported). > > Signed-off-by: Davidlohr Bueso <dave@stgolabs.net> > --- > Documentation/ABI/testing/sysfs-bus-cxl | 13 +++++++ > drivers/cxl/core/mbox.c | 44 +++++++++++++++++++++ > drivers/cxl/core/memdev.c | 51 +++++++++++++++++++++++++ > drivers/cxl/cxlmem.h | 3 ++ > 4 files changed, 111 insertions(+) > > diff --git a/Documentation/ABI/testing/sysfs-bus-cxl > b/Documentation/ABI/testing/sysfs-bus-cxl > index 7c2b846521f3..ca5216b37bcf 100644 > --- a/Documentation/ABI/testing/sysfs-bus-cxl > +++ b/Documentation/ABI/testing/sysfs-bus-cxl > @@ -52,6 +52,19 @@ Description: > host PCI device for this memory device, emit the CPU node > affinity for this device. > > +What: /sys/bus/cxl/devices/memX/security > +Date: July, 2022 > +KernelVersion: v5.21 > +Contact: linux-cxl@vger.kernel.org > +Description: > + Reading this file will display the security state for that > + device. The following states are available: disabled, frozen, > + locked and unlocked. When writing to the file, the following > + command(s) are supported: > + erase - Secure Erase user data by changing the media encryption > + keys for all user data areas of the device. This causes > + all CPU caches to be flushed. > + > What: /sys/bus/cxl/devices/*/devtype > Date: June, 2021 > KernelVersion: v5.14 > diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c > index 54f434733b56..54b4aec615ee 100644 > --- a/drivers/cxl/core/mbox.c > +++ b/drivers/cxl/core/mbox.c > @@ -787,6 +787,50 @@ int cxl_dev_state_identify(struct cxl_dev_state > *cxlds) > } > EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL); > > +/** > + * cxl_mem_sanitize() - Send sanitation related commands to the device. > + * @cxlds: The device data for the operation > + * @cmd: The command opcode to send > + * > + * Return: 0 if the command was executed successfully, regardless of > + * whether or not the actual security operation is done in the > background. > + * Upon error, return the result of the mailbox command or -EINVAL if > + * security requirements are not met. > + * > + * See CXL 2.0 @8.2.9.5.5 Sanitize. > + */ > +int cxl_mem_sanitize(struct cxl_dev_state *cxlds, enum cxl_opcode cmd) > +{ > + int rc; > + u32 sec_out; > + > + /* TODO: CXL_MBOX_OP_SECURE_SANITIZE */ > + if (cmd != CXL_MBOX_OP_SECURE_ERASE) > + return -EINVAL; > + > + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SECURITY_STATE, > + NULL, 0, &sec_out, sizeof(sec_out)); > + if (rc) > + return rc; > + /* > + * Prior to using these commands, any security applied to > + * the user data areas of the device shall be DISABLED (or > + * UNLOCKED for secure erase case). > + */ > + if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET || > + sec_out & CXL_PMEM_SEC_STATE_LOCKED) > + return -EINVAL; > + > + rc = cxl_mbox_send_cmd(cxlds, cmd, NULL, 0, NULL, 0); > + if (rc == 0) { > + /* flush all CPU caches before we read it */ > + flush_cache_all(); > + } > + > + return rc; > +} > +EXPORT_SYMBOL_NS_GPL(cxl_mem_sanitize, CXL); > + > int cxl_mem_create_range_info(struct cxl_dev_state *cxlds) > { > int rc; > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c > index f7cdcd33504a..13563facfd62 100644 > --- a/drivers/cxl/core/memdev.c > +++ b/drivers/cxl/core/memdev.c > @@ -106,12 +106,63 @@ static ssize_t numa_node_show(struct device > *dev, struct device_attribute *attr, > } > static DEVICE_ATTR_RO(numa_node); > > +#define CXL_SEC_CMD_SIZE 32 > + > +static ssize_t security_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); > + struct cxl_dev_state *cxlds = cxlmd->cxlds; > + u32 sec_out; > + int rc; > + > + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SECURITY_STATE, > + NULL, 0, &sec_out, sizeof(sec_out)); > + if (rc) > + return rc; > + > + if (!(sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)) > + return sprintf(buf, "disabled\n"); > + if (sec_out & CXL_PMEM_SEC_STATE_FROZEN) > + return sprintf(buf, "frozen\n"); > + if (sec_out & CXL_PMEM_SEC_STATE_LOCKED) > + return sprintf(buf, "locked\n"); > + else > + return sprintf(buf, "unlocked\n"); > +} > + > +static ssize_t security_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); > + struct cxl_dev_state *cxlds = cxlmd->cxlds; > + char cmd[CXL_SEC_CMD_SIZE+1]; > + ssize_t rc; > + > + rc = sscanf(buf, "%"__stringify(CXL_SEC_CMD_SIZE)"s", cmd); > + if (rc < 1) > + return -EINVAL; > + > + if (sysfs_streq(cmd, "erase")) { > + dev_dbg(dev, "secure-erase\n"); > + rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE); > + } else > + rc = -EINVAL; > + > + if (rc == 0) > + rc = len; > + return rc; > +} > +static DEVICE_ATTR_RW(security); > + > static struct attribute *cxl_memdev_attributes[] = { > &dev_attr_serial.attr, > &dev_attr_firmware_version.attr, > &dev_attr_payload_max.attr, > &dev_attr_label_storage_size.attr, > &dev_attr_numa_node.attr, > + &dev_attr_security.attr, > NULL, > }; > > diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h > index a375a69040d2..cd6650ff757f 100644 > --- a/drivers/cxl/cxlmem.h > +++ b/drivers/cxl/cxlmem.h > @@ -250,6 +250,7 @@ enum cxl_opcode { > CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS = 0x4303, > CXL_MBOX_OP_SCAN_MEDIA = 0x4304, > CXL_MBOX_OP_GET_SCAN_MEDIA = 0x4305, > + CXL_MBOX_OP_SECURE_ERASE = 0x4401, > CXL_MBOX_OP_GET_SECURITY_STATE = 0x4500, > CXL_MBOX_OP_SET_PASSPHRASE = 0x4501, > CXL_MBOX_OP_DISABLE_PASSPHRASE = 0x4502, > @@ -348,6 +349,8 @@ struct cxl_mem_command { > #define CXL_CMD_FLAG_FORCE_ENABLE BIT(0) > }; > > +int cxl_mem_sanitize(struct cxl_dev_state *cxlds, enum cxl_opcode cmd); > + > #define CXL_PMEM_SEC_STATE_USER_PASS_SET 0x01 > #define CXL_PMEM_SEC_STATE_MASTER_PASS_SET 0x02 > #define CXL_PMEM_SEC_STATE_LOCKED 0x04
On Wed, 20 Jul 2022, Dave Jiang wrote: >Patch below is about what I had in mind for the secure erase command. >Looks good to me. The only thing I think it needs is to make sure the >mem devs are not "in use" before secure erase in addition to the >security check that's already there below. I was planning on working >on this after getting the current security commands series wrapped up. >But if you are already developing this then I'll defer. > >Also here's the latest code that I'm still going through testing if >you want to play with it. I still need to replace the x86 patch with >your version. Ok I will play more and test your series during the rest of the week, as well as my own changes. I'll end up a formal series on top of this one (or whatever version you are at at the time) with the sanitize + secure-erase (and the relevant mock device updates). Thanks, Davidlohr
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index ae8ccd484491..4bcb02f625b4 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -255,6 +255,7 @@ enum cxl_opcode { CXL_MBOX_OP_DISABLE_PASSPHRASE = 0x4502, CXL_MBOX_OP_UNLOCK = 0x4503, CXL_MBOX_OP_FREEZE_SECURITY = 0x4504, + CXL_MBOX_OP_PASSPHRASE_ERASE = 0x4505, CXL_MBOX_OP_MAX = 0x10000 }; @@ -369,6 +370,13 @@ struct cxl_disable_pass { u8 pass[NVDIMM_PASSPHRASE_LEN]; } __packed; +/* passphrase erase payload */ +struct cxl_pass_erase { + u8 type; + u8 reserved[31]; + u8 pass[NVDIMM_PASSPHRASE_LEN]; +} __packed; + enum { CXL_PMEM_SEC_PASS_MASTER = 0, CXL_PMEM_SEC_PASS_USER, diff --git a/drivers/cxl/security.c b/drivers/cxl/security.c index d15520f280f0..4add7f62e758 100644 --- a/drivers/cxl/security.c +++ b/drivers/cxl/security.c @@ -134,12 +134,41 @@ static int cxl_pmem_security_unlock(struct nvdimm *nvdimm, return 0; } +static int cxl_pmem_security_passphrase_erase(struct nvdimm *nvdimm, + const struct nvdimm_key_data *key, + enum nvdimm_passphrase_type ptype) +{ + struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); + struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_pass_erase *erase; + int rc; + + erase = kzalloc(sizeof(*erase), GFP_KERNEL); + if (!erase) + return -ENOMEM; + + erase->type = ptype == NVDIMM_MASTER ? + CXL_PMEM_SEC_PASS_MASTER : CXL_PMEM_SEC_PASS_USER; + memcpy(erase->pass, key->data, NVDIMM_PASSPHRASE_LEN); + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_PASSPHRASE_ERASE, + erase, sizeof(*erase), NULL, 0); + kfree(erase); + if (rc < 0) + return rc; + + /* DIMM erased, invalidate all CPU caches before we read it */ + arch_invalidate_nvdimm_cache(); + return 0; +} + static const struct nvdimm_security_ops __cxl_security_ops = { .get_flags = cxl_pmem_get_security_flags, .change_key = cxl_pmem_security_change_key, .disable = cxl_pmem_security_disable, .freeze = cxl_pmem_security_freeze, .unlock = cxl_pmem_security_unlock, + .erase = cxl_pmem_security_passphrase_erase, }; const struct nvdimm_security_ops *cxl_security_ops = &__cxl_security_ops;
Create callback function to support the nvdimm_security_ops() ->erase() callback. Translate the operation to send "Passphrase Secure Erase" security command for CXL memory device. When the mem device is secure erased, arch_invalidate_nvdimm_cache() is called in order to invalidate all CPU caches before attempting to access the mem device again. See CXL 2.0 spec section 8.2.9.5.6.6 for reference. Signed-off-by: Dave Jiang <dave.jiang@intel.com> --- drivers/cxl/cxlmem.h | 8 ++++++++ drivers/cxl/security.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+)