xref: /linux/drivers/cxl/security.c (revision 39c089a01a7e431383710a566864644cbbc0f8fe)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */
3 #include <linux/libnvdimm.h>
4 #include <linux/unaligned.h>
5 #include <linux/module.h>
6 #include <linux/async.h>
7 #include <linux/slab.h>
8 #include <linux/memregion.h>
9 #include "cxlmem.h"
10 #include "cxl.h"
11 
12 static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
13 						 enum nvdimm_passphrase_type ptype)
14 {
15 	struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
16 	struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
17 	struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
18 	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
19 	unsigned long security_flags = 0;
20 	struct cxl_get_security_output {
21 		__le32 flags;
22 	} out;
23 	struct cxl_mbox_cmd mbox_cmd;
24 	u32 sec_out;
25 	int rc;
26 
27 	mbox_cmd = (struct cxl_mbox_cmd) {
28 		.opcode = CXL_MBOX_OP_GET_SECURITY_STATE,
29 		.size_out = sizeof(out),
30 		.payload_out = &out,
31 	};
32 
33 	rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
34 	if (rc < 0)
35 		return 0;
36 
37 	sec_out = le32_to_cpu(out.flags);
38 	/* cache security state */
39 	mds->security.state = sec_out;
40 
41 	if (ptype == NVDIMM_MASTER) {
42 		if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)
43 			set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
44 		else
45 			set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
46 		if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PLIMIT)
47 			set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
48 		return security_flags;
49 	}
50 
51 	if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
52 		if (sec_out & CXL_PMEM_SEC_STATE_FROZEN ||
53 		    sec_out & CXL_PMEM_SEC_STATE_USER_PLIMIT)
54 			set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
55 
56 		if (sec_out & CXL_PMEM_SEC_STATE_LOCKED)
57 			set_bit(NVDIMM_SECURITY_LOCKED, &security_flags);
58 		else
59 			set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
60 	} else {
61 		set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
62 	}
63 
64 	return security_flags;
65 }
66 
67 static int cxl_pmem_security_change_key(struct nvdimm *nvdimm,
68 					const struct nvdimm_key_data *old_data,
69 					const struct nvdimm_key_data *new_data,
70 					enum nvdimm_passphrase_type ptype)
71 {
72 	struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
73 	struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
74 	struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
75 	struct cxl_mbox_cmd mbox_cmd;
76 	struct cxl_set_pass set_pass;
77 
78 	set_pass = (struct cxl_set_pass) {
79 		.type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
80 						 CXL_PMEM_SEC_PASS_USER,
81 	};
82 	memcpy(set_pass.old_pass, old_data->data, NVDIMM_PASSPHRASE_LEN);
83 	memcpy(set_pass.new_pass, new_data->data, NVDIMM_PASSPHRASE_LEN);
84 
85 	mbox_cmd = (struct cxl_mbox_cmd) {
86 		.opcode = CXL_MBOX_OP_SET_PASSPHRASE,
87 		.size_in = sizeof(set_pass),
88 		.payload_in = &set_pass,
89 	};
90 
91 	return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
92 }
93 
94 static int __cxl_pmem_security_disable(struct nvdimm *nvdimm,
95 				       const struct nvdimm_key_data *key_data,
96 				       enum nvdimm_passphrase_type ptype)
97 {
98 	struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
99 	struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
100 	struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
101 	struct cxl_disable_pass dis_pass;
102 	struct cxl_mbox_cmd mbox_cmd;
103 
104 	dis_pass = (struct cxl_disable_pass) {
105 		.type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
106 						 CXL_PMEM_SEC_PASS_USER,
107 	};
108 	memcpy(dis_pass.pass, key_data->data, NVDIMM_PASSPHRASE_LEN);
109 
110 	mbox_cmd = (struct cxl_mbox_cmd) {
111 		.opcode = CXL_MBOX_OP_DISABLE_PASSPHRASE,
112 		.size_in = sizeof(dis_pass),
113 		.payload_in = &dis_pass,
114 	};
115 
116 	return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
117 }
118 
119 static int cxl_pmem_security_disable(struct nvdimm *nvdimm,
120 				     const struct nvdimm_key_data *key_data)
121 {
122 	return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_USER);
123 }
124 
125 static int cxl_pmem_security_disable_master(struct nvdimm *nvdimm,
126 					    const struct nvdimm_key_data *key_data)
127 {
128 	return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_MASTER);
129 }
130 
131 static int cxl_pmem_security_freeze(struct nvdimm *nvdimm)
132 {
133 	struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
134 	struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
135 	struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
136 	struct cxl_mbox_cmd mbox_cmd = {
137 		.opcode = CXL_MBOX_OP_FREEZE_SECURITY,
138 	};
139 
140 	return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
141 }
142 
143 static int cxl_pmem_security_unlock(struct nvdimm *nvdimm,
144 				    const struct nvdimm_key_data *key_data)
145 {
146 	struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
147 	struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
148 	struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
149 	u8 pass[NVDIMM_PASSPHRASE_LEN];
150 	struct cxl_mbox_cmd mbox_cmd;
151 	int rc;
152 
153 	memcpy(pass, key_data->data, NVDIMM_PASSPHRASE_LEN);
154 	mbox_cmd = (struct cxl_mbox_cmd) {
155 		.opcode = CXL_MBOX_OP_UNLOCK,
156 		.size_in = NVDIMM_PASSPHRASE_LEN,
157 		.payload_in = pass,
158 	};
159 
160 	rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
161 	if (rc < 0)
162 		return rc;
163 
164 	return 0;
165 }
166 
167 static int cxl_pmem_security_passphrase_erase(struct nvdimm *nvdimm,
168 					      const struct nvdimm_key_data *key,
169 					      enum nvdimm_passphrase_type ptype)
170 {
171 	struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
172 	struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
173 	struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
174 	struct cxl_mbox_cmd mbox_cmd;
175 	struct cxl_pass_erase erase;
176 	int rc;
177 
178 	erase = (struct cxl_pass_erase) {
179 		.type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
180 						 CXL_PMEM_SEC_PASS_USER,
181 	};
182 	memcpy(erase.pass, key->data, NVDIMM_PASSPHRASE_LEN);
183 	mbox_cmd = (struct cxl_mbox_cmd) {
184 		.opcode = CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE,
185 		.size_in = sizeof(erase),
186 		.payload_in = &erase,
187 	};
188 
189 	rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
190 	if (rc < 0)
191 		return rc;
192 
193 	return 0;
194 }
195 
196 static const struct nvdimm_security_ops __cxl_security_ops = {
197 	.get_flags = cxl_pmem_get_security_flags,
198 	.change_key = cxl_pmem_security_change_key,
199 	.disable = cxl_pmem_security_disable,
200 	.freeze = cxl_pmem_security_freeze,
201 	.unlock = cxl_pmem_security_unlock,
202 	.erase = cxl_pmem_security_passphrase_erase,
203 	.disable_master = cxl_pmem_security_disable_master,
204 };
205 
206 const struct nvdimm_security_ops *cxl_security_ops = &__cxl_security_ops;
207