-
-struct selinux_audit_rule {
- u32 au_seqno;
- struct context au_ctxt;
-};
-
-void selinux_audit_rule_free(struct selinux_audit_rule *rule)
-{
- if (rule) {
- context_destroy(&rule->au_ctxt);
- kfree(rule);
- }
-}
-
-int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
- struct selinux_audit_rule **rule)
-{
- struct selinux_audit_rule *tmprule;
- struct role_datum *roledatum;
- struct type_datum *typedatum;
- struct user_datum *userdatum;
- int rc = 0;
-
- *rule = NULL;
-
- if (!ss_initialized)
- return -ENOTSUPP;
-
- switch (field) {
- case AUDIT_SE_USER:
- case AUDIT_SE_ROLE:
- case AUDIT_SE_TYPE:
- /* only 'equals' and 'not equals' fit user, role, and type */
- if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
- return -EINVAL;
- break;
- case AUDIT_SE_SEN:
- case AUDIT_SE_CLR:
- /* we do not allow a range, indicated by the presense of '-' */
- if (strchr(rulestr, '-'))
- return -EINVAL;
- break;
- default:
- /* only the above fields are valid */
- return -EINVAL;
- }
-
- tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
- if (!tmprule)
- return -ENOMEM;
-
- context_init(&tmprule->au_ctxt);
-
- POLICY_RDLOCK;
-
- tmprule->au_seqno = latest_granting;
-
- switch (field) {
- case AUDIT_SE_USER:
- userdatum = hashtab_search(policydb.p_users.table, rulestr);
- if (!userdatum)
- rc = -EINVAL;
- else
- tmprule->au_ctxt.user = userdatum->value;
- break;
- case AUDIT_SE_ROLE:
- roledatum = hashtab_search(policydb.p_roles.table, rulestr);
- if (!roledatum)
- rc = -EINVAL;
- else
- tmprule->au_ctxt.role = roledatum->value;
- break;
- case AUDIT_SE_TYPE:
- typedatum = hashtab_search(policydb.p_types.table, rulestr);
- if (!typedatum)
- rc = -EINVAL;
- else
- tmprule->au_ctxt.type = typedatum->value;
- break;
- case AUDIT_SE_SEN:
- case AUDIT_SE_CLR:
- rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
- break;
- }
-
- POLICY_RDUNLOCK;
-
- if (rc) {
- selinux_audit_rule_free(tmprule);
- tmprule = NULL;
- }
-
- *rule = tmprule;
-
- return rc;
-}
-
-int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
- struct selinux_audit_rule *rule,
- struct audit_context *actx)
-{
- struct context *ctxt;
- struct mls_level *level;
- int match = 0;
-
- if (!rule) {
- audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
- "selinux_audit_rule_match: missing rule\n");
- return -ENOENT;
- }
-
- POLICY_RDLOCK;
-
- if (rule->au_seqno < latest_granting) {
- audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
- "selinux_audit_rule_match: stale rule\n");
- match = -ESTALE;
- goto out;
- }
-
- ctxt = sidtab_search(&sidtab, ctxid);
- if (!ctxt) {
- audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
- "selinux_audit_rule_match: unrecognized SID %d\n",
- ctxid);
- match = -ENOENT;
- goto out;
- }
-
- /* a field/op pair that is not caught here will simply fall through
- without a match */
- switch (field) {
- case AUDIT_SE_USER:
- switch (op) {
- case AUDIT_EQUAL:
- match = (ctxt->user == rule->au_ctxt.user);
- break;
- case AUDIT_NOT_EQUAL:
- match = (ctxt->user != rule->au_ctxt.user);
- break;
- }
- break;
- case AUDIT_SE_ROLE:
- switch (op) {
- case AUDIT_EQUAL:
- match = (ctxt->role == rule->au_ctxt.role);
- break;
- case AUDIT_NOT_EQUAL:
- match = (ctxt->role != rule->au_ctxt.role);
- break;
- }
- break;
- case AUDIT_SE_TYPE:
- switch (op) {
- case AUDIT_EQUAL:
- match = (ctxt->type == rule->au_ctxt.type);
- break;
- case AUDIT_NOT_EQUAL:
- match = (ctxt->type != rule->au_ctxt.type);
- break;
- }
- break;
- case AUDIT_SE_SEN:
- case AUDIT_SE_CLR:
- level = (op == AUDIT_SE_SEN ?
- &ctxt->range.level[0] : &ctxt->range.level[1]);
- switch (op) {
- case AUDIT_EQUAL:
- match = 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);
- break;
- case AUDIT_LESS_THAN:
- match = (mls_level_dom(&rule->au_ctxt.range.level[0],
- level) &&
- !mls_level_eq(&rule->au_ctxt.range.level[0],
- level));
- break;
- case AUDIT_LESS_THAN_OR_EQUAL:
- match = mls_level_dom(&rule->au_ctxt.range.level[0],
- level);
- break;
- case AUDIT_GREATER_THAN:
- match = (mls_level_dom(level,
- &rule->au_ctxt.range.level[0]) &&
- !mls_level_eq(level,
- &rule->au_ctxt.range.level[0]));
- break;
- case AUDIT_GREATER_THAN_OR_EQUAL:
- match = mls_level_dom(level,
- &rule->au_ctxt.range.level[0]);
- break;
- }
- }
-
-out:
- POLICY_RDUNLOCK;
- return match;
-}
-
-static int (*aurule_callback)(void) = NULL;
-
-static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
- u16 class, u32 perms, u32 *retained)
-{
- int err = 0;
-
- if (event == AVC_CALLBACK_RESET && aurule_callback)
- err = aurule_callback();
- return err;
-}
-
-static int __init aurule_init(void)
-{
- int err;
-
- err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET,
- SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
- if (err)
- panic("avc_add_callback() failed, error %d\n", err);
-
- return err;
-}
-__initcall(aurule_init);
-
-void selinux_audit_set_callback(int (*callback)(void))
-{
- aurule_callback = callback;
-}