This is part 5 of a 5 part post on identifying and fixing an· SELinux constraint violation. If you have not already read the previous parts, you may want to start at the beginning.

Giving mount_t the mcsreadall attribute.

Before we get to far down the road, let's build a quick module to test this attribute actually solves the problem.

# create the TE file assigning the attribute
$ cat << EOF > testmcsautofsnfs4.te
module testmcsautofsnfs4 1.0;
require {
    type mount_t;
    attribute mcsreadall;
}
typeattribute mount_t mcsreadall;
EOF

# generate a binary policy module
$ checkmodule -M -m testmcsautofsnfs4.te -o testmcsautofsnfs4.mod

# create a policy module package
$ semodule_package -o testmcsautofsnfs4.pp -m testmcsautofsnfs4.mod

# install the policy module
$ semodule -i testmcsautofsnfs4.pp

After the module is loaded, autofs mounts to the troublesome filesystem work once again, excellent.

Now remove this module to get back to a vanilla policy. We should be using interfaces rather than directly granting attributes.

$ semodule -r testmcsautofsnfs4

The source is already unpacked, and since what we are searching for is relatively unique, it won't take long to find via grep.

$ grep -R mcsreadall modules/
    modules/kernel/mcs.if:      attribute mcsreadall;
    modules/kernel/mcs.if:  typeattribute $1 mcsreadall;
    modules/kernel/mcs.te:attribute mcsreadall;

Sure enough, the interface comes right up.

########################################
## <summary>
##      This domain is allowed to read files and directories
##      regardless of their MCS category set.
## </summary>
## <param name="domain">
##      <summary>
##      Domain target for user exemption.
##      </summary>
## </param>
## <rolecap/>
#
interface(`mcs_file_read_all',`
        gen_require(`
                attribute mcsreadall;
        ')

        typeattribute $1 mcsreadall;
')

If the policy source was not handy, this information can also be quickly pulled from the selinux policy documentation that is part of the "selinux-policy-doc" rpm. That package contains "/usr/share/selinux/devel/policyhelp" which is a quick way to pull up the documentation in your web browser. Use the left hand panel to navigate to kernel -> mcs and mcs_file_read_all is sitting right there.

Ok, so we have the interface, how do we use it? First, update the .te file:

$ cat << 'EOF' > testmcsautofsnfs4.te
policy_module(testmcsautofsnfs4, 1.0)

optional_policy(`
    gen_require(`
        type mount_t;
    ')

    mcs_file_read_all(mount_t)
')
EOF

Unfortunately checkmodule does not support the macros necessary to use interfaces, so we have to call make directly.

$ make NAME=targeted -f /usr/share/selinux/devel/Makefile

This will generate a .pp, just as checkmodule + semodule_package had. Now to load it:

$ semodule -i testmcsautofsnfs4.pp

Test the mount again, everything remains working, excellent.

Pushing the change out to multiple systems

A binary policy package file is not terribly easy to centrally manage, what if you need the modification on a lot of systems while waiting for upstream to patch the base policy? Simple, make the module into an rpm to add to your site's internal repository.

The selinux packaging draft covers most of the details, here is a spec file template:

%define modulename examplesiteautofsnfs4
%define selinux_variants mls strict targeted
%define selinux_policyver %(sed -e 's,.*selinux-policy-\\([^/]*\\)/.*,\\1,' /usr/share/selinux/devel/policyhelp)


Summary: Example-Site selinux policy tweak, allow autofs to mount NFS with secontext
Name: examplesiteconf-selinux-autofsnfs4
Version: 1.0
Release: 1%{?dist}
License: GPLv2
Group: System Environment/Base
URL: http://example.org
BuildArch:      noarch
Source0:        %{modulename}.if
Source1:        %{modulename}.te
Source2:        %{modulename}.fc
Source3:        README
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildRequires:  checkpolicy, selinux-policy-devel, hardlink, selinux-policy-doc
%if "%{selinux_policyver}" != ""
Requires:       selinux-policy >= %{selinux_policyver}
%endif

%description
Provides Example-Site selinux configuration which allows mount_t
to read all mcs ranges. This is needed so that autofs can
successfully mount nfs4 with mount point category labeling.
For more information, see Red Hat case 00000000.

%prep
%{__mkdir} -p SELinux
cp -p %{SOURCE0} %{SOURCE1} %{SOURCE2} SELinux
cp %{SOURCE3} .

%build
cd SELinux
for selinuxvariant in %{selinux_variants}
do
    make NAME=${selinuxvariant} -f /usr/share/selinux/devel/Makefile
    mv %{modulename}.pp %{modulename}.pp.${selinuxvariant}
    make NAME=${selinuxvariant} -f /usr/share/selinux/devel/Makefile clean
done
cd -


%install
# Install SELinux policy modules
cd SELinux
for selinuxvariant in %{selinux_variants}
do
    install -d %{buildroot}%{_datadir}/selinux/${selinuxvariant}
    install -p -m 644 %{modulename}.pp.${selinuxvariant} \
           %{buildroot}%{_datadir}/selinux/${selinuxvariant}/%{modulename}.pp
done
cd -
rm -rf %{buildroot}/SELinux

# Hardlink identical policy module packages together
/usr/sbin/hardlink -cv %{buildroot}%{_datadir}/selinux

%clean
%{__rm} -rf %{buildroot}

%post
# Install SELinux policy modules
for selinuxvariant in %{selinux_variants}
do
  /usr/sbin/semodule -s ${selinuxvariant} -i \
    %{_datadir}/selinux/${selinuxvariant}/%{modulename}.pp &> /dev/null || :
done

%postun
# Clean up after package removal
if [ $1 -eq 0 ]; then
  # Remove SELinux policy modules
  for selinuxvariant in %{selinux_variants}
  do
    /usr/sbin/semodule -s ${selinuxvariant} -r %{modulename} &> /dev/null || :
  done
fi


%files
%defattr(-, root, root, 0755)
%doc README
%{_datadir}/selinux/*/%{modulename}.pp

%changelog
* Tue Aug 07 2012 Example-Site  1.0-1%{?dist}
- initial build