19f81a2edSLakshmi Ramasubramanian // SPDX-License-Identifier: GPL-2.0+
29f81a2edSLakshmi Ramasubramanian /*
39f81a2edSLakshmi Ramasubramanian  * Copyright (C) 2019 Microsoft Corporation
49f81a2edSLakshmi Ramasubramanian  *
59f81a2edSLakshmi Ramasubramanian  * Author: Lakshmi Ramasubramanian ([email protected])
69f81a2edSLakshmi Ramasubramanian  *
79f81a2edSLakshmi Ramasubramanian  * File: ima_queue_keys.c
89f81a2edSLakshmi Ramasubramanian  *       Enables deferred processing of keys
99f81a2edSLakshmi Ramasubramanian  */
109f81a2edSLakshmi Ramasubramanian 
11a2d2329eSChristian Brauner #include <linux/user_namespace.h>
125b3014b9SLakshmi Ramasubramanian #include <linux/workqueue.h>
139f81a2edSLakshmi Ramasubramanian #include <keys/asymmetric-type.h>
149f81a2edSLakshmi Ramasubramanian #include "ima.h"
159f81a2edSLakshmi Ramasubramanian 
169f81a2edSLakshmi Ramasubramanian /*
179f81a2edSLakshmi Ramasubramanian  * Flag to indicate whether a key can be processed
189f81a2edSLakshmi Ramasubramanian  * right away or should be queued for processing later.
199f81a2edSLakshmi Ramasubramanian  */
209f81a2edSLakshmi Ramasubramanian static bool ima_process_keys;
219f81a2edSLakshmi Ramasubramanian 
229f81a2edSLakshmi Ramasubramanian /*
239f81a2edSLakshmi Ramasubramanian  * To synchronize access to the list of keys that need to be measured
249f81a2edSLakshmi Ramasubramanian  */
259f81a2edSLakshmi Ramasubramanian static DEFINE_MUTEX(ima_keys_lock);
269f81a2edSLakshmi Ramasubramanian static LIST_HEAD(ima_keys);
279f81a2edSLakshmi Ramasubramanian 
285b3014b9SLakshmi Ramasubramanian /*
295b3014b9SLakshmi Ramasubramanian  * If custom IMA policy is not loaded then keys queued up
305b3014b9SLakshmi Ramasubramanian  * for measurement should be freed. This worker is used
315b3014b9SLakshmi Ramasubramanian  * for handling this scenario.
325b3014b9SLakshmi Ramasubramanian  */
335b3014b9SLakshmi Ramasubramanian static long ima_key_queue_timeout = 300000; /* 5 Minutes */
345b3014b9SLakshmi Ramasubramanian static void ima_keys_handler(struct work_struct *work);
355b3014b9SLakshmi Ramasubramanian static DECLARE_DELAYED_WORK(ima_keys_delayed_work, ima_keys_handler);
365b3014b9SLakshmi Ramasubramanian static bool timer_expired;
375b3014b9SLakshmi Ramasubramanian 
385b3014b9SLakshmi Ramasubramanian /*
395b3014b9SLakshmi Ramasubramanian  * This worker function frees keys that may still be
405b3014b9SLakshmi Ramasubramanian  * queued up in case custom IMA policy was not loaded.
415b3014b9SLakshmi Ramasubramanian  */
ima_keys_handler(struct work_struct * work)425b3014b9SLakshmi Ramasubramanian static void ima_keys_handler(struct work_struct *work)
435b3014b9SLakshmi Ramasubramanian {
445b3014b9SLakshmi Ramasubramanian 	timer_expired = true;
455b3014b9SLakshmi Ramasubramanian 	ima_process_queued_keys();
465b3014b9SLakshmi Ramasubramanian }
475b3014b9SLakshmi Ramasubramanian 
485b3014b9SLakshmi Ramasubramanian /*
495b3014b9SLakshmi Ramasubramanian  * This function sets up a worker to free queued keys in case
505b3014b9SLakshmi Ramasubramanian  * custom IMA policy was never loaded.
515b3014b9SLakshmi Ramasubramanian  */
ima_init_key_queue(void)525b3014b9SLakshmi Ramasubramanian void ima_init_key_queue(void)
535b3014b9SLakshmi Ramasubramanian {
545b3014b9SLakshmi Ramasubramanian 	schedule_delayed_work(&ima_keys_delayed_work,
555b3014b9SLakshmi Ramasubramanian 			      msecs_to_jiffies(ima_key_queue_timeout));
565b3014b9SLakshmi Ramasubramanian }
575b3014b9SLakshmi Ramasubramanian 
ima_free_key_entry(struct ima_key_entry * entry)589f81a2edSLakshmi Ramasubramanian static void ima_free_key_entry(struct ima_key_entry *entry)
599f81a2edSLakshmi Ramasubramanian {
609f81a2edSLakshmi Ramasubramanian 	if (entry) {
619f81a2edSLakshmi Ramasubramanian 		kfree(entry->payload);
629f81a2edSLakshmi Ramasubramanian 		kfree(entry->keyring_name);
639f81a2edSLakshmi Ramasubramanian 		kfree(entry);
649f81a2edSLakshmi Ramasubramanian 	}
659f81a2edSLakshmi Ramasubramanian }
669f81a2edSLakshmi Ramasubramanian 
ima_alloc_key_entry(struct key * keyring,const void * payload,size_t payload_len)679f81a2edSLakshmi Ramasubramanian static struct ima_key_entry *ima_alloc_key_entry(struct key *keyring,
689f81a2edSLakshmi Ramasubramanian 						 const void *payload,
699f81a2edSLakshmi Ramasubramanian 						 size_t payload_len)
709f81a2edSLakshmi Ramasubramanian {
719f81a2edSLakshmi Ramasubramanian 	int rc = 0;
7234e980bbSLakshmi Ramasubramanian 	const char *audit_cause = "ENOMEM";
739f81a2edSLakshmi Ramasubramanian 	struct ima_key_entry *entry;
749f81a2edSLakshmi Ramasubramanian 
759f81a2edSLakshmi Ramasubramanian 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
769f81a2edSLakshmi Ramasubramanian 	if (entry) {
779f81a2edSLakshmi Ramasubramanian 		entry->payload = kmemdup(payload, payload_len, GFP_KERNEL);
789f81a2edSLakshmi Ramasubramanian 		entry->keyring_name = kstrdup(keyring->description,
799f81a2edSLakshmi Ramasubramanian 					      GFP_KERNEL);
809f81a2edSLakshmi Ramasubramanian 		entry->payload_len = payload_len;
819f81a2edSLakshmi Ramasubramanian 	}
829f81a2edSLakshmi Ramasubramanian 
839f81a2edSLakshmi Ramasubramanian 	if ((entry == NULL) || (entry->payload == NULL) ||
849f81a2edSLakshmi Ramasubramanian 	    (entry->keyring_name == NULL)) {
859f81a2edSLakshmi Ramasubramanian 		rc = -ENOMEM;
869f81a2edSLakshmi Ramasubramanian 		goto out;
879f81a2edSLakshmi Ramasubramanian 	}
889f81a2edSLakshmi Ramasubramanian 
899f81a2edSLakshmi Ramasubramanian 	INIT_LIST_HEAD(&entry->list);
909f81a2edSLakshmi Ramasubramanian 
919f81a2edSLakshmi Ramasubramanian out:
929f81a2edSLakshmi Ramasubramanian 	if (rc) {
9334e980bbSLakshmi Ramasubramanian 		integrity_audit_message(AUDIT_INTEGRITY_PCR, NULL,
9434e980bbSLakshmi Ramasubramanian 					keyring->description,
9534e980bbSLakshmi Ramasubramanian 					func_measure_str(KEY_CHECK),
9634e980bbSLakshmi Ramasubramanian 					audit_cause, rc, 0, rc);
979f81a2edSLakshmi Ramasubramanian 		ima_free_key_entry(entry);
989f81a2edSLakshmi Ramasubramanian 		entry = NULL;
999f81a2edSLakshmi Ramasubramanian 	}
1009f81a2edSLakshmi Ramasubramanian 
1019f81a2edSLakshmi Ramasubramanian 	return entry;
1029f81a2edSLakshmi Ramasubramanian }
1039f81a2edSLakshmi Ramasubramanian 
ima_queue_key(struct key * keyring,const void * payload,size_t payload_len)1049f81a2edSLakshmi Ramasubramanian bool ima_queue_key(struct key *keyring, const void *payload,
1059f81a2edSLakshmi Ramasubramanian 		   size_t payload_len)
1069f81a2edSLakshmi Ramasubramanian {
1079f81a2edSLakshmi Ramasubramanian 	bool queued = false;
1089f81a2edSLakshmi Ramasubramanian 	struct ima_key_entry *entry;
1099f81a2edSLakshmi Ramasubramanian 
1109f81a2edSLakshmi Ramasubramanian 	entry = ima_alloc_key_entry(keyring, payload, payload_len);
1119f81a2edSLakshmi Ramasubramanian 	if (!entry)
1129f81a2edSLakshmi Ramasubramanian 		return false;
1139f81a2edSLakshmi Ramasubramanian 
1149f81a2edSLakshmi Ramasubramanian 	mutex_lock(&ima_keys_lock);
1159f81a2edSLakshmi Ramasubramanian 	if (!ima_process_keys) {
1169f81a2edSLakshmi Ramasubramanian 		list_add_tail(&entry->list, &ima_keys);
1179f81a2edSLakshmi Ramasubramanian 		queued = true;
1189f81a2edSLakshmi Ramasubramanian 	}
1199f81a2edSLakshmi Ramasubramanian 	mutex_unlock(&ima_keys_lock);
1209f81a2edSLakshmi Ramasubramanian 
1219f81a2edSLakshmi Ramasubramanian 	if (!queued)
1229f81a2edSLakshmi Ramasubramanian 		ima_free_key_entry(entry);
1239f81a2edSLakshmi Ramasubramanian 
1249f81a2edSLakshmi Ramasubramanian 	return queued;
1259f81a2edSLakshmi Ramasubramanian }
1269f81a2edSLakshmi Ramasubramanian 
1279f81a2edSLakshmi Ramasubramanian /*
1289f81a2edSLakshmi Ramasubramanian  * ima_process_queued_keys() - process keys queued for measurement
1299f81a2edSLakshmi Ramasubramanian  *
1309f81a2edSLakshmi Ramasubramanian  * This function sets ima_process_keys to true and processes queued keys.
1319f81a2edSLakshmi Ramasubramanian  * From here on keys will be processed right away (not queued).
1329f81a2edSLakshmi Ramasubramanian  */
ima_process_queued_keys(void)1339f81a2edSLakshmi Ramasubramanian void ima_process_queued_keys(void)
1349f81a2edSLakshmi Ramasubramanian {
1359f81a2edSLakshmi Ramasubramanian 	struct ima_key_entry *entry, *tmp;
1369f81a2edSLakshmi Ramasubramanian 	bool process = false;
1379f81a2edSLakshmi Ramasubramanian 
1389f81a2edSLakshmi Ramasubramanian 	if (ima_process_keys)
1399f81a2edSLakshmi Ramasubramanian 		return;
1409f81a2edSLakshmi Ramasubramanian 
1419f81a2edSLakshmi Ramasubramanian 	/*
1429f81a2edSLakshmi Ramasubramanian 	 * Since ima_process_keys is set to true, any new key will be
1439f81a2edSLakshmi Ramasubramanian 	 * processed immediately and not be queued to ima_keys list.
1449f81a2edSLakshmi Ramasubramanian 	 * First one setting the ima_process_keys flag to true will
1459f81a2edSLakshmi Ramasubramanian 	 * process the queued keys.
1469f81a2edSLakshmi Ramasubramanian 	 */
1479f81a2edSLakshmi Ramasubramanian 	mutex_lock(&ima_keys_lock);
1489f81a2edSLakshmi Ramasubramanian 	if (!ima_process_keys) {
1499f81a2edSLakshmi Ramasubramanian 		ima_process_keys = true;
1509f81a2edSLakshmi Ramasubramanian 		process = true;
1519f81a2edSLakshmi Ramasubramanian 	}
1529f81a2edSLakshmi Ramasubramanian 	mutex_unlock(&ima_keys_lock);
1539f81a2edSLakshmi Ramasubramanian 
1549f81a2edSLakshmi Ramasubramanian 	if (!process)
1559f81a2edSLakshmi Ramasubramanian 		return;
1569f81a2edSLakshmi Ramasubramanian 
1575b3014b9SLakshmi Ramasubramanian 	if (!timer_expired)
1585b3014b9SLakshmi Ramasubramanian 		cancel_delayed_work_sync(&ima_keys_delayed_work);
1599f81a2edSLakshmi Ramasubramanian 
1609f81a2edSLakshmi Ramasubramanian 	list_for_each_entry_safe(entry, tmp, &ima_keys, list) {
1615b3014b9SLakshmi Ramasubramanian 		if (!timer_expired)
162*39f60c1cSChristian Brauner 			process_buffer_measurement(&nop_mnt_idmap, NULL,
163a2d2329eSChristian Brauner 						   entry->payload,
1649f81a2edSLakshmi Ramasubramanian 						   entry->payload_len,
1659f81a2edSLakshmi Ramasubramanian 						   entry->keyring_name,
1669f81a2edSLakshmi Ramasubramanian 						   KEY_CHECK, 0,
167291af651STushar Sugandhi 						   entry->keyring_name,
168ca3c9bdbSRoberto Sassu 						   false, NULL, 0);
1699f81a2edSLakshmi Ramasubramanian 		list_del(&entry->list);
1709f81a2edSLakshmi Ramasubramanian 		ima_free_key_entry(entry);
1719f81a2edSLakshmi Ramasubramanian 	}
1729f81a2edSLakshmi Ramasubramanian }
1739f81a2edSLakshmi Ramasubramanian 
ima_should_queue_key(void)1749f81a2edSLakshmi Ramasubramanian inline bool ima_should_queue_key(void)
1759f81a2edSLakshmi Ramasubramanian {
1769f81a2edSLakshmi Ramasubramanian 	return !ima_process_keys;
1779f81a2edSLakshmi Ramasubramanian }
178