This page just describes how I have found out you can do to make stuff work in SELinux when they don’t. I feel there may be a better way to update SELinux in an organized manner. If you know how, don’t hesitate to send me an email at olle at iix dot se. Anyhow, here is my way of making stuff work at the moment.
Locate the problem
In this example. My nginx installation is unable to access a file called test.txt. This is the journal log:
Sep 22 20:01:32 hermes.iix.se audit[23928]: AVC avc: denied { read } for pid=23928 comm="nginx" name="test.txt" dev="vda1" ino=271350 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file permissive=0
The first thing we do is to asking audit whats up. this is usually done by piping the audit log to audit2why. If you don’t have audit, the logs should be in the /var/log/messages instead.
% sudo grep nginx /var/log/audit/audit.log | audit2why
type=AVC msg=audit(1537639292.775:2600603): avc: denied { read } for pid=23928 comm="nginx" name="test.txt" dev="vda1" ino=271350 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file permissive=0
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
In this case that didn’t really give any additional info. However sometimes audit2why can be pretty helpful.
Writing your module
As the reply from audit2why said, we can use audit2allow to generate a loadable module for this. You can actually do everything quick and dirty by just using the -M command and hoping for the best, which was what I used to do, but since that will end up with you generating hundreds of small modules for this and that, the situation quickly becomes untenable.
Instead you should begin by creating a repository of sorts. You decide if you want to put it under git control (and have it as a super nice reference in the future, plus having backups) or not (and spending all night trying to remember how you made it work last time). Now you will create your first module policy, replace nginx_hermes with your own fancy module name.
% sudo grep nginx /var/log/audit/audit.log | audit2allow -m nginx_hermes > nginx_hermes.te
% cat nginx_hermes.te
module nginx_hermes 1.0;
require {
type var_t;
type httpd_t;
class file read;
}
#============= httpd_t ==============
allow httpd_t var_t:file read;
This is a really good time to learn to understand what all this means. But you will kinda learn as you go since audit2allow will make all or most heavy lifting for you.
Compiling your module and package it
% checkmodule -M -m -o nginx_hermes.mod nginx_hermes.te
checkmodule: loading policy configuration from nginx_hermes.te
checkmodule: policy configuration loaded
checkmodule: writing binary representation (version 19) to nginx_hermes.mod
% semodule_package -o nginx_hermes.pp -m nginx_hermes.mod
Not much to say here. Maybe you want a Makefile for this? Here is mine. Just pop it into the same folder as your *.te files and run make
and it will build them for you.
PACKAGES = $(addsuffix .pp, $(basename $(wildcard *.te)))
all: $(PACKAGES)
.PHONY: all
%.mod: %.te
checkmodule -M -m -o $*.mod $*.te
%.pp: %.mod
semodule_package -o $*.pp -m $*.mod
clean:
$(RM) $(PACKAGES)
Install or update package
sudo semodule -i nginx_hermes.pp
If you change the .te in the future, you should also bump the version number and recompile, since that will upgrade the module in place when running -i. There used to be an update option (-u/–upgrade), but nowadays semodule usually gives you the frown if you try to use that instead of -i/–install.
What else?
You can also list modules with semodule -l
.
You can also use so called booleans sometimes which does a cocktail of stuff you might want. Those are run like this: setsebool -P httpd_can_network_connect 1
. You usually notice you want to use those when you get these comments from audit2allow:
require {
type http_port_t;
type xen_port_t;
type container_file_t;
type unreserved_port_t;
type httpd_t;
class lnk_file read;
class tcp_socket name_connect;
}
#============= httpd_t ==============
allow httpd_t container_file_t:lnk_file read;
#!!!! This avc can be allowed using one of the these booleans:
# httpd_can_network_connect, httpd_graceful_shutdown, httpd_can_network_relay, nis_enabled
allow httpd_t http_port_t:tcp_socket name_connect;
#!!!! This avc can be allowed using one of the these booleans:
# httpd_can_network_connect, nis_enabled
allow httpd_t unreserved_port_t:tcp_socket name_connect;
#!!!! This avc can be allowed using the boolean 'httpd_can_network_connect'
allow httpd_t xen_port_t:tcp_socket name_connect;