permissive domain interface (Re: typebounds lookup from userspace)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If "/selinux/access" can return the 6th value to show whether the given query should be handled as permissive domain or not, it helps userspace
> object managers.

I tried to make a patch as a proof of concept, like:

[root@saba ~]# semanage permissive -a staff_t
[kaigai@saba php-5.2.6]$ ./sapi/cli/php -r    \
'$scontext = "staff_u:staff_r:staff_t";
 $tcontext = "system_u:object_r:etc_t";
 $tclass = selinux_string_to_class("file");

 $avd = selinux_compute_av($scontext, $tcontext, $tclass);
 var_dump($avd);'

array(6) {
  ["allowed"]=>
  int(139347)
  ["decided"]=>
  int(-1)
  ["auditallow"]=>
  int(0)
  ["auditdeny"]=>
  int(-17)
  ["seqno"]=>
  int(2)
  ["permissive"]=>
  bool(true)
}      ^^^^

[kaigai@saba php-5.2.6]$ ./sapi/cli/php -r    \
'$scontext = "user_u:user_r:user_t";
 $tcontext = "system_u:object_r:etc_t";
 $tclass = selinux_string_to_class("file");

 $avd = selinux_compute_av($scontext, $tcontext, $tclass);
 var_dump($avd);'
array(6) {
  ["allowed"]=>
  int(139347)
  ["decided"]=>
  int(-1)
  ["auditallow"]=>
  int(0)
  ["auditdeny"]=>
  int(-17)
  ["seqno"]=>
  int(2)
  ["permissive"]=>
  bool(false)
}      ^^^^^
----

This patch also improves atomicity between av_decision and "permissive domain"
property at avc_has_perm_noaudit(). It should be checked within same critical
section protected by policy_rwlock in strictly, but the current implementation
has a theoretical possibility that a new policy is loaded between
security_compute_av() and security_permissive_sid(). :-)

Thanks,
--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@xxxxxxxxxxxxx>
Index: libselinux/include/selinux/selinux.h
===================================================================
--- libselinux/include/selinux/selinux.h	(revision 2950)
+++ libselinux/include/selinux/selinux.h	(working copy)
@@ -130,8 +130,11 @@
 	access_vector_t auditallow;
 	access_vector_t auditdeny;
 	unsigned int seqno;
+	unsigned int flags;
 };
 
+#define SELINUX_AV_FLAGS_PERMISSIVE		0x0001
+
 /* Structure for passing options, used by AVC and label subsystems */
 struct selinux_opt {
 	int type;
Index: libselinux/src/avc.c
===================================================================
--- libselinux/src/avc.c	(revision 2950)
+++ libselinux/src/avc.c	(working copy)
@@ -855,11 +855,12 @@
 	denied = requested & ~(ae->avd.allowed);
 
 	if (!requested || denied) {
-		if (avc_enforcing) {
+		if (!avc_enforcing || (ae->avd.flags & SELINUX_AV_FLAGS_PERMISSIVE))
+			ae->avd.allowed |= requested;
+		else {
 			errno = EACCES;
 			rc = -1;
-		} else
-			ae->avd.allowed |= requested;
+		}
 	}
 
       out:
@@ -873,7 +874,7 @@
 		 security_class_t tclass, access_vector_t requested,
 		 struct avc_entry_ref *aeref, void *auditdata)
 {
-	struct av_decision avd = { 0, 0, 0, 0, 0 };
+	struct av_decision avd = { 0, 0, 0, 0, 0, 0 };
 	int errsave, rc;
 
 	rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd);
Index: libselinux/src/compute_av.c
===================================================================
--- libselinux/src/compute_av.c	(revision 2950)
+++ libselinux/src/compute_av.c	(working copy)
@@ -49,9 +49,13 @@
 	if (ret < 0)
 		goto out2;
 
-	if (sscanf(buf, "%x %x %x %x %u", &avd->allowed,
-		   &avd->decided, &avd->auditallow, &avd->auditdeny,
-		   &avd->seqno) != 5) {
+	ret = sscanf(buf, "%x %x %x %x %u %x",
+		     &avd->allowed, &avd->decided,
+		     &avd->auditallow, &avd->auditdeny,
+		     &avd->seqno, &avd->flags);
+	if (ret == 5)
+		avd->flags = 0;
+	else if (ret < 5 || ret > 6) {
 		ret = -1;
 		goto out2;
 	}
 security/selinux/avc.c              |    2 +-
 security/selinux/include/security.h |    3 ++-
 security/selinux/selinuxfs.c        |    4 ++--
 security/selinux/ss/services.c      |   30 +++++-------------------------
 4 files changed, 10 insertions(+), 29 deletions(-)

diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index cb30c7e..0a8e3e1 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -904,7 +904,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
 	if (denied) {
 		if (flags & AVC_STRICT)
 			rc = -EACCES;
-		else if (!selinux_enforcing || security_permissive_sid(ssid))
+		else if (!selinux_enforcing || (p_ae->avd.flags & AV_FLAGS_PERMISSIVE))
 			avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
 					tsid, tclass);
 		else
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 7244737..3f3ebd2 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -84,9 +84,10 @@ struct av_decision {
 	u32 auditallow;
 	u32 auditdeny;
 	u32 seqno;
+	u32 flags;
 };
 
-int security_permissive_sid(u32 sid);
+#define AV_FLAGS_PERMISSIVE	0x0001
 
 int security_compute_av(u32 ssid, u32 tsid,
 	u16 tclass, u32 requested,
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 69c9dcc..17360c9 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -589,10 +589,10 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
 		goto out2;
 
 	length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
-			  "%x %x %x %x %u",
+			  "%x %x %x %x %u %x",
 			  avd.allowed, avd.decided,
 			  avd.auditallow, avd.auditdeny,
-			  avd.seqno);
+			  avd.seqno, avd.flags);
 out2:
 	kfree(tcon);
 out:
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index ab0cc0c..a815cfa 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -411,6 +411,7 @@ static int context_struct_compute_av(struct context *scontext,
 	avd->auditallow = 0;
 	avd->auditdeny = 0xffffffff;
 	avd->seqno = latest_granting;
+	avd->flags = 0;
 
 	/*
 	 * Check for all the invalid cases.
@@ -529,31 +530,6 @@ inval_class:
 	return 0;
 }
 
-/*
- * Given a sid find if the type has the permissive flag set
- */
-int security_permissive_sid(u32 sid)
-{
-	struct context *context;
-	u32 type;
-	int rc;
-
-	read_lock(&policy_rwlock);
-
-	context = sidtab_search(&sidtab, sid);
-	BUG_ON(!context);
-
-	type = context->type;
-	/*
-	 * we are intentionally using type here, not type-1, the 0th bit may
-	 * someday indicate that we are globally setting permissive in policy.
-	 */
-	rc = ebitmap_get_bit(&policydb.permissive_map, type);
-
-	read_unlock(&policy_rwlock);
-	return rc;
-}
-
 static int security_validtrans_handle_fail(struct context *ocontext,
 					   struct context *ncontext,
 					   struct context *tcontext,
@@ -769,6 +745,10 @@ int security_compute_av(u32 ssid,
 
 	rc = context_struct_compute_av(scontext, tcontext, tclass,
 				       requested, avd);
+
+	/* check permissive domain */
+	if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
+		avd->flags |= AV_FLAGS_PERMISSIVE;
 out:
 	read_unlock(&policy_rwlock);
 	return rc;

[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux