I decided to write a blog related to this workshop. You can go through this blog, try it and prepare some questions. I would also recommend you to look at writing SELinux Policy blog in which Dan Walsh explains some basics of SELinux.
But now back to my blog ;-). I was thinking during my Friday's travelling which a good example I would show you. An example which really works. I chose the combination of apache, CUPS and portreserve services (btw. portreserve was my first policy written in Red Hat).
Ready to play with SELinux?
First, we need to setup our environment. Stop all intended services and remove the default portreserve policy. We also need to run the restorecon command to restoring contexts.
# for s in portreserve cups httpd; do service $s status 2>&1 >/dev/null; if [ $? -eq 0 ]; then service $s stop; fi; done;# semodule -r portreserve# for files in `rpm -ql portreserve | grep -E "(etc|bin|log|lib|run)"`; do restorecon -R -v $files; done;# service portreserve startNow you can check the context of portreserve service.
# ps -eZ | grep initrcsystem_u:system_r:initrc_t:s0 3374 ? 00:00:00 portreserveWhat happened while we were starting the service? Init script executing the portreserve binary labeled bin_t did not transition and stayed in the same context as the parent process.
initrc_t -> bin_t -> initrc_tReally important to understand.
!! SELinux is all about labels!!
If we had tried to setup the cupsd_exec_t context for the portreserve binary, the service would have run in the cupsd_t domain.
initrc_t -> cupsd_exec_t -> cupsd_tsince we define this transition. So let's create a new policy which will say
initrc_t -> portrserve_exec_t -> portreserve_tUse the sepolgen command.
# sepolgen –helpSince the portreserve is a standard init daemon.
# service portreserve stop# sepolgen -t 0 `which portreserve`Created the following files in:./portreserve.te # Type Enforcement fileportreserve.if # Interface fileportreserve.fc # File Contexts fileportreserve.sh # Setup ScriptInstall the portreserve policy.
# sh portreserve.shDo some checks.
# semodule -l | grep portreserveportreserve 1.0.0# ls -Z `which portreserve`-rwxr-xr-x. root root system_u:object_r:portreserve_exec_t:s0 /sbin/portreserveIt was really easy ;-). We have now the basic portreserve policy. Why not try it?
# service portreserve start# ps -eZ | grep portresystem_u:system_r:portreserve_t:s0 3498 ? 00:00:00 portreserveMaybe you would like to ask me: "Is this policy really working? We have Enforcing mode and the daemon is running". Well I have two answers for you ;-).
1. You can check how is the initial policy good using
# ausearch -m avc -ts recentProbably you will see some AVC messages which are really important for the next steps.
2. The magic there is the portreserve is running as a permissive domain.
This means while SELinux access ckecks are performed for these domains, they are not enforced. The kernel allows the access and reports it as an AVC denial. We can push out a new policy as permissive domain and simply collect AVC messages. Users don’t have to switch to permissive mode globally and they can stay in the enforcing mode.
Now we can easy to complete our policy using ausearch, audit2allow tools (which are my favourite)
# service portreserve restart# ausearch -m avc -ts today | grep portreserve | audit2allow -R >> portreserve.teCompile and load it:
# make -f /usr/share/selinux/devel/Makefile# semodule -i portreserve.ppNow we should test if the policy works without the "permissive domain" declaration.
# date_time=`date | cut -d " " -f 5`# sed -i s/^permissive/#permissive/ portreserve.te# make -f /usr/share/selinux/devel/Makefile# semodule -i portreserve.pp# service portreserve restart 2>&1 >/dev/null; echo $?;# 0Looks good. Maybe one additional check would fine
# ausearch -m avc -ts $date_timeno matchesCONGRATULATIONS.