2020-01-09 02:45:04

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: [PATCH v8 0/3] IMA: Deferred measurement of keys

The IMA subsystem supports measuring asymmetric keys when the key is
created or updated[1]. But keys created or updated before a custom
IMA policy is loaded are currently not measured. This includes keys
added, for instance, to either the .ima or .builtin_trusted_keys keyrings,
which happens early in the boot process.

Measuring the early boot keys, by design, requires loading
a custom IMA policy. This change adds support for queuing keys
created or updated before a custom IMA policy is loaded.
The queued keys are processed when a custom policy is loaded.
Keys created or updated after a custom policy is loaded are measured
immediately (not queued). In the case when a custom policy is not loaded
within 5 minutes of IMA initialization, the queued keys are freed.

[1] https://lore.kernel.org/linux-integrity/[email protected]/

Testing performed:

* Ran kernel self-test following the instructions given in
https://www.kernel.org/doc/Documentation/kselftest.txt
* Ran the lkp-tests using the job script provided by
kernel test robot <[email protected]>
* Booted the kernel with this change.
* Added .builtin_trusted_keys in "keyrings=" option in
the IMA policy and verified the keys added to this
keyring are measured.
* Specified only func=KEY_CHECK and not "keyrings=" option,
and verified the keys added to builtin_trusted_keys keyring
are processed.
* Added keys at runtime and verified they are measured
if the IMA policy permitted.
=> For example, added keys to .ima keyring and verified.

Changelog:

v8

=> Rebased the changes to linux-next
=> Need to apply the following patch first
https://lore.kernel.org/linux-integrity/[email protected]/

v7

=> Updated cover letter per Mimi's suggestions.
=> Updated "Reported-by" tag to be specific about
the issues fixed in the patch.

v6

=> Replaced mutex with a spinlock to sychronize access to
queued keys. This fixes the problem reported by
"kernel test robot <[email protected]>"
https://lore.kernel.org/linux-integrity/[email protected]/T/#t
=> Changed ima_queue_key() to a static function. This fixes
the issue reported by "kbuild test robot <[email protected]>"
https://lore.kernel.org/linux-integrity/[email protected]/
=> Added the patch to free the queued keys if a custom IMA policy
was not loaded to this patch set.

v5

=> Removed temp keys list in ima_process_queued_keys()

v4

=> Check and set ima_process_keys flag with mutex held.

v3

=> Defined ima_process_keys flag to be static.
=> Set ima_process_keys with ima_keys_mutex held.
=> Added a comment in ima_process_queued_keys() function
to state the use of temporary list for keys.

v2

=> Rebased the changes to v5.5-rc1
=> Updated function names, variable names, and code comments
to be less verbose.

v1

=> Code cleanup

v0

=> Based changes on v5.4-rc8
=> The following patchsets should be applied in that order
https://lore.kernel.org/linux-integrity/[email protected]
https://lore.kernel.org/linux-integrity/[email protected]/
=> Added functions to queue and dequeue keys, and process
the queued keys when custom IMA policies are applied.

Lakshmi Ramasubramanian (3):
IMA: Define workqueue for early boot key measurements
IMA: Call workqueue functions to measure queued keys
IMA: Defined timer to free queued keys

security/integrity/ima/ima.h | 17 ++
security/integrity/ima/ima_asymmetric_keys.c | 159 +++++++++++++++++++
security/integrity/ima/ima_init.c | 8 +-
security/integrity/ima/ima_policy.c | 3 +
4 files changed, 186 insertions(+), 1 deletion(-)

--
2.17.1


2020-01-09 02:45:06

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: [PATCH v8 2/3] IMA: Call workqueue functions to measure queued keys

Measuring keys requires a custom IMA policy to be loaded.
Keys should be queued for measurement if a custom IMA policy
is not yet loaded. Keys queued for measurement, if any, should be
processed when a custom IMA policy is loaded.

This patch updates the IMA hook function ima_post_key_create_or_update()
to queue the key if a custom IMA policy has not yet been loaded.
And, ima_update_policy() function, which is called when
a custom IMA policy is loaded, is updated to process queued keys.

Signed-off-by: Lakshmi Ramasubramanian <[email protected]>
---
security/integrity/ima/ima_asymmetric_keys.c | 8 ++++++++
security/integrity/ima/ima_policy.c | 3 +++
2 files changed, 11 insertions(+)

diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c
index 1d56f003f1a7..eb71cbf224c1 100644
--- a/security/integrity/ima/ima_asymmetric_keys.c
+++ b/security/integrity/ima/ima_asymmetric_keys.c
@@ -145,6 +145,8 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
const void *payload, size_t payload_len,
unsigned long flags, bool create)
{
+ bool queued = false;
+
/* Only asymmetric keys are handled by this hook. */
if (key->type != &key_type_asymmetric)
return;
@@ -152,6 +154,12 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
if (!payload || (payload_len == 0))
return;

+ if (!ima_process_keys)
+ queued = ima_queue_key(keyring, payload, payload_len);
+
+ if (queued)
+ return;
+
/*
* keyring->description points to the name of the keyring
* (such as ".builtin_trusted_keys", ".ima", etc.) to
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 8f2ca487753b..1bdda05d963b 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -807,6 +807,9 @@ void ima_update_policy(void)
kfree(arch_policy_entry);
}
ima_update_policy_flag();
+
+ /* Custom IMA policy has been loaded */
+ ima_process_queued_keys();
}

/* Keep the enumeration in sync with the policy_tokens! */
--
2.17.1

2020-01-09 02:46:24

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: [PATCH v8 1/3] IMA: Define workqueue for early boot key measurements

Measuring keys requires a custom IMA policy to be loaded.
Keys created or updated before a custom IMA policy is loaded should
be queued and the keys should be processed after a custom policy
is loaded.

This patch defines workqueue for queuing keys when a custom IMA policy
has not yet been loaded.

A flag namely ima_process_keys is used to check if the key should be
queued or should be processed immediately.

Signed-off-by: Lakshmi Ramasubramanian <[email protected]>
Reported-by: kernel test robot <[email protected]> # sleeping
function called from invalid context
Reported-by: kbuild test robot <[email protected]> # sparse symbol
ima_queued_key() should be static
---
security/integrity/ima/ima.h | 15 +++
security/integrity/ima/ima_asymmetric_keys.c | 115 +++++++++++++++++++
2 files changed, 130 insertions(+)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index f06238e41a7c..c7fdf3d66b98 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -205,6 +205,21 @@ extern const char *const func_tokens[];

struct modsig;

+#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
+/*
+ * To track keys that need to be measured.
+ */
+struct ima_key_entry {
+ struct list_head list;
+ void *payload;
+ size_t payload_len;
+ char *keyring_name;
+};
+void ima_process_queued_keys(void);
+#else
+static inline void ima_process_queued_keys(void) {}
+#endif /* CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS */
+
/* LIM API function definitions */
int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
int mask, enum ima_hooks func, int *pcr,
diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c
index fea2e7dd3b09..1d56f003f1a7 100644
--- a/security/integrity/ima/ima_asymmetric_keys.c
+++ b/security/integrity/ima/ima_asymmetric_keys.c
@@ -14,6 +14,121 @@
#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_SPINLOCK(ima_keys_lock);
+static LIST_HEAD(ima_keys);
+
+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;
+}
+
+static 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;
+
+ spin_lock(&ima_keys_lock);
+ if (!ima_process_keys) {
+ list_add_tail(&entry->list, &ima_keys);
+ queued = true;
+ }
+ spin_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.
+ */
+ spin_lock(&ima_keys_lock);
+ if (!ima_process_keys) {
+ ima_process_keys = true;
+ process = true;
+ }
+ spin_unlock(&ima_keys_lock);
+
+ if (!process)
+ return;
+
+ list_for_each_entry_safe(entry, tmp, &ima_keys, list) {
+ 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);
+ }
+}
+
/**
* ima_post_key_create_or_update - measure asymmetric keys
* @keyring: keyring to which the key is linked to
--
2.17.1

2020-01-09 05:09:34

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v8 0/3] IMA: Deferred measurement of keys

On Wed, 2020-01-08 at 18:43 -0800, Lakshmi Ramasubramanian wrote:

> Changelog:
>
> v8
>
> => Rebased the changes to linux-next
> => Need to apply the following patch first
> https://lore.kernel.org/linux-integrity/[email protected]/

Unless you made some other changes, the previous version of this patch
set is already in next-integrity-testing.  There's no reason to re-
post these patches again, and definitely not against linux-next.

Mimi

2020-01-09 21:00:48

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: Re: [PATCH v8 0/3] IMA: Deferred measurement of keys

On 1/8/20 9:07 PM, Mimi Zohar wrote:

> On Wed, 2020-01-08 at 18:43 -0800, Lakshmi Ramasubramanian wrote:
>
>> Changelog:
>>
>> v8
>>
>> => Rebased the changes to linux-next
>> => Need to apply the following patch first
>> https://lore.kernel.org/linux-integrity/[email protected]/
>
> Unless you made some other changes, the previous version of this patch
> set is already in next-integrity-testing.  There's no reason to re-
> post these patches again, and definitely not against linux-next.
>
> Mimi
>

The change was to integrate the changes from the patch for the CONFIG issue:

https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git/commit/?h=next-integrity-testing&id=50a2506e069fc71f4be1bbcc2c5534bf58ed94ab

The following commit needs to be updated to use the new config
CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS instead of
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE

https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git/commit/?h=next-integrity-testing&id=e164a1695a5705c24c897b0bc7e9b97abb0830c8

Please let me know if I can clone next-integrity-testing and make the
above update. I'll post the updated patch today.

thanks,
-lakshmi