Dan Walsh's Blog

Got SELinux?

For those who read this blog, we have talked in the past about setting the machine in permissive or enforcing mode. In permissive mode, SELinux performs all of the checks and reports all of the AVC messages, but does not enforce the denials. Fedora 10, and also Fedora 9 with the latest updates, introduces a new capability in SELinux which lets the administrator change a single process (domain) to be permissive. A permissive domain is a domain that performs the SELinux access checks, however if SELinux policy would have denied access, the kernel allows the access and reports the AVC. All transition rules continue to apply, and files get created with the correct context.

This solves several major problems in SELinux.

In Red Hat Enterprise Linux 4 and 5, administrators often want to disable enforcement for a single process. SELinux policy enforcement causes the application to fail to run properly and they just do not want to deal with SELinux. We designed policy with booleans called DOMAIN_disable_trans. These booleans modify policy, turning off the rule that causes init scripts to transition to the corresponding confined domain. For example, you could turn on the httpd_disable_trans boolean and when the init script started /usr/sbin/httpd, it would continue to run in the initrc_t domain (which is unconfined) rather than transitioning to the httpd_t domain. The httpd web server would then run without SELinux getting in its way. A problem with this is that files created by a process running as initrc_t might not have the same labeling rules applied to them as files created by a process running as httpd_t, potentially causing mislabeled files to be created. Also other confined domains that are allowed to communicate with the httpd_t domain would not be allowed to communicate with the initrc_t domain, causing additional failures. We removed disabled_trans booleans in Fedora 7 to avoid these problems, even though we had no replacement. Until now.

Another problem SELinux has is that third party software companies want to ship with SELinux policy for their software but do not trust that they have tested it well enough to run their confined applications in enforcing mode. I have talked to developers of stock market software that wanted to write policy for an application, distribute it to a live environment of several hundred machines, and then gather the AVCs as they happen, using this information to fine-tune their policy. After a long period of time, where they saw no AVCs, they might be willing to put their policy in enforcing mode. In RHEL5 they need to put the entire machine in permissive mode, but permissive domains solve this problem.

Finally, when someone wants to write policy for a new confined domain, we tell the policy writer to build a minimal policy using tools like system-config-selinux. Then we advise them to put the machine in permissive mode, run the confined application, collect the AVC messages, use audit2allow to generate new policy, and try again. Lather, rinse, repeat. This puts the entire machine at risk, since it is no longer protected by SELinux. With permissive domains, you can mark the new domain as permissive and avoid putting the machine at risk.

So how do I put a domain in permissive mode?

Put a singe domain in permissive mode by executing:

# semanage permissive -a DOMAIN

If you wanted your default CGI scripts to run in permissive mode you would execute

# semanage permissive -a httpd_sys_script_t

CGI scripts on this machine will now run in permissive mode while the rest of the machine continues to run in enforcing mode. Note that AVC messages will still be generated and you can use audit2allow to customize your policy.

All the semanage command is doing is creating a policy module (named permissive_httpd_sys_script_t.pp) and installing it.

This is the generated policy.

module permissive_httpd_sys_script_t 1.0;

require { type httpd_sys_script_t;}

permissive httpd_sys_script_t;

If you want to get a list of the permissive domains you have installed, you can execute:

# semodule -l | grep permissivepermissive_httpd_sys_script_t 1.0

To remove the permissive domain execute:

# semanage permissive -d httpd_sys_script_t

If you are writing a new policy that you want to ship in permissive mode just add