Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ima: Attach CREDS_CHECK IMA hook to bprm_creds_from_file LSM hook

Since commit 56305aa9b6fa ("exec: Compute file based creds only once"), the
credentials to be applied to the process after execution are not calculated
anymore for each step of finding intermediate interpreters (including the
final binary), but only after the final binary to be executed without
interpreter has been found.

In particular, that means that the bprm_check_security LSM hook will not
see the updated cred->e[ug]id for the intermediate and for the final binary
to be executed, since the function doing this task has been moved from
prepare_binprm(), which calls the bprm_check_security hook, to
bprm_creds_from_file().

This breaks the IMA expectation for the CREDS_CHECK hook, introduced with
commit d906c10d8a31 ("IMA: Support using new creds in appraisal policy"),
which expects to evaluate "the credentials that will be committed when the
new process is started". This is clearly not the case for the CREDS_CHECK
IMA hook, which is attached to bprm_check_security.

This issue does not affect systems which load a policy with the BPRM_CHECK
hook with no other criteria, as is the case with the built-in "tcb" and/or
"appraise_tcb" IMA policies. The "tcb" built-in policy measures all
executions regardless of the new credentials, and the "appraise_tcb" policy
is written in terms of the file owner, rather than IMA hooks.

However, it does affect systems without a BPRM_CHECK policy rule or with a
BPRM_CHECK policy rule that does not include what CREDS_CHECK evaluates. As
an extreme example, taking a standalone rule like:

measure func=CREDS_CHECK euid=0

This will not measure for example sudo (because CREDS_CHECK still sees the
bprm->cred->euid set to the regular user UID), but only the subsequent
commands after the euid was applied to the children.

Make set[ug]id programs measured/appraised again by splitting
ima_bprm_check() in two separate hook implementations (CREDS_CHECK now
being implemented by ima_creds_check()), and by attaching CREDS_CHECK to
the bprm_creds_from_file LSM hook.

The limitation of this approach is that CREDS_CHECK will not be invoked
anymore for the intermediate interpreters, like it was before, but only for
the final binary. This limitation can be removed only by reverting commit
56305aa9b6fa ("exec: Compute file based creds only once").

Link: https://github.com/linux-integrity/linux/issues/3
Fixes: 56305aa9b6fa ("exec: Compute file based creds only once")
Cc: Serge E. Hallyn <serge@hallyn.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Jann Horn <jannh@google.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>

authored by

Roberto Sassu and committed by
Mimi Zohar
8f3fc4f3 3a866087

+32 -8
+32 -8
security/integrity/ima/ima_main.c
··· 573 573 */ 574 574 static int ima_bprm_check(struct linux_binprm *bprm) 575 575 { 576 - int ret; 577 576 struct lsm_prop prop; 578 577 579 578 security_current_getlsmprop_subj(&prop); 580 - ret = process_measurement(bprm->file, current_cred(), 581 - &prop, NULL, 0, MAY_EXEC, BPRM_CHECK); 582 - if (ret) 583 - return ret; 579 + return process_measurement(bprm->file, current_cred(), 580 + &prop, NULL, 0, MAY_EXEC, BPRM_CHECK); 581 + } 584 582 585 - security_cred_getlsmprop(bprm->cred, &prop); 586 - return process_measurement(bprm->file, bprm->cred, &prop, NULL, 0, 587 - MAY_EXEC, CREDS_CHECK); 583 + /** 584 + * ima_creds_check - based on policy, collect/store measurement. 585 + * @bprm: contains the linux_binprm structure 586 + * @file: contains the file descriptor of the binary being executed 587 + * 588 + * The OS protects against an executable file, already open for write, 589 + * from being executed in deny_write_access() and an executable file, 590 + * already open for execute, from being modified in get_write_access(). 591 + * So we can be certain that what we verify and measure here is actually 592 + * what is being executed. 593 + * 594 + * The difference from ima_bprm_check() is that ima_creds_check() is invoked 595 + * only after determining the final binary to be executed without interpreter, 596 + * and not when searching for intermediate binaries. The reason is that since 597 + * commit 56305aa9b6fab ("exec: Compute file based creds only once"), the 598 + * credentials to be applied to the process are calculated only at that stage 599 + * (bprm_creds_from_file security hook instead of bprm_check_security). 600 + * 601 + * On success return 0. On integrity appraisal error, assuming the file 602 + * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. 603 + */ 604 + static int ima_creds_check(struct linux_binprm *bprm, const struct file *file) 605 + { 606 + struct lsm_prop prop; 607 + 608 + security_current_getlsmprop_subj(&prop); 609 + return process_measurement((struct file *)file, bprm->cred, &prop, NULL, 610 + 0, MAY_EXEC, CREDS_CHECK); 588 611 } 589 612 590 613 /** ··· 1265 1242 static struct security_hook_list ima_hooks[] __ro_after_init = { 1266 1243 LSM_HOOK_INIT(bprm_check_security, ima_bprm_check), 1267 1244 LSM_HOOK_INIT(bprm_creds_for_exec, ima_bprm_creds_for_exec), 1245 + LSM_HOOK_INIT(bprm_creds_from_file, ima_creds_check), 1268 1246 LSM_HOOK_INIT(file_post_open, ima_file_check), 1269 1247 LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile), 1270 1248 LSM_HOOK_INIT(file_release, ima_file_free),