|  | // 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 | 
|  | */ | 
|  |  | 
|  | #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; | 
|  | } |