From: Matthew G. <mj...@go...> - 2017-08-29 19:41:22
|
Right now IMA BPRM validation is performed after setup_creds() but before commit_creds(), which means current->cred still refers to the fork()ing task rather than the child. This makes it difficult to implement appraisal rules that depend on the security context that the task will be transitioned to. Passing through bprm to the policy matching allows us to do so. Signed-off-by: Matthew Garrett <mj...@go...> -- Does this seem reasonable? I thought about adding an additional match type (BPRM_LATE or something) but this seems like a simpler approach. --- security/integrity/ima/ima.h | 6 +++--- security/integrity/ima/ima_api.c | 6 ++++-- security/integrity/ima/ima_appraise.c | 2 +- security/integrity/ima/ima_main.c | 15 ++++++++------- security/integrity/ima/ima_policy.c | 11 +++++++---- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index d52b487ad259..695614d85201 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -191,7 +191,7 @@ enum ima_hooks { }; /* LIM API function definitions */ -int ima_get_action(struct inode *inode, int mask, +int ima_get_action(struct linux_binprm *bprm, struct inode *inode, int mask, enum ima_hooks func, int *pcr); int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_collect_measurement(struct integrity_iint_cache *iint, @@ -212,8 +212,8 @@ void ima_free_template_entry(struct ima_template_entry *entry); const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); /* IMA policy related functions */ -int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, - int flags, int *pcr); +int ima_match_policy(struct linux_binprm *bprm, struct inode *inode, + enum ima_hooks func, int mask, int flags, int *pcr); void ima_init_policy(void); void ima_update_policy(void); void ima_update_policy_flag(void); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c2edba8de35e..1c1a1ffee398 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -156,6 +156,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, /** * ima_get_action - appraise & measure decision based on policy. + * @bprm: pointer to the BPRM struct to be validated * @inode: pointer to inode to measure * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC, * MAY_APPEND) @@ -172,13 +173,14 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * Returns IMA_MEASURE, IMA_APPRAISE mask. * */ -int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr) +int ima_get_action(struct linux_binprm *bprm, struct inode *inode, int mask, + enum ima_hooks func, int *pcr) { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; flags &= ima_policy_flag; - return ima_match_policy(inode, func, mask, flags, pcr); + return ima_match_policy(bprm, inode, func, mask, flags, pcr); } /* diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 809ba70fbbbf..bcd956fc4a04 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -53,7 +53,7 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) if (!ima_appraise) return 0; - return ima_match_policy(inode, func, mask, IMA_APPRAISE, NULL); + return ima_match_policy(NULL, inode, func, mask, IMA_APPRAISE, NULL); } static int ima_fix_xattr(struct dentry *dentry, diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 2aebb7984437..4b1f2630b736 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -155,8 +155,9 @@ void ima_file_free(struct file *file) ima_check_last_writer(iint, inode, file); } -static int process_measurement(struct file *file, char *buf, loff_t size, - int mask, enum ima_hooks func, int opened) +static int process_measurement(struct linux_binprm *bprm, struct file *file, + char *buf, loff_t size, int mask, + enum ima_hooks func, int opened) { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; @@ -178,7 +179,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size, * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ - action = ima_get_action(inode, mask, func, &pcr); + action = ima_get_action(bprm, inode, mask, func, &pcr); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) && (ima_policy_flag & IMA_MEASURE)); if (!action && !violation_check) @@ -282,7 +283,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size, int ima_file_mmap(struct file *file, unsigned long prot) { if (file && (prot & PROT_EXEC)) - return process_measurement(file, NULL, 0, MAY_EXEC, + return process_measurement(NULL, file, NULL, 0, MAY_EXEC, MMAP_CHECK, 0); return 0; } @@ -302,7 +303,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) */ int ima_bprm_check(struct linux_binprm *bprm) { - return process_measurement(bprm->file, NULL, 0, MAY_EXEC, + return process_measurement(bprm, bprm->file, NULL, 0, MAY_EXEC, BPRM_CHECK, 0); } @@ -318,7 +319,7 @@ int ima_bprm_check(struct linux_binprm *bprm) */ int ima_file_check(struct file *file, int mask, int opened) { - return process_measurement(file, NULL, 0, + return process_measurement(NULL, file, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK, opened); } @@ -413,7 +414,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, } func = read_idmap[read_id] ?: FILE_CHECK; - return process_measurement(file, buf, size, MAY_READ, func, 0); + return process_measurement(NULL, file, buf, size, MAY_READ, func, 0); } static int __init init_ima(void) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 95209a5f8595..93f6af4e3a20 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -240,13 +240,15 @@ static void ima_lsm_update_rules(void) /** * ima_match_rules - determine whether an inode matches the measure rule. * @rule: a pointer to a rule + * @bprm: a pointer to a binprm structure * @inode: a pointer to an inode * @func: LIM hook identifier * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) * * Returns true on rule match, false on failure. */ -static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, +static bool ima_match_rules(struct ima_rule_entry *rule, + struct linux_binprm *bprm, struct inode *inode, enum ima_hooks func, int mask) { struct task_struct *tsk = current; @@ -350,6 +352,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) /** * ima_match_policy - decision based on LSM and other conditions + * @bprm: pointer to a binprm for which the policy decision is being made * @inode: pointer to an inode for which the policy decision is being made * @func: IMA hook identifier * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) @@ -362,8 +365,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * list when walking it. Reads are many orders of magnitude more numerous * than writes so ima_match_policy() is classical RCU candidate. */ -int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, - int flags, int *pcr) +int ima_match_policy(struct linux_binprm *bprm, struct inode *inode, + enum ima_hooks func, int mask, int flags, int *pcr) { struct ima_rule_entry *entry; int action = 0, actmask = flags | (flags << 1); @@ -374,7 +377,7 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, if (!(entry->action & actmask)) continue; - if (!ima_match_rules(entry, inode, func, mask)) + if (!ima_match_rules(entry, bprm, inode, func, mask)) continue; action |= entry->flags & IMA_ACTION_FLAGS; -- 2.14.1.342.g6490525c54-goog |