IMA: Generalize early boot data measurement
Subsystems (5)
v2 cover IMA: Generalize early boot data measurement
The current implementation of early boot measurement in the IMA subsystem is very specific to asymmetric keys. It does not handle early boot measurement of data from other subsystems such as Linux Security Module (LSM), Device-Mapper, etc. As a result, data provided by these subsystems during system boot are not measured by IMA.
This patch series makes the early boot key measurement functions generic such that they can be used to measure any early boot data. The functions in ima_queue_keys.c are refactored to a new file ima_queue_data.c. The kernel configuration CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS is renamed to CONFIG_IMA_QUEUE_EARLY_BOOT_DATA so it can be used for enabling any early boot data measurement. Since measurement of asymmetric keys is the first consumer of early boot measurement, this kernel configuration is enabled if IMA_MEASURE_ASYMMETRIC_KEYS and SYSTEM_TRUSTED_KEYRING are both enabled.
The IMA hook to measure kernel critical data ima_measure_critical_data() is updated to utilize early boot measurement support.
This series is based on the following repo/branch:
repo: https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
branch: next-integrity
commit d012a7190fc1 ("Linux 5.9-rc2")
This patch is dependent on the following patch series:
https://patchwork.kernel.org/patch/11709527/ https://patchwork.kernel.org/patch/11742047/
Change Log:
v2:
=> Split the patches to first rename the file and functions,
and then introduce new arguments, followed by adding queuing support in ima_measure_critical_data().
Lakshmi Ramasubramanian (3):
IMA: Generalize early boot measurement of asymmetric keys
IMA: Support measurement of generic data during early boot
IMA: Support early boot measurement of critical data
security/integrity/ima/Kconfig | 2 +- security/integrity/ima/Makefile | 2 +- security/integrity/ima/ima.h | 39 ++-- security/integrity/ima/ima_asymmetric_keys.c | 7 +- security/integrity/ima/ima_init.c | 2 +- security/integrity/ima/ima_main.c | 10 + security/integrity/ima/ima_policy.c | 2 +- security/integrity/ima/ima_queue_data.c | 191 +++++++++++++++++++ security/integrity/ima/ima_queue_keys.c | 175 ----------------- 9 files changed, 232 insertions(+), 198 deletions(-) create mode 100644 security/integrity/ima/ima_queue_data.c delete mode 100644 security/integrity/ima/ima_queue_keys.c
Signature · 1 line
2.28.0
PATCH v2 1/3 IMA: Generalize early boot measurement of asymmetric keys
The current implementation of early boot measurement in
the IMA subsystem is very specific to asymmetric keys. It does not handle early boot measurement of data from other subsystems such as Linux Security Module (LSM), Device-Mapper, etc. As a result, data provided by these subsystems during system boot are not measured by IMA.
Update the early boot key measurement functions to handle any early boot data. Refactor the code from ima_queue_keys.c to a new file ima_queue_data.c. Rename the kernel configuration CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS to CONFIG_IMA_QUEUE_EARLY_BOOT_DATA so it can be used for enabling any early boot data measurement. Since measurement of asymmetric keys is the first consumer of early boot measurement, enable this kernel configuration if IMA_MEASURE_ASYMMETRIC_KEYS and SYSTEM_TRUSTED_KEYRING are both enabled.
--- security/integrity/ima/Kconfig | 2 +- security/integrity/ima/Makefile | 2 +- security/integrity/ima/ima.h | 32 ++-- security/integrity/ima/ima_asymmetric_keys.c | 6 +- security/integrity/ima/ima_init.c | 2 +- security/integrity/ima/ima_policy.c | 2 +- security/integrity/ima/ima_queue_data.c | 179 +++++++++++++++++++ security/integrity/ima/ima_queue_keys.c | 175 ------------------ 8 files changed, 202 insertions(+), 198 deletions(-) create mode 100644 security/integrity/ima/ima_queue_data.c delete mode 100644 security/integrity/ima/ima_queue_keys.c
security/integrity/ima/Kconfig +1 -1
@@ -322,7 +322,7 @@ config IMA_MEASURE_ASYMMETRIC_KEYS depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y default y -config IMA_QUEUE_EARLY_BOOT_KEYS +config IMA_QUEUE_EARLY_BOOT_DATA bool depends on IMA_MEASURE_ASYMMETRIC_KEYS depends on SYSTEM_TRUSTED_KEYRING
security/integrity/ima/Makefile +1 -1
@@ -13,4 +13,4 @@ ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o ima-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o ima-$(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o -ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o +ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_DATA) += ima_queue_data.o
security/integrity/ima/ima.h +16 -16
@@ -257,29 +257,29 @@ static inline bool ima_kernel_data_source_is_supported(const char *source)return false; } -#ifdef CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS +#ifdef CONFIG_IMA_QUEUE_EARLY_BOOT_DATA /* -* To track keys that need to be measured. +* To track data that need to be measured. */ -struct ima_key_entry { +struct ima_data_entry {struct list_head list;void *payload;size_t payload_len; -char *keyring_name; +const char *event_name; }; -void ima_init_key_queue (void ); -bool ima_should_queue_key (void ); -bool ima_queue_key (struct key *keyring,const void *payload, -size_t payload_len); -void ima_process_queued_keys (void ); +void ima_init_data_queue (void ); +bool ima_should_queue_data (void ); +bool ima_queue_data (const char *event_name,const void *payload, +size_t payload_len); +void ima_process_queued_data (void );#else -static inline void ima_init_key_queue (void ) {} -static inline bool ima_should_queue_key (void ) {return false; } -static inline bool ima_queue_key (struct key *keyring, -const void *payload, -size_t payload_len) {return false; } -static inline void ima_process_queued_keys (void ) {} -#endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS */ +static inline void ima_init_data_queue (void ) {} +static inline bool ima_should_queue_data (void ) {return false; } +static inline bool ima_queue_data (const char *event_name, +const void *payload, +size_t payload_len) {return false; } +static inline void ima_process_queued_data (void ) {} +#endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_DATA */ /* LIM API function definitions */ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
security/integrity/ima/ima_asymmetric_keys.c +3 -3
@@ -37,9 +37,9 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,if (!payload || (payload_len ==0 ))return ; -if (ima_should_queue_key ()) - queued =ima_queue_key (keyring, payload, payload_len); - +if (ima_should_queue_data ()) + queued =ima_queue_data (keyring->description, payload, + payload_len);if (queued)return ;
security/integrity/ima/ima_init.c +1 -1
@@ -145,7 +145,7 @@ int __init ima_init(void)if (rc !=0 )return rc; -ima_init_key_queue (); +ima_init_data_queue ();return rc; }
security/integrity/ima/ima_policy.c +1 -1
@@ -906,7 +906,7 @@ void ima_update_policy(void)ima_update_policy_flag ();/* Custom IMA policy has been loaded */ -ima_process_queued_keys (); +ima_process_queued_data (); }/* Keep the enumeration in sync with the policy_tokens! */
security/integrity/ima/ima_queue_data.c new file +179 -0
179 lines not on this page · raw message
security/integrity/ima/ima_queue_keys.c deleted +0 -175
175 lines not on this page · raw message
Signature · 1 line
2.28.0
PATCH v2 2/3 IMA: Support measurement of generic data during early boot
In reply to Lakshmi RamasubramanianEarly boot measurement of data is currently very specific to key measurement. To make it generic to handle any early boot data measurement, additional arguments need to be saved in the queue for deferred processing. This includes the IMA hook func, data specific to the given func, and a boolean flag to indicate whether the given payload needs to be measured or a hash of the payload needs to be measured.
Add new fields to ima_data_entry struct to pass additional data for the deferred handling of queued data. Update the queue functions to handle the new data saved in the ima_data_entry struct.
--- security/integrity/ima/ima.h | 11 ++++++-- security/integrity/ima/ima_asymmetric_keys.c | 3 ++- security/integrity/ima/ima_queue_data.c | 28 ++++++++++++++------ 3 files changed, 31 insertions(+), 11 deletions(-)
security/integrity/ima/ima.h +9 -2
@@ -266,18 +266,25 @@ struct ima_data_entry {void *payload;size_t payload_len;const char *event_name; +const char *event_data; +enum ima_hooks func; + bool measure_payload_hash; };void ima_init_data_queue (void );bool ima_should_queue_data (void );bool ima_queue_data (const char *event_name,const void *payload, -size_t payload_len); +size_t payload_len,const char *event_data, +enum ima_hooks func,bool measure_payload_hash);void ima_process_queued_data (void );#else static inline void ima_init_data_queue (void ) {}static inline bool ima_should_queue_data (void ) {return false; }static inline bool ima_queue_data (const char *event_name,const void *payload, -size_t payload_len) {return false; } +size_t payload_len, +const char *event_data, +enum ima_hooks func, +bool measure_payload_hash) {return false; }static inline void ima_process_queued_data (void ) {}#endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_DATA */
security/integrity/ima/ima_asymmetric_keys.c +2 -1
@@ -39,7 +39,8 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,if (ima_should_queue_data ()) queued =ima_queue_data (keyring->description, payload, - payload_len); + payload_len, keyring->description, +KEY_CHECK , false);if (queued)return ;
security/integrity/ima/ima_queue_data.c +20 -8
@@ -60,6 +60,7 @@ static void ima_free_data_entry(struct ima_data_entry *entry)kvfree (entry->payload);kfree (entry->event_name); +kfree (entry->event_data);kfree (entry); }
@@ -74,7 +75,10 @@ static void *ima_kvmemdup(const void *src, size_t len)static struct ima_data_entry *ima_alloc_data_entry (const char *event_name,const void *payload, -size_t payload_len) +size_t payload_len, +const char *event_data, +enum ima_hooks func, +bool measure_payload_hash) {struct ima_data_entry *entry;
@@ -88,9 +92,15 @@ static struct ima_data_entry *ima_alloc_data_entry(const char *event_name,*/ entry->payload =ima_kvmemdup (payload, payload_len); entry->event_name =kstrdup (event_name,GFP_KERNEL ); +if (event_data) + entry->event_data =kstrdup (event_data,GFP_KERNEL ); + entry->payload_len = payload_len; + entry->func = func; + entry->measure_payload_hash = measure_payload_hash; -if (!entry->payload || !entry->event_name) +if (!entry->payload || !entry->event_name || + (event_data && !entry->event_data)) goto out;INIT_LIST_HEAD (&entry->list);
@@ -98,19 +108,21 @@ static struct ima_data_entry *ima_alloc_data_entry(const char *event_name, out:integrity_audit_message (AUDIT_INTEGRITY_PCR ,NULL , - event_name,func_measure_str (KEY_CHECK ), + event_name,func_measure_str (func),"ENOMEM" , -ENOMEM ,0 , -ENOMEM );ima_free_data_entry (entry);return NULL ; }bool ima_queue_data (const char *event_name,const void *payload, -size_t payload_len) +size_t payload_len,const char *event_data, +enum ima_hooks func,bool measure_payload_hash) {bool queued = false;struct ima_data_entry *entry; - entry =ima_alloc_data_entry (event_name, payload, payload_len); + entry =ima_alloc_data_entry (event_name, payload, payload_len, + event_data, func, measure_payload_hash);if (!entry)return false;
@@ -165,9 +177,9 @@ void ima_process_queued_data(void)process_buffer_measurement (NULL , entry->payload, entry->payload_len, entry->event_name, -KEY_CHECK ,0 , - entry->event_name, - false); + entry->func,0 , + entry->event_data, + entry->measure_payload_hash);list_del (&entry->list);ima_free_data_entry (entry); }
Signature · 1 line
2.28.0
PATCH v2 3/3 IMA: Support early boot measurement of critical data
In reply to Lakshmi RamasubramanianThe IMA hook, namely ima_measure_critical_data(), to measure kernel critical data requires a custom IMA policy to be loaded.
Update ima_measure_critical_data() to utilize early boot measurement support to defer processing data if a custom IMA policy is not yet loaded.
--- security/integrity/ima/ima_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
security/integrity/ima/ima_main.c +10 -0
@@ -885,12 +885,22 @@ int ima_measure_critical_data(const char *event_name, const void *buf, int buf_len, bool measure_buf_hash) { + bool queued = false; +if (!event_name || !event_data_source || !buf || !buf_len)return -EINVAL ;if (!ima_kernel_data_source_is_supported (event_data_source))return -EPERM ; +if (ima_should_queue_data ()) + queued =ima_queue_data (event_name, buf, buf_len, + event_data_source,CRITICAL_DATA , + measure_buf_hash); + +if (queued) +return 0 ; +return process_buffer_measurement (NULL , buf, buf_len, event_name,CRITICAL_DATA ,0 , event_data_source, measure_buf_hash);
Signature · 1 line
2.28.0