[RFC] -v2 livecd running and selinux enforcing

Eric Paris eparis at redhat.com
Thu Jun 5 21:35:15 UTC 2008


Still ongoing selinux policy and toolchain work in this area is needed
and I should do more testing on a host machine with selinux disabled but
this is the livecd patch I've got working as of today.  I think that I
want to make my print >> sys.stderr message actually be fatal.  The
reason for this is because setting selinux --disabled in the kickstart
and not having /usr/sbin/lokkit results in an enabled livecd which
doesn't work...   No reason to just print a message and not stop the
work if we know for sure the results are useless...

This patch also has the f.close() fix that I sent yesterday, so it might
not apply if you already applied that one...

-Eric

diff -Naupr imgcreate.orig/creator.py imgcreate/creator.py
--- imgcreate.orig/creator.py	2008-05-06 12:16:08.000000000 -0400
+++ imgcreate/creator.py	2008-06-05 17:10:36.561313078 -0400
@@ -23,6 +23,7 @@ import sys
 import tempfile
 import shutil
 
+import selinux
 import yum
 import rpm
 
@@ -402,6 +403,52 @@ class ImageCreator(object):
         fstab.write(self._get_fstab())
         fstab.close()
 
+    def __create_selinuxfs(self):
+        # if selinux exists on the host we need to lie to the chroot
+        if os.path.exists("/selinux/enforce"):
+            selinux_dir = self._instroot + "/selinux"
+
+            # enforce=0 tells the chroot selinux is not enforcing
+            # policyvers=999 tell the chroot to make the highest version of policy it can
+            files = (('/enforce', '0'),
+                     ('/policyvers', '999'))
+            for (file, value) in files:
+                fd = os.open(selinux_dir + file, os.O_WRONLY | os.O_TRUNC | os.O_CREAT)
+                os.write(fd, value)
+                os.close(fd)
+
+            # we steal mls from the host system for now, might be best to always set it to 1????
+            files = ("/mls",)
+            for file in files:
+                shutil.copyfile("/selinux" + file, selinux_dir + file)
+
+            # make /load -> /dev/null so chroot policy loads don't hurt anything
+            os.mknod(selinux_dir + "/load", 0666 | stat.S_IFCHR, os.makedev(1, 3))
+
+        # selinux is on in the kickstart, so clean up as best we can to start
+        if kickstart.selinux_enabled(self.ks):
+            # label the fs like it is a root before the bind mounting
+            arglist = ["/sbin/setfiles", "-F", "-r", self._instroot, selinux.selinux_file_context_path(), self._instroot]
+            subprocess.call(arglist, close_fds = True)
+            # these dumb things don't get magically fixed, so make the user generic
+            for f in ("/proc", "/sys", "/selinux"):
+                arglist = ["/usr/bin/chcon", "-u", "system_u", self._instroot + f]
+                subprocess.call(arglist, close_fds = True)
+
+    def __destroy_selinuxfs(self):
+        # if the system was running selinux clean up our lies
+        if os.path.exists("/selinux/enforce"):
+            files = ('/enforce',
+                     '/policyvers',
+                     '/mls',
+                     '/load')
+            for file in files:
+                try:
+                    os.unlink(self._instroot + "/selinux" + file)
+                except OSError:
+                    pass
+
+
     def mount(self, base_on = None, cachedir = None):
         """Setup the target filesystem in preparation for an install.
 
@@ -427,7 +474,7 @@ class ImageCreator(object):
 
         self._mount_instroot(base_on)
 
-        for d in ("/dev/pts", "/etc", "/boot", "/var/log", "/var/cache/yum"):
+        for d in ("/dev/pts", "/etc", "/boot", "/var/log", "/var/cache/yum", "/sys", "/proc", "/selinux"):
             makedirs(self._instroot + d)
 
         cachesrc = cachedir or (self.__builddir + "/yum-cache")
@@ -439,10 +486,6 @@ class ImageCreator(object):
                           (cachesrc, "/var/cache/yum")]:
             self.__bindmounts.append(BindChrootMount(f, self._instroot, dest))
 
-        # /selinux should only be mounted if selinux is enabled (enforcing or permissive)
-        if kickstart.selinux_enabled(self.ks):
-            self.__bindmounts.append(BindChrootMount("/selinux", self._instroot, None))
-
         # Create minimum /dev
         origumask = os.umask(0000)
         devices = [('null',   1, 3, 0666),
@@ -460,6 +503,8 @@ class ImageCreator(object):
         os.symlink('/proc/self/fd/2', self._instroot + "/dev/stderr")
         os.umask(origumask)
 
+        self.__create_selinuxfs()
+
         self._do_bindmounts()
 
         os.symlink("../proc/mounts", self._instroot + "/etc/mtab")
@@ -479,6 +524,8 @@ class ImageCreator(object):
         except OSError:
             pass
 
+        self.__destroy_selinuxfs()
+
         self._undo_bindmounts()
 
         self._unmount_instroot()
@@ -543,7 +590,17 @@ class ImageCreator(object):
         for pkg in kickstart.get_excluded(self.ks,
                                           self._get_excluded_packages()):
             ayum.deselectPackage(pkg)
-        
+
+    # if the system is running selinux and the kickstart wants it disabled
+    # we need /usr/sbin/lokkit
+    def __can_handle_selinux(self, ayum):
+        has_req = 1
+        file = "/usr/sbin/lokkit"
+        if not kickstart.selinux_enabled(self.ks) and os.path.exists("/selinux/enforce"):
+            has_req = ayum.installHasFile(file)
+        if not has_req:
+            print >> sys.stderr, "Dude, you need a package which provides %s for your selinux setup to work" %(file)
+
     def install(self, repo_urls = {}):
         """Install packages into the install root.
 
@@ -579,6 +636,9 @@ class ImageCreator(object):
             self.__select_packages(ayum)
             self.__select_groups(ayum)
             self.__deselect_packages(ayum)
+
+            self.__can_handle_selinux(ayum)
+
             ayum.runInstall()
         except yum.Errors.RepoError, e:
             raise CreatorError("Unable to download from repo : %s" % (e,))
diff -Naupr imgcreate.orig/kickstart.py imgcreate/kickstart.py
--- imgcreate.orig/kickstart.py	2008-05-06 12:16:08.000000000 -0400
+++ imgcreate/kickstart.py	2008-06-04 14:56:35.033603440 -0400
@@ -369,14 +369,15 @@ class SelinuxConfig(KickstartConfig):
             path = self.path(fn)
             f = file(path, "w+")
             os.chmod(path, 0644)
+            f.close()
 
         if ksselinux.selinux == ksconstants.SELINUX_DISABLED:
             return
-        if not os.path.exists(self.path("/sbin/restorecon")):
+        if os.path.exists(self.path("/sbin/restorecon")):
+            self.call(["/sbin/restorecon", "-l", "-v", "-r", "-F", "-e", "/proc", "-e", "/sys", "-e", "/dev", "-e", "/selinux", "/"])
+        else:
             return
 
-        self.call(["/sbin/restorecon", "-l", "-v", "-r", "/"])
-
     def apply(self, ksselinux):
         if os.path.exists(self.path("/usr/sbin/lokkit")):
             args = ["/usr/sbin/lokkit", "-f", "--quiet", "--nostart"]
diff -Naupr imgcreate.orig/yuminst.py imgcreate/yuminst.py
--- imgcreate.orig/yuminst.py	2008-05-06 12:16:08.000000000 -0400
+++ imgcreate/yuminst.py	2008-06-05 17:00:00.574631892 -0400
@@ -79,7 +79,7 @@ class LiveCDYum(yum.YumBase):
     def selectPackage(self, pkg):
         """Select a given package.  Can be specified with name.arch or name*"""
         return self.install(pattern = pkg)
-        
+
     def deselectPackage(self, pkg):
         """Deselect package.  Can be specified as name.arch or name*"""
         sp = pkg.rsplit(".", 2)
@@ -138,6 +138,20 @@ class LiveCDYum(yum.YumBase):
         repo.setCallback(TextProgress())
         self.repos.add(repo)
         return repo
+
+    def installHasFile(self, file):
+        has_file = 0
+        provides_pkg = self.whatProvides(file, None, None)
+        dlpkgs = map(lambda x: x.po, filter(lambda txmbr: txmbr.ts_state in ("i", "u"), self.tsInfo.getMembers()))
+        for p in dlpkgs:
+            for q in provides_pkg:
+                if (p == q):
+                    has_file = 1
+        if has_file:
+            return True
+        else:
+            return False
+
             
     def runInstall(self):
         os.environ["HOME"] = "/"





More information about the fedora-selinux-list mailing list