From: Xu Kuohai <xukuo...@huawei.com>

To be consistent with most LSM hooks, convert the return value of
hook audit_rule_match to 0 or a negative error code.

Before:
- Hook audit_rule_match returns 1 if the rule matches, 0 if it not,
  and negative error code otherwise.

After:
- Hook audit_rule_match returns 0 on success or a negative error
  code on failure. An output parameter @match is introduced to hold
  the match result on success.

Signed-off-by: Xu Kuohai <xukuo...@huawei.com>
---
 include/linux/lsm_hook_defs.h     |  3 +-
 security/apparmor/audit.c         | 22 ++++++-------
 security/apparmor/include/audit.h |  2 +-
 security/security.c               | 15 ++++++++-
 security/selinux/include/audit.h  |  8 +++--
 security/selinux/ss/services.c    | 54 +++++++++++++++++--------------
 security/smack/smack_lsm.c        | 19 +++++++----
 7 files changed, 75 insertions(+), 48 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 54fec360947c..6b521744a23b 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -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 */
 
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 6b5181c668b5..352a183b3325 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -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;
 }
diff --git a/security/apparmor/include/audit.h 
b/security/apparmor/include/audit.h
index 0c8cc86b417b..a227741f33c8 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -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 */
diff --git a/security/security.c b/security/security.c
index 2c161101074d..5e9de8d0cdde 100644
--- a/security/security.c
+++ b/security/security.c
@@ -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 */
 
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 29c7d4c86f6d..2d0799270426 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -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.
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index e33e55384b75..2946d28a25b1 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -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)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 9a121ad53b16..ea0f0cf11ff3 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -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;
 }
 
-- 
2.30.2


Reply via email to