14c6926a2SDave Jiang // SPDX-License-Identifier: GPL-2.0
24c6926a2SDave Jiang /* Copyright(c) 2018 Intel Corporation. All rights reserved. */
34c6926a2SDave Jiang
44c6926a2SDave Jiang #include <linux/module.h>
54c6926a2SDave Jiang #include <linux/device.h>
64c6926a2SDave Jiang #include <linux/ndctl.h>
74c6926a2SDave Jiang #include <linux/slab.h>
84c6926a2SDave Jiang #include <linux/io.h>
94c6926a2SDave Jiang #include <linux/mm.h>
104c6926a2SDave Jiang #include <linux/cred.h>
114c6926a2SDave Jiang #include <linux/key.h>
124c6926a2SDave Jiang #include <linux/key-type.h>
134c6926a2SDave Jiang #include <keys/user-type.h>
144c6926a2SDave Jiang #include <keys/encrypted-type.h>
154c6926a2SDave Jiang #include "nd-core.h"
164c6926a2SDave Jiang #include "nd.h"
174c6926a2SDave Jiang
18d2a4ac73SDave Jiang #define NVDIMM_BASE_KEY 0
19d2a4ac73SDave Jiang #define NVDIMM_NEW_KEY 1
20d2a4ac73SDave Jiang
214c6926a2SDave Jiang static bool key_revalidate = true;
224c6926a2SDave Jiang module_param(key_revalidate, bool, 0444);
234c6926a2SDave Jiang MODULE_PARM_DESC(key_revalidate, "Require key validation at init.");
244c6926a2SDave Jiang
25037c8489SDave Jiang static const char zero_key[NVDIMM_PASSPHRASE_LEN];
26037c8489SDave Jiang
key_data(struct key * key)274c6926a2SDave Jiang static void *key_data(struct key *key)
284c6926a2SDave Jiang {
294c6926a2SDave Jiang struct encrypted_key_payload *epayload = dereference_key_locked(key);
304c6926a2SDave Jiang
314c6926a2SDave Jiang lockdep_assert_held_read(&key->sem);
324c6926a2SDave Jiang
334c6926a2SDave Jiang return epayload->decrypted_data;
344c6926a2SDave Jiang }
354c6926a2SDave Jiang
nvdimm_put_key(struct key * key)364c6926a2SDave Jiang static void nvdimm_put_key(struct key *key)
374c6926a2SDave Jiang {
3864e77c8cSDave Jiang if (!key)
3964e77c8cSDave Jiang return;
4064e77c8cSDave Jiang
414c6926a2SDave Jiang up_read(&key->sem);
424c6926a2SDave Jiang key_put(key);
434c6926a2SDave Jiang }
444c6926a2SDave Jiang
454c6926a2SDave Jiang /*
464c6926a2SDave Jiang * Retrieve kernel key for DIMM and request from user space if
474c6926a2SDave Jiang * necessary. Returns a key held for read and must be put by
484c6926a2SDave Jiang * nvdimm_put_key() before the usage goes out of scope.
494c6926a2SDave Jiang */
nvdimm_request_key(struct nvdimm * nvdimm)504c6926a2SDave Jiang static struct key *nvdimm_request_key(struct nvdimm *nvdimm)
514c6926a2SDave Jiang {
524c6926a2SDave Jiang struct key *key = NULL;
534c6926a2SDave Jiang static const char NVDIMM_PREFIX[] = "nvdimm:";
544c6926a2SDave Jiang char desc[NVDIMM_KEY_DESC_LEN + sizeof(NVDIMM_PREFIX)];
554c6926a2SDave Jiang struct device *dev = &nvdimm->dev;
564c6926a2SDave Jiang
574c6926a2SDave Jiang sprintf(desc, "%s%s", NVDIMM_PREFIX, nvdimm->dimm_id);
58028db3e2SLinus Torvalds key = request_key(&key_type_encrypted, desc, "");
594c6926a2SDave Jiang if (IS_ERR(key)) {
604c6926a2SDave Jiang if (PTR_ERR(key) == -ENOKEY)
6137379cfcSDan Williams dev_dbg(dev, "request_key() found no key\n");
624c6926a2SDave Jiang else
6337379cfcSDan Williams dev_dbg(dev, "request_key() upcall failed\n");
644c6926a2SDave Jiang key = NULL;
654c6926a2SDave Jiang } else {
664c6926a2SDave Jiang struct encrypted_key_payload *epayload;
674c6926a2SDave Jiang
684c6926a2SDave Jiang down_read(&key->sem);
694c6926a2SDave Jiang epayload = dereference_key_locked(key);
704c6926a2SDave Jiang if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) {
714c6926a2SDave Jiang up_read(&key->sem);
724c6926a2SDave Jiang key_put(key);
734c6926a2SDave Jiang key = NULL;
744c6926a2SDave Jiang }
754c6926a2SDave Jiang }
764c6926a2SDave Jiang
774c6926a2SDave Jiang return key;
784c6926a2SDave Jiang }
794c6926a2SDave Jiang
nvdimm_get_key_payload(struct nvdimm * nvdimm,struct key ** key)80d2e5b643SDave Jiang static const void *nvdimm_get_key_payload(struct nvdimm *nvdimm,
81d2e5b643SDave Jiang struct key **key)
82d2e5b643SDave Jiang {
83d2e5b643SDave Jiang *key = nvdimm_request_key(nvdimm);
84d2e5b643SDave Jiang if (!*key)
85d2e5b643SDave Jiang return zero_key;
86d2e5b643SDave Jiang
87d2e5b643SDave Jiang return key_data(*key);
88d2e5b643SDave Jiang }
89d2e5b643SDave Jiang
nvdimm_lookup_user_key(struct nvdimm * nvdimm,key_serial_t id,int subclass)9003b65b22SDave Jiang static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm,
91d2a4ac73SDave Jiang key_serial_t id, int subclass)
9203b65b22SDave Jiang {
9303b65b22SDave Jiang key_ref_t keyref;
9403b65b22SDave Jiang struct key *key;
9503b65b22SDave Jiang struct encrypted_key_payload *epayload;
9603b65b22SDave Jiang struct device *dev = &nvdimm->dev;
9703b65b22SDave Jiang
98813357feSDan Williams keyref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
9903b65b22SDave Jiang if (IS_ERR(keyref))
10003b65b22SDave Jiang return NULL;
10103b65b22SDave Jiang
10203b65b22SDave Jiang key = key_ref_to_ptr(keyref);
10303b65b22SDave Jiang if (key->type != &key_type_encrypted) {
10403b65b22SDave Jiang key_put(key);
10503b65b22SDave Jiang return NULL;
10603b65b22SDave Jiang }
107d2a4ac73SDave Jiang
10803b65b22SDave Jiang dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key));
10903b65b22SDave Jiang
110d2a4ac73SDave Jiang down_read_nested(&key->sem, subclass);
11103b65b22SDave Jiang epayload = dereference_key_locked(key);
11203b65b22SDave Jiang if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) {
11303b65b22SDave Jiang up_read(&key->sem);
11403b65b22SDave Jiang key_put(key);
11503b65b22SDave Jiang key = NULL;
11603b65b22SDave Jiang }
11703b65b22SDave Jiang return key;
11803b65b22SDave Jiang }
11903b65b22SDave Jiang
nvdimm_get_user_key_payload(struct nvdimm * nvdimm,key_serial_t id,int subclass,struct key ** key)120d2e5b643SDave Jiang static const void *nvdimm_get_user_key_payload(struct nvdimm *nvdimm,
121d2e5b643SDave Jiang key_serial_t id, int subclass, struct key **key)
122d2e5b643SDave Jiang {
123d2e5b643SDave Jiang *key = NULL;
124d2e5b643SDave Jiang if (id == 0) {
125d2e5b643SDave Jiang if (subclass == NVDIMM_BASE_KEY)
126d2e5b643SDave Jiang return zero_key;
127d2e5b643SDave Jiang else
128d2e5b643SDave Jiang return NULL;
129d2e5b643SDave Jiang }
130d2e5b643SDave Jiang
131d2e5b643SDave Jiang *key = nvdimm_lookup_user_key(nvdimm, id, subclass);
132d2e5b643SDave Jiang if (!*key)
133d2e5b643SDave Jiang return NULL;
134d2e5b643SDave Jiang
135d2e5b643SDave Jiang return key_data(*key);
136d2e5b643SDave Jiang }
137d2e5b643SDave Jiang
138d2e5b643SDave Jiang
nvdimm_key_revalidate(struct nvdimm * nvdimm)139d2e5b643SDave Jiang static int nvdimm_key_revalidate(struct nvdimm *nvdimm)
1404c6926a2SDave Jiang {
1414c6926a2SDave Jiang struct key *key;
1424c6926a2SDave Jiang int rc;
143d2e5b643SDave Jiang const void *data;
1444c6926a2SDave Jiang
1454c6926a2SDave Jiang if (!nvdimm->sec.ops->change_key)
146d2e5b643SDave Jiang return -EOPNOTSUPP;
1474c6926a2SDave Jiang
148d2e5b643SDave Jiang data = nvdimm_get_key_payload(nvdimm, &key);
1494c6926a2SDave Jiang
1504c6926a2SDave Jiang /*
1514c6926a2SDave Jiang * Send the same key to the hardware as new and old key to
1524c6926a2SDave Jiang * verify that the key is good.
1534c6926a2SDave Jiang */
154d2e5b643SDave Jiang rc = nvdimm->sec.ops->change_key(nvdimm, data, data, NVDIMM_USER);
1554c6926a2SDave Jiang if (rc < 0) {
1564c6926a2SDave Jiang nvdimm_put_key(key);
157d2e5b643SDave Jiang return rc;
1584c6926a2SDave Jiang }
159d2e5b643SDave Jiang
160d2e5b643SDave Jiang nvdimm_put_key(key);
161d78c620aSDan Williams nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
162d2e5b643SDave Jiang return 0;
1634c6926a2SDave Jiang }
1644c6926a2SDave Jiang
__nvdimm_security_unlock(struct nvdimm * nvdimm)1654c6926a2SDave Jiang static int __nvdimm_security_unlock(struct nvdimm *nvdimm)
1664c6926a2SDave Jiang {
1674c6926a2SDave Jiang struct device *dev = &nvdimm->dev;
1684c6926a2SDave Jiang struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
169d2e5b643SDave Jiang struct key *key;
170d2e5b643SDave Jiang const void *data;
1714c6926a2SDave Jiang int rc;
1724c6926a2SDave Jiang
1734c6926a2SDave Jiang /* The bus lock should be held at the top level of the call stack */
1744c6926a2SDave Jiang lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
1754c6926a2SDave Jiang
1764c6926a2SDave Jiang if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock
177d78c620aSDan Williams || !nvdimm->sec.flags)
1784c6926a2SDave Jiang return -EIO;
1794c6926a2SDave Jiang
18015a83487SDave Jiang /* cxl_test needs this to pre-populate the security state */
18115a83487SDave Jiang if (IS_ENABLED(CONFIG_NVDIMM_SECURITY_TEST))
18215a83487SDave Jiang nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
18315a83487SDave Jiang
184674f31a3SDave Jiang /* No need to go further if security is disabled */
185674f31a3SDave Jiang if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags))
186674f31a3SDave Jiang return 0;
187674f31a3SDave Jiang
1887d988097SDave Jiang if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
18937379cfcSDan Williams dev_dbg(dev, "Security operation in progress.\n");
1907d988097SDave Jiang return -EBUSY;
1917d988097SDave Jiang }
1927d988097SDave Jiang
1934c6926a2SDave Jiang /*
1944c6926a2SDave Jiang * If the pre-OS has unlocked the DIMM, attempt to send the key
1954c6926a2SDave Jiang * from request_key() to the hardware for verification. Failure
1964c6926a2SDave Jiang * to revalidate the key against the hardware results in a
1974c6926a2SDave Jiang * freeze of the security configuration. I.e. if the OS does not
1984c6926a2SDave Jiang * have the key, security is being managed pre-OS.
1994c6926a2SDave Jiang */
200d78c620aSDan Williams if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags)) {
2014c6926a2SDave Jiang if (!key_revalidate)
2024c6926a2SDave Jiang return 0;
2034c6926a2SDave Jiang
204d2e5b643SDave Jiang return nvdimm_key_revalidate(nvdimm);
2054c6926a2SDave Jiang } else
206d2e5b643SDave Jiang data = nvdimm_get_key_payload(nvdimm, &key);
2074c6926a2SDave Jiang
208d2e5b643SDave Jiang rc = nvdimm->sec.ops->unlock(nvdimm, data);
2094c6926a2SDave Jiang dev_dbg(dev, "key: %d unlock: %s\n", key_serial(key),
2104c6926a2SDave Jiang rc == 0 ? "success" : "fail");
211*dc370b28SDan Williams if (rc == 0)
212*dc370b28SDan Williams set_bit(NDD_INCOHERENT, &nvdimm->flags);
2134c6926a2SDave Jiang
2144c6926a2SDave Jiang nvdimm_put_key(key);
215d78c620aSDan Williams nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
2164c6926a2SDave Jiang return rc;
2174c6926a2SDave Jiang }
2184c6926a2SDave Jiang
nvdimm_security_unlock(struct device * dev)2194c6926a2SDave Jiang int nvdimm_security_unlock(struct device *dev)
2204c6926a2SDave Jiang {
2214c6926a2SDave Jiang struct nvdimm *nvdimm = to_nvdimm(dev);
2224c6926a2SDave Jiang int rc;
2234c6926a2SDave Jiang
2244c6926a2SDave Jiang nvdimm_bus_lock(dev);
2254c6926a2SDave Jiang rc = __nvdimm_security_unlock(nvdimm);
2264c6926a2SDave Jiang nvdimm_bus_unlock(dev);
2274c6926a2SDave Jiang return rc;
2284c6926a2SDave Jiang }
22903b65b22SDave Jiang
check_security_state(struct nvdimm * nvdimm)230d78c620aSDan Williams static int check_security_state(struct nvdimm *nvdimm)
231d78c620aSDan Williams {
232d78c620aSDan Williams struct device *dev = &nvdimm->dev;
233d78c620aSDan Williams
234d78c620aSDan Williams if (test_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags)) {
235d78c620aSDan Williams dev_dbg(dev, "Incorrect security state: %#lx\n",
236d78c620aSDan Williams nvdimm->sec.flags);
237d78c620aSDan Williams return -EIO;
238d78c620aSDan Williams }
239d78c620aSDan Williams
240d78c620aSDan Williams if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
241d78c620aSDan Williams dev_dbg(dev, "Security operation in progress.\n");
242d78c620aSDan Williams return -EBUSY;
243d78c620aSDan Williams }
244d78c620aSDan Williams
245d78c620aSDan Williams return 0;
246d78c620aSDan Williams }
247d78c620aSDan Williams
security_disable(struct nvdimm * nvdimm,unsigned int keyid,enum nvdimm_passphrase_type pass_type)248dcedadfaSDave Jiang static int security_disable(struct nvdimm *nvdimm, unsigned int keyid,
249dcedadfaSDave Jiang enum nvdimm_passphrase_type pass_type)
25003b65b22SDave Jiang {
25103b65b22SDave Jiang struct device *dev = &nvdimm->dev;
25203b65b22SDave Jiang struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
25303b65b22SDave Jiang struct key *key;
25403b65b22SDave Jiang int rc;
255d2e5b643SDave Jiang const void *data;
25603b65b22SDave Jiang
25703b65b22SDave Jiang /* The bus lock should be held at the top level of the call stack */
25803b65b22SDave Jiang lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
25903b65b22SDave Jiang
260dcedadfaSDave Jiang if (!nvdimm->sec.ops || !nvdimm->sec.flags)
261dcedadfaSDave Jiang return -EOPNOTSUPP;
262dcedadfaSDave Jiang
263dcedadfaSDave Jiang if (pass_type == NVDIMM_USER && !nvdimm->sec.ops->disable)
264dcedadfaSDave Jiang return -EOPNOTSUPP;
265dcedadfaSDave Jiang
266dcedadfaSDave Jiang if (pass_type == NVDIMM_MASTER && !nvdimm->sec.ops->disable_master)
26703b65b22SDave Jiang return -EOPNOTSUPP;
26803b65b22SDave Jiang
269d78c620aSDan Williams rc = check_security_state(nvdimm);
270d78c620aSDan Williams if (rc)
271d78c620aSDan Williams return rc;
2727d988097SDave Jiang
273d2e5b643SDave Jiang data = nvdimm_get_user_key_payload(nvdimm, keyid,
274d2e5b643SDave Jiang NVDIMM_BASE_KEY, &key);
275d2e5b643SDave Jiang if (!data)
27603b65b22SDave Jiang return -ENOKEY;
27703b65b22SDave Jiang
278dcedadfaSDave Jiang if (pass_type == NVDIMM_MASTER) {
279dcedadfaSDave Jiang rc = nvdimm->sec.ops->disable_master(nvdimm, data);
280dcedadfaSDave Jiang dev_dbg(dev, "key: %d disable_master: %s\n", key_serial(key),
281dcedadfaSDave Jiang rc == 0 ? "success" : "fail");
282dcedadfaSDave Jiang } else {
283d2e5b643SDave Jiang rc = nvdimm->sec.ops->disable(nvdimm, data);
28403b65b22SDave Jiang dev_dbg(dev, "key: %d disable: %s\n", key_serial(key),
28503b65b22SDave Jiang rc == 0 ? "success" : "fail");
286dcedadfaSDave Jiang }
28703b65b22SDave Jiang
28803b65b22SDave Jiang nvdimm_put_key(key);
289dcedadfaSDave Jiang if (pass_type == NVDIMM_MASTER)
290dcedadfaSDave Jiang nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
291dcedadfaSDave Jiang else
292d78c620aSDan Williams nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
29303b65b22SDave Jiang return rc;
29403b65b22SDave Jiang }
295d2a4ac73SDave Jiang
security_update(struct nvdimm * nvdimm,unsigned int keyid,unsigned int new_keyid,enum nvdimm_passphrase_type pass_type)2967b60422cSDan Williams static int security_update(struct nvdimm *nvdimm, unsigned int keyid,
29789fa9d8eSDave Jiang unsigned int new_keyid,
29889fa9d8eSDave Jiang enum nvdimm_passphrase_type pass_type)
299d2a4ac73SDave Jiang {
300d2a4ac73SDave Jiang struct device *dev = &nvdimm->dev;
301d2a4ac73SDave Jiang struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
302d2a4ac73SDave Jiang struct key *key, *newkey;
303d2a4ac73SDave Jiang int rc;
304d2e5b643SDave Jiang const void *data, *newdata;
305d2a4ac73SDave Jiang
306d2a4ac73SDave Jiang /* The bus lock should be held at the top level of the call stack */
307d2a4ac73SDave Jiang lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
308d2a4ac73SDave Jiang
309d2a4ac73SDave Jiang if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key
310d78c620aSDan Williams || !nvdimm->sec.flags)
311d2a4ac73SDave Jiang return -EOPNOTSUPP;
312d2a4ac73SDave Jiang
313d78c620aSDan Williams rc = check_security_state(nvdimm);
314d78c620aSDan Williams if (rc)
315d78c620aSDan Williams return rc;
316d2a4ac73SDave Jiang
317d2e5b643SDave Jiang data = nvdimm_get_user_key_payload(nvdimm, keyid,
318d2e5b643SDave Jiang NVDIMM_BASE_KEY, &key);
319d2e5b643SDave Jiang if (!data)
320d2a4ac73SDave Jiang return -ENOKEY;
321d2a4ac73SDave Jiang
322d2e5b643SDave Jiang newdata = nvdimm_get_user_key_payload(nvdimm, new_keyid,
323d2e5b643SDave Jiang NVDIMM_NEW_KEY, &newkey);
324d2e5b643SDave Jiang if (!newdata) {
325d2a4ac73SDave Jiang nvdimm_put_key(key);
326d2a4ac73SDave Jiang return -ENOKEY;
327d2a4ac73SDave Jiang }
328d2a4ac73SDave Jiang
329d2e5b643SDave Jiang rc = nvdimm->sec.ops->change_key(nvdimm, data, newdata, pass_type);
33089fa9d8eSDave Jiang dev_dbg(dev, "key: %d %d update%s: %s\n",
331d2a4ac73SDave Jiang key_serial(key), key_serial(newkey),
33289fa9d8eSDave Jiang pass_type == NVDIMM_MASTER ? "(master)" : "(user)",
333d2a4ac73SDave Jiang rc == 0 ? "success" : "fail");
334d2a4ac73SDave Jiang
335d2a4ac73SDave Jiang nvdimm_put_key(newkey);
336d2a4ac73SDave Jiang nvdimm_put_key(key);
33789fa9d8eSDave Jiang if (pass_type == NVDIMM_MASTER)
338d78c620aSDan Williams nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm,
33989fa9d8eSDave Jiang NVDIMM_MASTER);
34089fa9d8eSDave Jiang else
341d78c620aSDan Williams nvdimm->sec.flags = nvdimm_security_flags(nvdimm,
34289fa9d8eSDave Jiang NVDIMM_USER);
343d2a4ac73SDave Jiang return rc;
344d2a4ac73SDave Jiang }
34564e77c8cSDave Jiang
security_erase(struct nvdimm * nvdimm,unsigned int keyid,enum nvdimm_passphrase_type pass_type)3467b60422cSDan Williams static int security_erase(struct nvdimm *nvdimm, unsigned int keyid,
34789fa9d8eSDave Jiang enum nvdimm_passphrase_type pass_type)
34864e77c8cSDave Jiang {
34964e77c8cSDave Jiang struct device *dev = &nvdimm->dev;
35064e77c8cSDave Jiang struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
351037c8489SDave Jiang struct key *key = NULL;
35264e77c8cSDave Jiang int rc;
353037c8489SDave Jiang const void *data;
35464e77c8cSDave Jiang
35564e77c8cSDave Jiang /* The bus lock should be held at the top level of the call stack */
35664e77c8cSDave Jiang lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
35764e77c8cSDave Jiang
35864e77c8cSDave Jiang if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase
359d78c620aSDan Williams || !nvdimm->sec.flags)
36064e77c8cSDave Jiang return -EOPNOTSUPP;
36164e77c8cSDave Jiang
362d78c620aSDan Williams rc = check_security_state(nvdimm);
363d78c620aSDan Williams if (rc)
364d78c620aSDan Williams return rc;
36564e77c8cSDave Jiang
366d78c620aSDan Williams if (!test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.ext_flags)
36789fa9d8eSDave Jiang && pass_type == NVDIMM_MASTER) {
36837379cfcSDan Williams dev_dbg(dev,
36989fa9d8eSDave Jiang "Attempt to secure erase in wrong master state.\n");
37089fa9d8eSDave Jiang return -EOPNOTSUPP;
37189fa9d8eSDave Jiang }
37289fa9d8eSDave Jiang
373d2e5b643SDave Jiang data = nvdimm_get_user_key_payload(nvdimm, keyid,
374d2e5b643SDave Jiang NVDIMM_BASE_KEY, &key);
375d2e5b643SDave Jiang if (!data)
37664e77c8cSDave Jiang return -ENOKEY;
37764e77c8cSDave Jiang
378037c8489SDave Jiang rc = nvdimm->sec.ops->erase(nvdimm, data, pass_type);
379*dc370b28SDan Williams if (rc == 0)
380*dc370b28SDan Williams set_bit(NDD_INCOHERENT, &nvdimm->flags);
38189fa9d8eSDave Jiang dev_dbg(dev, "key: %d erase%s: %s\n", key_serial(key),
38289fa9d8eSDave Jiang pass_type == NVDIMM_MASTER ? "(master)" : "(user)",
38364e77c8cSDave Jiang rc == 0 ? "success" : "fail");
38464e77c8cSDave Jiang
38564e77c8cSDave Jiang nvdimm_put_key(key);
386d78c620aSDan Williams nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
38764e77c8cSDave Jiang return rc;
38864e77c8cSDave Jiang }
3897d988097SDave Jiang
security_overwrite(struct nvdimm * nvdimm,unsigned int keyid)3907b60422cSDan Williams static int security_overwrite(struct nvdimm *nvdimm, unsigned int keyid)
3917d988097SDave Jiang {
3927d988097SDave Jiang struct device *dev = &nvdimm->dev;
3937d988097SDave Jiang struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
394d2e5b643SDave Jiang struct key *key = NULL;
3957d988097SDave Jiang int rc;
396d2e5b643SDave Jiang const void *data;
3977d988097SDave Jiang
3987d988097SDave Jiang /* The bus lock should be held at the top level of the call stack */
3997d988097SDave Jiang lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
4007d988097SDave Jiang
4017d988097SDave Jiang if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite
402d78c620aSDan Williams || !nvdimm->sec.flags)
4037d988097SDave Jiang return -EOPNOTSUPP;
4047d988097SDave Jiang
405d78c620aSDan Williams rc = check_security_state(nvdimm);
406d78c620aSDan Williams if (rc)
407d78c620aSDan Williams return rc;
4087d988097SDave Jiang
409d2e5b643SDave Jiang data = nvdimm_get_user_key_payload(nvdimm, keyid,
410d2e5b643SDave Jiang NVDIMM_BASE_KEY, &key);
411d2e5b643SDave Jiang if (!data)
4127d988097SDave Jiang return -ENOKEY;
4137d988097SDave Jiang
414d2e5b643SDave Jiang rc = nvdimm->sec.ops->overwrite(nvdimm, data);
415*dc370b28SDan Williams if (rc == 0)
416*dc370b28SDan Williams set_bit(NDD_INCOHERENT, &nvdimm->flags);
4177d988097SDave Jiang dev_dbg(dev, "key: %d overwrite submission: %s\n", key_serial(key),
4187d988097SDave Jiang rc == 0 ? "success" : "fail");
4197d988097SDave Jiang
4207d988097SDave Jiang nvdimm_put_key(key);
4217d988097SDave Jiang if (rc == 0) {
4227d988097SDave Jiang set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
4237d988097SDave Jiang set_bit(NDD_WORK_PENDING, &nvdimm->flags);
424d78c620aSDan Williams set_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags);
4257d988097SDave Jiang /*
4267d988097SDave Jiang * Make sure we don't lose device while doing overwrite
4277d988097SDave Jiang * query.
4287d988097SDave Jiang */
4297d988097SDave Jiang get_device(dev);
4307d988097SDave Jiang queue_delayed_work(system_wq, &nvdimm->dwork, 0);
4317d988097SDave Jiang }
43289fa9d8eSDave Jiang
4337d988097SDave Jiang return rc;
4347d988097SDave Jiang }
4357d988097SDave Jiang
__nvdimm_security_overwrite_query(struct nvdimm * nvdimm)4367912d30fSJiapeng Chong static void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm)
4377d988097SDave Jiang {
4387d988097SDave Jiang struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev);
4397d988097SDave Jiang int rc;
4407d988097SDave Jiang unsigned int tmo;
4417d988097SDave Jiang
4427d988097SDave Jiang /* The bus lock should be held at the top level of the call stack */
4437d988097SDave Jiang lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
4447d988097SDave Jiang
4457d988097SDave Jiang /*
4467d988097SDave Jiang * Abort and release device if we no longer have the overwrite
4477d988097SDave Jiang * flag set. It means the work has been canceled.
4487d988097SDave Jiang */
4497d988097SDave Jiang if (!test_bit(NDD_WORK_PENDING, &nvdimm->flags))
4507d988097SDave Jiang return;
4517d988097SDave Jiang
4527d988097SDave Jiang tmo = nvdimm->sec.overwrite_tmo;
4537d988097SDave Jiang
4547d988097SDave Jiang if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite
455d78c620aSDan Williams || !nvdimm->sec.flags)
4567d988097SDave Jiang return;
4577d988097SDave Jiang
4587d988097SDave Jiang rc = nvdimm->sec.ops->query_overwrite(nvdimm);
4597d988097SDave Jiang if (rc == -EBUSY) {
4607d988097SDave Jiang
4617d988097SDave Jiang /* setup delayed work again */
4627d988097SDave Jiang tmo += 10;
4637d988097SDave Jiang queue_delayed_work(system_wq, &nvdimm->dwork, tmo * HZ);
4647d988097SDave Jiang nvdimm->sec.overwrite_tmo = min(15U * 60U, tmo);
4657d988097SDave Jiang return;
4667d988097SDave Jiang }
4677d988097SDave Jiang
4687d988097SDave Jiang if (rc < 0)
46937379cfcSDan Williams dev_dbg(&nvdimm->dev, "overwrite failed\n");
4707d988097SDave Jiang else
4717d988097SDave Jiang dev_dbg(&nvdimm->dev, "overwrite completed\n");
4727d988097SDave Jiang
4737f674025SJane Chu /*
4747f674025SJane Chu * Mark the overwrite work done and update dimm security flags,
4757f674025SJane Chu * then send a sysfs event notification to wake up userspace
4767f674025SJane Chu * poll threads to picked up the changed state.
4777f674025SJane Chu */
4787d988097SDave Jiang nvdimm->sec.overwrite_tmo = 0;
4797d988097SDave Jiang clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
4807d988097SDave Jiang clear_bit(NDD_WORK_PENDING, &nvdimm->flags);
481d78c620aSDan Williams nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
482dad42d17SJane Chu nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
4837f674025SJane Chu if (nvdimm->sec.overwrite_state)
4847f674025SJane Chu sysfs_notify_dirent(nvdimm->sec.overwrite_state);
4857f674025SJane Chu put_device(&nvdimm->dev);
4867d988097SDave Jiang }
4877d988097SDave Jiang
nvdimm_security_overwrite_query(struct work_struct * work)4887d988097SDave Jiang void nvdimm_security_overwrite_query(struct work_struct *work)
4897d988097SDave Jiang {
4907d988097SDave Jiang struct nvdimm *nvdimm =
4917d988097SDave Jiang container_of(work, typeof(*nvdimm), dwork.work);
4927d988097SDave Jiang
4937d988097SDave Jiang nvdimm_bus_lock(&nvdimm->dev);
4947d988097SDave Jiang __nvdimm_security_overwrite_query(nvdimm);
4957d988097SDave Jiang nvdimm_bus_unlock(&nvdimm->dev);
4967d988097SDave Jiang }
4977b60422cSDan Williams
4987b60422cSDan Williams #define OPS \
4997b60422cSDan Williams C( OP_FREEZE, "freeze", 1), \
5007b60422cSDan Williams C( OP_DISABLE, "disable", 2), \
501dcedadfaSDave Jiang C( OP_DISABLE_MASTER, "disable_master", 2), \
5027b60422cSDan Williams C( OP_UPDATE, "update", 3), \
5037b60422cSDan Williams C( OP_ERASE, "erase", 2), \
5047b60422cSDan Williams C( OP_OVERWRITE, "overwrite", 2), \
5057b60422cSDan Williams C( OP_MASTER_UPDATE, "master_update", 3), \
5067b60422cSDan Williams C( OP_MASTER_ERASE, "master_erase", 2)
5077b60422cSDan Williams #undef C
5087b60422cSDan Williams #define C(a, b, c) a
5097b60422cSDan Williams enum nvdimmsec_op_ids { OPS };
5107b60422cSDan Williams #undef C
5117b60422cSDan Williams #define C(a, b, c) { b, c }
5127b60422cSDan Williams static struct {
5137b60422cSDan Williams const char *name;
5147b60422cSDan Williams int args;
5157b60422cSDan Williams } ops[] = { OPS };
5167b60422cSDan Williams #undef C
5177b60422cSDan Williams
5187b60422cSDan Williams #define SEC_CMD_SIZE 32
5197b60422cSDan Williams #define KEY_ID_SIZE 10
5207b60422cSDan Williams
nvdimm_security_store(struct device * dev,const char * buf,size_t len)5217b60422cSDan Williams ssize_t nvdimm_security_store(struct device *dev, const char *buf, size_t len)
5227b60422cSDan Williams {
5237b60422cSDan Williams struct nvdimm *nvdimm = to_nvdimm(dev);
5247b60422cSDan Williams ssize_t rc;
5257b60422cSDan Williams char cmd[SEC_CMD_SIZE+1], keystr[KEY_ID_SIZE+1],
5267b60422cSDan Williams nkeystr[KEY_ID_SIZE+1];
5277b60422cSDan Williams unsigned int key, newkey;
5287b60422cSDan Williams int i;
5297b60422cSDan Williams
5307b60422cSDan Williams rc = sscanf(buf, "%"__stringify(SEC_CMD_SIZE)"s"
5317b60422cSDan Williams " %"__stringify(KEY_ID_SIZE)"s"
5327b60422cSDan Williams " %"__stringify(KEY_ID_SIZE)"s",
5337b60422cSDan Williams cmd, keystr, nkeystr);
5347b60422cSDan Williams if (rc < 1)
5357b60422cSDan Williams return -EINVAL;
5367b60422cSDan Williams for (i = 0; i < ARRAY_SIZE(ops); i++)
5377b60422cSDan Williams if (sysfs_streq(cmd, ops[i].name))
5387b60422cSDan Williams break;
5397b60422cSDan Williams if (i >= ARRAY_SIZE(ops))
5407b60422cSDan Williams return -EINVAL;
5417b60422cSDan Williams if (ops[i].args > 1)
5427b60422cSDan Williams rc = kstrtouint(keystr, 0, &key);
5437b60422cSDan Williams if (rc >= 0 && ops[i].args > 2)
5447b60422cSDan Williams rc = kstrtouint(nkeystr, 0, &newkey);
5457b60422cSDan Williams if (rc < 0)
5467b60422cSDan Williams return rc;
5477b60422cSDan Williams
5487b60422cSDan Williams if (i == OP_FREEZE) {
5497b60422cSDan Williams dev_dbg(dev, "freeze\n");
5507b60422cSDan Williams rc = nvdimm_security_freeze(nvdimm);
5517b60422cSDan Williams } else if (i == OP_DISABLE) {
5527b60422cSDan Williams dev_dbg(dev, "disable %u\n", key);
553dcedadfaSDave Jiang rc = security_disable(nvdimm, key, NVDIMM_USER);
554dcedadfaSDave Jiang } else if (i == OP_DISABLE_MASTER) {
555dcedadfaSDave Jiang dev_dbg(dev, "disable_master %u\n", key);
556dcedadfaSDave Jiang rc = security_disable(nvdimm, key, NVDIMM_MASTER);
5577b60422cSDan Williams } else if (i == OP_UPDATE || i == OP_MASTER_UPDATE) {
5587b60422cSDan Williams dev_dbg(dev, "%s %u %u\n", ops[i].name, key, newkey);
5597b60422cSDan Williams rc = security_update(nvdimm, key, newkey, i == OP_UPDATE
5607b60422cSDan Williams ? NVDIMM_USER : NVDIMM_MASTER);
5617b60422cSDan Williams } else if (i == OP_ERASE || i == OP_MASTER_ERASE) {
5627b60422cSDan Williams dev_dbg(dev, "%s %u\n", ops[i].name, key);
5637b60422cSDan Williams if (atomic_read(&nvdimm->busy)) {
5647b60422cSDan Williams dev_dbg(dev, "Unable to secure erase while DIMM active.\n");
5657b60422cSDan Williams return -EBUSY;
5667b60422cSDan Williams }
5677b60422cSDan Williams rc = security_erase(nvdimm, key, i == OP_ERASE
5687b60422cSDan Williams ? NVDIMM_USER : NVDIMM_MASTER);
5697b60422cSDan Williams } else if (i == OP_OVERWRITE) {
5707b60422cSDan Williams dev_dbg(dev, "overwrite %u\n", key);
5717b60422cSDan Williams if (atomic_read(&nvdimm->busy)) {
5727b60422cSDan Williams dev_dbg(dev, "Unable to overwrite while DIMM active.\n");
5737b60422cSDan Williams return -EBUSY;
5747b60422cSDan Williams }
5757b60422cSDan Williams rc = security_overwrite(nvdimm, key);
5767b60422cSDan Williams } else
5777b60422cSDan Williams return -EINVAL;
5787b60422cSDan Williams
5797b60422cSDan Williams if (rc == 0)
5807b60422cSDan Williams rc = len;
5817b60422cSDan Williams return rc;
5827b60422cSDan Williams }
583