Chapter 10. SELinux systemd Access Control
In Red Hat Enterprise Linux 7, system services are controlled by the
systemd
daemon. In previous releases of Red Hat Enterprise Linux, daemons could be started in two ways:
- At boot time, the System V
init
daemon launched aninit.rc
script and then this script launched the required daemon. For example, the Apache server, which was started at boot, got the following SELinux label:system_u:system_r:httpd_t:s0
- An administrator launched the
init.rc
script manually, causing the daemon to run. For example, when theservice httpd restart
command was invoked on the Apache server, the resulting SELinux label looked as follows:unconfined_u:system_r:httpd_t:s0
When launched manually, the process adopted the user portion of the SELinux label that started it, making the labeling in the two scenarios above inconsistent. With the
systemd
daemon, the transitions are very different. As systemd
handles all the calls to start and stop daemons on the system, using the init_t
type, it can override the user part of the label when a daemon is restarted manually. As a result, the labels in both scenarios above are system_u:system_r:httpd_t:s0
as expected and the SELinux policy could be improved to govern which domains are able to control which units.
10.1. SELinux Access Permissions for Services
In previous versions of Red Hat Enterprise Linux, an administrator was able to control, which users or applications were able to start or stop services based on the label of the System V Init script. Now,
systemd
starts and stops all services, and users and processes communicate with systemd
using the systemctl
utility. The systemd
daemon has the ability to consult the SELinux policy and check the label of the calling process and the label of the unit file that the caller tries to manage, and then ask SELinux whether or not the caller is allowed the access. This approach strengthens access control to critical system capabilities, which include starting and stopping system services.
For example, previously, administrators had to allow NetworkManager to execute
systemctl
to send a D-Bus message to systemd
, which would in turn start or stop whatever service NetworkManager requested. In fact, NetworkManager was allowed to do everything systemctl
could do. It was also impossible to setup confined administrators so that they could start or stop just particular services.
To fix these issues,
systemd
also works as an SELinux Access Manager. It can retrieve the label of the process running systemctl
or the process that sent a D-Bus message to systemd
. The daemon then looks up the label of the unit file that the process wanted to configure. Finally, systemd
can retrieve information from the kernel if the SELinux policy allows the specific access between the process label and the unit file label. This means a compromised application that needs to interact with systemd
for a specific service can now be confined by SELinux. Policy writers can also use these fine-grained controls to confine administrators. Policy changes involve a new class called service
, with the following permissions:
class service { start stop status reload kill load enable disable }
For example, a policy writer can now allow a domain to get the status of a service or start and stop a service, but not enable or disable a service. Access control operations in SELinux and
systemd
do not match in all cases. A mapping was defined to line up systemd
method calls with SELinux access checks. Table 10.1, “Mapping of systemd unit file method calls on SELinux access checks” maps access checks on unit files while Table 10.2, “Mapping of systemd general system calls on SELinux access checks” covers access checks for the system in general. If no match is found in either table, then the undefined
system check is called.
systemd unit file method | SELinux access check |
---|---|
DisableUnitFiles | disable |
EnableUnitFiles | enable |
GetUnit | status |
GetUnitByPID | status |
GetUnitFileState | status |
Kill | stop |
KillUnit | stop |
LinkUnitFiles | enable |
ListUnits | status |
LoadUnit | status |
MaskUnitFiles | disable |
PresetUnitFiles | enable |
ReenableUnitFiles | enable |
Reexecute | start |
Reload | reload |
ReloadOrRestart | start |
ReloadOrRestartUnit | start |
ReloadOrTryRestart | start |
ReloadOrTryRestartUnit | start |
ReloadUnit | reload |
ResetFailed | stop |
ResetFailedUnit | stop |
Restart | start |
RestartUnit | start |
Start | start |
StartUnit | start |
StartUnitReplace | start |
Stop | stop |
StopUnit | stop |
TryRestart | start |
TryRestartUnit | start |
UnmaskUnitFiles | enable |
systemd general system call | SELinux access check |
---|---|
ClearJobs | reboot |
FlushDevices | halt |
Get | status |
GetAll | status |
GetJob | status |
GetSeat | status |
GetSession | status |
GetSessionByPID | status |
GetUser | status |
Halt | halt |
Introspect | status |
KExec | reboot |
KillSession | halt |
KillUser | halt |
ListJobs | status |
ListSeats | status |
ListSessions | status |
ListUsers | status |
LockSession | halt |
PowerOff | halt |
Reboot | reboot |
SetUserLinger | halt |
TerminateSeat | halt |
TerminateSession | halt |
TerminateUser | halt |
Example 10.1. SELinux Policy for a System Service
By using the
sesearch
utility, you can list policy rules for a system service. For example, calling the sesearch -A -s NetworkManager_t -c service
command returns:
allow NetworkManager_t dnsmasq_unit_file_t : service { start stop status reload kill load } ; allow NetworkManager_t nscd_unit_file_t : service { start stop status reload kill load } ; allow NetworkManager_t ntpd_unit_file_t : service { start stop status reload kill load } ; allow NetworkManager_t pppd_unit_file_t : service { start stop status reload kill load } ; allow NetworkManager_t polipo_unit_file_t : service { start stop status reload kill load } ;