PackagingDrafts/SELinux

= Adding SELinux support to your package = This is a collection of common cases for solving SELinux issues at the packaging level. This page is only valid for Fedora Core 5 and newer.

File contexts
Problem: SELinux prevents your application from running because some files don't have the required context type.

Solution: There are two things to do in your package's scriptlets:
 * Label the files with the correct type
 * Save this configuration into the current SELinux policy, to keep your types in place after relabeling

Example: The awstats application is a CGI-based logfiles analyser. The CGI needs to have the  type to run with SELinux enabled. What needs to be added to the spec file: Requires(post): policycoreutils Requires(postun): policycoreutils

...

%post semanage fcontext -a -t httpd_sys_script_exec_t '%{_datadir}/awstats/wwwroot/cgi-bin(/.*)?' 2>/dev/null || : restorecon -R %{_datadir}/awstats/wwwroot/cgi-bin || :

%postun if [ $1 -eq 0 ] ; then # final removal semanage fcontext -d -t httpd_sys_script_exec_t '%{_datadir}/awstats/wwwroot/cgi-bin(/.*)?' 2>/dev/null || : fi

BEWARE: The  will add huge dependencies. To avoid dependency bloat it should be tried : a. to work without manual scripts (e.g. file bug against selinux-policy and request that your package will be handled), or a. split the SELinux related part into an own subpackage in a way like %package selinux Requires: %name = %version-%release Requires(...): policycoreutils

%post selinux ... or

a. move current main package (without the SELinux stuff) into e.g. a  subpackage, keep SELinux in main and require   by main. Unexperienced people will get the expected result (correctly labeled program) by " " while people without SELinux can install only.

Discussions about this approach:
 * http://www.redhat.com/archives/fedora-selinux-list/2006-April/msg00094.html
 * http://www.redhat.com/archives/fedora-extras-list/2006-April/msg00852.html

An alternative approach, which might be more manageable in the long term, would be to create a policy module for the application containing only file context definitions. The reasoning behind this approach is described here: http://www.redhat.com/archives/fedora-selinux-list/2006-May/msg00108.html

Creating new types
Problem: You need to define new types for your application

Solution: You need to create an SELinux module, defining the new types and how they should be dealt with.

Example: The mock application makes a chroot to build packages. The content of the chroot needs a special type to identify files that may need the execmod feature, and mock itself needs to run in its own domain, which is allowed to do execmem and execheap when building packages for mono or java applications. policy_module(mock, 0.7.1)
 * Make a directory to create and build the policy module for the package, e.g.  and change to that directory.
 * Create a file called, with the following content:



type mock_t; domain_type(mock_t)

type mock_exec_t; domain_entry_file(mock_t,mock_exec_t)

type mock_var_lib_t; files_type(mock_var_lib_t)



ifdef(

allow mock_t self:process { execheap execmem }; unconfined_domain_noaudit(mock_t) role system_r types mock_t;

allow mock_t mock_var_lib_t:file execmod;

mock_domtrans(unconfined_t)

') /usr/bin/mock                  --      gen_context(system_u:object_r:mock_exec_t,s0) /var/lib/mock(/.*)?                     gen_context(system_u:object_r:mock_var_lib_t,s0)
 * Create a file called, with the following content:
 * Create a file called, with the following content:

interface( gen_require( gen_require(
 * as root, run

You can ship the  files as additional SOURCE files in your package, do the compiling in %install, and load the module with the   command in %post (see the Pure-FTPd example below).

The preferred place for the module is in the directory. Any place could potentially be used, though  has restricted rights to read files itself, which makes a location under   preferable. We also need to standardize on some location, and this location makes it easy to find all the available modules.

You will need:
 * (to build the SELinux module in %install)
 * (to load the module)

Discussions about this approach :
 * http://www.redhat.com/archives/fedora-selinux-list/2006-April/msg00138.html
 * http://www.redhat.com/archives/fedora-selinux-list/2006-April/msg00062.html

A more detailed guide to bundling policy modules within RPM packages can be found in ["PackagingDrafts/SELinux/PolicyModules"]

Adding an existing SELinux policy to an application
Problem: There are applications in Extras that perform the same task as applications in Core. They should be protected by SELinux in the same way.

Solution: Label the new binaries the same way as the already-protected ones. Check that all the functionalities still work and that you have no AVC messages. If you do, extend the policy with an SELinux module.

Example: Pure-FTPd is an FTP server available in Extras. It should be protected is the same manner that vsftpd is in Core. Thus the file  should be labelled. But Pure-FTPd has additional features: it is capable of taking its user list from MySQL, PostgreSQL or LDAP. We have to write a module to allow it to connect to these servers. To do that, we ship the file  (the filename cannot contain dashes) in the package, containing this: policy_module(pureftpd, 1.0)

require { type ftpd_t; };

init_read_utmp(ftpd_t) init_dontaudit_write_utmp(ftpd_t)

corenet_tcp_connect_mysqld_port(ftpd_t) mysql_stream_connect(ftpd_t); mysql_rw_db_sockets(ftpd_t)

corenet_tcp_connect_postgresql_port(ftpd_t) postgresql_stream_connect(ftpd_t)

sysnet_use_ldap(ftpd_t)

Then we compile this policy in the %install step, together with the file_contexts: mkdir selinux; cd selinux echo "%{_sbindir}/pure-ftpd   system_u:object_r:ftpd_exec_t:s0" > pureftpd.fc echo '%{_localstatedir}/log/pureftpd.log    system_u:object_r:xferlog_t:s0' >> pureftpd.fc touch pureftpd.if make -f %{_datadir}/selinux/devel/Makefile install -p -m 644 -D pureftpd.pp $RPM_BUILD_ROOT%{_datadir}/selinux/packages/%{name}/pureftpd.pp


 * To build the policy, we need to add.

Requires(post): policycoreutils, initscripts, %{name} Requires(preun): policycoreutils, initscripts, %{name} Requires(postun): policycoreutils
 * It is also better to package all SELinux-related files and scriptlets in a separate rpm, named -selinux. This way, the administrator can choose to enable SELinux protection or not.
 * Scriptlets: The -selinux package should load the policy on install, and set the file contexts. It should unload the policy on uninstall, set back the file contexts, and it should replace the policy module on upgrades. The daemon needs to be restarted when it is relabeled, but not when the policy module is replaced. We chose a set of scriptlets very similar to  the ones we use for init scripts :

...

%post selinux if [ "$1" -le "1" ] ; then # First install semodule -i %{_datadir}/selinux/packages/%{name}/pureftpd.pp 2>/dev/null || : fixfiles -R pure-ftpd restore /sbin/service pure-ftpd condrestart > /dev/null 2>&1 fi

%preun selinux if [ "$1" -lt "1" ] ; then # Final removal semodule -r pureftpd 2>/dev/null || : fixfiles -R pure-ftpd restore /sbin/service pure-ftpd condrestart > /dev/null 2>&1 fi

%postun selinux if [ "$1" -ge "1" ] ; then # Upgrade semodule -i %{_datadir}/selinux/packages/%{name}/pureftpd.pp 2>/dev/null || : fi

TODO

 * Do all above scriptlets work with SELinux disabled ?
 * Do all above scriptlets work with SELinux not installed ?