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