From 2b4a2474a2027eb683bc421eff286fc617ce1d82 Mon Sep 17 00:00:00 2001 From: Tushar Sugandhi Date: Thu, 7 Jan 2021 20:07:01 -0800 Subject: IMA: generalize keyring specific measurement constructs IMA functions such as ima_match_keyring(), process_buffer_measurement(), ima_match_policy() etc. handle data specific to keyrings. Currently, these constructs are not generic to handle any func specific data. This makes it harder to extend them without code duplication. Refactor the keyring specific measurement constructs to be generic and reusable in other measurement scenarios. Signed-off-by: Tushar Sugandhi Reviewed-by: Tyler Hicks Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'security/integrity/ima/ima_main.c') diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f87cb29329e9..0c645699c7fb 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -816,13 +816,13 @@ int ima_post_load_data(char *buf, loff_t size, * @eventname: event name to be used for the buffer entry. * @func: IMA hook * @pcr: pcr to extend the measurement - * @keyring: keyring name to determine the action to be performed + * @func_data: func specific data, may be NULL * * Based on policy, the buffer is measured into the ima log. */ void process_buffer_measurement(struct inode *inode, const void *buf, int size, const char *eventname, enum ima_hooks func, - int pcr, const char *keyring) + int pcr, const char *func_data) { int ret = 0; const char *audit_cause = "ENOMEM"; @@ -861,7 +861,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size, if (func) { security_task_getsecid(current, &secid); action = ima_get_action(inode, current_cred(), secid, 0, func, - &pcr, &template, keyring); + &pcr, &template, func_data); if (!(action & IMA_MEASURE)) return; } -- cgit v1.2.3 From 291af651b350817f7f1cbe308faaf7fa7af2a92c Mon Sep 17 00:00:00 2001 From: Tushar Sugandhi Date: Thu, 7 Jan 2021 20:07:02 -0800 Subject: IMA: add support to measure buffer data hash The original IMA buffer data measurement sizes were small (e.g. boot command line), but the new buffer data measurement use cases have data sizes that are a lot larger. Just as IMA measures the file data hash, not the file data, IMA should similarly support the option for measuring buffer data hash. Introduce a boolean parameter to support measuring buffer data hash, which would be much smaller, instead of the buffer itself. Signed-off-by: Tushar Sugandhi Reviewed-by: Tyler Hicks Signed-off-by: Mimi Zohar --- security/integrity/ima/ima.h | 3 ++- security/integrity/ima/ima_appraise.c | 2 +- security/integrity/ima/ima_asymmetric_keys.c | 2 +- security/integrity/ima/ima_main.c | 29 +++++++++++++++++++++++----- security/integrity/ima/ima_queue_keys.c | 3 ++- 5 files changed, 30 insertions(+), 9 deletions(-) (limited to 'security/integrity/ima/ima_main.c') diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e5622ce8cbb1..0b4634515839 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -268,7 +268,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, struct ima_template_desc *template_desc); void process_buffer_measurement(struct inode *inode, const void *buf, int size, const char *eventname, enum ima_hooks func, - int pcr, const char *func_data); + int pcr, const char *func_data, + bool buf_hash); void ima_audit_measurement(struct integrity_iint_cache *iint, const unsigned char *filename); int ima_alloc_init_template(struct ima_event_data *event_data, diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 8361941ee0a1..46ffa38bab12 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -352,7 +352,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, if ((rc == -EPERM) && (iint->flags & IMA_MEASURE)) process_buffer_measurement(NULL, digest, digestsize, "blacklisted-hash", NONE, - pcr, NULL); + pcr, NULL, false); } return rc; diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c index 1c68c500c26f..a74095793936 100644 --- a/security/integrity/ima/ima_asymmetric_keys.c +++ b/security/integrity/ima/ima_asymmetric_keys.c @@ -60,5 +60,5 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, */ process_buffer_measurement(NULL, payload, payload_len, keyring->description, KEY_CHECK, 0, - keyring->description); + keyring->description, false); } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 0c645699c7fb..250e52114230 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -809,7 +809,7 @@ int ima_post_load_data(char *buf, loff_t size, } /* - * process_buffer_measurement - Measure the buffer to ima log. + * process_buffer_measurement - Measure the buffer or the buffer data hash * @inode: inode associated with the object being measured (NULL for KEY_CHECK) * @buf: pointer to the buffer that needs to be added to the log. * @size: size of buffer(in bytes). @@ -817,12 +817,14 @@ int ima_post_load_data(char *buf, loff_t size, * @func: IMA hook * @pcr: pcr to extend the measurement * @func_data: func specific data, may be NULL + * @buf_hash: measure buffer data hash * - * Based on policy, the buffer is measured into the ima log. + * Based on policy, either the buffer data or buffer data hash is measured */ void process_buffer_measurement(struct inode *inode, const void *buf, int size, const char *eventname, enum ima_hooks func, - int pcr, const char *func_data) + int pcr, const char *func_data, + bool buf_hash) { int ret = 0; const char *audit_cause = "ENOMEM"; @@ -837,6 +839,8 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size, struct ima_digest_data hdr; char digest[IMA_MAX_DIGEST_SIZE]; } hash = {}; + char digest_hash[IMA_MAX_DIGEST_SIZE]; + int digest_hash_len = hash_digest_size[ima_hash_algo]; int violation = 0; int action = 0; u32 secid; @@ -879,13 +883,27 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size, goto out; } + if (buf_hash) { + memcpy(digest_hash, hash.hdr.digest, digest_hash_len); + + ret = ima_calc_buffer_hash(digest_hash, digest_hash_len, + iint.ima_hash); + if (ret < 0) { + audit_cause = "hashing_error"; + goto out; + } + + event_data.buf = digest_hash; + event_data.buf_len = digest_hash_len; + } + ret = ima_alloc_init_template(&event_data, &entry, template); if (ret < 0) { audit_cause = "alloc_entry"; goto out; } - ret = ima_store_template(entry, violation, NULL, buf, pcr); + ret = ima_store_template(entry, violation, NULL, event_data.buf, pcr); if (ret < 0) { audit_cause = "store_entry"; ima_free_template_entry(entry); @@ -920,7 +938,8 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) return; process_buffer_measurement(file_inode(f.file), buf, size, - "kexec-cmdline", KEXEC_CMDLINE, 0, NULL); + "kexec-cmdline", KEXEC_CMDLINE, 0, NULL, + false); fdput(f); } diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c index 69a8626a35c0..c2f2ad34f9b7 100644 --- a/security/integrity/ima/ima_queue_keys.c +++ b/security/integrity/ima/ima_queue_keys.c @@ -162,7 +162,8 @@ void ima_process_queued_keys(void) entry->payload_len, entry->keyring_name, KEY_CHECK, 0, - entry->keyring_name); + entry->keyring_name, + false); list_del(&entry->list); ima_free_key_entry(entry); } -- cgit v1.2.3 From d6e645012d97164609260ac567b304681734c5e2 Mon Sep 17 00:00:00 2001 From: Tushar Sugandhi Date: Thu, 7 Jan 2021 20:07:03 -0800 Subject: IMA: define a hook to measure kernel integrity critical data IMA provides capabilities to measure file and buffer data. However, various data structures, policies, and states stored in kernel memory also impact the integrity of the system. Several kernel subsystems contain such integrity critical data. These kernel subsystems help protect the integrity of the system. Currently, IMA does not provide a generic function for measuring kernel integrity critical data. Define ima_measure_critical_data, a new IMA hook, to measure kernel integrity critical data. Signed-off-by: Tushar Sugandhi Reviewed-by: Tyler Hicks Signed-off-by: Mimi Zohar --- include/linux/ima.h | 7 +++++++ security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_api.c | 2 +- security/integrity/ima/ima_main.c | 24 ++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) (limited to 'security/integrity/ima/ima_main.c') diff --git a/include/linux/ima.h b/include/linux/ima.h index 7db9cca1af34..59bd90ac3c35 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -31,6 +31,9 @@ extern void ima_post_path_mknod(struct dentry *dentry); extern int ima_file_hash(struct file *file, char *buf, size_t buf_size); extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size); extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size); +extern void ima_measure_critical_data(const char *event_name, + const void *buf, size_t buf_len, + bool hash); #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM extern void ima_appraise_parse_cmdline(void); @@ -128,6 +131,10 @@ static inline int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size } static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {} + +static inline void ima_measure_critical_data(const char *event_name, + const void *buf, size_t buf_len, + bool hash) {} #endif /* CONFIG_IMA */ #ifndef CONFIG_IMA_KEXEC diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 0b4634515839..aa312472c7c5 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -201,6 +201,7 @@ static inline unsigned int ima_hash_key(u8 *digest) hook(POLICY_CHECK, policy) \ hook(KEXEC_CMDLINE, kexec_cmdline) \ hook(KEY_CHECK, key) \ + hook(CRITICAL_DATA, critical_data) \ hook(MAX_CHECK, none) #define __ima_hook_enumify(ENUM, str) ENUM, diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index e76499b1ce78..1dd70dc68ffd 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -176,7 +176,7 @@ err_out: * subj=, obj=, type=, func=, mask=, fsmagic= * subj,obj, and type: are LSM specific. * func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK - * | KEXEC_CMDLINE | KEY_CHECK + * | KEXEC_CMDLINE | KEY_CHECK | CRITICAL_DATA * mask: contains the permission mask * fsmagic: hex value * diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 250e52114230..251e7b4006f4 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -943,6 +943,30 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) fdput(f); } +/** + * ima_measure_critical_data - measure kernel integrity critical data + * @event_name: event name for the record in the IMA measurement list + * @buf: pointer to buffer data + * @buf_len: length of buffer data (in bytes) + * @hash: measure buffer data hash + * + * Measure data critical to the integrity of the kernel into the IMA log + * and extend the pcr. Examples of critical data could be various data + * structures, policies, and states stored in kernel memory that can + * impact the integrity of the system. + */ +void ima_measure_critical_data(const char *event_name, + const void *buf, size_t buf_len, + bool hash) +{ + if (!event_name || !buf || !buf_len) + return; + + process_buffer_measurement(NULL, buf, buf_len, event_name, + CRITICAL_DATA, 0, NULL, + hash); +} + static int __init init_ima(void) { int error; -- cgit v1.2.3 From 9f5d7d23cc5ec61a92076b73665fcb9aaa5bb5a0 Mon Sep 17 00:00:00 2001 From: Tushar Sugandhi Date: Thu, 7 Jan 2021 20:07:06 -0800 Subject: IMA: extend critical data hook to limit the measurement based on a label The IMA hook ima_measure_critical_data() does not support a way to specify the source of the critical data provider. Thus, the data measurement cannot be constrained based on the data source label in the IMA policy. Extend the IMA hook ima_measure_critical_data() to support passing the data source label as an input parameter, so that the policy rule can be used to limit the measurements based on the label. Signed-off-by: Tushar Sugandhi Reviewed-by: Tyler Hicks Signed-off-by: Mimi Zohar --- include/linux/ima.h | 7 +++++-- security/integrity/ima/ima_main.c | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'security/integrity/ima/ima_main.c') diff --git a/include/linux/ima.h b/include/linux/ima.h index 59bd90ac3c35..2ac834badbbe 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -31,7 +31,8 @@ extern void ima_post_path_mknod(struct dentry *dentry); extern int ima_file_hash(struct file *file, char *buf, size_t buf_size); extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size); extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size); -extern void ima_measure_critical_data(const char *event_name, +extern void ima_measure_critical_data(const char *event_label, + const char *event_name, const void *buf, size_t buf_len, bool hash); @@ -132,9 +133,11 @@ static inline int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {} -static inline void ima_measure_critical_data(const char *event_name, +static inline void ima_measure_critical_data(const char *event_label, + const char *event_name, const void *buf, size_t buf_len, bool hash) {} + #endif /* CONFIG_IMA */ #ifndef CONFIG_IMA_KEXEC diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 251e7b4006f4..6a429846f90a 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -945,6 +945,7 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) /** * ima_measure_critical_data - measure kernel integrity critical data + * @event_label: unique event label for grouping and limiting critical data * @event_name: event name for the record in the IMA measurement list * @buf: pointer to buffer data * @buf_len: length of buffer data (in bytes) @@ -955,15 +956,16 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) * structures, policies, and states stored in kernel memory that can * impact the integrity of the system. */ -void ima_measure_critical_data(const char *event_name, +void ima_measure_critical_data(const char *event_label, + const char *event_name, const void *buf, size_t buf_len, bool hash) { - if (!event_name || !buf || !buf_len) + if (!event_name || !event_label || !buf || !buf_len) return; process_buffer_measurement(NULL, buf, buf_len, event_name, - CRITICAL_DATA, 0, NULL, + CRITICAL_DATA, 0, event_label, hash); } -- cgit v1.2.3