[PATCH v1 6/6] KEYS: measure keys when they are created or updated

Lakshmi Ramasubramanian nramas at linux.microsoft.com
Wed Oct 23 00:18:18 UTC 2019


A new LSM function namely, security_key_create_or_update, has
been added. This function is called by key_create_or_update
function when a new key is created or an existing key is updated.
This call is made when the key has been instantiated and linked
to the target keyring.

security_key_create_or_update is passed the target keyring, key,
key creation flags, and a boolean flag indicating whether
the key was newly created or an existing key was updated.
This function calls the ima function ima_post_key_create_or_update
to measure the key.

Signed-off-by: Lakshmi Ramasubramanian <nramas at linux.microsoft.com>
---
 include/linux/ima.h      | 15 +++++++-
 include/linux/security.h | 13 ++++++-
 security/keys/key.c      | 78 +++++++++++++++++++++++++++++++++++-----
 security/security.c      | 10 ++++++
 4 files changed, 105 insertions(+), 11 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index a20ad398d260..ce763901380d 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -24,7 +24,11 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
 			      enum kernel_read_file_id id);
 extern void ima_post_path_mknod(struct dentry *dentry);
 extern void ima_kexec_cmdline(const void *buf, int size);
-
+extern int ima_post_key_create_or_update(struct key *keyring,
+					 struct key *key,
+					 const struct cred *cred,
+					 unsigned long flags,
+					 bool create);
 #ifdef CONFIG_IMA_KEXEC
 extern void ima_add_kexec_buffer(struct kimage *image);
 #endif
@@ -91,6 +95,15 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
 }
 
 static inline void ima_kexec_cmdline(const void *buf, int size) {}
+
+static inline int ima_post_key_create_or_update(struct key *keyring,
+						struct key *key,
+						const struct cred *cred,
+						unsigned long flags,
+						bool create)
+{
+	return 0;
+}
 #endif /* CONFIG_IMA */
 
 #ifndef CONFIG_IMA_KEXEC
diff --git a/include/linux/security.h b/include/linux/security.h
index 5f7441abbf42..c8348da3db2e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1677,7 +1677,9 @@ void security_key_free(struct key *key);
 int security_key_permission(key_ref_t key_ref,
 			    const struct cred *cred, unsigned perm);
 int security_key_getsecurity(struct key *key, char **_buffer);
-
+int security_key_create_or_update(struct key *keyring, struct key *key,
+				  const struct cred *cred,
+				  unsigned long flags, bool create);
 #else
 
 static inline int security_key_alloc(struct key *key,
@@ -1704,6 +1706,15 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
 	return 0;
 }
 
+static inline int security_key_create_or_update(struct key *keyring,
+						struct key *key,
+						const struct cred *cred,
+						unsigned long flags,
+						bool create)
+{
+	return 0;
+}
+
 #endif
 #endif /* CONFIG_KEYS */
 
diff --git a/security/keys/key.c b/security/keys/key.c
index 764f4c57913e..b913feaf196e 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -781,7 +781,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
 }
 
 /**
- * key_create_or_update - Update or create and instantiate a key.
+ * __key_create_or_update - Update or create and instantiate a key.
  * @keyring_ref: A pointer to the destination keyring with possession flag.
  * @type: The type of key.
  * @description: The searchable description for the key.
@@ -789,6 +789,8 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
  * @plen: The length of @payload.
  * @perm: The permissions mask for a new key.
  * @flags: The quota flags for a new key.
+ * @create: Set to true if the key was newly created.
+ *          Set to false if the key was updated.
  *
  * Search the destination keyring for a key of the same description and if one
  * is found, update it, otherwise create and instantiate a new one and create a
@@ -805,13 +807,14 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
  * On success, the possession flag from the keyring ref will be tacked on to
  * the key ref before it is returned.
  */
-key_ref_t key_create_or_update(key_ref_t keyring_ref,
-			       const char *type,
-			       const char *description,
-			       const void *payload,
-			       size_t plen,
-			       key_perm_t perm,
-			       unsigned long flags)
+static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
+					const char *type,
+					const char *description,
+					const void *payload,
+					size_t plen,
+					key_perm_t perm,
+					unsigned long flags,
+					bool *create)
 {
 	struct keyring_index_key index_key = {
 		.description	= description,
@@ -936,6 +939,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 		goto error_link_end;
 	}
 
+	*create = true;
 	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
 
 error_link_end:
@@ -948,7 +952,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 error:
 	return key_ref;
 
- found_matching_key:
+found_matching_key:
 	/* we found a matching key, so we're going to try to update it
 	 * - we can drop the locks first as we have the key pinned
 	 */
@@ -964,9 +968,65 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 		}
 	}
 
+	*create = false;
 	key_ref = __key_update(key_ref, &prep);
 	goto error_free_prep;
 }
+
+/**
+ * key_create_or_update - Update or create and instantiate a key.
+ * @keyring_ref: A pointer to the destination keyring with possession flag.
+ * @type: The type of key.
+ * @description: The searchable description for the key.
+ * @payload: The data to use to instantiate or update the key.
+ * @plen: The length of @payload.
+ * @perm: The permissions mask for a new key.
+ * @flags: The quota flags for a new key.
+ *
+ * Calls the internal function __key_create_or_update.
+ * If successful calls the security LSM hook.
+ */
+key_ref_t key_create_or_update(key_ref_t keyring_ref,
+			       const char *type,
+			       const char *description,
+			       const void *payload,
+			       size_t plen,
+			       key_perm_t perm,
+			       unsigned long flags)
+{
+	key_ref_t key_ref;
+	struct key *keyring, *key = NULL;
+	int ret = 0;
+	bool create = false;
+
+	key_ref = __key_create_or_update(keyring_ref, type, description,
+					 payload, plen, perm, flags,
+					 &create);
+	if (IS_ERR(key_ref))
+		goto out;
+
+	keyring = key_ref_to_ptr(keyring_ref);
+	key = key_ref_to_ptr(key_ref);
+
+	/* let the security module know about
+	 * the created or updated key.
+	 */
+	ret = security_key_create_or_update(keyring, key,
+					    current_cred(),
+					    flags, create);
+	if (ret < 0)
+		goto security_error;
+	else
+		goto out;
+
+security_error:
+	key_unlink(keyring, key);
+	key_put(key);
+	key_ref = ERR_PTR(ret);
+
+out:
+	return key_ref;
+}
 EXPORT_SYMBOL(key_create_or_update);
 
 /**
diff --git a/security/security.c b/security/security.c
index 250ee2d76406..707a9e7fa94d 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2303,6 +2303,16 @@ int security_key_getsecurity(struct key *key, char **_buffer)
 	return call_int_hook(key_getsecurity, 0, key, _buffer);
 }
 
+int security_key_create_or_update(struct key *keyring,
+				  struct key *key,
+				  const struct cred *cred,
+				  unsigned long flags,
+				  bool create)
+{
+	return ima_post_key_create_or_update(keyring, key, cred,
+					     flags, create);
+}
+
 #endif	/* CONFIG_KEYS */
 
 #ifdef CONFIG_AUDIT
-- 
2.17.1



More information about the Linux-security-module-archive mailing list