From: Mimi Z. <zo...@li...> - 2017-08-31 14:01:09
|
On Tue, 2017-08-29 at 11:42 -0700, Matthew Garrett wrote: > 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. There are other LSM hooks in fs/exec.c. Instead of you modifying process_measurements(), could you defer the policy check until after the commit_creds? We could define the corresponding IMA hook. Mimi > 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; |