hulk inclusion category: feature feature: digest-lists
---------------------------
This patch adds the new policy keyword parser to measure and appraise any file opened by the user space parser, while the parser opened digest_list_data_add or digest_list_data_del securityfs interfaces.
This ensures that all files processed by the user space parser are processed without including the FILE_CHECK hook in the policy. With this keyword it would be possible to have a policy to measure/appraise only executable code and digest lists.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- security/integrity/ima/ima_appraise.c | 2 +- security/integrity/ima/ima_digest_list.c | 17 +++++++++++++ security/integrity/ima/ima_digest_list.h | 13 ++++++++++ security/integrity/ima/ima_fs.c | 15 ++++++++--- security/integrity/ima/ima_policy.c | 32 +++++++++++++++++++++++- 5 files changed, 73 insertions(+), 6 deletions(-)
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 78b7f2fcd7d8..52d2b3861b86 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -247,7 +247,7 @@ int ima_appraise_measurement(enum ima_hooks func, /* Allow access to digest lists without metadata, only if they * are signed or found in a digest list (immutable) */ - if (func == DIGEST_LIST_CHECK) { + if (func == DIGEST_LIST_CHECK || ima_current_is_parser()) { if (xattr_value->type == EVM_IMA_XATTR_DIGSIG) break; if (found_digest && diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c index fbcc3d8a58a6..11d00fe63ffb 100644 --- a/security/integrity/ima/ima_digest_list.c +++ b/security/integrity/ima/ima_digest_list.c @@ -361,3 +361,20 @@ bool ima_check_current_is_parser(void) return ima_lookup_digest(parser_iint->ima_hash->digest, parser_iint->ima_hash->algo, COMPACT_PARSER); } + +struct task_struct *parser_task; + +void ima_set_parser(void) +{ + parser_task = current; +} + +void ima_unset_parser(void) +{ + parser_task = NULL; +} + +bool ima_current_is_parser(void) +{ + return (current == parser_task); +} diff --git a/security/integrity/ima/ima_digest_list.h b/security/integrity/ima/ima_digest_list.h index f102530324a5..a47b2c6ee8de 100644 --- a/security/integrity/ima/ima_digest_list.h +++ b/security/integrity/ima/ima_digest_list.h @@ -25,6 +25,9 @@ extern struct ima_h_table ima_digests_htable; int ima_parse_compact_list(loff_t size, void *buf, int op); void ima_check_measured_appraised(struct file *file); bool ima_check_current_is_parser(void); +void ima_set_parser(void); +void ima_unset_parser(void); +bool ima_current_is_parser(void); #else static inline int ima_parse_compact_list(loff_t size, void *buf, int op) { @@ -37,5 +40,15 @@ static inline bool ima_check_current_is_parser(void) { return false; } +static inline void ima_set_parser(void) +{ +} +static inline void ima_unset_parser(void) +{ +} +static inline bool ima_current_is_parser(void) +{ + return false; +} #endif /*CONFIG_IMA_DIGEST_LIST*/ #endif /*LINUX_IMA_DIGEST_LIST_H*/ diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 804e7183a908..8c28ff907aa7 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -393,17 +393,21 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf, result = ima_parse_add_rule(data); } } else if (dentry == digest_list_data) { - if (!ima_check_current_is_parser()) + if (!ima_check_current_is_parser()) { result = -EACCES; - else + } else { + ima_set_parser(); result = ima_parse_compact_list(datalen, data, DIGEST_LIST_OP_ADD); + } } else if (dentry == digest_list_data_del) { - if (!ima_check_current_is_parser()) + if (!ima_check_current_is_parser()) { result = -EACCES; - else + } else { + ima_set_parser(); result = ima_parse_compact_list(datalen, data, DIGEST_LIST_OP_DEL); + } } else { pr_err("Unknown data type\n"); result = -EINVAL; @@ -494,6 +498,9 @@ static int ima_release_data_upload(struct inode *inode, struct file *file) if ((file->f_flags & O_ACCMODE) == O_RDONLY) return seq_release(inode, file);
+ if (dentry == digest_list_data || dentry == digest_list_data_del) + ima_unset_parser(); + if (dentry != ima_policy) { clear_bit(flag, &ima_fs_flags); return 0; diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index fa5ce0de932b..c5b6d11e534f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -22,6 +22,7 @@ #include <linux/seq_file.h>
#include "ima.h" +#include "ima_digest_list.h"
/* flags definitions */ #define IMA_FUNC 0x0001 @@ -34,6 +35,7 @@ #define IMA_EUID 0x0080 #define IMA_PCR 0x0100 #define IMA_FSNAME 0x0200 +#define IMA_PARSER 0x0400
#define UNKNOWN 0 #define MEASURE 0x0001 /* same as IMA_MEASURE */ @@ -136,6 +138,10 @@ static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { {.action = MEASURE, .func = DIGEST_LIST_CHECK, .flags = IMA_FUNC}, };
+static struct ima_rule_entry ima_parser_measure_rule __ro_after_init = { + .action = MEASURE, .flags = IMA_PARSER +}; + static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, @@ -203,6 +209,11 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, };
+static struct ima_rule_entry ima_parser_appraise_rule __ro_after_init = { + .action = APPRAISE, + .flags = IMA_PARSER | IMA_DIGSIG_REQUIRED +}; + static LIST_HEAD(ima_default_rules); static LIST_HEAD(ima_policy_rules); static LIST_HEAD(ima_temp_rules); @@ -334,6 +345,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, if ((rule->flags & IMA_FOWNER) && !rule->fowner_op(inode->i_uid, rule->fowner)) return false; + if ((rule->flags & IMA_PARSER) && + !ima_current_is_parser()) + return false; for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; u32 osid; @@ -546,6 +560,10 @@ void __init ima_init_policy(void) break; }
+ if (ima_policy) + list_add_tail(&ima_parser_measure_rule.list, + &ima_default_rules); + /* * Insert the builtin "secure_boot" policy rules requiring file * signatures, prior to any other appraise rules. @@ -599,6 +617,11 @@ void __init ima_init_policy(void) &ima_default_rules); }
+ if (ima_use_secure_boot || ima_use_appraise_tcb || + ima_use_appraise_exec_tcb) + list_add_tail(&ima_parser_appraise_rule.list, + &ima_default_rules); + ima_update_policy_flag(); }
@@ -646,7 +669,7 @@ enum { Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, Opt_appraise_type, Opt_permit_directio, - Opt_pcr + Opt_pcr, Opt_parser };
static match_table_t policy_tokens = { @@ -680,6 +703,7 @@ static match_table_t policy_tokens = { {Opt_appraise_type, "appraise_type=%s"}, {Opt_permit_directio, "permit_directio"}, {Opt_pcr, "pcr=%s"}, + {Opt_parser, "parser"}, {Opt_err, NULL} };
@@ -1029,6 +1053,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) else entry->flags |= IMA_PCR;
+ break; + case Opt_parser: + entry->flags |= IMA_PARSER; break; case Opt_err: ima_log_string(ab, "UNKNOWN", p); @@ -1275,6 +1302,9 @@ int ima_policy_show(struct seq_file *m, void *v) seq_puts(m, " "); }
+ if (entry->flags & IMA_PARSER) + seq_puts(m, "parser "); + for (i = 0; i < MAX_LSM_RULES; i++) { if (entry->lsm[i].rule) { switch (i) {