Skip to content

Commit 48dcdbb

Browse files
Davidlohr Buesodjbw
authored andcommitted
cxl/mem: Wire up Sanitization support
Implement support for CXL 3.0 8.2.9.8.5.1 Sanitize. This is done by adding a security/sanitize' memdev sysfs file to trigger the operation and extend the status file to make it poll(2)-capable for completion. Unlike all other background commands, this is the only operation that is special and monopolizes the device for long periods of time. In addition to the traditional pmem security requirements, all regions must also be offline in order to perform the operation. This permits avoiding explicit global CPU cache management, relying instead on the implict cache management when a region transitions between CXL_CONFIG_ACTIVE and CXL_CONFIG_COMMIT. The expectation is that userspace can use it such as: cxl disable-memdev memX echo 1 > /sys/bus/cxl/devices/memX/security/sanitize cxl wait-sanitize memX cxl enable-memdev memX Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net> Link: https://lore.kernel.org/r/20230612181038.14421-5-dave@stgolabs.net Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 0c36b6a commit 48dcdbb

5 files changed

Lines changed: 151 additions & 2 deletions

File tree

Documentation/ABI/testing/sysfs-bus-cxl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,25 @@ KernelVersion: v6.5
6464
Contact: linux-cxl@vger.kernel.org
6565
Description:
6666
(RO) Reading this file will display the CXL security state for
67-
that device. Such states can be: 'disabled', or those available
68-
only for persistent memory: 'locked', 'unlocked' or 'frozen'.
67+
that device. Such states can be: 'disabled', 'sanitize', when
68+
a sanitization is currently underway; or those available only
69+
for persistent memory: 'locked', 'unlocked' or 'frozen'. This
70+
sysfs entry is select/poll capable from userspace to notify
71+
upon completion of a sanitize operation.
72+
73+
74+
What: /sys/bus/cxl/devices/memX/security/sanitize
75+
Date: June, 2023
76+
KernelVersion: v6.5
77+
Contact: linux-cxl@vger.kernel.org
78+
Description:
79+
(WO) Write a boolean 'true' string value to this attribute to
80+
sanitize the device to securely re-purpose or decommission it.
81+
This is done by ensuring that all user data and meta-data,
82+
whether it resides in persistent capacity, volatile capacity,
83+
or the LSA, is made permanently unavailable by whatever means
84+
is appropriate for the media type. This functionality requires
85+
the device to be not be actively decoding any HPA ranges.
6986

7087

7188
What: /sys/bus/cxl/devices/*/devtype

drivers/cxl/core/mbox.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,61 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
10751075
}
10761076
EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);
10771077

1078+
/**
1079+
* cxl_mem_sanitize() - Send a sanitization command to the device.
1080+
* @cxlds: The device data for the operation
1081+
* @cmd: The specific sanitization command opcode
1082+
*
1083+
* Return: 0 if the command was executed successfully, regardless of
1084+
* whether or not the actual security operation is done in the background,
1085+
* such as for the Sanitize case.
1086+
* Error return values can be the result of the mailbox command, -EINVAL
1087+
* when security requirements are not met or invalid contexts.
1088+
*
1089+
* See CXL 3.0 @8.2.9.8.5.1 Sanitize and @8.2.9.8.5.2 Secure Erase.
1090+
*/
1091+
int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
1092+
{
1093+
int rc;
1094+
u32 sec_out = 0;
1095+
struct cxl_get_security_output {
1096+
__le32 flags;
1097+
} out;
1098+
struct cxl_mbox_cmd sec_cmd = {
1099+
.opcode = CXL_MBOX_OP_GET_SECURITY_STATE,
1100+
.payload_out = &out,
1101+
.size_out = sizeof(out),
1102+
};
1103+
struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd };
1104+
1105+
if (cmd != CXL_MBOX_OP_SANITIZE)
1106+
return -EINVAL;
1107+
1108+
rc = cxl_internal_send_cmd(cxlds, &sec_cmd);
1109+
if (rc < 0) {
1110+
dev_err(cxlds->dev, "Failed to get security state : %d", rc);
1111+
return rc;
1112+
}
1113+
1114+
/*
1115+
* Prior to using these commands, any security applied to
1116+
* the user data areas of the device shall be DISABLED (or
1117+
* UNLOCKED for secure erase case).
1118+
*/
1119+
sec_out = le32_to_cpu(out.flags);
1120+
if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)
1121+
return -EINVAL;
1122+
1123+
rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
1124+
if (rc < 0) {
1125+
dev_err(cxlds->dev, "Failed to sanitize device : %d", rc);
1126+
return rc;
1127+
}
1128+
1129+
return 0;
1130+
}
1131+
EXPORT_SYMBOL_NS_GPL(cxl_mem_sanitize, CXL);
1132+
10781133
static int add_dpa_res(struct device *dev, struct resource *parent,
10791134
struct resource *res, resource_size_t start,
10801135
resource_size_t size, const char *type)

drivers/cxl/core/memdev.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/* Copyright(c) 2020 Intel Corporation. */
33

4+
#include <linux/io-64-nonatomic-lo-hi.h>
45
#include <linux/device.h>
56
#include <linux/slab.h>
67
#include <linux/idr.h>
@@ -114,6 +115,12 @@ static ssize_t security_state_show(struct device *dev,
114115
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
115116
struct cxl_dev_state *cxlds = cxlmd->cxlds;
116117
unsigned long state = cxlds->security.state;
118+
u64 reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
119+
u32 pct = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_PCT_MASK, reg);
120+
u16 cmd = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
121+
122+
if (cmd == CXL_MBOX_OP_SANITIZE && pct != 100)
123+
return sysfs_emit(buf, "sanitize\n");
117124

118125
if (!(state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
119126
return sysfs_emit(buf, "disabled\n");
@@ -129,6 +136,33 @@ static ssize_t security_state_show(struct device *dev,
129136
static struct device_attribute dev_attr_security_state =
130137
__ATTR(state, 0444, security_state_show, NULL);
131138

139+
static ssize_t security_sanitize_store(struct device *dev,
140+
struct device_attribute *attr,
141+
const char *buf, size_t len)
142+
{
143+
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
144+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
145+
struct cxl_port *port = dev_get_drvdata(&cxlmd->dev);
146+
ssize_t rc;
147+
bool sanitize;
148+
149+
if (kstrtobool(buf, &sanitize) || !sanitize)
150+
return -EINVAL;
151+
152+
if (!port || !is_cxl_endpoint(port))
153+
return -EINVAL;
154+
155+
/* ensure no regions are mapped to this memdev */
156+
if (port->commit_end != -1)
157+
return -EBUSY;
158+
159+
rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SANITIZE);
160+
161+
return rc ? rc : len;
162+
}
163+
static struct device_attribute dev_attr_security_sanitize =
164+
__ATTR(sanitize, 0200, NULL, security_sanitize_store);
165+
132166
static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
133167
{
134168
struct cxl_dev_state *cxlds = cxlmd->cxlds;
@@ -376,6 +410,7 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
376410

377411
static struct attribute *cxl_memdev_security_attributes[] = {
378412
&dev_attr_security_state.attr,
413+
&dev_attr_security_sanitize.attr,
379414
NULL,
380415
};
381416

@@ -594,6 +629,34 @@ static const struct file_operations cxl_memdev_fops = {
594629
.llseek = noop_llseek,
595630
};
596631

632+
static void put_sanitize(void *data)
633+
{
634+
struct cxl_dev_state *cxlds = data;
635+
636+
sysfs_put(cxlds->security.sanitize_node);
637+
}
638+
639+
static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
640+
{
641+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
642+
struct device *dev = &cxlmd->dev;
643+
struct kernfs_node *sec;
644+
645+
sec = sysfs_get_dirent(dev->kobj.sd, "security");
646+
if (!sec) {
647+
dev_err(dev, "sysfs_get_dirent 'security' failed\n");
648+
return -ENODEV;
649+
}
650+
cxlds->security.sanitize_node = sysfs_get_dirent(sec, "state");
651+
sysfs_put(sec);
652+
if (!cxlds->security.sanitize_node) {
653+
dev_err(dev, "sysfs_get_dirent 'state' failed\n");
654+
return -ENODEV;
655+
}
656+
657+
return devm_add_action_or_reset(cxlds->dev, put_sanitize, cxlds);
658+
}
659+
597660
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
598661
{
599662
struct cxl_memdev *cxlmd;
@@ -622,6 +685,10 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
622685
if (rc)
623686
goto err;
624687

688+
rc = cxl_memdev_security_init(cxlmd);
689+
if (rc)
690+
goto err;
691+
625692
rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
626693
if (rc)
627694
return ERR_PTR(rc);

drivers/cxl/cxlmem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,12 +267,14 @@ struct cxl_poison_state {
267267
* @poll: polling for sanitization is enabled, device has no mbox irq support
268268
* @poll_tmo_secs: polling timeout
269269
* @poll_dwork: polling work item
270+
* @sanitize_node: sanitation sysfs file to notify
270271
*/
271272
struct cxl_security_state {
272273
unsigned long state;
273274
bool poll;
274275
int poll_tmo_secs;
275276
struct delayed_work poll_dwork;
277+
struct kernfs_node *sanitize_node;
276278
};
277279

278280
/**
@@ -746,6 +748,8 @@ static inline void cxl_mem_active_dec(void)
746748
}
747749
#endif
748750

751+
int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd);
752+
749753
struct cxl_hdm {
750754
struct cxl_component_regs regs;
751755
unsigned int decoder_count;

drivers/cxl/pci.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ static irqreturn_t cxl_pci_mbox_irq(int irq, void *id)
126126
reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
127127
opcode = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
128128
if (opcode == CXL_MBOX_OP_SANITIZE) {
129+
if (cxlds->security.sanitize_node)
130+
sysfs_notify_dirent(cxlds->security.sanitize_node);
131+
129132
dev_dbg(cxlds->dev, "Sanitization operation ended\n");
130133
} else {
131134
/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
@@ -150,6 +153,9 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
150153
cxlds->security.poll_tmo_secs = 0;
151154
put_device(cxlds->dev);
152155

156+
if (cxlds->security.sanitize_node)
157+
sysfs_notify_dirent(cxlds->security.sanitize_node);
158+
153159
dev_dbg(cxlds->dev, "Sanitization operation ended\n");
154160
} else {
155161
int timeout = cxlds->security.poll_tmo_secs + 10;

0 commit comments

Comments
 (0)