How get file name from inode number?

Hi All,

I will generate SELinux denial using following command:

# cd /root ; passwd --help >& output.txt


# ausearch -m AVC -ts recent
type=AVC msg=audit(1535037404.461:1066390): avc: denied { write } for pid=11511 comm="passwd" path="output.txt" dev="dm-1" ino=1310732 scontext=staff_u:sysadm_r:passwd_t:s0:c0.c1023 tcontext=staff_u:object_r:admin_home_t:s0 tclass=file permissive=0

We can see that passwd process with passwd_t SELinux domain is trying to create file output.txt with label admin_home_t. We can find that admin_home_t is label for /root directory based on the output from semanage fcontext command.


# semanage fcontext -l | grep admin_home_t
/root(/.*)? all files system_u:object_r:admin_home_t:s0

But sometimes it’s not clear where the object from the AVC is stored. We just see name of the object. What could be helpful here is inode of object in the AVC message.
In our example the inode is ino=1310732.

We can use the following command to get file name and path from inode number:

# find / -xdev -inum 1310732
/root/output.txt

Now you can find where exactly the object is stored. 🙂

How to enable full auditing in audit daemon?

Full auditing in audit deamon could be useful e.g. to identify which object on system has too tight rules and object is causing dac_override SELinux denial. More info in my previous post.

 Open /etc/audit/rules.d/audit.rules file in an editor.

 1. Remove following line if it exists:

-a task,never

2. Add following line at the end of the file:

-w /etc/shadow -p w

 3. Restart the audit daemon:

 # service auditd restart

 4. Re-run your scenario.

Full auditing is useful when full paths to accessed objects are needed or certain audit event fields, which are normally hidden, should be visible.

The procedure works on Red Hat Enterprise Linux  >= 5 and Fedoras.

If /etc/audit/rules.d/audit.rules file does not exist, please edit /etc/audit/audit.rules directly. Older versions of audit did not generate /etc/audit/audit.rules from /etc/audit/rules.d/audit.rules.

 

Thanks Milos Malik for this article.

Why do you see DAC_OVERRIDE SELinux denials?

Hello everyone!

You could have seen SELinux denials (AVC messages) in your system in the recent release of Fedora 28 and of course Fedora Rawhide. I removed lot of rules allowing DAC_OVERRIDE capability for the process domain to bring the tightened security on SELinux enabled systems. In many cases, DAC_OVERRIDE capability is not needed and there is issue with handling UNIX permissions on objects stored in the system.

But what does DAC_OVERRIDE capability means?
In capabilities(7) man page you can find explanation. “If process has DAC_OVERRIDE capability, it can bypass file read, write and execute permissions check.”

What does it mean in reality?
Process could read, write and execute files even when there are no proper flags set on the file.

And this is a solid security hole.

Dan Walsh mentioned on his blog, that there is a myth that root is all powerful. This is not completely true, because on SELinux enabled systems, even processes ran under root user must have DAC_OVERRIDE capability allowed by SELinux policy. Aaand this is the problem for many cases on Fedora system!

Lot of daemons run as root:root user and group permissions and are accessing several files/directories in the system, but these files have too tight permissions.

Let’s make an example:

Directory below is owned by mpd user.

# ll -aZ /var/run/ | grep lirc
drwxr-xr-x. 2 lirc lirc system_u:object_r:lircd_var_run_t:s0 80 Jul 3 10:18 lirc


Following process is trying to access this directory and write logs files.


# ps -efZ | grep lircd
system_u:system_r:lircd_t:s0 root 6404 1 0 10:18 ? 00:00:00 /usr/sbin/lircd --nodaemon
system_u:system_r:lircd_t:s0 root 6405 6404 0 10:18 ? 00:00:00 [uname]

As we can see the process is owned by user root and group root. Which means that kernel will look on “others” group in UNIX permissions, and there is no written access for others.

This action should be terminated by kernel because permissions are too tight, but in discretionary access control root could bypass all permissions and access the file in the system. However, this is not allowed in mandatory access control which is implemented by SELinux.

For this reason processes owned by root needs DAC_OVERRIDE capability, or changed permissions on files/directories. In most cases this is a bug in the application package.

Dan Walsh also wrote a nice blog about this issue. He’s describing same situation on dovecot example.

Newest SELinux policy every day!

SELinux policy for Fedora Rawhide and Fedora 27 is changing very dynamically and new rules are appearing in SELinux policy repositories almost every day.

New selinux-policy RPM packages aren’t created every day, but if you want to have always up-to-date SELinux policy you can use copr repository with nightly builds. These builds are created every day.

Enabling this repo is very easy, just enable it via:

$ dnf copr enable lvrabec/selinux-policy-nightly 

And that’s it!
This is the fastest way how to deal with new denials in bleeding edge Fedora Rawhide.

No more massive patches in selinux-policy rpm package

Hi SELinux folks,

Building selinux-policy rpm package was quite complicated and confusing for developers because of massive patches against Tresys reference base and contrib repositories. The data flow during policy build was following:

This flow is unfit for selinux-policy rpm package because of the patch size (difficult to manage and near impossible to manually check). The following data flow should fix this:

From now on, we don’t use patches against refpolicy. Tarballs created directly from github are used instead. First build with this change is selinux-policy-3.14.1-1.fc28

Hope this sheds more light on building selinux-policy rpm package. 🙂

Using rpm macros in product SELinux subpackages

Some time ago, I published a post about shipping custom SELinux modules together with product as rpm subpackage. One of the steps  in shipping custom SELinux module is creating a  spec file for SELinux package, which can be messy, especially %post and %postun phases.

In order to simplify writing spec files, we have created several macros.

Loading custom SELinux modules

First improvement concerns loading and removing custom SELinux modules. You can see the difference in the following example:

Without macros:

%post
#
# Install all modules in a single transaction
#
%_format MODULES %{_datadir}/selinux/packages/$x.pp.bz2
%{_sbindir}/semodule -n -s %{selinuxtype} -i $MODULES
if %{_sbindir}/selinuxenabled ; then
    %{_sbindir}/load_policy
    %relabel_files
fi
 
 
%postun
if [ $1 -eq 0 ]; then
	%{_sbindir}/semodule -n -r %{modulenames} &> /dev/null || :
	if %{_sbindir}/selinuxenabled ; then
		%{_sbindir}/load_policy
		%relabel_files
	fi
fi


With macros:

%post
#
# Install all modules in a single transaction
#
%_format MODULES %{_datadir}/selinux/packages/$x.pp.bz2
%selinux_modules_install -s %{selinuxtype} $MODULES
 
%postun
if [ $1 -eq 0 ]; then
    %selinux_modules_uninstall -s %{selinuxtype} $MODULES
fi

As you can see, module loading is done by one macro instead of 5 lines of code.

Labeling objects from custom policy

Next improvement in spec file is a pair of macros connected to labeling files coming from the custom policy. There is no need to specify all objects in spec file as we did in previously.

# Relabel files
%global relabel_files() \ # ADD files in *.fc file

Instead of specifying objects labeled by custom policy, following macros can be used:

%pre
%selinux_relabel_pre -s %{selinuxtype}

%posttrans
%selinux_relabel_post -s %{selinuxtype}

These macros will handle labeling objects coming from the custom SELinux module and after successfull package installation, all new objects should have correct SELinux label.

Handling SELinux booleans

Last improvement is setting booleans by macros. These macros provide solution for handling booleans in spec files and behave as follows:

  • If a boolean mentioned in the product .spec file was not set by user previously, it will be changed in the %post install phase and reverted during the %post uninstall phase will.
  • If a boolean mentioned in the product .spec file was set by user previously, it will be changed to a value from this file. However, it will not be reverted during the uninstallation of a product SELinux subpackage.

Usage of booleans macros:

# In preamble define booleans and values which should be used
%global selinuxbooleans booleanname=1 booleanname2=0

# Also some new packages will be needed:
%if 0%{?fedora}
Requires(post): policycoreutils-python-utils
%else
Requires(post): policycoreutils-python
%endif

# use selinux_set_booleans after custom SELinux module is loaded.

%post
%selinux_modules_install -s %{selinuxtype} $MODULES
%selinux_set_booleans -s %{selinuxtype} %{selinuxbooleans}

%postun
%selinux_modules_uninstall -s %{selinuxtype} $MODULES
%selinux_unset_booleans -s %{selinuxtype} %{selinuxbooleans}

All these improvements can be used in Fedora Rawhide and Fedora 26. Repository with sources can be found here.

Shipping custom module using SELinux priorities

Hello everyone!

Some time ago I introduced first part of shipping own custom module with rpm package of your application. This solution allows you to maintain your own SELinux policy module which brings lot of benefits like:

  • changes in policy can be modified immediately
    • no need to wait while selinux maintainer will fix it
  • independent from selinux-policy distro updates
    • policy changes will be updates together with your application
  • own policy module can reflect lates features inside application
    • policy and application will be synchronized

However technical solution had some troubles introduced in second part. This issues disappeared with new release of SELinux userspace (>=2.4).  New userspace brings feature call module priorities.  Benefits of this feature are described in following example:

$ rpm -q docker-selinux
package docker-selinux is not installed

# semodule -lfull | grep docker
100 docker            pp

 

Creating local module quickly in CIL!

Welcome!

Today, I’ll show you how to create local policy module for testing purposes or workaround while issue will be fixed in our distro selinux-policy. Local modules will be written in CIL (common intermediate language) so this post concerns Fedora 23 and higher.

As an example we can look on following BZ:
https://bugzilla.redhat.com/show_bug.cgi?id=1349998

In description of BZ we can find this AVC:

type=AVC msg=audit(1466793837.663:1360): avc:  denied  { setrlimit }
for  pid=15770 comm="zabbix_agentd" scontext=system_u:system_r:zabbix_agent_t:s0
tcontext=system_u:system_r:zabbix_agent_t:s0 tclass=process permissive=0

Important parts of AVC for us:

avc:  denied  { setrlimit }
scontext=system_u:system_r:zabbix_agent_t:s0
tcontext=system_u:system_r:zabbix_agent_t:s0
tclass=process

From these parts we can create allowing rule in CIL. Template for creating allow rules:

(allow source_context target_context (tclass (permissions)))

If we apply template on our AVC it looks like this:

(allow zabbix_agent_t zabbix_agent_t(process (setrlimit)))

Now, we add this line to file:
(Note: Name of your local module must be different than any other used in distro policy!)

$ cat zabbix_setrlimit.cil 
(allow zabbix_agent_t zabbix_agent_t(process (setrlimit)))

Finally, we could load this local module into kernel:

# semodule -i zabbix_setrlimit.cil

And that’s it! Rule from AVC report is loaded into kernel! You can verify it using:

$ sesearch -A -s zabbix_agent_t -t zabbix_agent_t -c process -p setrlimit
Found 1 semantic av rules:
   allow zabbix_agent_t zabbix_agent_t : process { fork sigchld sigkill sigstop signull signal getsched setsched setpgid getcap setrlimit } ; 

Pretty easy, don’t you think? 😉

How to modify SELinux module from distro policy?

Hi!

Today, I’ll show you how to modify SELinux module from distro policy without rebuilding whole selinux-policy rpm package. This can be useful during testing new features in your application or debugging SELinux policy. All current Fedora stable releases (Fedora 23, Fedora 24) support this feature.

For example, we have openwsman SELinux module containing following macro:

optional_policy(`
     unconfined_domain(openwsman_t)
')

That means, openwsman_t domain is part of unconfined_domain_type attribute:

$ seinfo -xtopenwsman_t | grep unconfined_domain_type
unconfined_domain_type

This macro makes SELinux domain unconfined. Let’s say, we want openwsman_t domain confined, so we need to remove rule above.
First step is download openwsman policy source files from our repo.

$ ls
openwsman.fc  openwsman.if  openwsman.te

We can edit openwsman.te file:

$ diff -u openwsman.te.old openwsman.te
--- openwsman.te.old	2016-08-17 19:38:30.617111430 +0200
+++ openwsman.te	2016-08-17 19:38:41.105155383 +0200
@@ -68,7 +68,3 @@
     sblim_getattr_exec_sfcbd(openwsman_t)
 ')
 
-optional_policy(`
-    unconfined_domain(openwsman_t)
-')
-

Modified policy needs to be compiled:

$ make -f /usr/share/selinux/devel/Makefile openwsman.pp

Now, we have compiled policy in .pp format:

$ ls
openwsman.fc  openwsman.if  openwsman.pp  openwsman.te  openwsman.te.old  tmp/

Last step, we load modified policy to kernel:

# semodule -i openwsman.pp 
libsemanage.semanage_direct_install_info: Overriding openwsman module at lower priority 100 with module at priority 400.

We can check if modified policy is loaded into kernel and openwsman_t domain is part of unconfined_domain_type:

# semodule -lfull | grep openwsman
400 openwsman                pp         
100 openwsman                pp 

$ seinfo -xtopenwsman_t | grep unconfined_domain_type
$

Two SELinux modules called openwsman are loaded. Firt one, with priority 400 is our local modified module. Second, with priority 100, coming from distro policy. Only SELinux module with the highest priority is active on system.

This is pretty easy and quick solution for modifying distro policy modules, isn’t it? 😉