diff options
Diffstat (limited to 'security/integrity/ima')
-rw-r--r-- | security/integrity/ima/Kconfig | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_audit.c | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 4 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 38 | ||||
-rw-r--r-- | security/integrity/ima/ima_iint.c | 6 | ||||
-rw-r--r-- | security/integrity/ima/ima_init.c | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 107 | ||||
-rw-r--r-- | security/integrity/ima/ima_queue.c | 4 |
10 files changed, 112 insertions, 60 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 3d7846de8069..b6ecfd4d8d78 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -2,15 +2,14 @@ # config IMA bool "Integrity Measurement Architecture(IMA)" - depends on ACPI depends on SECURITY select SECURITYFS select CRYPTO select CRYPTO_HMAC select CRYPTO_MD5 select CRYPTO_SHA1 - select TCG_TPM - select TCG_TIS + select TCG_TPM if !S390 + select TCG_TIS if TCG_TPM help The Trusted Computing Group(TCG) runtime Integrity Measurement Architecture(IMA) maintains a list of hash diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 47fb65d1fcbd..16d100d3fc38 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -135,7 +135,7 @@ enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); void ima_init_policy(void); void ima_update_policy(void); -int ima_parse_add_rule(char *); +ssize_t ima_parse_add_rule(char *); void ima_delete_rules(void); /* LSM based policy rules require audit */ diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index 5af76340470c..c5c5a72c30be 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c @@ -41,7 +41,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, return; ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); - audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u", + audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u", current->pid, current_cred()->uid, audit_get_loginuid(current), audit_get_sessionid(current)); diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 952e51373f58..9b3ade7468b2 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -27,7 +27,7 @@ static int init_desc(struct hash_desc *desc) desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(desc->tfm)) { - pr_info("failed to load %s transform: %ld\n", + pr_info("IMA: failed to load %s transform: %ld\n", ima_hash, PTR_ERR(desc->tfm)); rc = PTR_ERR(desc->tfm); return rc; @@ -112,7 +112,7 @@ static void __init ima_pcrread(int idx, u8 *pcr) return; if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) - pr_err("Error Communicating to TPM chip\n"); + pr_err("IMA: Error Communicating to TPM chip\n"); } /* diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 07cb9c338cc4..8fe736aabe71 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -244,32 +244,34 @@ static const struct file_operations ima_ascii_measurements_ops = { static ssize_t ima_write_policy(struct file *file, const char __user *buf, size_t datalen, loff_t *ppos) { - char *data; - int rc; + char *data = NULL; + ssize_t result; if (datalen >= PAGE_SIZE) - return -ENOMEM; - if (*ppos != 0) { - /* No partial writes. */ - return -EINVAL; - } + datalen = PAGE_SIZE - 1; + + /* No partial writes. */ + result = -EINVAL; + if (*ppos != 0) + goto out; + + result = -ENOMEM; data = kmalloc(datalen + 1, GFP_KERNEL); if (!data) - return -ENOMEM; + goto out; - if (copy_from_user(data, buf, datalen)) { - kfree(data); - return -EFAULT; - } *(data + datalen) = '\0'; - rc = ima_parse_add_rule(data); - if (rc < 0) { - datalen = -EINVAL; - valid_policy = 0; - } + result = -EFAULT; + if (copy_from_user(data, buf, datalen)) + goto out; + + result = ima_parse_add_rule(data); +out: + if (result < 0) + valid_policy = 0; kfree(data); - return datalen; + return result; } static struct dentry *ima_dir; diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index 2c744d488014..2dc2d6594145 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -80,17 +80,17 @@ void iint_free(struct kref *kref) iint->version = 0; iint->flags = 0UL; if (iint->readcount != 0) { - printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__, + printk(KERN_INFO "%s: readcount: %ld\n", __func__, iint->readcount); iint->readcount = 0; } if (iint->writecount != 0) { - printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__, + printk(KERN_INFO "%s: writecount: %ld\n", __func__, iint->writecount); iint->writecount = 0; } if (iint->opencount != 0) { - printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__, + printk(KERN_INFO "%s: opencount: %ld\n", __func__, iint->opencount); iint->opencount = 0; } diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index b1bcb702a27c..17f1f060306f 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -83,7 +83,7 @@ int __init ima_init(void) ima_used_chip = 1; if (!ima_used_chip) - pr_info("No TPM chip found, activating TPM-bypass!\n"); + pr_info("IMA: No TPM chip found, activating TPM-bypass!\n"); ima_add_boot_aggregate(); /* boot aggregate must be first entry */ ima_init_policy(); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index b2c89d9de2a4..f93641382e9f 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -195,7 +195,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, (iint->writecount < 0)) && !ima_limit_imbalance(file)) { printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", - __FUNCTION__, iint->readcount, iint->writecount, + __func__, iint->readcount, iint->writecount, iint->opencount); dump_stack(); } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 8643a93c5963..aef8c0a923ab 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -246,6 +246,9 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, { int result; + if (entry->lsm[lsm_rule].rule) + return -EINVAL; + entry->lsm[lsm_rule].type = audit_type; result = security_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal, args, @@ -253,6 +256,13 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, return result; } +static void ima_log_string(struct audit_buffer *ab, char *key, char *value) +{ + audit_log_format(ab, "%s=", key); + audit_log_untrustedstring(ab, value); + audit_log_format(ab, " "); +} + static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) { struct audit_buffer *ab; @@ -261,28 +271,41 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); - entry->action = -1; - while ((p = strsep(&rule, " \n")) != NULL) { + entry->uid = -1; + entry->action = UNKNOWN; + while ((p = strsep(&rule, " \t")) != NULL) { substring_t args[MAX_OPT_ARGS]; int token; unsigned long lnum; if (result < 0) break; - if (!*p) + if ((*p == '\0') || (*p == ' ') || (*p == '\t')) continue; token = match_token(p, policy_tokens, args); switch (token) { case Opt_measure: - audit_log_format(ab, "%s ", "measure"); + ima_log_string(ab, "action", "measure"); + + if (entry->action != UNKNOWN) + result = -EINVAL; + entry->action = MEASURE; break; case Opt_dont_measure: - audit_log_format(ab, "%s ", "dont_measure"); + ima_log_string(ab, "action", "dont_measure"); + + if (entry->action != UNKNOWN) + result = -EINVAL; + entry->action = DONT_MEASURE; break; case Opt_func: - audit_log_format(ab, "func=%s ", args[0].from); + ima_log_string(ab, "func", args[0].from); + + if (entry->func) + result = -EINVAL; + if (strcmp(args[0].from, "FILE_CHECK") == 0) entry->func = FILE_CHECK; /* PATH_CHECK is for backwards compat */ @@ -298,7 +321,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) entry->flags |= IMA_FUNC; break; case Opt_mask: - audit_log_format(ab, "mask=%s ", args[0].from); + ima_log_string(ab, "mask", args[0].from); + + if (entry->mask) + result = -EINVAL; + if ((strcmp(args[0].from, "MAY_EXEC")) == 0) entry->mask = MAY_EXEC; else if (strcmp(args[0].from, "MAY_WRITE") == 0) @@ -313,14 +340,26 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) entry->flags |= IMA_MASK; break; case Opt_fsmagic: - audit_log_format(ab, "fsmagic=%s ", args[0].from); + ima_log_string(ab, "fsmagic", args[0].from); + + if (entry->fsmagic) { + result = -EINVAL; + break; + } + result = strict_strtoul(args[0].from, 16, &entry->fsmagic); if (!result) entry->flags |= IMA_FSMAGIC; break; case Opt_uid: - audit_log_format(ab, "uid=%s ", args[0].from); + ima_log_string(ab, "uid", args[0].from); + + if (entry->uid != -1) { + result = -EINVAL; + break; + } + result = strict_strtoul(args[0].from, 10, &lnum); if (!result) { entry->uid = (uid_t) lnum; @@ -331,50 +370,51 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) } break; case Opt_obj_user: - audit_log_format(ab, "obj_user=%s ", args[0].from); + ima_log_string(ab, "obj_user", args[0].from); result = ima_lsm_rule_init(entry, args[0].from, LSM_OBJ_USER, AUDIT_OBJ_USER); break; case Opt_obj_role: - audit_log_format(ab, "obj_role=%s ", args[0].from); + ima_log_string(ab, "obj_role", args[0].from); result = ima_lsm_rule_init(entry, args[0].from, LSM_OBJ_ROLE, AUDIT_OBJ_ROLE); break; case Opt_obj_type: - audit_log_format(ab, "obj_type=%s ", args[0].from); + ima_log_string(ab, "obj_type", args[0].from); result = ima_lsm_rule_init(entry, args[0].from, LSM_OBJ_TYPE, AUDIT_OBJ_TYPE); break; case Opt_subj_user: - audit_log_format(ab, "subj_user=%s ", args[0].from); + ima_log_string(ab, "subj_user", args[0].from); result = ima_lsm_rule_init(entry, args[0].from, LSM_SUBJ_USER, AUDIT_SUBJ_USER); break; case Opt_subj_role: - audit_log_format(ab, "subj_role=%s ", args[0].from); + ima_log_string(ab, "subj_role", args[0].from); result = ima_lsm_rule_init(entry, args[0].from, LSM_SUBJ_ROLE, AUDIT_SUBJ_ROLE); break; case Opt_subj_type: - audit_log_format(ab, "subj_type=%s ", args[0].from); + ima_log_string(ab, "subj_type", args[0].from); result = ima_lsm_rule_init(entry, args[0].from, LSM_SUBJ_TYPE, AUDIT_SUBJ_TYPE); break; case Opt_err: - audit_log_format(ab, "UNKNOWN=%s ", p); + ima_log_string(ab, "UNKNOWN", p); + result = -EINVAL; break; } } - if (entry->action == UNKNOWN) + if (!result && (entry->action == UNKNOWN)) result = -EINVAL; - audit_log_format(ab, "res=%d", !result ? 0 : 1); + audit_log_format(ab, "res=%d", !!result); audit_log_end(ab); return result; } @@ -384,13 +424,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) * @rule - ima measurement policy rule * * Uses a mutex to protect the policy list from multiple concurrent writers. - * Returns 0 on success, an error code on failure. + * Returns the length of the rule parsed, an error code on failure */ -int ima_parse_add_rule(char *rule) +ssize_t ima_parse_add_rule(char *rule) { const char *op = "update_policy"; + char *p; struct ima_measure_rule_entry *entry; - int result = 0; + ssize_t result, len; int audit_info = 0; /* Prevent installed policy from changing */ @@ -410,18 +451,28 @@ int ima_parse_add_rule(char *rule) INIT_LIST_HEAD(&entry->list); - result = ima_parse_rule(rule, entry); - if (!result) { - mutex_lock(&ima_measure_mutex); - list_add_tail(&entry->list, &measure_policy_rules); - mutex_unlock(&ima_measure_mutex); - } else { + p = strsep(&rule, "\n"); + len = strlen(p) + 1; + + if (*p == '#') { + kfree(entry); + return len; + } + + result = ima_parse_rule(p, entry); + if (result) { kfree(entry); integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, op, "invalid policy", result, audit_info); + return result; } - return result; + + mutex_lock(&ima_measure_mutex); + list_add_tail(&entry->list, &measure_policy_rules); + mutex_unlock(&ima_measure_mutex); + + return len; } /* ima_delete_rules called to cleanup invalid policy */ diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 46ba62b1adf5..8e28f04a5e2e 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -71,7 +71,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry) qe = kmalloc(sizeof(*qe), GFP_KERNEL); if (qe == NULL) { - pr_err("OUT OF MEMORY ERROR creating queue entry.\n"); + pr_err("IMA: OUT OF MEMORY ERROR creating queue entry.\n"); return -ENOMEM; } qe->entry = entry; @@ -94,7 +94,7 @@ static int ima_pcr_extend(const u8 *hash) result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); if (result != 0) - pr_err("Error Communicating to TPM chip\n"); + pr_err("IMA: Error Communicating to TPM chip\n"); return result; } |