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