@@ -25,7 +25,7 @@ Description:
[obj_user=] [obj_role=] [obj_type=]]
option: [[appraise_type=]] [permit_directio]
- base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
+ base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
[FIRMWARE_CHECK]
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
@@ -312,7 +312,9 @@ static int load_aout_binary(struct linux_binprm *bprm)
if (retval < 0)
return retval;
- install_exec_creds(bprm);
+ retval = install_exec_creds(bprm);
+ if (retval)
+ return retval;
if (N_MAGIC(ex) == OMAGIC) {
unsigned long text_addr, map_size;
@@ -256,7 +256,9 @@ static int load_aout_binary(struct linux_binprm * bprm)
if (retval < 0)
return retval;
- install_exec_creds(bprm);
+ retval = install_exec_creds(bprm);
+ if (retval)
+ return retval;
if (N_MAGIC(ex) == OMAGIC) {
unsigned long text_addr, map_size;
@@ -866,7 +866,10 @@ static int load_elf_binary(struct linux_binprm *bprm)
current->flags |= PF_RANDOMIZE;
setup_new_exec(bprm);
- install_exec_creds(bprm);
+
+ retval = install_exec_creds(bprm);
+ if (retval)
+ goto out_free_dentry;
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
@@ -433,7 +433,10 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
current->mm->start_stack = current->mm->start_brk + stack_size;
#endif
- install_exec_creds(bprm);
+ retval = install_exec_creds(bprm);
+ if (retval)
+ goto error;
+
if (create_elf_fdpic_tables(bprm, current->mm,
&exec_params, &interp_params) < 0)
goto error;
@@ -948,7 +948,9 @@ static int load_flat_binary(struct linux_binprm *bprm)
}
}
- install_exec_creds(bprm);
+ retval = install_exec_creds(bprm);
+ if (retval)
+ return retval;
set_binfmt(&flat_format);
@@ -1425,8 +1425,10 @@ EXPORT_SYMBOL(bprm_change_interp);
/*
* install the new credentials for this executable
*/
-void install_exec_creds(struct linux_binprm *bprm)
+int install_exec_creds(struct linux_binprm *bprm)
{
+ int ret = 0;
+
security_bprm_committing_creds(bprm);
commit_creds(bprm->cred);
@@ -1445,8 +1447,10 @@ void install_exec_creds(struct linux_binprm *bprm)
* ptrace_attach() from altering our determination of the task's
* credentials; any time after this it may be unlocked.
*/
- security_bprm_committed_creds(bprm);
+ ret = security_bprm_committed_creds(bprm);
mutex_unlock(¤t->signal->cred_guard_mutex);
+
+ return ret;
}
EXPORT_SYMBOL(install_exec_creds);
@@ -135,7 +135,7 @@ extern int bprm_change_interp(const char *interp, struct linux_binprm *bprm);
extern int copy_strings_kernel(int argc, const char *const *argv,
struct linux_binprm *bprm);
extern int prepare_bprm_creds(struct linux_binprm *bprm);
-extern void install_exec_creds(struct linux_binprm *bprm);
+extern int install_exec_creds(struct linux_binprm *bprm);
extern void set_binfmt(struct linux_binfmt *new);
extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t);
@@ -16,6 +16,7 @@ struct linux_binprm;
#ifdef CONFIG_IMA
extern int ima_bprm_check(struct linux_binprm *bprm);
+extern int ima_creds_check(struct linux_binprm *bprm);
extern int ima_file_check(struct file *file, int mask, int opened);
extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot);
@@ -34,6 +35,11 @@ static inline int ima_bprm_check(struct linux_binprm *bprm)
return 0;
}
+static inline int ima_creds_check(struct linux_binprm *bprm)
+{
+ return 0;
+}
+
static inline int ima_file_check(struct file *file, int mask, int opened)
{
return 0;
@@ -232,7 +232,7 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
int security_bprm_set_creds(struct linux_binprm *bprm);
int security_bprm_check(struct linux_binprm *bprm);
void security_bprm_committing_creds(struct linux_binprm *bprm);
-void security_bprm_committed_creds(struct linux_binprm *bprm);
+int security_bprm_committed_creds(struct linux_binprm *bprm);
int security_sb_alloc(struct super_block *sb);
void security_sb_free(struct super_block *sb);
int security_sb_copy_data(char *orig, char *copy);
@@ -536,8 +536,9 @@ static inline void security_bprm_committing_creds(struct linux_binprm *bprm)
{
}
-static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
+static inline int security_bprm_committed_creds(struct linux_binprm *bprm)
{
+ return 0;
}
static inline int security_sb_alloc(struct super_block *sb)
@@ -78,6 +78,7 @@ static void iint_free(struct integrity_iint_cache *iint)
iint->ima_mmap_status = INTEGRITY_UNKNOWN;
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
iint->ima_read_status = INTEGRITY_UNKNOWN;
+ iint->ima_creds_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
iint->measured_pcrs = 0;
kmem_cache_free(iint_cache, iint);
@@ -177,6 +177,7 @@ static inline unsigned long ima_hash_key(u8 *digest)
hook(FILE_CHECK) \
hook(MMAP_CHECK) \
hook(BPRM_CHECK) \
+ hook(CREDS_CHECK) \
hook(POST_SETATTR) \
hook(MODULE_CHECK) \
hook(FIRMWARE_CHECK) \
@@ -165,7 +165,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic=
* subj,obj, and type: are LSM specific.
- * func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK
+ * func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
* mask: contains the permission mask
* fsmagic: hex value
*
@@ -86,6 +86,8 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
return iint->ima_mmap_status;
case BPRM_CHECK:
return iint->ima_bprm_status;
+ case CREDS_CHECK:
+ return iint->ima_creds_status;
case FILE_CHECK:
case POST_SETATTR:
return iint->ima_file_status;
@@ -106,6 +108,9 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
case BPRM_CHECK:
iint->ima_bprm_status = status;
break;
+ case CREDS_CHECK:
+ iint->ima_creds_status = status;
+ break;
case FILE_CHECK:
case POST_SETATTR:
iint->ima_file_status = status;
@@ -127,6 +132,9 @@ static void ima_cache_flags(struct integrity_iint_cache *iint,
case BPRM_CHECK:
iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED);
break;
+ case CREDS_CHECK:
+ iint->flags |= (IMA_CREDS_APPRAISED | IMA_APPRAISED);
+ break;
case FILE_CHECK:
case POST_SETATTR:
iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
@@ -14,7 +14,7 @@
*
* File: ima_main.c
* implements the IMA hooks: ima_bprm_check, ima_file_mmap,
- * and ima_file_check.
+ * ima_creds_check and ima_file_check.
*/
#include <linux/module.h>
#include <linux/file.h>
@@ -306,6 +306,28 @@ int ima_bprm_check(struct linux_binprm *bprm)
BPRM_CHECK, 0);
}
+/**
+ * ima_creds_check - based on policy, collect/store measurement.
+ * @bprm: contains the linux_binprm structure
+ *
+ * The OS protects against an executable file, already open for write,
+ * from being executed in deny_write_access() and an executable file,
+ * already open for execute, from being modified in get_write_access().
+ * So we can be certain that what we verify and measure here is actually
+ * what is being executed.
+ *
+ * This is identical to ima_bprm_check, except called after child credentials
+ * have been committed.
+ *
+ * On success return 0. On integrity appraisal error, assuming the file
+ * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
+ */
+int ima_creds_check(struct linux_binprm *bprm)
+{
+ return process_measurement(bprm->file, NULL, 0, MAY_EXEC,
+ CREDS_CHECK, 0);
+}
+
/**
* ima_path_check - based on policy, collect/store measurement.
* @file: pointer to the file to be measured
@@ -339,6 +339,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
return IMA_MMAP_APPRAISE;
case BPRM_CHECK:
return IMA_BPRM_APPRAISE;
+ case CREDS_CHECK:
+ return IMA_CREDS_APPRAISE;
case FILE_CHECK:
case POST_SETATTR:
return IMA_FILE_APPRAISE;
@@ -691,6 +693,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
entry->func = MMAP_CHECK;
else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
entry->func = BPRM_CHECK;
+ else if (strcmp(args[0].from, "CREDS_CHECK") == 0)
+ entry->func = CREDS_CHECK;
else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") ==
0)
entry->func = KEXEC_KERNEL_CHECK;
@@ -48,10 +48,14 @@
#define IMA_BPRM_APPRAISED 0x00002000
#define IMA_READ_APPRAISE 0x00004000
#define IMA_READ_APPRAISED 0x00008000
+#define IMA_CREDS_APPRAISE 0x00010000
+#define IMA_CREDS_APPRAISED 0x00020000
#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
- IMA_BPRM_APPRAISE | IMA_READ_APPRAISE)
+ IMA_BPRM_APPRAISE | IMA_READ_APPRAISE | \
+ IMA_CREDS_APPRAISE)
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
- IMA_BPRM_APPRAISED | IMA_READ_APPRAISED)
+ IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \
+ IMA_CREDS_APPRAISED)
enum evm_ima_xattr_type {
IMA_XATTR_DIGEST = 0x01,
@@ -109,6 +113,7 @@ struct integrity_iint_cache {
enum integrity_status ima_mmap_status:4;
enum integrity_status ima_bprm_status:4;
enum integrity_status ima_read_status:4;
+ enum integrity_status ima_creds_status:4;
enum integrity_status evm_status:4;
struct ima_digest_data *ima_hash;
};
@@ -346,9 +346,10 @@ void security_bprm_committing_creds(struct linux_binprm *bprm)
call_void_hook(bprm_committing_creds, bprm);
}
-void security_bprm_committed_creds(struct linux_binprm *bprm)
+int security_bprm_committed_creds(struct linux_binprm *bprm)
{
call_void_hook(bprm_committed_creds, bprm);
+ return ima_creds_check(bprm);
}
int security_sb_alloc(struct super_block *sb)
It may be desirable to perform appraisal after credentials are committed, for instance in the case where validation is only required if the binary has transitioned into a privileged security context. Add an additional call into IMA in the committed_credentials security hook and abort execution if it fails. This will only be called at install_exec_creds() time, which means it will only be run on binary interpreters rather than on the scripts or files handled by binfmt_misc. The following patch will rectify this. Signed-off-by: Matthew Garrett <mjg59@google.com> --- Documentation/ABI/testing/ima_policy | 2 +- arch/x86/ia32/ia32_aout.c | 4 +++- fs/binfmt_aout.c | 4 +++- fs/binfmt_elf.c | 5 ++++- fs/binfmt_elf_fdpic.c | 5 ++++- fs/binfmt_flat.c | 4 +++- fs/exec.c | 8 ++++++-- include/linux/binfmts.h | 2 +- include/linux/ima.h | 6 ++++++ include/linux/security.h | 5 +++-- security/integrity/iint.c | 1 + security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_api.c | 2 +- security/integrity/ima/ima_appraise.c | 8 ++++++++ security/integrity/ima/ima_main.c | 24 +++++++++++++++++++++++- security/integrity/ima/ima_policy.c | 4 ++++ security/integrity/integrity.h | 9 +++++++-- security/security.c | 3 ++- 18 files changed, 81 insertions(+), 16 deletions(-)