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@xxxxxxxxxxxxxxxxxxx> --- 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