18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2019 Microsoft Corporation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * File: ima_queue_keys.c
88c2ecf20Sopenharmony_ci *       Enables deferred processing of keys
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
128c2ecf20Sopenharmony_ci#include <keys/asymmetric-type.h>
138c2ecf20Sopenharmony_ci#include "ima.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*
168c2ecf20Sopenharmony_ci * Flag to indicate whether a key can be processed
178c2ecf20Sopenharmony_ci * right away or should be queued for processing later.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_cistatic bool ima_process_keys;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci * To synchronize access to the list of keys that need to be measured
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ima_keys_lock);
258c2ecf20Sopenharmony_cistatic LIST_HEAD(ima_keys);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * If custom IMA policy is not loaded then keys queued up
298c2ecf20Sopenharmony_ci * for measurement should be freed. This worker is used
308c2ecf20Sopenharmony_ci * for handling this scenario.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_cistatic long ima_key_queue_timeout = 300000; /* 5 Minutes */
338c2ecf20Sopenharmony_cistatic void ima_keys_handler(struct work_struct *work);
348c2ecf20Sopenharmony_cistatic DECLARE_DELAYED_WORK(ima_keys_delayed_work, ima_keys_handler);
358c2ecf20Sopenharmony_cistatic bool timer_expired;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/*
388c2ecf20Sopenharmony_ci * This worker function frees keys that may still be
398c2ecf20Sopenharmony_ci * queued up in case custom IMA policy was not loaded.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_cistatic void ima_keys_handler(struct work_struct *work)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	timer_expired = true;
448c2ecf20Sopenharmony_ci	ima_process_queued_keys();
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * This function sets up a worker to free queued keys in case
498c2ecf20Sopenharmony_ci * custom IMA policy was never loaded.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_civoid ima_init_key_queue(void)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	schedule_delayed_work(&ima_keys_delayed_work,
548c2ecf20Sopenharmony_ci			      msecs_to_jiffies(ima_key_queue_timeout));
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void ima_free_key_entry(struct ima_key_entry *entry)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	if (entry) {
608c2ecf20Sopenharmony_ci		kfree(entry->payload);
618c2ecf20Sopenharmony_ci		kfree(entry->keyring_name);
628c2ecf20Sopenharmony_ci		kfree(entry);
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic struct ima_key_entry *ima_alloc_key_entry(struct key *keyring,
678c2ecf20Sopenharmony_ci						 const void *payload,
688c2ecf20Sopenharmony_ci						 size_t payload_len)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	int rc = 0;
718c2ecf20Sopenharmony_ci	const char *audit_cause = "ENOMEM";
728c2ecf20Sopenharmony_ci	struct ima_key_entry *entry;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
758c2ecf20Sopenharmony_ci	if (entry) {
768c2ecf20Sopenharmony_ci		entry->payload = kmemdup(payload, payload_len, GFP_KERNEL);
778c2ecf20Sopenharmony_ci		entry->keyring_name = kstrdup(keyring->description,
788c2ecf20Sopenharmony_ci					      GFP_KERNEL);
798c2ecf20Sopenharmony_ci		entry->payload_len = payload_len;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if ((entry == NULL) || (entry->payload == NULL) ||
838c2ecf20Sopenharmony_ci	    (entry->keyring_name == NULL)) {
848c2ecf20Sopenharmony_ci		rc = -ENOMEM;
858c2ecf20Sopenharmony_ci		goto out;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&entry->list);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciout:
918c2ecf20Sopenharmony_ci	if (rc) {
928c2ecf20Sopenharmony_ci		integrity_audit_message(AUDIT_INTEGRITY_PCR, NULL,
938c2ecf20Sopenharmony_ci					keyring->description,
948c2ecf20Sopenharmony_ci					func_measure_str(KEY_CHECK),
958c2ecf20Sopenharmony_ci					audit_cause, rc, 0, rc);
968c2ecf20Sopenharmony_ci		ima_free_key_entry(entry);
978c2ecf20Sopenharmony_ci		entry = NULL;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return entry;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cibool ima_queue_key(struct key *keyring, const void *payload,
1048c2ecf20Sopenharmony_ci		   size_t payload_len)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	bool queued = false;
1078c2ecf20Sopenharmony_ci	struct ima_key_entry *entry;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	entry = ima_alloc_key_entry(keyring, payload, payload_len);
1108c2ecf20Sopenharmony_ci	if (!entry)
1118c2ecf20Sopenharmony_ci		return false;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	mutex_lock(&ima_keys_lock);
1148c2ecf20Sopenharmony_ci	if (!ima_process_keys) {
1158c2ecf20Sopenharmony_ci		list_add_tail(&entry->list, &ima_keys);
1168c2ecf20Sopenharmony_ci		queued = true;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci	mutex_unlock(&ima_keys_lock);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (!queued)
1218c2ecf20Sopenharmony_ci		ima_free_key_entry(entry);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return queued;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/*
1278c2ecf20Sopenharmony_ci * ima_process_queued_keys() - process keys queued for measurement
1288c2ecf20Sopenharmony_ci *
1298c2ecf20Sopenharmony_ci * This function sets ima_process_keys to true and processes queued keys.
1308c2ecf20Sopenharmony_ci * From here on keys will be processed right away (not queued).
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_civoid ima_process_queued_keys(void)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct ima_key_entry *entry, *tmp;
1358c2ecf20Sopenharmony_ci	bool process = false;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (ima_process_keys)
1388c2ecf20Sopenharmony_ci		return;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	/*
1418c2ecf20Sopenharmony_ci	 * Since ima_process_keys is set to true, any new key will be
1428c2ecf20Sopenharmony_ci	 * processed immediately and not be queued to ima_keys list.
1438c2ecf20Sopenharmony_ci	 * First one setting the ima_process_keys flag to true will
1448c2ecf20Sopenharmony_ci	 * process the queued keys.
1458c2ecf20Sopenharmony_ci	 */
1468c2ecf20Sopenharmony_ci	mutex_lock(&ima_keys_lock);
1478c2ecf20Sopenharmony_ci	if (!ima_process_keys) {
1488c2ecf20Sopenharmony_ci		ima_process_keys = true;
1498c2ecf20Sopenharmony_ci		process = true;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	mutex_unlock(&ima_keys_lock);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (!process)
1548c2ecf20Sopenharmony_ci		return;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (!timer_expired)
1578c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&ima_keys_delayed_work);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, tmp, &ima_keys, list) {
1608c2ecf20Sopenharmony_ci		if (!timer_expired)
1618c2ecf20Sopenharmony_ci			process_buffer_measurement(NULL, entry->payload,
1628c2ecf20Sopenharmony_ci						   entry->payload_len,
1638c2ecf20Sopenharmony_ci						   entry->keyring_name,
1648c2ecf20Sopenharmony_ci						   KEY_CHECK, 0,
1658c2ecf20Sopenharmony_ci						   entry->keyring_name);
1668c2ecf20Sopenharmony_ci		list_del(&entry->list);
1678c2ecf20Sopenharmony_ci		ima_free_key_entry(entry);
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ciinline bool ima_should_queue_key(void)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	return !ima_process_keys;
1748c2ecf20Sopenharmony_ci}
175