xref: /openbmc/linux/drivers/nvdimm/security.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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