Hi all

I have a situation that I'd like to hear your opinion on.

In bug #535992 a what seems like simple problem is asking for quite some
work. It covers a currently cosmetic denial (i.e. SELinux is preventing
something but that does not seem to have any noticeable impact on the
system) regarding kdevtmpfs trying to work with device files.

Now you'll say - duh, that is what kdevtmpfs is for: working with the device
files in /dev (which is a devtmpfs mount). Exactly my thoughts. So I wanted
to include a policy that allows kernel_t (which is the domain that kdevtmpfs
works in) to manage all device nodes in /dev using the
dev_manage_all_dev_nodes() interface.

But here is the problem: that interface also assigns a set of attributes to
the (kernel_t) domain so that a number of neverallow rules are not violated.
Sadly, the kernel_t domain is part of the base module, meaning that it
cannot depend on definitions that are not part of the base module either
(isolation requirement). The attributes however are part of the "storage"
module, which is not part of base.

Simple - let's make storage part of base, right? Not that that is hard, but
we're in the middle of a migration between userspaces (2.3 versus 2.4) which
puts in some additional problems: with userspace 2.4, new policy modules are
loaded on priority level 400 whereas olders are at priority 100.

Now you'll say - whoah priorities? Really? What's that about?

Well, this is a new feature in the 2.4 userspace. Instead of using policy
module versions (which is now no longer supported in the 2.4 userspace) the
userspace now supports priorities. SELinux policy modules can be loaded at
higher priorities (and thus become active) while the lower priorities are
still in the SELinux store. If the higher priority module is unloaded, the
lower priority module becomes active again.

And this is the problem that we'll get: the older storage module (at
priority 100, or even at priority 400 for those using ~arch systems for a
while now) might still become active when we load the new policies (which no
longer would include the storage module). So we need to make sure that this
never happens, preferably by removing all modules from priority 100 to begin
with, and to remove the storage module when we are loading the new policies.

 (╯°□°)╯︵ ┻━┻
                  -- "Screw that!"

Finally, that's a solution. And it can even be automated (the patch is
below), but I'm afraid that there might be situations where the automated
approach does not work, and we are not able to teach most Gentoo/SELinux
users to get at the same SELinux managing level as us SELinux-related
developers.

So I have the following conundrum.

1. I can temporarily ignore the issue, perhaps hiding the cosmetic denial
   behind dontaudit statements
2. I can restrictively add to kernel_t those rules that do not trigger the
   neverallow rules and ignore/dontaudit the rest
3. I can break isolation a bit and explicitly add kernel_t to the neverallow
   rule exemption
4. I can move the necessary attributes and statements into the devices
   module (which is part of the base)
5. I can move forward with the storage-becomes-base approach

Using 5 to me is the most beautiful solution, but quite intensive. The lack
of understanding of priorities and the entire matter might confuse users
currently (2.4 is too new for that).

Using 4 requires some rework which will make it harder to follow upstream
for the affected modules (storage and devices most likely, perhaps also kernel)
(as the changes involve changing existing modules, not just adding new
rules).

Using 3 is simpler, almost a no-brainer, but is not upstreamable (as it
breaks modular isolation). More for quick solutions to improve the situation
while working on a better solution (option 5?)

Using 2 and 1 do not really implement the solution (and thus don't resolve
the issue). I think that upstream will also prefer 2/1 because there is no
visible impact of kdevtmpfs not having all these accesses. But I personally
think that this is a matter of specific use cases (which we just have not
hit yet) and not within the expectations of the kdevtmpfs code itself.

I'll also prod upstream about the issue of course, but this I also like to
discuss for Gentoo in detail.

The fix for the checks on selinux-base-policy is below:


Index: selinux-base-policy-9999.ebuild
===================================================================
RCS file: 
/var/cvsroot/gentoo-x86/sec-policy/selinux-base-policy/selinux-base-policy-9999.ebuild,v
retrieving revision 1.21
diff -u -B -r1.21 selinux-base-policy-9999.ebuild
--- selinux-base-policy-9999.ebuild     7 Dec 2014 13:21:06 -0000       1.21
+++ selinux-base-policy-9999.ebuild     4 Mar 2015 19:30:00 -0000
@@ -1,4 +1,4 @@
-# Copyright 1999-2014 Gentoo Foundation
+# Copyright 1999-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 # $Header: 
/var/cvsroot/gentoo-x86/sec-policy/selinux-base-policy/selinux-base-policy-9999.ebuild,v
 1.21 2014/12/07 13:21:06 perfinion Exp $
 EAPI="5"
@@ -28,7 +28,7 @@
 PDEPEND="unconfined? ( sec-policy/selinux-unconfined )"
 DEPEND=""
 
-MODS="application authlogin bootloader clock consoletype cron dmesg fstools 
getty hostname hotplug init iptables libraries locallogin logging lvm miscfiles 
modutils mount mta netutils nscd portage raid rsync selinuxutil setrans ssh 
staff storage su sysadm sysnetwork tmpfiles udev userdomain usermanage 
unprivuser xdg"
+MODS="application authlogin bootloader clock consoletype cron dmesg fstools 
getty hostname hotplug init iptables libraries locallogin logging lvm miscfiles 
modutils mount mta netutils nscd portage raid rsync selinuxutil setrans ssh 
staff su sysadm sysnetwork tmpfiles udev userdomain usermanage unprivuser xdg"
 LICENSE="GPL-2"
 SLOT="0"
 S="${WORKDIR}/"
@@ -122,13 +122,92 @@
                COMMAND="-i ${i}.pp ${COMMAND}"
        done
 
-       for i in ${POLICY_TYPES}; do
-               einfo "Inserting the following modules, with base, into the $i 
module store: ${MODS}"
+       # Check if we are using 2.4 userspace or not
+       # Clunky check because semodule does not have a --version and we want
+       # to check semodule's version support, not semanage or other tools.
+       semodule --help | grep -q "priority"
+       if [ $? -eq 0 ] ; then
+               # Priority support found so we are using 2.4 userspace
+               # Before continuing, check that all modules of priority=100 are 
gone
+               for i in ${POLICY_TYPES} ; do
+                       semodule -s ${i} --list-modules=full | grep -q "^100 
storage"
+                       if [ $? -eq 0 ] ; then
+                               # Still a storage module at priority 100 found.
+                               # Is a set already loaded at priority 400?
+                               semodule -s ${i} --list-modules=full | grep -q 
"^400 base"
+                               if [ $? -eq 0 ] ; then
+                                       # Also a set at 400.
+                                       # Let's clear those at priority 100.
+                                       local CURMODLIST=$(semodule -s ${i} 
--priority=100 -l);
+                                       ewarn "A full set of SELinux policy 
modules is running at priority 400 (which is good)"
+                                       ewarn "but also at priority 100. The 
latter should be removed from the system as we"
+                                       ewarn "might get into collisions 
(especially with the storage module). Trying to clear:"
+                                       semodule -s ${i} --priority=100 -r 
${CURMODLIST};
+                                       if [ $? -eq 0 ] ; then
+                                               # Priority 100 cleared.
+                                               einfo "All modules on priority 
100 have been removed. We can now continue safely."
+                                       else
+                                               eerror "It was not possible to 
remove the modules at priority 100. Please ensure that"
+                                               eerror "there are no modules at 
this priority left. In extreme cases it might be"
+                                               eerror "necessary to create an 
empty module to override an older one before removing"
+                                               eerror "the older module."
+                                               eerror "Use 'semodule 
--priority=100 -r modulename' to remove modules."
+                                               eerror "Use 'semodule 
--list-modules=full' to list all modules/priority sets"
+                                               die "Could not clear SELinux 
policy modules at priority level 100"
+                                       fi
+                               else
+                                       # None at priority 400 yet. We need to 
load the current set at priority 100 first
+                                       # while removing the storage module, 
and then reload at priority 400,
+                                       semodule -s ${i} --priority=100 -i 
base.pp ${COMMAND} -r storage
+                                       if [ $? -ne 0 ] ; then
+                                               # Failed to load at priority 
100.
+                                               eerror "We have detected that 
the storage module is loaded with priority 100 but no full"
+                                               eerror "policy set yet at 
priority 400 (which is default for the 2.4 userspace). Recent"
+                                               eerror "policies no longer 
contain the storage module (it has become part of the base"
+                                               eerror "module) which might 
result in dependency problems with the currently-loaded"
+                                               eerror "storage module at 
priority 100."
+                                               eerror "Sadly we were not able 
to automatically resolve this. Please make sure that no"
+                                               eerror "SELinux policy modules 
are running with priority 100 anymore."
+                                               die "Could not load policies at 
priority 100 in order to remove the active storage module"
+                                       fi
+                               fi
+                       else
+                               # No storage module at priority 100 anymore
+                               # Check if there is a storage module at 
priority 400.
+                               semodule -s ${i} --list-modules=full | grep -q 
"^400 storage"
+                               if [ $? -eq 0 ] ; then
+                                       # Storage module running at priority 400
+                                       # Load the new base set while removing 
the storage module
+                                       semodule -s ${i} -i base.pp ${COMMAND} 
-r storage
+                                       if [ $? -ne 0 ] ; then
+                                               # Could not reload while 
removing storage module
+                                               eerror "A running storage 
SELinux module is found but could not be removed. Recent"
+                                               eerror "policies no longer 
contain the storage module (it has become part of the base"
+                                               eerror "module) which might 
result in dependency problems with the currently-loaded"
+                                               eerror "storage module."
+                                               eerror "Sadly we were not able 
to automatically resolve this. Please make sure that no"
+                                               eerror "SELinux policy modules 
are running anymore."
+                                               die "Could not remove storage 
module from the policy store."
+                                       fi
+                               fi
+                       fi
+                       # Now try to load the new set
+                       einfo "Inserting the following modules, with base, into 
the $i module store: ${MODS}"
 
-               cd /usr/share/selinux/${i} || die "Could not enter 
/usr/share/selinux/${i}"
+                       cd /usr/share/selinux/${i} || die "Could not enter 
/usr/share/selinux/${i}"
 
-               semodule -s ${i} -b base.pp ${COMMAND} || die "Failed to load 
in base and modules ${MODS} in the $i policy store"
-       done
+                       semodule -s ${i} -i base.pp ${COMMAND} || die "Failed 
to load in base and modules \"${MODS}\" in the $i policy store"
+               done
+       else
+               # No priority support so not using 2.4 userspace
+               for i in ${POLICY_TYPES}; do
+                       einfo "Inserting the following modules, with base, into 
the $i module store: ${MODS}"
+
+                       cd /usr/share/selinux/${i} || die "Could not enter 
/usr/share/selinux/${i}"
+
+                       semodule -s ${i} -b base.pp ${COMMAND} || die "Failed 
to load in base and modules ${MODS} in the $i policy store"
+               done
+       fi
 
        # Relabel depending packages
        local PKGSET="";

Reply via email to