diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-01-29 03:52:09 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-01-29 03:52:09 +0100 |
commit | 73a0bff2058f2403c604371c325fec737ac2ac61 (patch) | |
tree | b862ab7ec0b6bf155cc491ec34343ac1df25bfa9 /security/integrity/ima/ima_queue_keys.c | |
parent | Merge tag 'tomoyo-pr-20200128' of git://git.osdn.net/gitroot/tomoyo/tomoyo-test1 (diff) | |
parent | Merge branch 'next-integrity.defer-measuring-keys' into next-integrity (diff) | |
download | linux-73a0bff2058f2403c604371c325fec737ac2ac61.tar.xz linux-73a0bff2058f2403c604371c325fec737ac2ac61.zip |
Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity
Pull IMA updates from Mimi Zohar:
"Two new features - measuring certificates and querying IMA for a file
hash - and three bug fixes:
- Measuring certificates is like the rest of IMA, based on policy,
but requires loading a custom policy. Certificates loaded onto a
keyring, for example during early boot, before a custom policy has
been loaded, are queued and only processed after loading the custom
policy.
- IMA calculates and caches files hashes. Other kernel subsystems,
and possibly kernel modules, are interested in accessing these
cached file hashes.
The bug fixes prevent classifying a file short read (e.g. shutdown) as
an invalid file signature, add a missing blank when displaying the
securityfs policy rules containing LSM labels, and, lastly, fix the
handling of the IMA policy information for unknown LSM labels"
* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
IMA: Defined delayed workqueue to free the queued keys
IMA: Call workqueue functions to measure queued keys
IMA: Define workqueue for early boot key measurements
IMA: pre-allocate buffer to hold keyrings string
ima: ima/lsm policy rule loading logic bug fixes
ima: add the ability to query the cached hash of a given file
ima: Add a space after printing LSM rules for readability
IMA: fix measuring asymmetric keys Kconfig
IMA: Read keyrings= option from the IMA policy
IMA: Add support to limit measuring keys
KEYS: Call the IMA hook to measure keys
IMA: Define an IMA hook to measure keys
IMA: Add KEY_CHECK func to measure keys
IMA: Check IMA policy flag
ima: avoid appraise error for hash calc interrupt
Diffstat (limited to 'security/integrity/ima/ima_queue_keys.c')
-rw-r--r-- | security/integrity/ima/ima_queue_keys.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c new file mode 100644 index 000000000000..c87c72299191 --- /dev/null +++ b/security/integrity/ima/ima_queue_keys.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Microsoft Corporation + * + * Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com) + * + * File: ima_queue_keys.c + * Enables deferred processing of keys + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/workqueue.h> +#include <keys/asymmetric-type.h> +#include "ima.h" + +/* + * Flag to indicate whether a key can be processed + * right away or should be queued for processing later. + */ +static bool ima_process_keys; + +/* + * To synchronize access to the list of keys that need to be measured + */ +static DEFINE_MUTEX(ima_keys_lock); +static LIST_HEAD(ima_keys); + +/* + * If custom IMA policy is not loaded then keys queued up + * for measurement should be freed. This worker is used + * for handling this scenario. + */ +static long ima_key_queue_timeout = 300000; /* 5 Minutes */ +static void ima_keys_handler(struct work_struct *work); +static DECLARE_DELAYED_WORK(ima_keys_delayed_work, ima_keys_handler); +static bool timer_expired; + +/* + * This worker function frees keys that may still be + * queued up in case custom IMA policy was not loaded. + */ +static void ima_keys_handler(struct work_struct *work) +{ + timer_expired = true; + ima_process_queued_keys(); +} + +/* + * This function sets up a worker to free queued keys in case + * custom IMA policy was never loaded. + */ +void ima_init_key_queue(void) +{ + schedule_delayed_work(&ima_keys_delayed_work, + msecs_to_jiffies(ima_key_queue_timeout)); +} + +static void ima_free_key_entry(struct ima_key_entry *entry) +{ + if (entry) { + kfree(entry->payload); + kfree(entry->keyring_name); + kfree(entry); + } +} + +static struct ima_key_entry *ima_alloc_key_entry(struct key *keyring, + const void *payload, + size_t payload_len) +{ + int rc = 0; + struct ima_key_entry *entry; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (entry) { + entry->payload = kmemdup(payload, payload_len, GFP_KERNEL); + entry->keyring_name = kstrdup(keyring->description, + GFP_KERNEL); + entry->payload_len = payload_len; + } + + if ((entry == NULL) || (entry->payload == NULL) || + (entry->keyring_name == NULL)) { + rc = -ENOMEM; + goto out; + } + + INIT_LIST_HEAD(&entry->list); + +out: + if (rc) { + ima_free_key_entry(entry); + entry = NULL; + } + + return entry; +} + +bool ima_queue_key(struct key *keyring, const void *payload, + size_t payload_len) +{ + bool queued = false; + struct ima_key_entry *entry; + + entry = ima_alloc_key_entry(keyring, payload, payload_len); + if (!entry) + return false; + + mutex_lock(&ima_keys_lock); + if (!ima_process_keys) { + list_add_tail(&entry->list, &ima_keys); + queued = true; + } + mutex_unlock(&ima_keys_lock); + + if (!queued) + ima_free_key_entry(entry); + + return queued; +} + +/* + * ima_process_queued_keys() - process keys queued for measurement + * + * This function sets ima_process_keys to true and processes queued keys. + * From here on keys will be processed right away (not queued). + */ +void ima_process_queued_keys(void) +{ + struct ima_key_entry *entry, *tmp; + bool process = false; + + if (ima_process_keys) + return; + + /* + * Since ima_process_keys is set to true, any new key will be + * processed immediately and not be queued to ima_keys list. + * First one setting the ima_process_keys flag to true will + * process the queued keys. + */ + mutex_lock(&ima_keys_lock); + if (!ima_process_keys) { + ima_process_keys = true; + process = true; + } + mutex_unlock(&ima_keys_lock); + + if (!process) + return; + + if (!timer_expired) + cancel_delayed_work_sync(&ima_keys_delayed_work); + + list_for_each_entry_safe(entry, tmp, &ima_keys, list) { + if (!timer_expired) + process_buffer_measurement(entry->payload, + entry->payload_len, + entry->keyring_name, + KEY_CHECK, 0, + entry->keyring_name); + list_del(&entry->list); + ima_free_key_entry(entry); + } +} + +inline bool ima_should_queue_key(void) +{ + return !ima_process_keys; +} |