#include <linux/percpu.h>
#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. */
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;
+ char *namebuf = NULL, *objname = NULL;
u32 ssid, tsid, newsid;
u16 tclass;
ssize_t length;
char *newcon = NULL;
u32 len;
+ int nargs;
length = task_has_security(current, SECURITY__COMPUTE_CREATE);
if (length)
if (!tcon)
goto out;
- length = -EINVAL;
- if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
+ length = -ENOMEM;
+ namebuf = kzalloc(size + 1, GFP_KERNEL);
+ if (!namebuf)
goto out;
+ length = -EINVAL;
+ nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
+ if (nargs < 3 || nargs > 4)
+ goto out;
+ 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)
goto out;
if (length)
goto out;
- length = security_transition_sid_user(ssid, tsid, tclass, &newsid);
+ length = security_transition_sid_user(ssid, tsid, tclass,
+ objname, &newsid);
if (length)
goto out;
length = len;
out:
kfree(newcon);
+ kfree(namebuf);
kfree(tcon);
kfree(scon);
return length;
};
struct vfsmount *selinuxfs_mount;
+static struct kobject *selinuxfs_kobj;
static int __init init_sel_fs(void)
{
if (!selinux_enabled)
return 0;
+
+ selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
+ if (!selinuxfs_kobj)
+ return -ENOMEM;
+
err = register_filesystem(&sel_fs_type);
- if (err)
+ if (err) {
+ kobject_put(selinuxfs_kobj);
return err;
+ }
selinuxfs_mount = kern_mount(&sel_fs_type);
if (IS_ERR(selinuxfs_mount)) {
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
void exit_sel_fs(void)
{
+ kobject_put(selinuxfs_kobj);
unregister_filesystem(&sel_fs_type);
}
#endif