selinux: fix case of names with whitespace/multibytes on /selinux/create
authorKohei Kaigai <Kohei.Kaigai@emea.nec.com>
Thu, 26 May 2011 18:59:25 +0000 (14:59 -0400)
committerEric Paris <eparis@redhat.com>
Thu, 26 May 2011 21:20:53 +0000 (17:20 -0400)
I submit the patch again, according to patch submission convension.

This patch enables to accept percent-encoded object names as forth
argument of /selinux/create interface to avoid possible bugs when we
give an object name including whitespace or multibutes.

E.g) if and when a userspace object manager tries to create a new object
 named as "resolve.conf but fake", it shall give this name as the forth
 argument of the /selinux/create. But sscanf() logic in kernel space
 fetches only the part earlier than the first whitespace.
 In this case, selinux may unexpectedly answer a default security context
 configured to "resolve.conf", but it is bug.

Although I could not test this patch on named TYPE_TRANSITION rules
actually, But debug printk() message seems to me the logic works
correctly.
I assume the libselinux provides an interface to apply this logic
transparently, so nothing shall not be changed from the viewpoint of
application.

Signed-off-by: KaiGai Kohei <kohei.kaigai@emea.nec.com>
Signed-off-by: Eric Paris <eparis@redhat.com>
security/selinux/selinuxfs.c

index fde4e9d..1948904 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/audit.h>
 #include <linux/uaccess.h>
 #include <linux/kobject.h>
+#include <linux/ctype.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -751,6 +752,14 @@ out:
        return length;
 }
 
+static inline int hexcode_to_int(int code) {
+       if (code == '\0' || !isxdigit(code))
+               return -1;
+       if (isdigit(code))
+               return code - '0';
+       return tolower(code) - 'a' + 10;
+}
+
 static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 {
        char *scon = NULL, *tcon = NULL;
@@ -785,8 +794,34 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
        nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
        if (nargs < 3 || nargs > 4)
                goto out;
-       if (nargs == 4)
+       if (nargs == 4) {
+               /*
+                * If and when the name of new object to be queried contains
+                * either whitespace or multibyte characters, they shall be
+                * encoded based on the percentage-encoding rule.
+                * If not encoded, the sscanf logic picks up only left-half
+                * of the supplied name; splitted by a whitespace unexpectedly.
+                */
+               char   *r, *w;
+               int     c1, c2;
+
+               r = w = namebuf;
+               do {
+                       c1 = *r++;
+                       if (c1 == '+')
+                               c1 = ' ';
+                       else if (c1 == '%') {
+                               if ((c1 = hexcode_to_int(*r++)) < 0)
+                                       goto out;
+                               if ((c2 = hexcode_to_int(*r++)) < 0)
+                                       goto out;
+                               c1 = (c1 << 4) | c2;
+                       }
+                       *w++ = c1;
+               } while (c1 != '\0');
+
                objname = namebuf;
+       }
 
        length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
        if (length)