Skip to contentSkip to conversation

libselinux: class and permission mapping support

PATCH In review Eamon Walsh 5 participants 13 messages Jun 6, 2007 – Jun 8, 2007 SELinux security module

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 libselinux: class and permission mapping support

This provides support for userspace object managers to register a mapping of class and permission values. After the mapping is registered all libselinux functions that take a security class or permission value must be provided with mapped values instead of the "real," kernel values.

Changes from the original interface proposal: No selinux_init() function, just a straight set_mapping() function. Also, to simplify things the incoming mapping does not include explicit values; the classes and permissions are numbered implicitly by their ordering. NULL strings are used to terminate the lists.

Tested with X server, no problems encountered.

This patch includes the interface and implementation of the mapping set function.

---

include/selinux/selinux.h | 8 +++++
src/mapping.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++

2 files changed, 75 insertions(+)
include/selinux/selinux.h +0 -0
Index: libselinux/include/selinux/selinux.h
===================================================================
@@ -280,6 +280,14 @@

/* Commit the pending values for the booleans */
extern int security_commit_booleans(void);

+/* Userspace class mapping support */
+struct security_class_mapping {
+ const char *name;
+ const char *perms[sizeof(access_vector_t) * 8 + 1];
+};
+
+int selinux_set_mapping(struct security_class_mapping *map); +
/* Common helpers */

/* Convert between security class values and string names */

src/mapping.c +67 -0

67 lines not on this page · raw message

Signature · 8 lines
Eamon Walsh <[email protected]>
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#1 lore raw
Quoted 13 lines · Eamon Walsh

This provides support for userspace object managers to register a mapping of class and permission values. After the mapping is registered all libselinux functions that take a security class or permission value must be provided with mapped values instead of the "real," kernel values.

Changes from the original interface proposal: No selinux_init() function, just a straight set_mapping() function. Also, to simplify things the incoming mapping does not include explicit values; the classes and permissions are numbered implicitly by their ordering. NULL strings are used to terminate the lists.

Quoted 5 lines

Tested with X server, no problems encountered.

This patch includes the interface and implementation of the mapping set function.

Hrm, I thought we agreed that remapping access vectors at runtime was a bad idea?

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#2 lore raw
Quoted 14 lines · Joshua Brindle
Quoted 13 lines · Eamon Walsh

This provides support for userspace object managers to register a mapping of class and permission values. After the mapping is registered all libselinux functions that take a security class or permission value must be provided with mapped values instead of the "real," kernel values.

Changes from the original interface proposal: No selinux_init() function, just a straight set_mapping() function. Also, to simplify things the incoming mapping does not include explicit values; the classes and permissions are numbered implicitly by their ordering. NULL strings are used to terminate the lists.

Quoted 9 lines
Quoted 5 lines

Tested with X server, no problems encountered.

This patch includes the interface and implementation of the mapping set function.

Hrm, I thought we agreed that remapping access vectors at runtime was a bad idea?

I did think that initially, but I didn't realize that the mapping could be done underneath the AVC instead of on every single call to avc_has_perm or whatnot.

The overhead of the remapping should be negligible compared to the cost of an selinuxfs operation, right? And it frees the userspace object manager from having to manage the translation tables itself.

Signature · 7 lines
Eamon Walsh <[email protected]>
National Security Agency

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#3 lore raw
In reply to Eamon Walsh
Quoted 12 lines · Eamon Walsh

This provides support for userspace object managers to register a mapping of class and permission values. After the mapping is registered all libselinux functions that take a security class or permission value must be provided with mapped values instead of the "real," kernel values.

Changes from the original interface proposal: No selinux_init() function, just a straight set_mapping() function. Also, to simplify things the incoming mapping does not include explicit values; the classes and permissions are numbered implicitly by their ordering. NULL strings are used to terminate the lists.

Quoted 4 lines

Tested with X server, no problems encountered.

This patch includes the interface and implementation of the mapping set function.

Can you post a snippet of code from the X server showing the usage of this interface by an object manager?

I was thinking that we weren't going down this route due to complexity/performance concerns about having to remap the access vectors on checks, but it doesn't look too bad from your patches, especially since the mapping happens on compute_av and the AVC can just always use the mapped values.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#4 lore raw
Quoted 14 lines · Stephen Smalley
Quoted 12 lines · Eamon Walsh

This provides support for userspace object managers to register a mapping of class and permission values. After the mapping is registered all libselinux functions that take a security class or permission value must be provided with mapped values instead of the "real," kernel values.

Changes from the original interface proposal: No selinux_init() function, just a straight set_mapping() function. Also, to simplify things the incoming mapping does not include explicit values; the classes and permissions are numbered implicitly by their ordering. NULL strings are used to terminate the lists.

Quoted 8 lines
Quoted 5 lines

Tested with X server, no problems encountered.

This patch includes the interface and implementation of the mapping set function.

Can you post a snippet of code from the X server showing the usage of this interface by an object manager

In a header file:

/* Private Flask definitions */
#define SECCLASS_DRAWABLE 1
#define DRAWABLE__CREATE 0x00000001UL
#define DRAWABLE__DESTROY 0x00000002UL
#define DRAWABLE__DRAW 0x00000004UL
#define DRAWABLE__COPY 0x00000008UL
#define DRAWABLE__GETATTR 0x00000010UL
#define SECCLASS_WINDOW 2
#define WINDOW__ADDCHILD 0x00000001UL
#define WINDOW__CREATE 0x00000002UL
#define WINDOW__DESTROY 0x00000004UL
#define WINDOW__MAP 0x00000008UL
#define WINDOW__UNMAP 0x00000010UL
#define WINDOW__CHSTACK 0x00000020UL
#define WINDOW__CHPROPLIST 0x00000040UL
#define WINDOW__CHPROP 0x00000080UL
#define WINDOW__LISTPROP 0x00000100UL
#define WINDOW__GETATTR 0x00000200UL
#define WINDOW__SETATTR 0x00000400UL
#define WINDOW__SETFOCUS 0x00000800UL
#define WINDOW__MOVE 0x00001000UL
#define WINDOW__CHSELECTION 0x00002000UL
#define WINDOW__CHPARENT 0x00004000UL
#define WINDOW__CTRLLIFE 0x00008000UL
#define WINDOW__ENUMERATE 0x00010000UL
#define WINDOW__TRANSPARENT 0x00020000UL
#define WINDOW__MOUSEMOTION 0x00040000UL
#define WINDOW__CLIENTCOMEVENT 0x00080000UL
#define WINDOW__INPUTEVENT 0x00100000UL
#define WINDOW__DRAWEVENT 0x00200000UL
#define WINDOW__WINDOWCHANGEEVENT 0x00400000UL
#define WINDOW__WINDOWCHANGEREQUEST 0x00800000UL
#define WINDOW__SERVERCHANGEEVENT 0x01000000UL
#define WINDOW__EXTENSIONEVENT 0x02000000UL
#define SECCLASS_GC 3
#define GC__CREATE 0x00000001UL
#define GC__FREE 0x00000002UL
#define GC__GETATTR 0x00000004UL
#define GC__SETATTR 0x00000008UL
#define SECCLASS_FONT 4
...

In the initialization code:

/* Dynamically allocated security classes and permissions */ /* Do not change these without changing the private Flask definitions */ static struct security_class_mapping map[] = {
{ "drawable",

     { "create", "destroy", "draw", "copy", "getattr", NULL }},
   { "window",
     { "addchild", "create", "destroy", "map", "unmap", "chstack",
	"chproplist", "chprop", "listprop", "getattr", "setattr", "setfocus",
	"move", "chselection", "chparent", "ctrllife", "enumerate",
	"transparent", "mousemotion", "clientcomevent", "inputevent",
	"drawevent", "windowchangeevent", "windowchangerequest",
	"serverchangeevent", "extensionevent", NULL }},
   { "gc",
     { "create", "free", "getattr", "setattr", NULL }},
   { "font",
     { "load", "free", "getattr", "use", NULL }},
   { "colormap",
     { "create", "free", "install", "uninstall", "list", "read", "store",
	"getattr", "setattr", NULL }},
   { "property",
     { "create", "free", "read", "write", NULL }},
   { "cursor",
     { "create", "createglyph", "free", "assign", "setattr", NULL }},
   { "xclient",
     { "kill", NULL }},
   { "xinput",
     { "lookup", "getattr", "setattr", "setfocus", "warppointer",
	"activegrab", "passivegrab", "ungrab", "bell", "mousemotion",
	"relabelinput", NULL }},
   { "xserver",
     { "screensaver", "gethostlist", "sethostlist", "getfontpath",
	"setfontpath", "getattr", "grab", "ungrab", NULL }},
   { "xextension",
     { "query", "use", NULL }},

{ NULL }
};

if (selinux_set_mapping(map) < 0) {
FatalError("XSELinux: Failed to set up security class mapping\n");
}

That's it, no other changes.

Signature · 8 lines
Eamon Walsh <[email protected]>
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#5 lore raw
In reply to Eamon Walsh
Quoted 69 lines · Eamon Walsh

This provides support for userspace object managers to register a mapping of class and permission values. After the mapping is registered all libselinux functions that take a security class or permission value must be provided with mapped values instead of the "real," kernel values.

Changes from the original interface proposal: No selinux_init() function, just a straight set_mapping() function. Also, to simplify things the incoming mapping does not include explicit values; the classes and permissions are numbered implicitly by their ordering. NULL strings are used to terminate the lists.

Tested with X server, no problems encountered.

This patch includes the interface and implementation of the mapping set function.

---

 include/selinux/selinux.h |    8 +++++
 src/mapping.c             |   67 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

Index: libselinux/include/selinux/selinux.h
===================================================================

include/selinux/selinux.h +8 -0
@@ -280,6 +280,14 @@
 /* Commit the pending values for the booleans */
 extern int security_commit_booleans(void);
 
+/* Userspace class mapping support */
+struct security_class_mapping {
+	const char *name;
+	const char *perms[sizeof(access_vector_t) * 8 + 1];
+};
+
+int selinux_set_mapping(struct security_class_mapping *map);
+
 /* Common helpers */
 
 /* Convert between security class values and string names */

Index: libselinux/src/mapping.c
===================================================================

src/mapping.c +21 -0
@@ -0,0 +1,67 @@
+/*
+ * Class and permission mappings.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <selinux/selinux.h>
+#include "mapping.h"
+
+/* class and permission mappings */
+struct selinux_mapping *current_mapping = NULL;
+security_class_t current_mapping_size = 0;
+
+/* mapping setting function */
+int
+selinux_set_mapping(struct security_class_mapping *map)
+{
+	size_t size = sizeof(struct selinux_mapping);
+	security_class_t i, j;
+	unsigned k;

src/mapping.c line 31

Quoted 10 lines
src/mapping.c +10 -0
+
+	free(current_mapping);
+	current_mapping = NULL;
+	current_mapping_size = 0;
+
+	/* Find number of classes in the input mapping plus one */
+	i = 1;
+	while (map && map[i-1].name)
+		i++;
+

Shouldn't you check for map being NULL at the beginning? if map == NULL, i = 1, ...

src/mapping.c line 36

Quoted 5 lines
src/mapping.c +5 -0
+	/* Allocate space for the class records */
+	current_mapping = (struct selinux_mapping *)calloc(i, size);
+	if (!current_mapping)
+		goto err;
+

Now calloc is called with i = 1 ...

Quoted 14 lines
src/mapping.c +14 -0
+	/* Store the raw class and permission values */
+	j = 0;
+	while (map && map[j].name) {
+		struct security_class_mapping *p_in = map + (j++);
+		struct selinux_mapping *p_out = current_mapping + j;
+
+		p_out->value = string_to_security_class(p_in->name);
+		if (!p_out->value)
+			goto err2;
+
+		k = 0;
+		while (p_in->perms && p_in->perms[k]) {
+			p_out->perms[k] = string_to_av_perm(p_out->value,
+							    p_in->perms[k]);

src/mapping.c line 60

Quoted 10 lines
src/mapping.c +10 -0
+			if (!p_out->perms[k])
+				goto err2;
+			k++;
+		}
+		p_out->num_perms = k;
+	}
+
+	/* Set the mapping size here so the above lookups are "raw" */
+	current_mapping_size = i;
+	return 0;

current_mapping_size = 1
return 0
for map == NULL

This doesn't seem like the correct behavior.

Quoted 8 lines
src/mapping.c +7 -0
+err2:
+	free(current_mapping);
+	current_mapping = NULL;
+	current_mapping_size = 0;
+err:
+	return -1;
+}
Signature · 8 lines
James Carter <[email protected]>
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#6 lore raw

PATCH 1/2 libselinux: class and permission mapping support (try 2)

Changes from the first version: disallow a NULL mapping with error EINVAL; add assert statements to the map/unmap helpers to catch out-of-bounds value bugs in callers.

This provides support for userspace object managers to register a mapping of class and permission values. After the mapping is registered all libselinux functions that take a security class or permission value must be provided with mapped values instead of the "real," kernel values.

Changes from the original interface proposal: No selinux_init() function, just a straight set_mapping() function. Also, to simplify things the incoming mapping does not include explicit values; the classes and permissions are numbered implicitly by their ordering. NULL strings are used to terminate the lists.

Tested with X server, no problems encountered.

This patch includes the interface and implementation of the mapping set function.

---

include/selinux/selinux.h | 8 +++++
src/mapping.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++

2 files changed, 80 insertions(+)
include/selinux/selinux.h +0 -0
Index: libselinux/include/selinux/selinux.h
===================================================================
@@ -280,6 +280,14 @@

/* Commit the pending values for the booleans */
extern int security_commit_booleans(void);

+/* Userspace class mapping support */
+struct security_class_mapping {
+ const char *name;
+ const char *perms[sizeof(access_vector_t) * 8 + 1];
+};
+
+int selinux_set_mapping(struct security_class_mapping *map); +
/* Common helpers */

/* Convert between security class values and string names */

src/mapping.c +72 -0

72 lines not on this page · raw message

Signature · 8 lines
Eamon Walsh <[email protected]>
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#7 lore raw

PATCH 2/2 libselinux: class and permission mapping support (try 2)

In reply to James Carter

This patch includes the internal map and unmap functions and the changes to the selinuxfs interfaces to make it work.

---

compute_av.c      |    8 ++-
compute_create.c  |    5 +-
compute_member.c  |    5 +-
compute_relabel.c |    5 +-
mapping.h         |  121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
stringrep.c       |   17 +++++--
6 files changed, 148 insertions(+), 13 deletions(-)
src/mapping.h +120 -0
Index: libselinux/src/mapping.h
===================================================================
@@ -0,0 +1,121 @@
+/*
+ * This file describes the class and permission mappings used to + * hide the kernel numbers from userspace by allowing userspace object
+ * managers to specify a list of classes and permissions.
+ */
+#ifndef _SELINUX_MAPPING_H_
+#define _SELINUX_MAPPING_H_
+
+#include <assert.h>
+#include <selinux/selinux.h>
+
+struct selinux_mapping {
+	security_class_t value; /* real, kernel value */
+	unsigned num_perms;
+	access_vector_t perms[sizeof(access_vector_t) * 8];
+};
+
+extern struct selinux_mapping *current_mapping;
+extern security_class_t current_mapping_size;
+
+/*
+ * Get real, kernel values from mapped values
+ */
+
+static inline security_class_t
+unmap_class(security_class_t tclass)
+{
+	if (tclass < current_mapping_size)
+		return current_mapping[tclass].value;
+
+	assert(current_mapping_size == 0);
+	return tclass;
+}
+
+static inline access_vector_t
+unmap_perm(security_class_t tclass, access_vector_t tperm)
+{
+	if (tclass < current_mapping_size) {
+		unsigned i;
+		access_vector_t kperm = 0;
+
+		for (i=0; i<current_mapping[tclass].num_perms; i++)
+			if (tperm & (1<<i)) {
+				kperm |= current_mapping[tclass].perms[i];
+				tperm &= ~(1<<i);
+			}
+		assert(tperm == 0);
+		return kperm;
+	}
+
+	assert(current_mapping_size == 0);
+	return tperm;
+}
+
+/*
+ * Get mapped values from real, kernel values
+ */
+
+static inline security_class_t
+map_class(security_class_t kclass)
+{
+	security_class_t i;
+
+	for (i=0; i<current_mapping_size; i++)
+		if (current_mapping[i].value == kclass)
+			return i;
+
+	assert(current_mapping_size == 0);
+	return kclass;
+}
+
+static inline access_vector_t
+map_perm(security_class_t tclass, access_vector_t kperm)
+{
+	if (tclass < current_mapping_size) {
+		unsigned i;
+		access_vector_t tperm = 0;
+
+		for (i=0; i<current_mapping[tclass].num_perms; i++)
+			if (kperm & current_mapping[tclass].perms[i]) {
+				tperm |= 1<<i;
+				kperm &= ~current_mapping[tclass].perms[i];
+			}
+		assert(kperm == 0);
+		return tperm;
+	}
+
+	assert(current_mapping_size == 0);
+	return kperm;
+}
+
+static inline void
+map_decision(security_class_t tclass, struct av_decision *avd)
+{
+	if (tclass < current_mapping_size) {
+		unsigned i;
+		access_vector_t result;
+
+		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
+			if (avd->allowed & current_mapping[tclass].perms[i])
+				result |= 1<<i;
+		avd->allowed = result;
+
+		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
+			if (avd->decided & current_mapping[tclass].perms[i])
+				result |= 1<<i;
+		avd->decided = result;
+
+		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
+			if (avd->auditallow & current_mapping[tclass].perms[i])
+				result |= 1<<i;
+		avd->auditallow = result;
+
+		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
+			if (avd->auditdeny & current_mapping[tclass].perms[i])
+				result |= 1<<i;
+		avd->auditdeny = result;
+	}
+}
+
+#endif				/* _SELINUX_MAPPING_H_ */
src/stringrep.c +0 -0
Index: libselinux/src/stringrep.c
===================================================================
@@ -11,6 +11,7 @@

#include <selinux/flask.h>
#include <selinux/av_permissions.h>
#include "selinux_internal.h"
+#include "mapping.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

@@ -151,12 +152,12 @@

	if (isdigit(s[0])) {
		val = atoi(s);
		if (val > 0 && val < NCLASSES)
-			return val;
+			return map_class(val);
	} else {
		for (val = 0; val < NCLASSES; val++) {
			if (strcmp(s, (class_to_string_data.str
				       + class_to_string[val])) == 0)
-				return val;
+				return map_class(val);
		}
	}

@@ -169,9 +170,10 @@

	const uint16_t *common_pts_idx = 0;
	access_vector_t perm, common_base = 0;
	unsigned int i;

+ security_class_t kclass = unmap_class(tclass);

	for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
-		if (av_inherit[i].tclass == tclass) {
+		if (av_inherit[i].tclass == kclass) {
			common_pts_idx =
			    &common_perm_to_string.data[av_inherit[i].
							common_pts_idx];
@@ -186,13 +188,13 @@
		if (strcmp
		    (s,
		     common_perm_to_string_data.str + common_pts_idx[i]) == 0)
-			return perm;
+			return map_perm(tclass, perm);
		perm <<= 1;
		i++;
	}

	for (i = 0; i < NVECTORS; i++) {
-		if ((av_perm_to_string[i].tclass == tclass) &&
+		if ((av_perm_to_string[i].tclass == kclass) &&
		    (strcmp(s, (av_perm_to_string_data.str
				+ av_perm_to_string[i].nameidx)) == 0))
			return av_perm_to_string[i].value;

@@ -204,6 +206,8 @@

const char *security_class_to_string(security_class_t tclass) {
+ tclass = unmap_class(tclass);
+

	if (tclass > 0 && tclass < NCLASSES)
		return class_to_string_data.str + class_to_string[tclass];

@@ -218,6 +222,9 @@

	access_vector_t common_base = 0;
	unsigned int i;

+ av = unmap_perm(tclass, av);
+ tclass = unmap_class(tclass);
+

	if (!av)
		return NULL;
src/compute_av.c +0 -0
Index: libselinux/src/compute_av.c
===================================================================
@@ -5,9 +5,10 @@

#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "selinux_internal.h"
#include "policy.h"
-#include <limits.h>
+#include "mapping.h"

int security_compute_av_raw(security_context_t scon,
security_context_t tcon,
@@ -36,7 +37,8 @@

		goto out;
	}

- snprintf(buf, len, "%s %s %hu %x", scon, tcon, tclass, requested);
+ snprintf(buf, len, "%s %s %hu %x", scon, tcon,
+ unmap_class(tclass), unmap_perm(tclass, requested));

	ret = write(fd, buf, strlen(buf));
	if (ret < 0)
@@ -54,6 +56,8 @@
		goto out2;
	}

+ map_decision(tclass, avd);
+

	ret = 0;
      out2:
	free(buf);
src/compute_create.c +0 -0
Index: libselinux/src/compute_create.c
===================================================================
@@ -5,9 +5,10 @@

#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "selinux_internal.h"
#include "policy.h"
-#include <limits.h>
+#include "mapping.h"

int security_compute_create_raw(security_context_t scon,
security_context_t tcon,
@@ -35,7 +36,7 @@

		ret = -1;
		goto out;
	}

- snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+ snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));

	ret = write(fd, buf, strlen(buf));
	if (ret < 0)
src/compute_member.c +0 -0
Index: libselinux/src/compute_member.c
===================================================================
@@ -5,9 +5,10 @@

#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "selinux_internal.h"
#include "policy.h"
-#include <limits.h>
+#include "mapping.h"

int security_compute_member_raw(security_context_t scon,
security_context_t tcon,
@@ -35,7 +36,7 @@

		ret = -1;
		goto out;
	}

- snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+ snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));

	ret = write(fd, buf, strlen(buf));
	if (ret < 0)
src/compute_relabel.c +0 -0
Index: libselinux/src/compute_relabel.c
===================================================================
@@ -5,9 +5,10 @@

#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "selinux_internal.h"
#include "policy.h"
-#include <limits.h>
+#include "mapping.h"

int security_compute_relabel_raw(security_context_t scon,
security_context_t tcon,
@@ -35,7 +36,7 @@

		ret = -1;
		goto out;
	}

- snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+ snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));

	ret = write(fd, buf, strlen(buf));
	if (ret < 0)
Signature · 8 lines
Eamon Walsh <[email protected]>
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#8 lore raw

Re: [PATCH 2/2] libselinux: class and permission mapping support (try 2)

Quoted 25 lines · Eamon Walsh

This patch includes the internal map and unmap functions and the changes to the selinuxfs interfaces to make it work.

---

 compute_av.c      |    8 ++-
 compute_create.c  |    5 +-
 compute_member.c  |    5 +-
 compute_relabel.c |    5 +-
 mapping.h         |  121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 stringrep.c       |   17 +++++--
 6 files changed, 148 insertions(+), 13 deletions(-)

Index: libselinux/src/mapping.h
===================================================================

src/mapping.h +6 -0
@@ -0,0 +1,121 @@
+/*
+ * This file describes the class and permission mappings used to 
+ * hide the kernel numbers from userspace by allowing userspace object
+ * managers to specify a list of classes and permissions.
+ */
+#ifndef _SELINUX_MAPPING_H_

src/mapping.h line 16

Quoted 10 lines
src/mapping.h +10 -0
+#define _SELINUX_MAPPING_H_
+
+#include <assert.h>
+#include <selinux/selinux.h>
+
+struct selinux_mapping {
+	security_class_t value; /* real, kernel value */
+	unsigned num_perms;
+	access_vector_t perms[sizeof(access_vector_t) * 8];
+};

Should 8 be sizeof(access_vector_t)?

Karl

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#9 lore raw

PATCH 1/3 libselinux: class and permission mapping support (try 3)

Changes from the second version: rebase to object class discovery patchset; flush the AVC when setting a mapping.

Changes from the first version: disallow a NULL mapping with error EINVAL; add assert statements to the map/unmap helpers to catch out-of-bounds value bugs in callers.

This provides support for userspace object managers to register a mapping of class and permission values. After the mapping is registered all libselinux functions that take a security class or permission value must be provided with mapped values instead of the "real," kernel values.

Changes from the original interface proposal: No selinux_init() function, just a straight set_mapping() function. Also, to simplify things the incoming mapping does not include explicit values; the classes and permissions are numbered implicitly by their ordering. NULL strings are used to terminate the lists.

Tested with X server, no problems encountered.

This patch includes the interface and implementation of the mapping set function.

---

include/selinux/selinux.h | 8 +
src/mapping.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++

2 files changed, 197 insertions(+)
include/selinux/selinux.h +0 -0
Index: libselinux/include/selinux/selinux.h
===================================================================
@@ -280,6 +280,14 @@

/* Commit the pending values for the booleans */
extern int security_commit_booleans(void);

+/* Userspace class mapping support */
+struct security_class_mapping {
+ const char *name;
+ const char *perms[sizeof(access_vector_t) * 8 + 1];
+};
+
+int selinux_set_mapping(struct security_class_mapping *map); +
/* Common helpers */

/* Convert between security class values and string names */

src/mapping.c +189 -0

189 lines not on this page · raw message

Signature · 8 lines
Eamon Walsh <[email protected]>
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#10 lore raw

PATCH 2/3 libselinux: class and permission mapping support (try 3)

In reply to Karl MacMillan

This patch makes avc_reset() exit properly if the AVC was not initialized.

---

avc.c          |    5 +++++
avc_internal.c |    1 +
avc_internal.h |    1 +
3 files changed, 7 insertions(+)
src/avc_internal.h +0 -0
Index: libselinux/src/avc_internal.h
===================================================================
@@ -71,6 +71,7 @@

/* message prefix and enforcing mode*/
#define AVC_PREFIX_SIZE 16
extern char avc_prefix[AVC_PREFIX_SIZE] hidden;
+extern int avc_running hidden;
extern int avc_enforcing hidden;

/* user-supplied callback interface for avc */

src/avc_internal.c +0 -0
Index: libselinux/src/avc_internal.c
===================================================================
@@ -44,6 +44,7 @@
 

/* message prefix string and avc enforcing mode */ char avc_prefix[AVC_PREFIX_SIZE] = "uavc"; +int avc_running = 0;
int avc_enforcing = 1;
int avc_netlink_trouble = 0;

src/avc.c +0 -0
Index: libselinux/src/avc.c
===================================================================
@@ -225,6 +225,7 @@
		avc_netlink_thread = avc_create_thread(&avc_netlink_loop);
		avc_netlink_trouble = 0;
	}
+	avc_running = 1;
      out:
	return rc;
}
@@ -534,6 +535,9 @@
	struct avc_node *node, *tmp;
	errno = 0;

+ if (!avc_running)
+ return 0;
+

	avc_get_lock(avc_lock);

	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
@@ -609,6 +613,7 @@
	avc_free_lock(avc_lock);
	avc_free_lock(avc_log_lock);
	avc_free(avc_audit_buf);

+ avc_running = 0;
}

/* ratelimit stuff put aside for now --EFW */

Signature · 8 lines
Eamon Walsh <[email protected]>
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#11 lore raw

PATCH 3/3 libselinux: class and permission mapping support (try 3)

In reply to Karl MacMillan

This patch includes the internal map and unmap functions and the changes to the selinuxfs interfaces to make it work.

---

compute_av.c      |    8 ++++++--
compute_create.c  |    5 +++--
compute_member.c  |    5 +++--
compute_relabel.c |    5 +++--
mapping.h         |   34 ++++++++++++++++++++++++++++++++++
stringrep.c       |   29 ++++++++++++++++++++---------
6 files changed, 69 insertions(+), 17 deletions(-)
src/mapping.h +33 -0
Index: libselinux/src/mapping.h
===================================================================
@@ -0,0 +1,34 @@
+/*
+ * This file describes the class and permission mappings used to + * hide the kernel numbers from userspace by allowing userspace object
+ * managers to specify a list of classes and permissions.
+ */
+#ifndef _SELINUX_MAPPING_H_
+#define _SELINUX_MAPPING_H_
+
+#include <selinux/selinux.h>
+
+/*
+ * Get real, kernel values from mapped values
+ */
+
+extern security_class_t
+unmap_class(security_class_t tclass);
+
+extern access_vector_t
+unmap_perm(security_class_t tclass, access_vector_t tperm);
+
+/*
+ * Get mapped values from real, kernel values
+ */
+
+extern security_class_t
+map_class(security_class_t kclass);
+
+extern access_vector_t
+map_perm(security_class_t tclass, access_vector_t kperm);
+
+extern void
+map_decision(security_class_t tclass, struct av_decision *avd);
+
+#endif				/* _SELINUX_MAPPING_H_ */
src/stringrep.c +0 -0
Index: libselinux/src/stringrep.c
===================================================================
@@ -17,6 +17,7 @@

#include <selinux/av_permissions.h>
#include "selinux_internal.h"
#include "policy.h"
+#include "mapping.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

@@ -315,12 +316,12 @@

	if (isdigit(s[0])) {
		val = atoi(s);
		if (val > 0 && val < NCLASSES)
-			return val;
+			return map_class(val);
	} else {
		for (val = 0; val < NCLASSES; val++) {
			if (strcmp(s, (class_to_string_data.str
				       + class_to_string[val])) == 0)
-				return val;
+				return map_class(val);
		}
	}

@@ -333,9 +334,10 @@

	const uint16_t *common_pts_idx = 0;
	access_vector_t perm, common_base = 0;
	unsigned int i;

+ security_class_t kclass = unmap_class(tclass);

	for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
-		if (av_inherit[i].tclass == tclass) {
+		if (av_inherit[i].tclass == kclass) {
			common_pts_idx =
			    &common_perm_to_string.data[av_inherit[i].
							common_pts_idx];
@@ -350,16 +352,16 @@
		if (strcmp
		    (s,
		     common_perm_to_string_data.str + common_pts_idx[i]) == 0)
-			return perm;
+			return map_perm(tclass, perm);
		perm <<= 1;
		i++;
	}

	for (i = 0; i < NVECTORS; i++) {

- if ((av_perm_to_string[i].tclass == tclass) &&
+ if ((av_perm_to_string[i].tclass == kclass) &&
(strcmp(s, (av_perm_to_string_data.str
+ av_perm_to_string[i].nameidx)) == 0))
- return av_perm_to_string[i].value;

+			return map_perm(tclass, av_perm_to_string[i].value);
	}

	errno = EINVAL;

@@ -368,6 +370,8 @@

static const char *security_class_to_string_compat(security_class_t tclass) {
+ tclass = unmap_class(tclass);
+

	if (tclass > 0 && tclass < NCLASSES)
		return class_to_string_data.str + class_to_string[tclass];

@@ -382,6 +386,9 @@

	access_vector_t common_base = 0;
	unsigned int i;

+ av = unmap_perm(tclass, av);
+ tclass = unmap_class(tclass);
+

	if (!av)
		return NULL;

@@ -432,22 +439,23 @@

		}
	}

- return node->value;
+ return map_class(node->value);
}

access_vector_t string_to_av_perm(security_class_t tclass, const char *s)

{
	struct discover_class_node *node;

+ security_class_t kclass = unmap_class(tclass);

	if (obj_class_compat)
		return string_to_av_perm_compat(tclass,s);

- node = get_class_cache_entry_value(tclass);

+	node = get_class_cache_entry_value(kclass);
	if (node != NULL) {
		size_t i;
		for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++)
			if (strcmp(node->perms[i],s) == 0)
-				return (1<<i);
+				return map_perm(tclass, 1<<i);
	}

	errno = EINVAL;
@@ -461,6 +469,7 @@
	if (obj_class_compat)
		return security_class_to_string_compat(tclass);
+	tclass = unmap_class(tclass);
	node = get_class_cache_entry_value(tclass);
	if (node == NULL) {
		errno = EINVAL;
@@ -478,6 +487,8 @@
	if (obj_class_compat)
		return security_av_perm_to_string_compat(tclass,av);

+ av = unmap_perm(tclass, av);

+	tclass = unmap_class(tclass);
	node = get_class_cache_entry_value(tclass);
	if (av && node)
		for (i = 0; i<MAXVECTORS; i++)
src/compute_av.c +0 -0
Index: libselinux/src/compute_av.c
===================================================================
@@ -5,9 +5,10 @@

#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "selinux_internal.h"
#include "policy.h"
-#include <limits.h>
+#include "mapping.h"

int security_compute_av_raw(security_context_t scon,
security_context_t tcon,
@@ -36,7 +37,8 @@

		goto out;
	}

- snprintf(buf, len, "%s %s %hu %x", scon, tcon, tclass, requested);
+ snprintf(buf, len, "%s %s %hu %x", scon, tcon,
+ unmap_class(tclass), unmap_perm(tclass, requested));

	ret = write(fd, buf, strlen(buf));
	if (ret < 0)
@@ -54,6 +56,8 @@
		goto out2;
	}

+ map_decision(tclass, avd);
+

	ret = 0;
      out2:
	free(buf);
src/compute_create.c +0 -0
Index: libselinux/src/compute_create.c
===================================================================
@@ -5,9 +5,10 @@

#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "selinux_internal.h"
#include "policy.h"
-#include <limits.h>
+#include "mapping.h"

int security_compute_create_raw(security_context_t scon,
security_context_t tcon,
@@ -35,7 +36,7 @@

		ret = -1;
		goto out;
	}

- snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+ snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));

	ret = write(fd, buf, strlen(buf));
	if (ret < 0)
src/compute_member.c +0 -0
Index: libselinux/src/compute_member.c
===================================================================
@@ -5,9 +5,10 @@

#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "selinux_internal.h"
#include "policy.h"
-#include <limits.h>
+#include "mapping.h"

int security_compute_member_raw(security_context_t scon,
security_context_t tcon,
@@ -35,7 +36,7 @@

		ret = -1;
		goto out;
	}

- snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+ snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));

	ret = write(fd, buf, strlen(buf));
	if (ret < 0)
src/compute_relabel.c +0 -0
Index: libselinux/src/compute_relabel.c
===================================================================
@@ -5,9 +5,10 @@

#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "selinux_internal.h"
#include "policy.h"
-#include <limits.h>
+#include "mapping.h"

int security_compute_relabel_raw(security_context_t scon,
security_context_t tcon,
@@ -35,7 +36,7 @@

		ret = -1;
		goto out;
	}

- snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+ snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));

	ret = write(fd, buf, strlen(buf));
	if (ret < 0)
Signature · 8 lines
Eamon Walsh <[email protected]>
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
Acked-by on v1 3/3
#12 lore raw

Re: [PATCH 3/3] libselinux: class and permission mapping support (try 3)

Quoted 4 lines · Eamon Walsh

This patch includes the internal map and unmap functions and the changes to the selinuxfs interfaces to make it work.

All three patches:

Quoted 285 lines

---

 compute_av.c      |    8 ++++++--
 compute_create.c  |    5 +++--
 compute_member.c  |    5 +++--
 compute_relabel.c |    5 +++--
 mapping.h         |   34 ++++++++++++++++++++++++++++++++++
 stringrep.c       |   29 ++++++++++++++++++++---------
 6 files changed, 69 insertions(+), 17 deletions(-)

Index: libselinux/src/mapping.h
===================================================================

src/mapping.h +34 -0
@@ -0,0 +1,34 @@
+/*
+ * This file describes the class and permission mappings used to 
+ * hide the kernel numbers from userspace by allowing userspace object
+ * managers to specify a list of classes and permissions.
+ */
+#ifndef _SELINUX_MAPPING_H_
+#define _SELINUX_MAPPING_H_
+
+#include <selinux/selinux.h>
+
+/*
+ * Get real, kernel values from mapped values
+ */
+
+extern security_class_t
+unmap_class(security_class_t tclass);
+
+extern access_vector_t
+unmap_perm(security_class_t tclass, access_vector_t tperm);
+
+/*
+ * Get mapped values from real, kernel values
+ */
+
+extern security_class_t
+map_class(security_class_t kclass);
+
+extern access_vector_t
+map_perm(security_class_t tclass, access_vector_t kperm);
+
+extern void
+map_decision(security_class_t tclass, struct av_decision *avd);
+
+#endif				/* _SELINUX_MAPPING_H_ */

Index: libselinux/src/stringrep.c
===================================================================

src/stringrep.c +20 -9
@@ -17,6 +17,7 @@
 #include <selinux/av_permissions.h>
 #include "selinux_internal.h"
 #include "policy.h"
+#include "mapping.h"
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
@@ -315,12 +316,12 @@
 	if (isdigit(s[0])) {
 		val = atoi(s);
 		if (val > 0 && val < NCLASSES)
-			return val;
+			return map_class(val);
 	} else {
 		for (val = 0; val < NCLASSES; val++) {
 			if (strcmp(s, (class_to_string_data.str
 				       + class_to_string[val])) == 0)
-				return val;
+				return map_class(val);
 		}
 	}
 
@@ -333,9 +334,10 @@
 	const uint16_t *common_pts_idx = 0;
 	access_vector_t perm, common_base = 0;
 	unsigned int i;
+	security_class_t kclass = unmap_class(tclass);
 
 	for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
-		if (av_inherit[i].tclass == tclass) {
+		if (av_inherit[i].tclass == kclass) {
 			common_pts_idx =
 			    &common_perm_to_string.data[av_inherit[i].
 							common_pts_idx];
@@ -350,16 +352,16 @@
 		if (strcmp
 		    (s,
 		     common_perm_to_string_data.str + common_pts_idx[i]) == 0)
-			return perm;
+			return map_perm(tclass, perm);
 		perm <<= 1;
 		i++;
 	}
 
 	for (i = 0; i < NVECTORS; i++) {
-		if ((av_perm_to_string[i].tclass == tclass) &&
+		if ((av_perm_to_string[i].tclass == kclass) &&
 		    (strcmp(s, (av_perm_to_string_data.str
 				+ av_perm_to_string[i].nameidx)) == 0))
-			return av_perm_to_string[i].value;
+			return map_perm(tclass, av_perm_to_string[i].value);
 	}
 
 	errno = EINVAL;
@@ -368,6 +370,8 @@
 
 static const char *security_class_to_string_compat(security_class_t tclass)
 {
+	tclass = unmap_class(tclass);
+
 	if (tclass > 0 && tclass < NCLASSES)
 		return class_to_string_data.str + class_to_string[tclass];
 
@@ -382,6 +386,9 @@
 	access_vector_t common_base = 0;
 	unsigned int i;
 
+	av = unmap_perm(tclass, av);
+	tclass = unmap_class(tclass);
+
 	if (!av)
 		return NULL;
 
@@ -432,22 +439,23 @@
 		}
 	}
 
-	return node->value;
+	return map_class(node->value);
 }
 
 access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
 {
 	struct discover_class_node *node;
+	security_class_t kclass = unmap_class(tclass);
 
 	if (obj_class_compat)
 		return string_to_av_perm_compat(tclass,s);
 
-	node = get_class_cache_entry_value(tclass);
+	node = get_class_cache_entry_value(kclass);
 	if (node != NULL) {
 		size_t i;
 		for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++)
 			if (strcmp(node->perms[i],s) == 0)
-				return (1<<i);
+				return map_perm(tclass, 1<<i);
 	}
 
 	errno = EINVAL;
@@ -461,6 +469,7 @@
 	if (obj_class_compat)
 		return security_class_to_string_compat(tclass);
 
+	tclass = unmap_class(tclass);
 	node = get_class_cache_entry_value(tclass);
 	if (node == NULL) {
 		errno = EINVAL;
@@ -478,6 +487,8 @@
 	if (obj_class_compat)
 		return security_av_perm_to_string_compat(tclass,av);
 
+	av = unmap_perm(tclass, av);
+	tclass = unmap_class(tclass);
 	node = get_class_cache_entry_value(tclass);
 	if (av && node)
 		for (i = 0; i<MAXVECTORS; i++)

Index: libselinux/src/compute_av.c
===================================================================

src/compute_av.c +6 -2
@@ -5,9 +5,10 @@
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
+#include <limits.h>
 #include "selinux_internal.h"
 #include "policy.h"
-#include <limits.h>
+#include "mapping.h"
 
 int security_compute_av_raw(security_context_t scon,
 			    security_context_t tcon,
@@ -36,7 +37,8 @@
 		goto out;
 	}
 
-	snprintf(buf, len, "%s %s %hu %x", scon, tcon, tclass, requested);
+	snprintf(buf, len, "%s %s %hu %x", scon, tcon,
+		 unmap_class(tclass), unmap_perm(tclass, requested));
 
 	ret = write(fd, buf, strlen(buf));
 	if (ret < 0)
@@ -54,6 +56,8 @@
 		goto out2;
 	}
 
+	map_decision(tclass, avd);
+
 	ret = 0;
       out2:
 	free(buf);

Index: libselinux/src/compute_create.c
===================================================================

src/compute_create.c +3 -2
@@ -5,9 +5,10 @@
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
+#include <limits.h>
 #include "selinux_internal.h"
 #include "policy.h"
-#include <limits.h>
+#include "mapping.h"
 
 int security_compute_create_raw(security_context_t scon,
 				security_context_t tcon,
@@ -35,7 +36,7 @@
 		ret = -1;
 		goto out;
 	}
-	snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+	snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));
 
 	ret = write(fd, buf, strlen(buf));
 	if (ret < 0)

Index: libselinux/src/compute_member.c
===================================================================

src/compute_member.c +3 -2
@@ -5,9 +5,10 @@
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
+#include <limits.h>
 #include "selinux_internal.h"
 #include "policy.h"
-#include <limits.h>
+#include "mapping.h"
 
 int security_compute_member_raw(security_context_t scon,
 				security_context_t tcon,
@@ -35,7 +36,7 @@
 		ret = -1;
 		goto out;
 	}
-	snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+	snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));
 
 	ret = write(fd, buf, strlen(buf));
 	if (ret < 0)

Index: libselinux/src/compute_relabel.c
===================================================================

src/compute_relabel.c +3 -2
@@ -5,9 +5,10 @@
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
+#include <limits.h>
 #include "selinux_internal.h"
 #include "policy.h"
-#include <limits.h>
+#include "mapping.h"
 
 int security_compute_relabel_raw(security_context_t scon,
 				 security_context_t tcon,
@@ -35,7 +36,7 @@
 		ret = -1;
 		goto out;
 	}
-	snprintf(buf, size, "%s %s %hu", scon, tcon, tclass);
+	snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));
 
 	ret = write(fd, buf, strlen(buf));
 	if (ret < 0)
Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.