[PATCH] libselinux init functions

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

 



Hi all,

I am working on the newest release of SELinux userspace packages and
sysvinit, and find there are a defect for init function of libselinux.
  * libselinux-2.1.9
  * sysvinit-2.88dsf

AFAIK, while sysvinit is configured with SELinux, /sbin/init would be
linked to libselinux. So before /sbin/init running, init_selinuxmnt()
would be called.

// libselinux-2.1.9/src/init.c

static void init_lib(void) __attribute__ ((constructor));
static void init_lib(void)
{
        selinux_page_size = sysconf(_SC_PAGE_SIZE);
        init_selinuxmnt();
}

As called before /sbin/init, init_selinuxmnt() is called before any
other userspace process.
At this time, procfs(/proc) and selinuxfs(/sys/fs/selinux or /selinux)
have not been mounted, because kernel do not mount them.

So, after init_lib() -> init_selinuxmnt(), global variable
"selinux_mnt" is still null.

/sbin/init would call is_selinux_enabled() to check whether selinux
enabled. Because "selinux_mnt" is null, is_selinux_enabled() always
return 0.

// libselinux-2.1.9/src/enabled.c

int is_selinux_enabled(void)
{
        int enabled = 0;

        if (selinux_mnt) {
                enabled = 1;
                if (getcon_raw(&con) == 0) {
                        if (!strcmp(con, "kernel"))
                                enabled = 0;
                        freecon(con);
                }
        }

        return enabled;
}

Then, selinux_init_load_policy(&enforce) is never called, so SELinux
init failed. :(

// sysvinit-2.88dsf/src/init.c

#ifdef WITH_SELINUX
	if (getenv("SELINUX_INIT") == NULL) {
		const int rc = mount("proc", "/proc", "proc", 0, 0);
		if (is_selinux_enabled() > 0) {
			putenv("SELINUX_INIT=YES");
			...
			if (selinux_init_load_policy(&enforce) == 0) {
				execv(myname, argv);
			} else {
				if (enforce > 0) {
					....
					exit(1);
				}
			}
		}
		....
	}
#endif


My patch is mounting procfs before selinuxfs_exists(), which would
check whether selinux exist in /proc/filesystem.
And mounting selinuxfs mountpoint after selinuxfs_exists().

Then, the init_lib() flow should be:
init_lib()
 `-- if (selinux_mnt) return
 `-- mount proc fs
 `-- if (!selinuxfs_exists()) goto out
 `-- mount selinuxfs (/sys/fs/selinux or /selinux)
 `-- check selinuxfs mountpoint in /proc/mounts
 `-- verify_selinuxmnt()
       `-- set selinux_mnt

Any suggestion would be welcome. Thanks. :)

-- 
- Pascal
From 4a36b34ea23e56814b56c043df6088caad6022d3 Mon Sep 17 00:00:00 2001
From: Xin Ouyang <Xin.Ouyang@xxxxxxxxxxxxx>
Date: Mon, 12 Mar 2012 18:05:16 +0800
Subject: [PATCH] libselinux: Mount /proc and SELINUXFS.

Since /proc and SELINUXFS are not mounted before init process's
first running, checking for filesystem type and mount point of
selinuxfs would always fail.
So mount them before checking to fix this.
---
 src/init.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/src/init.c b/src/init.c
index 00afde7..a4ce726 100644
--- a/src/init.c
+++ b/src/init.c
@@ -11,12 +11,17 @@
 #include <sys/vfs.h>
 #include <stdint.h>
 #include <limits.h>
+#include <sys/mount.h>
 
 #include "dso.h"
 #include "policy.h"
 #include "selinux_internal.h"
 #include "setrans_internal.h"
 
+#ifndef MNT_DETACH /* Missing in glibc2.7 */
+#  define MNT_DETACH 2
+#endif
+
 char *selinux_mnt = NULL;
 int selinux_page_size = 0;
 int obj_class_compat = 1;
@@ -86,6 +91,7 @@ static void init_selinuxmnt(void)
 	FILE *fp=NULL;
 	size_t len;
 	ssize_t num;
+	int rc = -1;
 
 	if (selinux_mnt)
 		return;
@@ -94,10 +100,22 @@ static void init_selinuxmnt(void)
 
 	if (verify_selinuxmnt(OLDSELINUXMNT) == 0) return;
 
+	rc = mount("none", "/proc", "proc", 0, 0);
+
 	/* Drop back to detecting it the long way. */
 	if (!selinuxfs_exists())
 		goto out;
 
+	/* Since SELINUXFS is not mounted before init process's first running, 
+	 * there would be no SELINUXFS item in /proc/mounts.
+	 * So mount it before checking /proc/mounts to fix this. */
+        if (mount(SELINUXFS, SELINUXMNT, SELINUXFS, 0, 0) != 0 
+				&& errno != EBUSY)
+		goto out;
+        else if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) != 0 
+				&& errno != EBUSY)
+		goto out;
+
 	/* At this point, the usual spot doesn't have an selinuxfs so
 	 * we look around for it */
 	fp = fopen("/proc/mounts", "r");
@@ -126,6 +144,10 @@ static void init_selinuxmnt(void)
 
       out:
 	free(buf);
+
+	if (rc == 0)
+		umount2("/proc", MNT_DETACH);
+
 	if (fp)
 		fclose(fp);
 	return;
-- 
1.7.5.4


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

  Powered by Linux