@@ -418,7 +418,8 @@ LSM_HOOK(void, LSM_RET_VOID, key_post_create_or_update, struct key *keyring,
LSM_HOOK(int, 0, audit_rule_init, u32 field, u32 op, char *rulestr,
void **lsmrule, gfp_t gfp)
LSM_HOOK(int, 0, audit_rule_known, struct audit_krule *krule)
-LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
+LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule,
+ bool *match)
LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
#endif /* CONFIG_AUDIT */
@@ -264,11 +264,11 @@ int aa_audit_rule_known(struct audit_krule *rule)
return 0;
}
-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
+int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, bool *match)
{
struct aa_audit_rule *rule = vrule;
struct aa_label *label;
- int found = 0;
+ bool found = false;
label = aa_secid_to_label(sid);
@@ -276,16 +276,14 @@ int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
return -ENOENT;
if (aa_label_is_subset(label, rule->label))
- found = 1;
+ found = true;
+
+ if (field == AUDIT_SUBJ_ROLE && op == Audit_equal)
+ *match = found;
+ else if (field == AUDIT_SUBJ_ROLE && op == Audit_not_equal)
+ *match = !found;
+ else
+ *match = false;
- switch (field) {
- case AUDIT_SUBJ_ROLE:
- switch (op) {
- case Audit_equal:
- return found;
- case Audit_not_equal:
- return !found;
- }
- }
return 0;
}
@@ -202,6 +202,6 @@ static inline int complain_error(int error)
void aa_audit_rule_free(void *vrule);
int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, gfp_t gfp);
int aa_audit_rule_known(struct audit_krule *rule);
-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
+int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, bool *match);
#endif /* __AA_AUDIT_H */
@@ -5450,7 +5450,20 @@ void security_audit_rule_free(void *lsmrule)
*/
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
{
- return call_int_hook(audit_rule_match, secid, field, op, lsmrule);
+ int rc;
+ bool match = false;
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.audit_rule_match, list) {
+ rc = hp->hook.audit_rule_match(secid, field, op, lsmrule,
+ &match);
+ if (rc < 0)
+ return rc;
+ if (match)
+ break;
+ }
+
+ return match;
}
#endif /* CONFIG_AUDIT */
@@ -45,11 +45,13 @@ void selinux_audit_rule_free(void *rule);
* @field: the field this rule refers to
* @op: the operator the rule uses
* @rule: pointer to the audit rule to check against
+ * @match: if the context id matches the rule
*
- * Returns 1 if the context id matches the rule, 0 if it does not, and
- * -errno on failure.
+ * Returns 0 on success and -errno on failure. @match holds the match
+ * result.
*/
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule,
+ bool *match);
/**
* selinux_audit_rule_known - check to see if rule contains selinux fields.
@@ -3633,29 +3633,32 @@ int selinux_audit_rule_known(struct audit_krule *rule)
return 0;
}
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
+ bool *match)
{
struct selinux_state *state = &selinux_state;
struct selinux_policy *policy;
struct context *ctxt;
struct mls_level *level;
struct selinux_audit_rule *rule = vrule;
- int match = 0;
+ int rc = 0;
if (unlikely(!rule)) {
WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
return -ENOENT;
}
- if (!selinux_initialized())
+ if (!selinux_initialized()) {
+ *match = false;
return 0;
+ }
rcu_read_lock();
policy = rcu_dereference(state->policy);
if (rule->au_seqno < policy->latest_granting) {
- match = -ESTALE;
+ rc = -ESTALE;
goto out;
}
@@ -3663,7 +3666,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
sid);
- match = -ENOENT;
+ rc = -ENOENT;
goto out;
}
@@ -3674,10 +3677,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
case AUDIT_OBJ_USER:
switch (op) {
case Audit_equal:
- match = (ctxt->user == rule->au_ctxt.user);
+ rc = (ctxt->user == rule->au_ctxt.user);
break;
case Audit_not_equal:
- match = (ctxt->user != rule->au_ctxt.user);
+ rc = (ctxt->user != rule->au_ctxt.user);
break;
}
break;
@@ -3685,10 +3688,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
case AUDIT_OBJ_ROLE:
switch (op) {
case Audit_equal:
- match = (ctxt->role == rule->au_ctxt.role);
+ rc = (ctxt->role == rule->au_ctxt.role);
break;
case Audit_not_equal:
- match = (ctxt->role != rule->au_ctxt.role);
+ rc = (ctxt->role != rule->au_ctxt.role);
break;
}
break;
@@ -3696,10 +3699,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
case AUDIT_OBJ_TYPE:
switch (op) {
case Audit_equal:
- match = (ctxt->type == rule->au_ctxt.type);
+ rc = (ctxt->type == rule->au_ctxt.type);
break;
case Audit_not_equal:
- match = (ctxt->type != rule->au_ctxt.type);
+ rc = (ctxt->type != rule->au_ctxt.type);
break;
}
break;
@@ -3712,39 +3715,42 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
&ctxt->range.level[0] : &ctxt->range.level[1]);
switch (op) {
case Audit_equal:
- match = mls_level_eq(&rule->au_ctxt.range.level[0],
- level);
+ rc = mls_level_eq(&rule->au_ctxt.range.level[0],
+ level);
break;
case Audit_not_equal:
- match = !mls_level_eq(&rule->au_ctxt.range.level[0],
- level);
+ rc = !mls_level_eq(&rule->au_ctxt.range.level[0],
+ level);
break;
case Audit_lt:
- match = (mls_level_dom(&rule->au_ctxt.range.level[0],
- level) &&
+ rc = (mls_level_dom(&rule->au_ctxt.range.level[0],
+ level) &&
!mls_level_eq(&rule->au_ctxt.range.level[0],
level));
break;
case Audit_le:
- match = mls_level_dom(&rule->au_ctxt.range.level[0],
- level);
+ rc = mls_level_dom(&rule->au_ctxt.range.level[0],
+ level);
break;
case Audit_gt:
- match = (mls_level_dom(level,
- &rule->au_ctxt.range.level[0]) &&
+ rc = (mls_level_dom(level,
+ &rule->au_ctxt.range.level[0]) &&
!mls_level_eq(level,
&rule->au_ctxt.range.level[0]));
break;
case Audit_ge:
- match = mls_level_dom(level,
- &rule->au_ctxt.range.level[0]);
+ rc = mls_level_dom(level,
+ &rule->au_ctxt.range.level[0]);
break;
}
}
out:
rcu_read_unlock();
- return match;
+ if (rc < 0)
+ return rc;
+ *match = !!rc;
+ return 0;
}
static int aurule_avc_callback(u32 event)
@@ -4764,11 +4764,15 @@ static int smack_audit_rule_known(struct audit_krule *krule)
* @field: audit rule flags given from user-space
* @op: required testing operator
* @vrule: smack internal rule presentation
+ * @match: the match result
*
* The core Audit hook. It's used to take the decision of
* whether to audit or not to audit a given object.
+ *
+ * Returns 0 on success or negative error code on failure.
*/
-static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
+static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
+ bool *match)
{
struct smack_known *skp;
char *rule = vrule;
@@ -4778,8 +4782,10 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
return -ENOENT;
}
- if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+ if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) {
+ *match = false;
return 0;
+ }
skp = smack_from_secid(secid);
@@ -4789,10 +4795,11 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
* label.
*/
if (op == Audit_equal)
- return (rule == skp->smk_known);
- if (op == Audit_not_equal)
- return (rule != skp->smk_known);
-
+ *match = (rule == skp->smk_known);
+ else if (op == Audit_not_equal)
+ *match = (rule != skp->smk_known);
+ else
+ *match = false;
return 0;
}