From 7163a993840f0906d4ce1e3f193575c99dac21e1 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Thu, 3 Jan 2013 14:19:09 -0500 Subject: ima: re-initialize IMA policy LSM info Although the IMA policy does not change, the LSM policy can be reloaded, leaving the IMA LSM based rules referring to the old, stale LSM policy. This patch updates the IMA LSM based rules to reflect the reloaded LSM policy. Reported-by: Sven Vermeulen tested-by: Sven Vermeulen Signed-off-by: Mimi Zohar Cc: Eric Paris Cc: Casey Schaufler --- security/integrity/ima/ima_policy.c | 68 +++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 10 deletions(-) (limited to 'security/integrity/ima/ima_policy.c') diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index af7d182d5a46..70f888de880d 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -49,6 +49,7 @@ struct ima_rule_entry { kuid_t fowner; struct { void *rule; /* LSM file metadata specific */ + void *args_p; /* audit value */ int type; /* audit type */ } lsm[MAX_LSM_RULES]; }; @@ -119,6 +120,35 @@ static int __init default_appraise_policy_setup(char *str) } __setup("ima_appraise_tcb", default_appraise_policy_setup); +/* + * Although the IMA policy does not change, the LSM policy can be + * reloaded, leaving the IMA LSM based rules referring to the old, + * stale LSM policy. + * + * Update the IMA LSM based rules to reflect the reloaded LSM policy. + * We assume the rules still exist; and BUG_ON() if they don't. + */ +static void ima_lsm_update_rules(void) +{ + struct ima_rule_entry *entry, *tmp; + int result; + int i; + + mutex_lock(&ima_rules_mutex); + list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) { + for (i = 0; i < MAX_LSM_RULES; i++) { + if (!entry->lsm[i].rule) + continue; + result = security_filter_rule_init(entry->lsm[i].type, + Audit_equal, + entry->lsm[i].args_p, + &entry->lsm[i].rule); + BUG_ON(!entry->lsm[i].rule); + } + } + mutex_unlock(&ima_rules_mutex); +} + /** * ima_match_rules - determine whether an inode matches the measure rule. * @rule: a pointer to a rule @@ -149,10 +179,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule, for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; u32 osid, sid; + int retried = 0; if (!rule->lsm[i].rule) continue; - +retry: switch (i) { case LSM_OBJ_USER: case LSM_OBJ_ROLE: @@ -176,6 +207,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule, default: break; } + if ((rc < 0) && (!retried)) { + retried = 1; + ima_lsm_update_rules(); + goto retry; + } if (!rc) return false; } @@ -306,19 +342,27 @@ static match_table_t policy_tokens = { }; static int ima_lsm_rule_init(struct ima_rule_entry *entry, - char *args, int lsm_rule, int audit_type) + substring_t *args, int lsm_rule, int audit_type) { int result; if (entry->lsm[lsm_rule].rule) return -EINVAL; + entry->lsm[lsm_rule].args_p = match_strdup(args); + if (!entry->lsm[lsm_rule].args_p) + return -ENOMEM; + entry->lsm[lsm_rule].type = audit_type; result = security_filter_rule_init(entry->lsm[lsm_rule].type, - Audit_equal, args, + Audit_equal, + entry->lsm[lsm_rule].args_p, &entry->lsm[lsm_rule].rule); - if (!entry->lsm[lsm_rule].rule) + if (!entry->lsm[lsm_rule].rule) { + kfree(entry->lsm[lsm_rule].args_p); return -EINVAL; + } + return result; } @@ -481,37 +525,37 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; case Opt_obj_user: ima_log_string(ab, "obj_user", args[0].from); - result = ima_lsm_rule_init(entry, args[0].from, + result = ima_lsm_rule_init(entry, args, LSM_OBJ_USER, AUDIT_OBJ_USER); break; case Opt_obj_role: ima_log_string(ab, "obj_role", args[0].from); - result = ima_lsm_rule_init(entry, args[0].from, + result = ima_lsm_rule_init(entry, args, LSM_OBJ_ROLE, AUDIT_OBJ_ROLE); break; case Opt_obj_type: ima_log_string(ab, "obj_type", args[0].from); - result = ima_lsm_rule_init(entry, args[0].from, + result = ima_lsm_rule_init(entry, args, LSM_OBJ_TYPE, AUDIT_OBJ_TYPE); break; case Opt_subj_user: ima_log_string(ab, "subj_user", args[0].from); - result = ima_lsm_rule_init(entry, args[0].from, + result = ima_lsm_rule_init(entry, args, LSM_SUBJ_USER, AUDIT_SUBJ_USER); break; case Opt_subj_role: ima_log_string(ab, "subj_role", args[0].from); - result = ima_lsm_rule_init(entry, args[0].from, + result = ima_lsm_rule_init(entry, args, LSM_SUBJ_ROLE, AUDIT_SUBJ_ROLE); break; case Opt_subj_type: ima_log_string(ab, "subj_type", args[0].from); - result = ima_lsm_rule_init(entry, args[0].from, + result = ima_lsm_rule_init(entry, args, LSM_SUBJ_TYPE, AUDIT_SUBJ_TYPE); break; @@ -589,9 +633,13 @@ ssize_t ima_parse_add_rule(char *rule) void ima_delete_rules(void) { struct ima_rule_entry *entry, *tmp; + int i; mutex_lock(&ima_rules_mutex); list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) { + for (i = 0; i < MAX_LSM_RULES; i++) + kfree(entry->lsm[i].args_p); + list_del(&entry->list); kfree(entry); } -- cgit v1.2.3 From 16cac49f727621c6b0467ffe15ed72c2febb1296 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Thu, 13 Dec 2012 11:15:04 -0500 Subject: ima: rename FILE_MMAP to MMAP_CHECK Rename FILE_MMAP hook to MMAP_CHECK to be consistent with the other hook names. Signed-off-by: Mimi Zohar --- Documentation/ABI/testing/ima_policy | 2 +- security/integrity/ima/ima.h | 2 +- security/integrity/ima/ima_api.c | 4 ++-- security/integrity/ima/ima_main.c | 2 +- security/integrity/ima/ima_policy.c | 7 ++++--- 5 files changed, 9 insertions(+), 8 deletions(-) (limited to 'security/integrity/ima/ima_policy.c') diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index ec0a38ef3145..6a0fc808fb6d 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -23,7 +23,7 @@ Description: lsm: [[subj_user=] [subj_role=] [subj_type=] [obj_user=] [obj_role=] [obj_type=]] - base: func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK][MODULE_CHECK] + base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK] mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] fsmagic:= hex value uid:= decimal value diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 3b2adb794f15..1385c5c172f7 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -127,7 +127,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); struct integrity_iint_cache *integrity_iint_find(struct inode *inode); /* IMA policy related functions */ -enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, MODULE_CHECK, POST_SETATTR }; +enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, POST_SETATTR }; int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, int flags); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 0cea3db21657..fc722b44c416 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -100,12 +100,12 @@ err_out: * ima_get_action - appraise & measure decision based on policy. * @inode: pointer to inode to measure * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) - * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP, MODULE_CHECK) + * @function: calling function (FILE_CHECK, BPRM_CHECK, MMAP_CHECK, MODULE_CHECK) * * 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 | FILE_MMAP | MODULE_CHECK + * func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK * mask: contains the permission mask * fsmagic: hex value * diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 1cd4eb2c3b90..970693d1a320 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -228,7 +228,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) { if (file && (prot & PROT_EXEC)) return process_measurement(file, file->f_dentry->d_name.name, - MAY_EXEC, FILE_MMAP); + MAY_EXEC, MMAP_CHECK); return 0; } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 70f888de880d..95194539d75e 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -75,7 +75,7 @@ static struct ima_rule_entry default_rules[] = { {.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, - {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, + {.action = MEASURE,.func = MMAP_CHECK,.mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, @@ -448,8 +448,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->func = FILE_CHECK; else if (strcmp(args[0].from, "MODULE_CHECK") == 0) entry->func = MODULE_CHECK; - else if (strcmp(args[0].from, "FILE_MMAP") == 0) - entry->func = FILE_MMAP; + else if ((strcmp(args[0].from, "FILE_MMAP") == 0) + || (strcmp(args[0].from, "MMAP_CHECK") == 0)) + entry->func = MMAP_CHECK; else if (strcmp(args[0].from, "BPRM_CHECK") == 0) entry->func = BPRM_CHECK; else -- cgit v1.2.3 From 0e5a247cb37a97d843ef76d09d5f80deb7893ba3 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 8 Jun 2012 13:58:49 +0300 Subject: ima: added policy support for 'security.ima' type The 'security.ima' extended attribute may contain either the file data's hash or a digital signature. This patch adds support for requiring a specific extended attribute type. It extends the IMA policy with a new keyword 'appraise_type=imasig'. (Default is hash.) Changelog v2: - Fixed Documentation/ABI/testing/ima_policy option syntax Changelog v1: - Differentiate between 'required' vs. 'actual' extended attribute Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- Documentation/ABI/testing/ima_policy | 4 +++- security/integrity/ima/ima_appraise.c | 5 +++++ security/integrity/ima/ima_main.c | 1 + security/integrity/ima/ima_policy.c | 18 +++++++++++++++++- security/integrity/integrity.h | 2 ++ 5 files changed, 28 insertions(+), 2 deletions(-) (limited to 'security/integrity/ima/ima_policy.c') diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 6a0fc808fb6d..de16de3f148d 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -18,10 +18,11 @@ Description: rule format: action [condition ...] action: measure | dont_measure | appraise | dont_appraise | audit - condition:= base | lsm + condition:= base | lsm [option] base: [[func=] [mask=] [fsmagic=] [uid=] [fowner]] lsm: [[subj_user=] [subj_role=] [subj_type=] [obj_user=] [obj_role=] [obj_type=]] + option: [[appraise_type=]] base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK] mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] @@ -29,6 +30,7 @@ Description: uid:= decimal value fowner:=decimal value lsm: are LSM specific + option: appraise_type:= [imasig] default policy: # PROC_SUPER_MAGIC diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index fa675c907e0f..8004332ccb8f 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -102,6 +102,11 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint, switch (xattr_value->type) { case IMA_XATTR_DIGEST: + if (iint->flags & IMA_DIGSIG_REQUIRED) { + cause = "IMA signature required"; + status = INTEGRITY_FAIL; + break; + } rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE); if (rc) { diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index cd00ba39e8e0..3cdd78768c29 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -169,6 +169,7 @@ static int process_measurement(struct file *file, const char *filename, * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED, * IMA_AUDIT, IMA_AUDITED) */ iint->flags |= action; + action &= IMA_DO_MASK; action &= ~((iint->flags & IMA_DONE_MASK) >> 1); /* Nothing to do, just return existing appraised status */ diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 95194539d75e..1a2543a8ee53 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -245,6 +245,8 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, if (!ima_match_rules(entry, inode, func, mask)) continue; + action |= entry->flags & IMA_ACTION_FLAGS; + action |= entry->action & IMA_DO_MASK; if (entry->action & IMA_DO_MASK) actmask &= ~(entry->action | entry->action << 1); @@ -318,7 +320,8 @@ enum { Opt_audit, Opt_obj_user, Opt_obj_role, Opt_obj_type, Opt_subj_user, Opt_subj_role, Opt_subj_type, - Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner + Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner, + Opt_appraise_type }; static match_table_t policy_tokens = { @@ -338,6 +341,7 @@ static match_table_t policy_tokens = { {Opt_fsmagic, "fsmagic=%s"}, {Opt_uid, "uid=%s"}, {Opt_fowner, "fowner=%s"}, + {Opt_appraise_type, "appraise_type=%s"}, {Opt_err, NULL} }; @@ -560,6 +564,18 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) LSM_SUBJ_TYPE, AUDIT_SUBJ_TYPE); break; + case Opt_appraise_type: + if (entry->action != APPRAISE) { + result = -EINVAL; + break; + } + + ima_log_string(ab, "appraise_type", args[0].from); + if ((strcmp(args[0].from, "imasig")) == 0) + entry->flags |= IMA_DIGSIG_REQUIRED; + else + result = -EINVAL; + break; case Opt_err: ima_log_string(ab, "UNKNOWN", p); result = -EINVAL; diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 0a298def5036..9334691b2b75 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -26,7 +26,9 @@ #define IMA_AUDITED 0x0080 /* iint cache flags */ +#define IMA_ACTION_FLAGS 0xff00 #define IMA_DIGSIG 0x0100 +#define IMA_DIGSIG_REQUIRED 0x0200 #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT) #define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \ -- cgit v1.2.3 From d79d72e02485c00b886179538dc8deaffa3be507 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Mon, 3 Dec 2012 17:08:11 -0500 Subject: ima: per hook cache integrity appraisal status With the new IMA policy 'appraise_type=' option, different hooks can require different methods for appraising a file's integrity. For example, the existing 'ima_appraise_tcb' policy defines a generic rule, requiring all root files to be appraised, without specfying the appraisal method. A more specific rule could require all kernel modules, for example, to be signed. appraise fowner=0 func=MODULE_CHECK appraise_type=imasig appraise fowner=0 As a result, the integrity appraisal results for the same inode, but for different hooks, could differ. This patch caches the integrity appraisal results on a per hook basis. Changelog v2: - Rename ima_cache_status() to ima_set_cache_status() - Rename and move get_appraise_status() to ima_get_cache_status() Changelog v0: - include IMA_APPRAISE/APPRAISED_SUBMASK in IMA_DO/DONE_MASK (Dmitry) - Support independent MODULE_CHECK appraise status. - fixed IMA_XXXX_APPRAISE/APPRAISED flags Signed-off-by: Mimi Zohar Signed-off-by: Dmitry Kasatkin --- security/integrity/iint.c | 10 ++++- security/integrity/ima/ima.h | 13 ++++++- security/integrity/ima/ima_appraise.c | 71 ++++++++++++++++++++++++++++++----- security/integrity/ima/ima_main.c | 19 ++++++---- security/integrity/ima/ima_policy.c | 22 +++++++++++ security/integrity/integrity.h | 26 +++++++++++-- 6 files changed, 136 insertions(+), 25 deletions(-) (limited to 'security/integrity/ima/ima_policy.c') diff --git a/security/integrity/iint.c b/security/integrity/iint.c index d82a5a13d855..74522dbd10a6 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -72,7 +72,10 @@ static void iint_free(struct integrity_iint_cache *iint) { iint->version = 0; iint->flags = 0UL; - iint->ima_status = INTEGRITY_UNKNOWN; + iint->ima_file_status = INTEGRITY_UNKNOWN; + iint->ima_mmap_status = INTEGRITY_UNKNOWN; + iint->ima_bprm_status = INTEGRITY_UNKNOWN; + iint->ima_module_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; kmem_cache_free(iint_cache, iint); } @@ -149,7 +152,10 @@ static void init_once(void *foo) memset(iint, 0, sizeof *iint); iint->version = 0; iint->flags = 0UL; - iint->ima_status = INTEGRITY_UNKNOWN; + iint->ima_file_status = INTEGRITY_UNKNOWN; + iint->ima_mmap_status = INTEGRITY_UNKNOWN; + iint->ima_bprm_status = INTEGRITY_UNKNOWN; + iint->ima_module_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; } diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 991844db98d9..ab68bed8ac36 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -142,13 +142,16 @@ void ima_delete_rules(void); #define IMA_APPRAISE_FIX 0x02 #ifdef CONFIG_IMA_APPRAISE -int ima_appraise_measurement(struct integrity_iint_cache *iint, +int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename); int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); +enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, + int func); #else -static inline int ima_appraise_measurement(struct integrity_iint_cache *iint, +static inline int ima_appraise_measurement(int func, + struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename) { @@ -165,6 +168,12 @@ static inline void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) { } + +static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache + *iint, int func) +{ + return INTEGRITY_UNKNOWN; +} #endif /* LSM based policy rules require audit */ diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 8004332ccb8f..2d4becab8918 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -51,6 +51,62 @@ static int ima_fix_xattr(struct dentry *dentry, sizeof(iint->ima_xattr), 0); } +/* Return specific func appraised cached result */ +enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, + int func) +{ + switch(func) { + case MMAP_CHECK: + return iint->ima_mmap_status; + case BPRM_CHECK: + return iint->ima_bprm_status; + case MODULE_CHECK: + return iint->ima_module_status; + case FILE_CHECK: + default: + return iint->ima_file_status; + } +} + +static void ima_set_cache_status(struct integrity_iint_cache *iint, + int func, enum integrity_status status) +{ + switch(func) { + case MMAP_CHECK: + iint->ima_mmap_status = status; + break; + case BPRM_CHECK: + iint->ima_bprm_status = status; + break; + case MODULE_CHECK: + iint->ima_module_status = status; + break; + case FILE_CHECK: + default: + iint->ima_file_status = status; + break; + } +} + +static void ima_cache_flags(struct integrity_iint_cache *iint, int func) +{ + switch(func) { + case MMAP_CHECK: + iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); + break; + case BPRM_CHECK: + iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED); + break; + case MODULE_CHECK: + iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED); + break; + case FILE_CHECK: + default: + iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); + break; + } +} + /* * ima_appraise_measurement - appraise file measurement * @@ -59,7 +115,7 @@ static int ima_fix_xattr(struct dentry *dentry, * * Return 0 on success, error code otherwise */ -int ima_appraise_measurement(struct integrity_iint_cache *iint, +int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename) { struct dentry *dentry = file->f_dentry; @@ -75,9 +131,6 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint, if (!inode->i_op->getxattr) return INTEGRITY_UNKNOWN; - if (iint->flags & IMA_APPRAISED) - return iint->ima_status; - rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, 0, GFP_NOFS); if (rc <= 0) { @@ -99,7 +152,6 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint, cause = "invalid-HMAC"; goto out; } - switch (xattr_value->type) { case IMA_XATTR_DIGEST: if (iint->flags & IMA_DIGSIG_REQUIRED) { @@ -148,9 +200,9 @@ out: integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, op, cause, rc, 0); } else { - iint->flags |= IMA_APPRAISED; + ima_cache_flags(iint, func); } - iint->ima_status = status; + ima_set_cache_status(iint, func, status); kfree(xattr_value); return status; } @@ -196,10 +248,11 @@ void ima_inode_post_setattr(struct dentry *dentry) must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); iint = integrity_iint_find(inode); if (iint) { + iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | + IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | + IMA_ACTION_FLAGS); if (must_appraise) iint->flags |= IMA_APPRAISE; - else - iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); } if (!must_appraise) rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 3cdd78768c29..66b7f408eff2 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -151,8 +151,10 @@ static int process_measurement(struct file *file, const char *filename, if (!ima_initialized || !S_ISREG(inode->i_mode)) return 0; - /* Determine if in appraise/audit/measurement policy, - * returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask. */ + /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action + * bitmask based on the appraise/audit/measurement policy. + * Included is the appraise submask. + */ action = ima_get_action(inode, mask, function); if (!action) return 0; @@ -166,16 +168,17 @@ static int process_measurement(struct file *file, const char *filename, goto out; /* Determine if already appraised/measured based on bitmask - * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED, - * IMA_AUDIT, IMA_AUDITED) */ + * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, + * IMA_AUDIT, IMA_AUDITED) + */ iint->flags |= action; action &= IMA_DO_MASK; action &= ~((iint->flags & IMA_DONE_MASK) >> 1); /* Nothing to do, just return existing appraised status */ if (!action) { - if (iint->flags & IMA_APPRAISED) - rc = iint->ima_status; + if (must_appraise) + rc = ima_get_cache_status(iint, function); goto out_digsig; } @@ -191,8 +194,8 @@ static int process_measurement(struct file *file, const char *filename, if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname); - if (action & IMA_APPRAISE) - rc = ima_appraise_measurement(iint, file, pathname); + if (action & IMA_APPRAISE_SUBMASK) + rc = ima_appraise_measurement(function, iint, file, pathname); if (action & IMA_AUDIT) ima_audit_measurement(iint, pathname); kfree(pathbuf); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 1a2543a8ee53..4d7c0ae656d3 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -218,6 +218,25 @@ retry: return true; } +/* + * In addition to knowing that we need to appraise the file in general, + * we need to differentiate between calling hooks. + */ +static int get_subaction(int func) +{ + switch(func) { + case MMAP_CHECK: + return IMA_MMAP_APPRAISE; + case BPRM_CHECK: + return IMA_BPRM_APPRAISE; + case MODULE_CHECK: + return IMA_MODULE_APPRAISE; + case FILE_CHECK: + default: + return IMA_FILE_APPRAISE; + } +} + /** * ima_match_policy - decision based on LSM and other conditions * @inode: pointer to an inode for which the policy decision is being made @@ -248,6 +267,9 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, action |= entry->flags & IMA_ACTION_FLAGS; action |= entry->action & IMA_DO_MASK; + if (entry->action & IMA_APPRAISE) + action |= get_subaction(func); + if (entry->action & IMA_DO_MASK) actmask &= ~(entry->action | entry->action << 1); else diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 329ad263e130..0ae08fc88585 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -30,9 +30,24 @@ #define IMA_DIGSIG 0x01000000 #define IMA_DIGSIG_REQUIRED 0x02000000 -#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT) -#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \ - | IMA_COLLECTED) +#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ + IMA_APPRAISE_SUBMASK) +#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \ + IMA_COLLECTED | IMA_APPRAISED_SUBMASK) + +/* iint subaction appraise cache flags */ +#define IMA_FILE_APPRAISE 0x00000100 +#define IMA_FILE_APPRAISED 0x00000200 +#define IMA_MMAP_APPRAISE 0x00000400 +#define IMA_MMAP_APPRAISED 0x00000800 +#define IMA_BPRM_APPRAISE 0x00001000 +#define IMA_BPRM_APPRAISED 0x00002000 +#define IMA_MODULE_APPRAISE 0x00004000 +#define IMA_MODULE_APPRAISED 0x00008000 +#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ + IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE) +#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ + IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED) enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01, @@ -52,7 +67,10 @@ struct integrity_iint_cache { u64 version; /* track inode changes */ unsigned long flags; struct evm_ima_xattr_data ima_xattr; - enum integrity_status ima_status:4; + enum integrity_status ima_file_status:4; + enum integrity_status ima_mmap_status:4; + enum integrity_status ima_bprm_status:4; + enum integrity_status ima_module_status:4; enum integrity_status evm_status:4; }; -- cgit v1.2.3 From 5a73fcfa8875a94c2956e7ff8fba54d31a3e2854 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 5 Dec 2012 15:14:38 -0500 Subject: ima: differentiate appraise status only for hook specific rules Different hooks can require different methods for appraising a file's integrity. As a result, an integrity appraisal status is cached on a per hook basis. Only a hook specific rule, requires the inode to be re-appraised. This patch eliminates unnecessary appraisals. Signed-off-by: Mimi Zohar Signed-off-by: Dmitry Kasatkin --- security/integrity/ima/ima_main.c | 9 ++++++--- security/integrity/ima/ima_policy.c | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'security/integrity/ima/ima_policy.c') diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 66b7f408eff2..3e751a9743a1 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -146,7 +146,7 @@ static int process_measurement(struct file *file, const char *filename, struct integrity_iint_cache *iint; char *pathbuf = NULL; const char *pathname = NULL; - int rc = -ENOMEM, action, must_appraise; + int rc = -ENOMEM, action, must_appraise, _func; if (!ima_initialized || !S_ISREG(inode->i_mode)) return 0; @@ -161,6 +161,9 @@ static int process_measurement(struct file *file, const char *filename, must_appraise = action & IMA_APPRAISE; + /* Is the appraise rule hook specific? */ + _func = (action & IMA_FILE_APPRAISE) ? FILE_CHECK : function; + mutex_lock(&inode->i_mutex); iint = integrity_inode_get(inode); @@ -178,7 +181,7 @@ static int process_measurement(struct file *file, const char *filename, /* Nothing to do, just return existing appraised status */ if (!action) { if (must_appraise) - rc = ima_get_cache_status(iint, function); + rc = ima_get_cache_status(iint, _func); goto out_digsig; } @@ -195,7 +198,7 @@ static int process_measurement(struct file *file, const char *filename, if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname); if (action & IMA_APPRAISE_SUBMASK) - rc = ima_appraise_measurement(function, iint, file, pathname); + rc = ima_appraise_measurement(_func, iint, file, pathname); if (action & IMA_AUDIT) ima_audit_measurement(iint, pathname); kfree(pathbuf); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 4d7c0ae656d3..4adcd0f8c1dd 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -220,10 +220,13 @@ retry: /* * In addition to knowing that we need to appraise the file in general, - * we need to differentiate between calling hooks. + * we need to differentiate between calling hooks, for hook specific rules. */ -static int get_subaction(int func) +static int get_subaction(struct ima_rule_entry *rule, int func) { + if (!(rule->flags & IMA_FUNC)) + return IMA_FILE_APPRAISE; + switch(func) { case MMAP_CHECK: return IMA_MMAP_APPRAISE; @@ -268,7 +271,7 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, action |= entry->action & IMA_DO_MASK; if (entry->action & IMA_APPRAISE) - action |= get_subaction(func); + action |= get_subaction(entry, func); if (entry->action & IMA_DO_MASK) actmask &= ~(entry->action | entry->action << 1); -- cgit v1.2.3 From 85865c1fa189fcba49089e6254a0226f2269bebc Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Mon, 3 Sep 2012 23:23:13 +0300 Subject: ima: add policy support for file system uuid The IMA policy permits specifying rules to enable or disable measurement/appraisal/audit based on the file system magic number. If, for example, the policy contains an ext4 measurement rule, the rule is enabled for all ext4 partitions. Sometimes it might be necessary to enable measurement/appraisal/audit only for one partition and disable it for another partition of the same type. With the existing IMA policy syntax, this can not be done. This patch provides support for IMA policy rules to specify the file system by its UUID (eg. fsuuid=397449cd-687d-4145-8698-7fed4a3e0363). For partitions not being appraised, it might be a good idea to mount file systems with the 'noexec' option to prevent executing non-verified binaries. Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- Documentation/ABI/testing/ima_policy | 4 +++- security/integrity/ima/ima_policy.c | 22 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'security/integrity/ima/ima_policy.c') diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index de16de3f148d..f1c5cc9d17a8 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -19,7 +19,8 @@ Description: action: measure | dont_measure | appraise | dont_appraise | audit condition:= base | lsm [option] - base: [[func=] [mask=] [fsmagic=] [uid=] [fowner]] + base: [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=] + [fowner]] lsm: [[subj_user=] [subj_role=] [subj_type=] [obj_user=] [obj_role=] [obj_type=]] option: [[appraise_type=]] @@ -27,6 +28,7 @@ Description: base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK] mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] fsmagic:= hex value + fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6) uid:= decimal value fowner:=decimal value lsm: are LSM specific diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 4adcd0f8c1dd..23f49e37a957 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "ima.h" @@ -25,6 +26,7 @@ #define IMA_FSMAGIC 0x0004 #define IMA_UID 0x0008 #define IMA_FOWNER 0x0010 +#define IMA_FSUUID 0x0020 #define UNKNOWN 0 #define MEASURE 0x0001 /* same as IMA_MEASURE */ @@ -45,6 +47,7 @@ struct ima_rule_entry { enum ima_hooks func; int mask; unsigned long fsmagic; + u8 fsuuid[16]; kuid_t uid; kuid_t fowner; struct { @@ -172,6 +175,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, if ((rule->flags & IMA_FSMAGIC) && rule->fsmagic != inode->i_sb->s_magic) return false; + if ((rule->flags & IMA_FSUUID) && + memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid))) + return false; if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) return false; if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid)) @@ -346,7 +352,7 @@ enum { Opt_obj_user, Opt_obj_role, Opt_obj_type, Opt_subj_user, Opt_subj_role, Opt_subj_type, Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner, - Opt_appraise_type + Opt_appraise_type, Opt_fsuuid }; static match_table_t policy_tokens = { @@ -364,6 +370,7 @@ static match_table_t policy_tokens = { {Opt_func, "func=%s"}, {Opt_mask, "mask=%s"}, {Opt_fsmagic, "fsmagic=%s"}, + {Opt_fsuuid, "fsuuid=%s"}, {Opt_uid, "uid=%s"}, {Opt_fowner, "fowner=%s"}, {Opt_appraise_type, "appraise_type=%s"}, @@ -519,6 +526,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) if (!result) entry->flags |= IMA_FSMAGIC; break; + case Opt_fsuuid: + ima_log_string(ab, "fsuuid", args[0].from); + + if (memchr_inv(entry->fsuuid, 0x00, + sizeof(entry->fsuuid))) { + result = -EINVAL; + break; + } + + part_pack_uuid(args[0].from, entry->fsuuid); + entry->flags |= IMA_FSUUID; + result = 0; + break; case Opt_uid: ima_log_string(ab, "uid", args[0].from); -- cgit v1.2.3