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="";