diff mbox series

[v2,1/4] libnvdimm: fix updating of kernel key during nvdimm key update

Message ID 153937679428.70378.14173556349575982662.stgit@djiang5-desk3.ch.intel.com (mailing list archive)
State New, archived
Headers show
Series misc patches for nvdimm security fixes | expand

Commit Message

Dave Jiang Oct. 12, 2018, 8:39 p.m. UTC
There are several issues WRT kernel key update when we are doing nvdimm
security key update.

1. The kernel key created needs to have proper permission for update
2. We need to check key_update() return value and make sure it didn't fail
3. We need to not hold the key->sem when calling key_update() since it will
   call down_write() when doing modification to the key.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/nvdimm/security.c |   23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c
index 2e764abe015a..8de34b03d402 100644
--- a/drivers/nvdimm/security.c
+++ b/drivers/nvdimm/security.c
@@ -27,7 +27,8 @@  static struct key *make_kernel_key(struct key *key)
 
 	new_key = key_alloc(&key_type_logon, key->description,
 			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
-			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL);
+			KEY_POS_ALL & ~KEY_POS_SETATTR,
+			KEY_ALLOC_NOT_IN_QUOTA, NULL);
 	if (IS_ERR(new_key))
 		return NULL;
 
@@ -413,11 +414,23 @@  int nvdimm_security_change_key(struct nvdimm *nvdimm,
 		dev_warn(dev, "key update failed: %d\n", rc);
 
 	if (old_key) {
-		/* copy new payload to old payload */
-		if (rc == 0)
-			key_update(make_key_ref(old_key, 1), new_data,
-					old_key->datalen);
 		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);