All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dave Jiang <dave.jiang@intel.com>
To: Mimi Zohar <zohar@linux.ibm.com>,
	dan.j.williams@intel.com, zohar@linux.vnet.ibm.com
Cc: linux-nvdimm@lists.01.org
Subject: Re: [PATCH 02/11] libnvdimm/security: change clear text nvdimm keys to encrypted keys
Date: Mon, 12 Nov 2018 08:45:03 -0700	[thread overview]
Message-ID: <1cc6edd6-8926-1be1-04f3-85ce59bfdfb4@intel.com> (raw)
In-Reply-To: <1541957268.3734.53.camel@linux.ibm.com>


On 11/11/2018 10:27 AM, Mimi Zohar wrote:
> On Fri, 2018-11-09 at 15:13 -0700, Dave Jiang wrote:
>> In order to make nvdimm more secure, encrypted keys will be used instead of
>> clear text keys. A master key will be created to seal encrypted nvdimm
>> keys. The master key can be a trusted key generated from TPM 2.0 or a less
>> secure user key.
> Trusted keys also work for TPM 1.2.  Are you intentionally limiting
> the master key to TPM 2.0?
>
> Traditionally there is a single master key for the system, which would
> be sealed to a set of boot time PCR values.  After decrypting all of
> the encrypted keys, the master key would be removed from the keyring
> and a PCR extended.  Extending a PCR would prevent the master key from
> being unsealed again and used to decrypt encrypted keys, without
> rebooting the system.  Normally this would be done before pivoting
> root.
>
> If you're not referring to the system master key and are intentionally
> limiting usage to TPM 2.0, more details on the master key security
> requirements should be included.
>
> Using trusted keys that are encrypted/decrypted using a user key
> should really be limited to testing environments.

Do you have any recommendation for systems that do not support TPM?



>
>> In the process of this conversion, the kernel cached key will be removed
>> in order to simplify the verification process. The hardware will be used to
>> verify the decrypted user payload directly.
> Making this sort of change implies there is no concern in breaking
> existing userspace.  Either the code hasn't yet been upstreamed or
> there are not any users. If the code hasn't been upstreamed, it would
> make more sense to squash the git history:
>
> - making code review easier
> - making the git history bisect safe
>
> Mimi
>
>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>> ---
>>   Documentation/nvdimm/security.txt |   29 ++-
>>   drivers/nvdimm/dimm.c             |    3
>>   drivers/nvdimm/dimm_devs.c        |    2
>>   drivers/nvdimm/nd-core.h          |    3
>>   drivers/nvdimm/nd.h               |    5 -
>>   drivers/nvdimm/security.c         |  316 ++++++++++---------------------------
>>   6 files changed, 108 insertions(+), 250 deletions(-)
>>
>> diff --git a/Documentation/nvdimm/security.txt b/Documentation/nvdimm/security.txt
>> index 50cbb6cb96a1..11240ce48755 100644
>> --- a/Documentation/nvdimm/security.txt
>> +++ b/Documentation/nvdimm/security.txt
>> @@ -39,34 +39,39 @@ The DIMM id would be provided along with the key payload (passphrase) to
>>   the kernel.
>>
>>   The security keys are managed on the basis of a single key per DIMM. The
>> -key "passphrase" is expected to be 32bytes long or padded to 32bytes. This is
>> +key "passphrase" is expected to be 32bytes long. This is
>>   similar to the ATA security specification [2]. A key is initially acquired
>>   via the request_key() kernel API call and retrieved from userspace. It is up to
>>   the user to provide an upcall application to retrieve the key in whatever
>>   fashion meets their security requirements.
>>
>> -A nvdimm user logon key has the description format of:
>> +A nvdimm encrypted key has the description format of:
>>   nvdimm:<bus-provider-specific-unique-id>
>>
>> +See Documentation/security/keys/trusted-encrypted.rst for details on encrypted
>> +keys. The encrypted key for the DIMM is generated from a master key that is
>> +either a trusted key created via TPM2 or a less secure user key. The payload
>> +for the nvdimm encrypted key is randomly generated by the kernel and is not
>> +visible to the user. The user is responsible for retaining the encrypted key
>> +blob generated from the encrypted key to be loaded at the next boot session.
>> +
>>   4. Unlocking
>>   ------------
>>   When the DIMMs are being enumerated by the kernel, the kernel will attempt to
>> -retrieve the key from its keyring. If that fails, it will attempt to
>>   acquire the key from the userspace upcall function. This is the only time
>>   a locked DIMM can be unlocked. Once unlocked, the DIMM will remain unlocked
>>   until reboot.
>>
>>   5. Update
>>   ---------
>> -When doing an update, it is expected that the new key with the 64bit payload of
>> -format described above is added via the keyutils API or utility. The update
>> -command written to the sysfs attribute will be with the format:
>> +When doing an update, it is expected that the new key is added via the
>> +keyutils API or utility. The update command written to the sysfs attribute
>> +will be with the format:
>>   update <old keyid> <new keyid>
>>
>> -It is expected that a user logon key has been injected via keyutils to provide
>> -the payload for the update operation. The kernel will take the new user key,
>> -attempt the update operation with the nvdimm, and replace the existing key's
>> -payload with the new passphrase.
>> +It is expected that a encrypted key has been injected via keyutils to provide
>> +the payload for the update operation. The kernel will take the new user key
>> +and the old user key to attempt the update operation.
>>
>>   If there is no old key id due to a security enabling, then a 0 should be
>>   passed in.  If a nvdimm has an existing passphrase, then an "old" key should
>> @@ -80,7 +85,7 @@ frozen by a user with root privelege.
>>   7. Disable
>>   ----------
>>   The security disable command format is:
>> -disable <old keyid>
>> +disable <current keyid>
>>
>>   An "old" key with the passphrase payload that is tied to the nvdimm should be
>>   injected with a key description that does not have the "nvdimm:" prefix and
>> @@ -89,7 +94,7 @@ its keyid should be passed in via sysfs.
>>   8. Secure Erase
>>   ---------------
>>   The command format for doing a secure erase is:
>> -erase <old keyid>
>> +erase <current keyid>
>>
>>   An "old" key with the passphrase payload that is tied to the nvdimm should be
>>   injected with a key description that does not have the "nvdimm:" prefix and
>> diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
>> index 225a8474c44a..c3886a22b5e4 100644
>> --- a/drivers/nvdimm/dimm.c
>> +++ b/drivers/nvdimm/dimm.c
>> @@ -112,9 +112,6 @@ static int nvdimm_probe(struct device *dev)
>>   static int nvdimm_remove(struct device *dev)
>>   {
>>   	struct nvdimm_drvdata *ndd = dev_get_drvdata(dev);
>> -	struct nvdimm *nvdimm = to_nvdimm(dev);
>> -
>> -	nvdimm_security_release(nvdimm);
>>
>>   	if (!ndd)
>>   		return 0;
>> diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
>> index 5d34251c4f3b..269f401a5e68 100644
>> --- a/drivers/nvdimm/dimm_devs.c
>> +++ b/drivers/nvdimm/dimm_devs.c
>> @@ -485,7 +485,7 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_dat
>>   	nvdimm->num_flush = num_flush;
>>   	nvdimm->flush_wpq = flush_wpq;
>>   	atomic_set(&nvdimm->busy, 0);
>> -	mutex_init(&nvdimm->key_mutex);
>> +	mutex_init(&nvdimm->sec_mutex);
>>   	dev = &nvdimm->dev;
>>   	dev_set_name(dev, "nmem%d", nvdimm->id);
>>   	dev->parent = &nvdimm_bus->dev;
>> diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
>> index 6e2877996a9b..cfb87f71db8d 100644
>> --- a/drivers/nvdimm/nd-core.h
>> +++ b/drivers/nvdimm/nd-core.h
>> @@ -45,8 +45,7 @@ struct nvdimm {
>>   	const char *dimm_id;
>>   	const struct nvdimm_security_ops *security_ops;
>>   	enum nvdimm_security_state state;
>> -	struct key *key;
>> -	struct mutex key_mutex;
>> +	struct mutex sec_mutex;
>>   };
>>
>>   /**
>> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
>> index 892f127bfd38..f8d8f0a2a40d 100644
>> --- a/drivers/nvdimm/nd.h
>> +++ b/drivers/nvdimm/nd.h
>> @@ -428,7 +428,6 @@ bool pmem_should_map_pages(struct device *dev);
>>
>>   #ifdef CONFIG_NVDIMM_SECURITY
>>   int nvdimm_security_unlock_dimm(struct nvdimm *nvdimm);
>> -void nvdimm_security_release(struct nvdimm *nvdimm);
>>   int nvdimm_security_get_state(struct nvdimm *nvdimm);
>>   int nvdimm_security_change_key(struct nvdimm *nvdimm, unsigned int old_keyid,
>>   		unsigned int new_keyid);
>> @@ -441,10 +440,6 @@ static inline int nvdimm_security_unlock_dimm(struct nvdimm *nvdimm)
>>   	return 0;
>>   }
>>
>> -static inline void nvdimm_security_release(struct nvdimm *nvdimm)
>> -{
>> -}
>> -
>>   static inline int nvdimm_security_get_state(struct nvdimm *nvdimm)
>>   {
>>   	return -EOPNOTSUPP;
>> diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c
>> index 5aacc590b4c0..ee741199d623 100644
>> --- a/drivers/nvdimm/security.c
>> +++ b/drivers/nvdimm/security.c
>> @@ -10,43 +10,10 @@
>>   #include <linux/key.h>
>>   #include <linux/key-type.h>
>>   #include <keys/user-type.h>
>> +#include <keys/encrypted-type.h>
>>   #include "nd-core.h"
>>   #include "nd.h"
>>
>> -/*
>> - * Replacing the user key with a kernel key. The function expects that
>> - * we hold the sem for the key passed in. The function will release that
>> - * sem when done process. We will also hold the sem for the valid new key
>> - * returned.
>> - */
>> -static struct key *make_kernel_key(struct key *key)
>> -{
>> -	struct key *new_key;
>> -	struct user_key_payload *payload;
>> -	int rc;
>> -
>> -	new_key = key_alloc(&key_type_logon, key->description,
>> -			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
>> -			KEY_POS_ALL & ~KEY_POS_SETATTR,
>> -			KEY_ALLOC_NOT_IN_QUOTA, NULL);
>> -	if (IS_ERR(new_key))
>> -		return NULL;
>> -
>> -	payload = key->payload.data[0];
>> -	rc = key_instantiate_and_link(new_key, payload->data,
>> -			payload->datalen, NULL, NULL);
>> -	up_read(&key->sem);
>> -	if (rc < 0) {
>> -		key_put(new_key);
>> -		return NULL;
>> -	}
>> -
>> -	key_put(key);
>> -
>> -	down_read(&new_key->sem);
>> -	return new_key;
>> -}
>> -
>>   /*
>>    * Retrieve user injected key
>>    */
>> @@ -61,6 +28,10 @@ static struct key *nvdimm_lookup_user_key(struct device *dev,
>>   		return NULL;
>>
>>   	key = key_ref_to_ptr(keyref);
>> +	if (key->type != &key_type_encrypted) {
>> +		key_put(key);
>> +		return NULL;
>> +	}
>>   	dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key));
>>
>>   	return key;
>> @@ -76,7 +47,7 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm)
>>   	struct device *dev = &nvdimm->dev;
>>
>>   	sprintf(desc, "%s%s", NVDIMM_PREFIX, nvdimm->dimm_id);
>> -	key = request_key(&key_type_logon, desc, "");
>> +	key = request_key(&key_type_encrypted, desc, "");
>>   	if (IS_ERR(key)) {
>>   		if (PTR_ERR(key) == -ENOKEY)
>>   			dev_warn(dev, "request_key() found no key\n");
>> @@ -88,52 +59,6 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm)
>>   	return key;
>>   }
>>
>> -struct key *nvdimm_get_and_verify_key(struct nvdimm *nvdimm,
>> -		unsigned int user_key_id)
>> -{
>> -	int rc;
>> -	struct key *user_key, *key;
>> -	struct device *dev = &nvdimm->dev;
>> -	struct user_key_payload *upayload, *payload;
>> -
>> -	lockdep_assert_held(&nvdimm->key_mutex);
>> -	key = nvdimm->key;
>> -	if (!key) {
>> -		dev_dbg(dev, "No cached kernel key\n");
>> -		return ERR_PTR(-EAGAIN);;
>> -	}
>> -	dev_dbg(dev, "cached_key: %#x\n", key_serial(key));
>> -
>> -	user_key = nvdimm_lookup_user_key(dev, user_key_id);
>> -	if (!user_key) {
>> -		dev_dbg(dev, "Old user key lookup failed\n");
>> -		return ERR_PTR(-EINVAL);
>> -	}
>> -	dev_dbg(dev, "user_key: %#x\n", key_serial(user_key));
>> -
>> -	down_read(&key->sem);
>> -	down_read(&user_key->sem);
>> -	payload = key->payload.data[0];
>> -	upayload = user_key->payload.data[0];
>> -
>> -	rc = memcmp(payload->data, upayload->data, NVDIMM_PASSPHRASE_LEN);
>> -	up_read(&user_key->sem);
>> -	key_put(user_key);
>> -	up_read(&key->sem);
>> -
>> -	if (rc != 0) {
>> -		dev_warn(dev, "Supplied old user key fails check.\n");
>> -		return ERR_PTR(-EINVAL);
>> -	}
>> -	return key;
>> -}
>> -
>> -static void key_destroy(struct key *key)
>> -{
>> -	key_invalidate(key);
>> -	key_put(key);
>> -}
>> -
>>   int nvdimm_security_get_state(struct nvdimm *nvdimm)
>>   {
>>   	if (!nvdimm->security_ops)
>> @@ -146,14 +71,15 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid)
>>   {
>>   	int rc = 0;
>>   	struct key *key;
>> -	struct user_key_payload *payload;
>> +	struct encrypted_key_payload *epayload;
>>   	struct device *dev = &nvdimm->dev;
>> +	void *data;
>>
>>   	if (!nvdimm->security_ops)
>>   		return -EOPNOTSUPP;
>>
>>   	nvdimm_bus_lock(dev);
>> -	mutex_lock(&nvdimm->key_mutex);
>> +	mutex_lock(&nvdimm->sec_mutex);
>>   	if (atomic_read(&nvdimm->busy)) {
>>   		dev_warn(dev, "Unable to secure erase while DIMM active.\n");
>>   		rc = -EBUSY;
>> @@ -166,26 +92,23 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid)
>>   		goto out;
>>   	}
>>
>> -	/* look for a key from cached key if exists */
>> -	key = nvdimm_get_and_verify_key(nvdimm, keyid);
>> -	if (IS_ERR(key)) {
>> +	key = nvdimm_lookup_user_key(dev, keyid);
>> +	if (!key) {
>>   		dev_dbg(dev, "Unable to get and verify key\n");
>> -		rc = PTR_ERR(key);
>> +		rc = -ENOKEY;
>>   		goto out;
>>   	}
>>
>>   	down_read(&key->sem);
>> -	payload = key->payload.data[0];
>> +	epayload = dereference_key_locked(key);
>> +	data = epayload->decrypted_data;
>>   	rc = nvdimm->security_ops->erase(nvdimm,
>> -			(const struct nvdimm_key_data *)payload->data);
>> +			(const struct nvdimm_key_data *)data);
>>   	up_read(&key->sem);
>> -
>> -	/* remove key since secure erase kills the passphrase */
>> -	key_destroy(key);
>> -	nvdimm->key = NULL;
>> +	key_put(key);
>>
>>    out:
>> -	mutex_unlock(&nvdimm->key_mutex);
>> +	mutex_unlock(&nvdimm->sec_mutex);
>>   	nvdimm_bus_unlock(dev);
>>   	nvdimm_security_get_state(nvdimm);
>>   	return rc;
>> @@ -201,11 +124,15 @@ int nvdimm_security_freeze_lock(struct nvdimm *nvdimm)
>>   	if (nvdimm->state == NVDIMM_SECURITY_UNSUPPORTED)
>>   		return -EOPNOTSUPP;
>>
>> +	mutex_lock(&nvdimm->sec_mutex);
>>   	rc = nvdimm->security_ops->freeze_lock(nvdimm);
>> -	if (rc < 0)
>> +	if (rc < 0) {
>> +		mutex_unlock(&nvdimm->sec_mutex);
>>   		return rc;
>> +	}
>>
>>   	nvdimm_security_get_state(nvdimm);
>> +	mutex_unlock(&nvdimm->sec_mutex);
>>   	return 0;
>>   }
>>
>> @@ -213,8 +140,9 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
>>   {
>>   	int rc;
>>   	struct key *key;
>> -	struct user_key_payload *payload;
>> +	struct encrypted_key_payload *epayload;
>>   	struct device *dev = &nvdimm->dev;
>> +	void *data;
>>
>>   	if (!nvdimm->security_ops)
>>   		return -EOPNOTSUPP;
>> @@ -222,57 +150,52 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid)
>>   	if (nvdimm->state == NVDIMM_SECURITY_UNSUPPORTED)
>>   		return -EOPNOTSUPP;
>>
>> -	mutex_lock(&nvdimm->key_mutex);
>> +	mutex_lock(&nvdimm->sec_mutex);
>>   	/* look for a key from cached key */
>> -	key = nvdimm_get_and_verify_key(nvdimm, keyid);
>> -	if (IS_ERR(key)) {
>> -		mutex_unlock(&nvdimm->key_mutex);
>> -		return PTR_ERR(key);
>> +	key = nvdimm_lookup_user_key(dev, keyid);
>> +	if (!key) {
>> +		mutex_unlock(&nvdimm->sec_mutex);
>> +		return -ENOKEY;
>>   	}
>>
>>   	down_read(&key->sem);
>> -	payload = key->payload.data[0];
>> +	epayload = dereference_key_locked(key);
>> +	data = epayload->decrypted_data;
>>
>>   	rc = nvdimm->security_ops->disable(nvdimm,
>> -			(const struct nvdimm_key_data *)payload->data);
>> +			(const struct nvdimm_key_data *)data);
>>   	up_read(&key->sem);
>> -	if (rc < 0) {
>> +	if (rc < 0)
>>   		dev_warn(dev, "security disable failed\n");
>> -		goto out;
>> -	}
>>
>> -	/* If we succeed then remove the key */
>> -	key_destroy(key);
>> -	nvdimm->key = NULL;
>> -
>> - out:
>> -	mutex_unlock(&nvdimm->key_mutex);
>> +	key_put(key);
>>   	nvdimm_security_get_state(nvdimm);
>> +	mutex_unlock(&nvdimm->sec_mutex);
>>   	return rc;
>>   }
>>
>> -static int nvdimm_self_verify_key(struct nvdimm *nvdimm)
>> +static struct key *nvdimm_self_verify_key(struct nvdimm *nvdimm)
>>   {
>>   	struct key *key;
>> -	struct user_key_payload *payload;
>> +	struct encrypted_key_payload *epayload;
>>   	void *data;
>>   	int rc;
>>
>> -	lockdep_assert_held(&nvdimm->key_mutex);
>> -
>> +	lockdep_assert_held(&nvdimm->sec_mutex);
>>   	key = nvdimm_request_key(nvdimm);
>>   	if (!key)
>> -		return -ENOKEY;
>> +		return NULL;
>> +
>> +	down_read(&key->sem);
>> +	epayload = dereference_key_locked(key);
>> +	data = epayload->decrypted_data;
>>
>> -	if (key->datalen != NVDIMM_PASSPHRASE_LEN) {
>> +	if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) {
>>   		key_put(key);
>> -		return -EINVAL;
>> +		key = NULL;
>> +		goto out;
>>   	}
>>
>> -	down_read(&key->sem);
>> -	payload = key->payload.data[0];
>> -	data = payload->data;
>> -
>>   	/*
>>   	 * We send the same key to the hardware as new and old key to
>>   	 * verify that the key is good.
>> @@ -280,19 +203,21 @@ static int nvdimm_self_verify_key(struct nvdimm *nvdimm)
>>   	rc = nvdimm->security_ops->change_key(nvdimm, data, data);
>>   	if (rc < 0) {
>>   		key_put(key);
>> -		return rc;
>> +		key = NULL;
>>   	}
>> +
>> +out:
>>   	up_read(&key->sem);
>> -	nvdimm->key = key;
>> -	return 0;
>> +	return key;
>>   }
>>
>>   int nvdimm_security_unlock_dimm(struct nvdimm *nvdimm)
>>   {
>> -	struct key *key;
>> -	int rc = -ENXIO;
>> -	struct user_key_payload *payload;
>> +	struct key *key = NULL;
>> +	int rc;
>> +	struct encrypted_key_payload *epayload;
>>   	struct device *dev = &nvdimm->dev;
>> +	void *data;
>>
>>   	if (!nvdimm->security_ops)
>>   		return 0;
>> @@ -301,7 +226,7 @@ int nvdimm_security_unlock_dimm(struct nvdimm *nvdimm)
>>   			nvdimm->state == NVDIMM_SECURITY_DISABLED)
>>   		return 0;
>>
>> -	mutex_lock(&nvdimm->key_mutex);
>> +	mutex_lock(&nvdimm->sec_mutex);
>>   	/*
>>   	 * If the pre-OS has unlocked the DIMM, we will attempt to send
>>   	 * the key from request_key() to the hardware for verification.
>> @@ -310,60 +235,50 @@ int nvdimm_security_unlock_dimm(struct nvdimm *nvdimm)
>>   	 * other security operations.
>>   	 */
>>   	if (nvdimm->state == NVDIMM_SECURITY_UNLOCKED) {
>> -		rc = nvdimm_self_verify_key(nvdimm);
>> -		if (rc < 0) {
>> +		key = nvdimm_self_verify_key(nvdimm);
>> +		if (!key) {
>>   			rc = nvdimm_security_freeze_lock(nvdimm);
>> -			mutex_unlock(&nvdimm->key_mutex);
>> -			return rc;
>> +			mutex_unlock(&nvdimm->sec_mutex);
>> +			return -ENOKEY;
>>   		}
>>   	}
>>
>> -	key = nvdimm->key;
>> -	if (!key) {
>> +	if (!key)
>>   		key = nvdimm_request_key(nvdimm);
>> -		if (key && key->datalen != NVDIMM_PASSPHRASE_LEN) {
>> -			key_put(key);
>> -			key = NULL;
>> -			rc = -EINVAL;
>> -		}
>> -	}
>> +
>>   	if (!key) {
>> -		mutex_unlock(&nvdimm->key_mutex);
>> -		return rc;
>> +		mutex_unlock(&nvdimm->sec_mutex);
>> +		return -ENOKEY;
>>   	}
>>
>>   	dev_dbg(dev, "%s: key: %#x\n", __func__, key_serial(key));
>>   	down_read(&key->sem);
>> -	payload = key->payload.data[0];
>> +	epayload = dereference_key_locked(key);
>> +	data = epayload->decrypted_data;
>> +
>> +	if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) {
>> +		up_read(&key->sem);
>> +		key_put(key);
>> +		mutex_unlock(&nvdimm->sec_mutex);
>> +		return -EINVAL;
>> +	}
>> +
>>   	rc = nvdimm->security_ops->unlock(nvdimm,
>> -			(const struct nvdimm_key_data *)payload->data);
>> +			(const struct nvdimm_key_data *)data);
>>   	up_read(&key->sem);
>>
>>   	if (rc == 0) {
>> -		if (!nvdimm->key)
>> -			nvdimm->key = key;
>>   		nvdimm->state = NVDIMM_SECURITY_UNLOCKED;
>>   		dev_dbg(dev, "DIMM %s unlocked\n", dev_name(dev));
>> -	} else {
>> -		key_invalidate(key);
>> -		key_put(key);
>> -		nvdimm->key = NULL;
>> +	} else
>>   		dev_warn(dev, "Failed to unlock dimm: %s\n", dev_name(dev));
>> -	}
>>
>> -	mutex_unlock(&nvdimm->key_mutex);
>> +	key_put(key);
>>   	nvdimm_security_get_state(nvdimm);
>> +	mutex_unlock(&nvdimm->sec_mutex);
>>   	return rc;
>>   }
>>
>> -void nvdimm_security_release(struct nvdimm *nvdimm)
>> -{
>> -	mutex_lock(&nvdimm->key_mutex);
>> -	key_put(nvdimm->key);
>> -	nvdimm->key = NULL;
>> -	mutex_unlock(&nvdimm->key_mutex);
>> -}
>> -
>>   int nvdimm_security_change_key(struct nvdimm *nvdimm,
>>   		unsigned int old_keyid, unsigned int new_keyid)
>>   {
>> @@ -371,7 +286,7 @@ int nvdimm_security_change_key(struct nvdimm *nvdimm,
>>   	struct key *key, *old_key;
>>   	void *old_data = NULL, *new_data;
>>   	struct device *dev = &nvdimm->dev;
>> -	struct user_key_payload *payload, *old_payload;
>> +	struct encrypted_key_payload *epayload, *old_epayload;
>>
>>   	if (!nvdimm->security_ops)
>>   		return -EOPNOTSUPP;
>> @@ -379,15 +294,10 @@ int nvdimm_security_change_key(struct nvdimm *nvdimm,
>>   	if (nvdimm->state == NVDIMM_SECURITY_FROZEN)
>>   		return -EBUSY;
>>
>> -	mutex_lock(&nvdimm->key_mutex);
>> +	mutex_lock(&nvdimm->sec_mutex);
>>   	/* look for a key from cached key if exists */
>> -	old_key = nvdimm_get_and_verify_key(nvdimm, old_keyid);
>> -	if (IS_ERR(old_key) && PTR_ERR(old_key) == -EAGAIN)
>> -		old_key = NULL;
>> -	else if (IS_ERR(old_key)) {
>> -		mutex_unlock(&nvdimm->key_mutex);
>> -		return PTR_ERR(old_key);
>> -	} else
>> +	old_key = nvdimm_lookup_user_key(dev, old_keyid);
>> +	if (old_key)
>>   		dev_dbg(dev, "%s: old key: %#x\n", __func__,
>>   				key_serial(old_key));
>>
>> @@ -402,76 +312,28 @@ int nvdimm_security_change_key(struct nvdimm *nvdimm,
>>   	dev_dbg(dev, "%s: new key: %#x\n", __func__, key_serial(key));
>>
>>   	down_read(&key->sem);
>> -	payload = key->payload.data[0];
>> -	if (payload->datalen != NVDIMM_PASSPHRASE_LEN) {
>> -		rc = -EINVAL;
>> -		up_read(&key->sem);
>> -		goto out;
>> -	}
>> -
>> -	/*
>> -	 * Since there is no existing key this user key will become the
>> -	 * kernel's key.
>> -	 */
>> -	if (!old_key) {
>> -		key = make_kernel_key(key);
>> -		if (!key) {
>> -			rc = -ENOMEM;
>> -			goto out;
>> -		}
>> -	}
>> -
>> -	/*
>> -	 * We don't need to release key->sem here because
>> -	 * make_kernel_key() will have upgraded the user key to kernel
>> -	 * and handled the semaphore handoff.
>> -	 */
>> -	payload = key->payload.data[0];
>> +	epayload = dereference_key_locked(key);
>> +	new_data = epayload->decrypted_data;
>>
>>   	if (old_key) {
>>   		down_read(&old_key->sem);
>> -		old_payload = old_key->payload.data[0];
>> -		old_data = old_payload->data;
>> +		old_epayload = dereference_key_locked(old_key);
>> +		old_data = old_epayload->decrypted_data;
>>   	}
>>
>> -	new_data = payload->data;
>> -
>>   	rc = nvdimm->security_ops->change_key(nvdimm, old_data,
>>   			new_data);
>>   	if (rc)
>>   		dev_warn(dev, "key update failed: %d\n", rc);
>>
>> -	if (old_key) {
>> +	if (old_key)
>>   		up_read(&old_key->sem);
>> -		/*
>> -		 * With the key update done via hardware, we no longer need
>> -		 * the old payload and need to replace it with the new
>> -		 * payload. key_update() will acquire write sem of the
>> -		 * old key and update with new data.
>> -		 */
>> -		if (rc == 0) {
>> -			rc = key_update(make_key_ref(old_key, 1), new_data,
>> -					old_key->datalen);
>> -			if (rc < 0) {
>> -				dev_warn(dev,
>> -					"kernel key update failed: %d\n", rc);
>> -				key_destroy(old_key);
>> -				nvdimm->key = NULL;
>> -			}
>> -		}
>> -	}
>>   	up_read(&key->sem);
>> -
>> -	if (!old_key) {
>> -		if (rc == 0) {
>> -			dev_dbg(dev, "key cached: %#x\n", key_serial(key));
>> -			nvdimm->key = key;
>> -		} else
>> -			key_destroy(key);
>> -	}
>>   	nvdimm_security_get_state(nvdimm);
>>
>>    out:
>> -	mutex_unlock(&nvdimm->key_mutex);
>> +	mutex_unlock(&nvdimm->sec_mutex);
>> +	key_put(old_key);
>> +	key_put(key);
>>   	return rc;
>>   }
>>
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

  parent reply	other threads:[~2018-11-12 15:45 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-11-09 22:13 [PATCH 00/11] Additional patches for nvdimm security support Dave Jiang
2018-11-09 22:13 ` [PATCH 01/11] keys-encrypted: add nvdimm key format type to encrypted keys Dave Jiang
2018-11-27  7:20   ` Dan Williams
2018-11-27  7:20     ` Dan Williams
2018-11-27 16:20     ` Dave Jiang
2018-11-27 16:20       ` Dave Jiang
2018-11-27 18:24       ` Mimi Zohar
2018-11-27 18:24         ` Mimi Zohar
2018-11-27 19:10         ` Dan Williams
2018-11-27 19:10           ` Dan Williams
2018-11-27 19:35           ` Mimi Zohar
2018-11-27 19:35             ` Mimi Zohar
2018-11-27 19:48             ` Dan Williams
2018-11-27 19:48               ` Dan Williams
2018-11-27 20:10               ` Mimi Zohar
2018-11-27 20:10                 ` Mimi Zohar
2018-11-27 20:15                 ` Dave Jiang
2018-11-09 22:13 ` [PATCH 02/11] libnvdimm/security: change clear text nvdimm keys " Dave Jiang
2018-11-10  1:45   ` Dan Williams
2018-11-11 17:27   ` Mimi Zohar
2018-11-11 19:20     ` Dan Williams
2018-11-11 19:20       ` Dan Williams
2018-11-11 19:20       ` Dan Williams
2018-11-11 20:09       ` Mimi Zohar
2018-11-11 20:09         ` Mimi Zohar
2018-11-11 20:09         ` Mimi Zohar
2018-11-12 15:42         ` Dave Jiang
2018-11-12 15:42           ` Dave Jiang
2018-11-12 15:42           ` Dave Jiang
2018-11-12 18:49           ` Mimi Zohar
2018-11-12 18:49             ` Mimi Zohar
2018-11-12 18:49             ` Mimi Zohar
2018-11-12 20:13             ` Dave Jiang
2018-11-12 20:13               ` Dave Jiang
2018-11-12 20:13               ` Dave Jiang
2018-11-12 15:45     ` Dave Jiang [this message]
2018-11-12 19:04       ` Mimi Zohar
2018-11-09 22:14 ` [PATCH 03/11] libnvdimm/security: add override module param for key self verification Dave Jiang
2018-11-09 22:14 ` [PATCH 04/11] libnvdimm/security: introduce NDD_SECURITY_BUSY flag Dave Jiang
2018-11-09 22:14 ` [PATCH 05/11] acpi/nfit, libnvdimm/security: Add security DSM overwrite support Dave Jiang
2018-11-09 22:14 ` [PATCH 06/11] tools/testing/nvdimm: Add overwrite support for nfit_test Dave Jiang
2018-11-09 22:14 ` [PATCH 07/11] libnvdimm/security: add overwrite status notification Dave Jiang
2018-11-10  2:59   ` Elliott, Robert (Persistent Memory)
2018-11-12 20:26     ` Dave Jiang
2018-11-09 22:14 ` [PATCH 08/11] libnvdimm/security: add documentation for ovewrite Dave Jiang
2018-11-09 22:14 ` [PATCH 09/11] acpi/nfit, libnvdimm/security: add Intel DSM 1.8 master passphrase support Dave Jiang
2018-11-25 21:24   ` Dan Williams
2018-11-09 22:14 ` [PATCH 10/11] tools/testing/nvdimm: add Intel DSM 1.8 support for nfit_test Dave Jiang
2018-11-10  3:15   ` Elliott, Robert (Persistent Memory)
2018-11-12 20:27     ` Dave Jiang
2018-11-09 22:14 ` [PATCH 11/11] acpi/nfit: prevent indiscriminate DSM payload dumping for security DSMs Dave Jiang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1cc6edd6-8926-1be1-04f3-85ce59bfdfb4@intel.com \
    --to=dave.jiang@intel.com \
    --cc=dan.j.williams@intel.com \
    --cc=linux-nvdimm@lists.01.org \
    --cc=zohar@linux.ibm.com \
    --cc=zohar@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.