From 0aac2d3d8804271eaca33f93650b04f1bd8b249c Mon Sep 17 00:00:00 2001 From: Jan Vcelak Date: Fri, 30 Jul 2010 16:14:55 -0500 Subject: add selinux plugin This patch adds an selinux plugin that sets up an environment with selinux turned *off* in the build chroot. How does this work? From the author's description: It is done the same as the patch sent by Thomas Liu in bz 614440 does. Actually, this proceeding was suggested by Dan Walsh in bz 573111. 1.) Fake /proc/filesystems is created in conf["cachedir"]. It includes the same content as the same file in host environment, except line with selinuxfs. This file is bind mounted into build environment. 2.) Option '--setopt=tsflags=nocontext' is added to yum commands. This is done by wrapping mock.util.do with _selinuxDoYum in "preyum" hook. This function just adds the option and passes the command to original mock.util.do function. The wrapping is removed in "postyum" hook. I didn't find cleaner method, without modifying main code. Signed-off-by: Clark Williams --- Makefile.am | 4 +- py/mock.py | 4 +- py/mock/plugins/selinux.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 py/mock/plugins/selinux.py diff --git a/Makefile.am b/Makefile.am index ca05ec6..b9ef2fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,7 +47,9 @@ plugins_PYTHON = \ py/mock/plugins/ccache.py \ py/mock/plugins/root_cache.py \ py/mock/plugins/tmpfs.py \ - py/mock/plugins/yum_cache.py + py/mock/plugins/yum_cache.py \ + py/mock/plugins/selinux.py + pkgpython_PYTHON = \ py/mock/__init__.py \ diff --git a/py/mock.py b/py/mock.py index dd002de..a0e585d 100755 --- a/py/mock.py +++ b/py/mock.py @@ -244,7 +244,7 @@ def setup_default_config_opts(config_opts, unprivUid): # root_cache next. # after that, any plugins that must create dirs (yum_cache) # any plugins without preinit hooks should be last. - config_opts['plugins'] = ('tmpfs', 'root_cache', 'yum_cache', 'bind_mount', 'ccache') + config_opts['plugins'] = ('tmpfs', 'root_cache', 'yum_cache', 'bind_mount', 'ccache', 'selinux') config_opts['plugin_dir'] = os.path.join(PKGPYTHONDIR, "plugins") config_opts['plugin_conf'] = { 'ccache_enable': True, @@ -273,6 +273,8 @@ def setup_default_config_opts(config_opts, unprivUid): 'tmpfs_opts': { 'required_ram_mb': 900, 'max_fs_size': None}, + 'selinux_enable': True, + 'selinux_opts': {}, } # dependent on guest OS diff --git a/py/mock/plugins/selinux.py b/py/mock/plugins/selinux.py new file mode 100644 index 0000000..6d15a94 --- /dev/null +++ b/py/mock/plugins/selinux.py @@ -0,0 +1,97 @@ +# vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0: +# License: GPL2 or later see COPYING +# Written by Jan Vcelak +# Copyright (C) 2010 Jan Vcelak + +# python library imports +import os +import sys + +# our imports +from mock.trace_decorator import decorate, traceLog, getLog +import mock.util + +requires_api_version = "1.0" + +# plugin entry point +decorate(traceLog()) +def init(rootObj, conf): + if mock.util.selinuxEnabled(): + getLog().info("selinux enabled") + SELinux(rootObj, conf) + else: + getLog().info("selinux disabled") + +# classes +class SELinux(object): + """On SELinux enabled box, this plugin will pretend, that SELinux is disabled in build environment. + + - fake /proc/filesystems is mounted into build enviroment, excluding selinuxfs + - option '--setopt=tsflags=nocontext' is appended to each 'yum' command + """ + + decorate(traceLog()) + def __init__(self, rootObj, conf): + self.rootObj = rootObj + self.conf = conf + + self.filesystems = os.path.join(conf["cachedir"], "filesystems") + self.chrootFilesystems = rootObj.makeChrootPath("/proc/filesystems") + + rootObj.addHook("preinit", self._selinuxPreInitHook) + rootObj.addHook("postbuild", self._selinuxPostBuildHook) + rootObj.addHook("initfailed", self._selinuxPostBuildHook) + if self._selinuxYumIsSetoptSupported(): + rootObj.addHook("preyum", self._selinuxPreYumHook) + rootObj.addHook("postyum", self._selinuxPostYumHook) + else: + getLog().warn("selinux: 'yum' does not support '--setopt' option") + + decorate(traceLog()) + def _selinuxPreInitHook(self): + host = open("/proc/filesystems") + build = open(self.filesystems, "w") + + for line in host: + if not "selinuxfs" in line: + build.write(line) + + build.close() + host.close() + + self.rootObj.mountCmds.append("mount -n --bind %s %s" % (self.filesystems, self.chrootFilesystems)) + self.rootObj.umountCmds.insert(0, "umount -n %s" % self.chrootFilesystems) + + decorate(traceLog()) + def _selinuxPostBuildHook(self): + os.unlink(self.filesystems) + + decorate(traceLog()) + def _selinuxPreYumHook(self): + self._originalUtilDo = mock.util.do + mock.util.do = self._selinuxDoYum + + decorate(traceLog()) + def _selinuxPostYumHook(self): + mock.util.do = self._originalUtilDo + + decorate(traceLog()) + def _selinuxDoYum(self, command, *args, **kargs): + option = "--setopt=tsflags=nocontexts" + + if type(command) is list: + command.append(option) + elif type(command) is str: + command += " %s" % option + + return self._originalUtilDo(command, *args, **kargs) + + decorate(traceLog()) + def _selinuxYumIsSetoptSupported(self): + # ugly hack: discover, whether yum supports --setopt option + sys.path.insert(0, '/usr/share/yum-cli') + import cli + supported = hasattr(cli.YumBaseCli, "_parseSetOpts") + sys.path.pop(0) + + return supported -- cgit