[RFC] [PATCH]

Darrel Goeddel dgoeddel at trustedcs.com
Thu Feb 16 22:52:48 UTC 2006


OK, I lied.  The next version (below) only has interface changes.
None of the other changes are in yet.  I'll have another version
tomorrow for that...

This has the new interface for getting task sids - selinux_task_ctxid().
It also gets rid of using void pointers for audit rules in the interface.
Stephen, was I on the same page as you with that change?

This should solidify the interface so Dustin can start playing with it.


diff --git a/include/linux/audit.h b/include/linux/audit.h
index 4bb4b9f..dd4f759 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -140,6 +140,11 @@
 #define AUDIT_PERS	10
 #define AUDIT_ARCH	11
 #define AUDIT_MSGTYPE	12
+#define AUDIT_SE_USER	13	/* security label user */
+#define AUDIT_SE_ROLE	14	/* security label role */
+#define AUDIT_SE_TYPE	15	/* security label type */
+#define AUDIT_SE_SEN	16	/* security label sensitivity label */
+#define AUDIT_SE_CLR	17	/* security label clearance label */
 
 				/* These are ONLY useful when checking
 				 * at syscall exit time (AUDIT_AT_EXIT). */
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
new file mode 100644
index 0000000..822a177
--- /dev/null
+++ b/include/linux/selinux.h
@@ -0,0 +1,89 @@
+/*
+ * SELinux services exported to the rest of the kernel.
+ *
+ * Author: James Morris <jmorris at redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris at redhat.com>
+ * Copyright (C) 2006 Trusted Computer Solutions <dgoeddel at trustedcs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#ifndef _LINUX_SELINUX_H
+#define _LINUX_SELINUX_H
+
+#ifdef CONFIG_SECURITY_SELINUX
+
+struct selinux_audit_rule;
+
+/**
+ *	selinux_audit_rule_init - alloc/init an selinux audit rule structure.
+ *	@field: the field this rule refers to
+ *	@op: the operater the rule uses
+ *	@rulestr: the text "target" of the rule
+ *	@rule: address of the rule structure pointer to be returned
+ *
+ *	Returns 0 if successful, -errno if not.  On success, the rule structure
+ *	will be allocated internally.  The caller must free this structure with
+ *	selinux_audit_rule_free() after use.
+ */
+int selinux_audit_rule_init(u32 field, u32 op, const char *rulestr,
+                            struct selinux_audit_rule **rule);
+
+/**
+ *	selinux_audit_rule_free - free an selinux audit rule structure.
+ *	@rule: address of the rule structure to be freed
+ *
+ *	This will free all memory associated with the given rule.
+ */
+void selinux_audit_rule_free(struct selinux_audit_rule *rule);
+
+/**
+ *	selinux_audit_rule_match - determine if a context ID matches a rule.
+ *	@ctxid: the context ID to check
+ *	@rule: the audit rule created by selinux_audit_rule_init()
+ *
+ *	Returns 1 if the context id matches the rule, 0 if it does not, and
+ *	-errno on failure.
+ */
+int selinux_audit_rule_match(u32 ctxid, struct selinux_audit_rule *rule);
+
+/**
+ *	selinux_task_ctxid - determine a context ID for a process.
+ *	@tsk: the task object
+ *	@ctxid: ID value returned via this
+ *
+ *	On return, ctxid will contain an ID for the context.  This value
+ *	should only be used opaquely.
+ */
+void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid);
+
+#else
+
+static inline int selinux_audit_rule_init(u32 field, u32 op,
+                                          const char *rulestr,
+                                          struct selinux_audit_rule **rule)
+{
+	return -ENOTSUPP;
+}
+
+static inline void selinux_audit_rule_free(struct selinux_audit_rule *rule)
+{
+	return;
+}
+
+static inline int selinux_audit_rule_match(u32 ctxid,
+                                           struct selinux_audit_rule *rule)
+{
+	return 0;
+}
+
+static inline void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
+{
+	*ctxid = 0;
+}
+
+#endif	/* CONFIG_SECURITY_SELINUX */
+
+#endif /* _LINUX_SELINUX_H */
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 688c0a2..faf2e02 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
 
-selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o
+selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o exports.o
 
 selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
 
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
new file mode 100644
index 0000000..56e13ac
--- /dev/null
+++ b/security/selinux/exports.c
@@ -0,0 +1,45 @@
+/*
+ * SELinux services exported to the rest of the kernel.
+ *
+ * Author: James Morris <jmorris at redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/selinux.h>
+
+#include "security.h"
+#include "objsec.h"
+
+int selinux_audit_rule_init(u32 field, u32 op, const char *rulestr,
+                            struct selinux_audit_rule **rule)
+{
+	return security_aurule_init(field, op, rulestr, rule);
+}
+
+void selinux_audit_rule_free(struct selinux_audit_rule *rule)
+{
+	return security_aurule_free(rule);
+}
+
+int selinux_audit_rule_match(u32 ctxid, struct selinux_audit_rule *rule)
+{
+	return security_aurule_match(ctxid, rule);
+}
+
+void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
+{
+	struct task_security_struct *tsec = tsk->security;
+	*ctxid = tsec->sid;
+}
+
+EXPORT_SYMBOL_GPL(selinux_audit_rule_init);
+EXPORT_SYMBOL_GPL(selinux_audit_rule_free);
+EXPORT_SYMBOL_GPL(selinux_audit_rule_match);
+EXPORT_SYMBOL_GPL(selinux_task_ctxid);
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 5f016c9..51a719e 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -96,5 +96,12 @@ int security_fs_use(const char *fstype, 
 int security_genfs_sid(const char *fstype, char *name, u16 sclass,
 	u32 *sid);
 
+struct selinux_audit_rule;
+
+int security_aurule_init(u32 field, u32 op, const char *rulestr,
+                         struct selinux_audit_rule **rule);
+void security_aurule_free(struct selinux_audit_rule *rule);
+int security_aurule_match(u32 ctxid, struct selinux_audit_rule *rule);
+
 #endif /* _SELINUX_SECURITY_H_ */
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d877cd1..48f0b85 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1810,3 +1810,248 @@ out:
 	POLICY_RDUNLOCK;
 	return rc;
 }
+
+struct selinux_audit_rule {
+	u32 au_skip;
+	u32 au_op;
+	u32 au_field;
+	u32 au_seqno;
+	struct context au_ctxt;
+	char *au_str;
+};
+
+/* needs policy read lock held */
+static void aurule_init_context(struct selinux_audit_rule *rule)
+{
+	struct role_datum *roledatum;
+	struct type_datum *typedatum;
+	struct user_datum *userdatum;
+	char *tmpstr;
+	int rc = 0;
+
+	switch (rule->au_field) {
+	case AUDIT_SE_USER:
+		userdatum = hashtab_search(policydb.p_users.table,
+		                           rule->au_str);
+		if (!userdatum)
+			rc = -EINVAL;
+		else
+			rule->au_ctxt.user = userdatum->value;
+		break;
+	case AUDIT_SE_ROLE:
+		roledatum = hashtab_search(policydb.p_roles.table,
+		                           rule->au_str);
+		if (!roledatum)
+			rc = -EINVAL;
+		else
+			rule->au_ctxt.role = roledatum->value;
+		break;
+	case AUDIT_SE_TYPE:
+		typedatum = hashtab_search(policydb.p_types.table,
+		                           rule->au_str);
+		if (!typedatum)
+			rc = -EINVAL;
+		else
+			rule->au_ctxt.type = typedatum->value;
+		break;
+	case AUDIT_SE_SEN:
+	case AUDIT_SE_CLR:
+		/* TODO:figure out proper allocation below */
+		tmpstr = kstrdup(rule->au_str, GFP_KERNEL);
+		rc = mls_context_to_sid(':', &tmpstr, &rule->au_ctxt, NULL,
+		                        SECSID_NULL);
+		kfree(tmpstr);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	if (rc) {
+		rule->au_skip = 1;
+		context_destroy(&rule->au_ctxt);
+	} else {
+		/* we merely flags this rule to not be processed - the role,
+		   user, type, or level of the rule may not be valid now, but
+		   may be after a future policy reload. */
+		rule->au_skip = 0;
+	}
+
+	return;
+}
+
+int security_aurule_init(u32 field, u32 op, const char *rulestr,
+                         struct selinux_audit_rule **rule)
+{
+	struct selinux_audit_rule *tmprule;
+
+	*rule = NULL;
+
+	switch (field) {
+	case AUDIT_SE_USER:
+	case AUDIT_SE_ROLE:
+	case AUDIT_SE_TYPE:
+		/* only 'equals' and 'not equals' make sense */
+		if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+			return -EINVAL;
+	case AUDIT_SE_SEN:
+	case AUDIT_SE_CLR:
+		/* we do not allow a range, indicated by '-' */
+		if (strchr(rulestr, '-'))
+			return -EINVAL;
+	}
+
+	/* TODO:figure out proper allocations below */
+	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
+	if (!tmprule)
+		return -ENOMEM;
+	tmprule->au_str = kstrdup(rulestr, GFP_KERNEL);
+	if (!tmprule->au_str) {
+		kfree(tmprule);
+		return -ENOMEM;
+	}
+	tmprule->au_op = op;
+	tmprule->au_field = field;
+	context_init(&tmprule->au_ctxt);
+
+	if (!ss_initialized) {
+		tmprule->au_seqno = latest_granting;
+		tmprule->au_skip = 1;
+		*rule = tmprule;
+		return 0;
+	}
+
+	POLICY_RDLOCK;
+
+	tmprule->au_seqno = latest_granting;
+	aurule_init_context(tmprule);
+
+	POLICY_RDUNLOCK;
+
+	*rule = tmprule;
+
+	return 0;
+}
+
+void security_aurule_free(struct selinux_audit_rule *rule)
+{
+	kfree(rule->au_str);
+	context_destroy(&rule->au_ctxt);
+	kfree(rule);
+}
+
+int security_aurule_match(u32 ctxid, struct selinux_audit_rule *rule)
+{
+	struct context *ctxt;
+	struct mls_level *level;
+	int match = 0;
+
+	if (!rule || !ss_initialized)
+		return 0;
+
+	POLICY_RDLOCK;
+
+	if (rule->au_seqno < latest_granting) {
+		context_destroy(&rule->au_ctxt);
+		rule->au_seqno = latest_granting;
+		aurule_init_context(rule);
+	}
+
+	if (rule->au_skip)
+		goto out;
+
+	ctxt = sidtab_search(&sidtab, ctxid);
+	if (!ctxt) {
+		/* TODO: what to do? */
+		printk(KERN_ERR "security_aurule_match: unrecognized SID %d\n",
+		       ctxid);
+		match = -EINVAL;
+		goto out;
+	}
+
+	switch (rule->au_field) {
+	case AUDIT_SE_USER:
+		switch (rule->au_op) {
+		case AUDIT_EQUAL:
+			match = (ctxt->user == rule->au_ctxt.user);
+			break;
+		case AUDIT_NOT_EQUAL:
+			match = (ctxt->user != rule->au_ctxt.user);
+			break;
+		default:
+			match = -EINVAL;
+			break;
+		}
+		break;
+	case AUDIT_SE_ROLE:
+		switch (rule->au_op) {
+		case AUDIT_EQUAL:
+			match = (ctxt->role == rule->au_ctxt.role);
+			break;
+		case AUDIT_NOT_EQUAL:
+			match = (ctxt->role != rule->au_ctxt.role);
+			break;
+		default:
+			match = -EINVAL;
+			break;
+		}
+		break;
+	case AUDIT_SE_TYPE:
+		switch (rule->au_op) {
+		case AUDIT_EQUAL:
+			match = (ctxt->type == rule->au_ctxt.type);
+			break;
+		case AUDIT_NOT_EQUAL:
+			match = (ctxt->type != rule->au_ctxt.type);
+			break;
+		default:
+			match = -EINVAL;
+			break;
+		}
+		break;
+	case AUDIT_SE_SEN:
+	case AUDIT_SE_CLR:
+		level = (rule->au_op == AUDIT_SE_SEN ?
+		         &ctxt->range.level[0] : &ctxt->range.level[1]);
+		switch (rule->au_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);
+			break;
+		case AUDIT_LESS_THAN_OR_EQUAL:
+			match = (mls_level_eq(&rule->au_ctxt.range.level[0],
+			                      level) ||
+			         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]);
+			break;
+		case AUDIT_GREATER_THAN_OR_EQUAL:
+			match = (mls_level_eq(&rule->au_ctxt.range.level[0],
+			                      level) ||
+			         mls_level_dom(level,
+			                      &rule->au_ctxt.range.level[0]));
+			break;
+		default:
+			match = -EINVAL;
+			break;
+		}
+	default:
+		match = -EINVAL;
+		break;
+	}
+
+out:
+	POLICY_RDUNLOCK;
+	return match;
+}

-- 

Darrel




More information about the Linux-audit mailing list