How to configure SELinux to allow specific services to communicate with Avahi?
I have a service, running on a Fedora 20 machine, that when started attempts to register services with Avahi. This works perfectly if my service is started while SELinux is in permissive mode, but the service will not register when SELinux is enforcing.
I am aware of the httpd_dbus_avahi
boolean in SELinux. This works perfectly to allow Apache to register services, but I have been unable to find much information about how to allow other specific services to communicate with Avahi.
More specifically I am attempting to allow tvheadend to register its HTSP service with Avahi, but I am also curious how any particular service can be allowed to communicate with Avahi without being stopped by SELinux. I am NOT interested in turning off SELinux or making the process permissive that wants to communicate with Avahi.
EDIT: added all SELinux and service unit information relating to tvheadend
---SELinux---
audit.log messages
After executing semodule -DB
and restarting the tvheadend service. The following are all messages that appeared in the audit log. The last message seems like the problem, but I am not sure what to make of it...
type=SERVICE_STOP msg=audit(1393282994.012:512): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg=' comm="tvheadend" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
type=SERVICE_START msg=audit(1393283083.635:513): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg=' comm="tvheadend" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
type=USER_AVC msg=audit(1393283084.291:514): pid=752 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_return dest=:1.114 spid=731 tpid=14478 scontext=system_u:system_r:avahi_t:s0 tcontext=system_u:system_r:init_t:s0 tclass=dbus exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'
Process
Output from ps -AZ | grep tvheadend
system_u:system_r:init_t:s0 2599 ? 00:00:06 tvheadend
I noticed that the init_t
process type seems a little strange since all other services on my system have the initrc_t
process type. I am not sure why the tvheadend service is different in this way.
User
Output from sudo -u hts id
uid=1001(hts) gid=1003(hts) groups=1003(hts),39(video) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
I use this user only for running the tvheadend service. This user has a home directory on a separate partition much larger than the system partition since DVR files generated by tvheadend can become quite large.
When I created this user I did not use the --system
switch with the useradd
command. Perhaps I should have?
Executable
Output from ls -Z /usr/local/bin | grep tvheadend
-rwxr-xr-x. root root system_u:object_r:bin_t:s0 tvheadend
---Service---
Unit File
[Unit]
Description=TVHeadEnd
After=syslog.target network.target avahi-daemon.service sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb0.demux0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb0.dvr0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb0.frontend0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb0.net0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb1.demux0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb1.dvr0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb1.frontend0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb1.net0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-video4linux-vbi0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-video4linux-vbi1.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-video4linux-video0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-video4linux-video1.device
Wants=sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb0.demux0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb0.dvr0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb0.frontend0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb0.net0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb1.demux0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb1.dvr0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb1.frontend0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-dvb-dvb1.net0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-video4linux-vbi0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-video4linux-vbi1.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-video4linux-video0.device sys-devices-pci0000:00-0000:00:1c.0-0000:05:00.0-video4linux-video1.device
[Service]
Type=forking
GuessMainPID=no
EnvironmentFile=/etc/sysconfig/tvheadend
ExecStart=/usr/local/bin/tvheadend -f -u $TVH_USER -g $TVH_GROUP -p $TVH_PID -b $TVH_ADDRESS --http_port $TVH_HTTP_PORT --htsp_port $TVH_HTSP_PORT
PIDFile=$TVH_PID
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
Unit Environment File
TVH_USER=hts
TVH_GROUP=hts
TVH_PID=/var/run/tvheadend.pid
TVH_ADDRESS=0.0.0.0
TVH_HTTP_PORT=9981
TVH_HTSP_PORT=9982
Solution 1:
Running this service as init_t
is probably not a great idea.
The reason you get this behaviour is because tvheadend
is probably labelled bin_t
, and no transition rule exists to move a file of this type out of the init_t
context.
You can search this to know for sure..
$ sesearch -s init_t --type -c process | grep bin_t
This command returns no results. No transitions out of init_t for a bin_t
process.
You should also avoid running this type in initrc_t
too since its not appropriate for the service. As a general matter of fact -- the best solution would be to properly write a confined policy for you're service, however this is beyond the scope of this answer.
Instead, you need to get your process out of init_t
to another type. Because no policy exists for this application it is probably best to move this into unconfined_t
, for which a type transition does exist.
$ sesearch -s init_t --type -c process -t unconfined_exec_t
Found 1 semantic te rules:
type_transition init_t unconfined_exec_t : process unconfined_t;
We can also check that the rule that is being hit in policy will not get hit in unconfined_t
(which it shouldn't).
$ sesearch -s avahi_t -p send_msg -c dbus -t unconfined_t --allow
Found 2 semantic av rules:
allow avahi_t unconfined_t : dbus send_msg ;
allow system_bus_type unconfined_t : dbus send_msg ;
To do this, simply relabel your tvheadend
program to unconfined_exec_t
.
semanage fcontext -a -t unconfined_exec_t -f f /usr/bin/tvheadend
Then restore.
restorecon /usr/bin/tvheadend
Now, re-running your service should work. If you re-run ps -AZ | grep tvheadend
you should see your process running in unconfined_t
.
Ideally a new policy should be used for this program, but if no policy exists its best to run it without policy at all in the unconfined_t
domain. initrc_t
and init_t
are not really meant to be used to run services (although some do incorrectly go in there), initrc_t
was originally conceived to run SYSV shell scripts and init_t
is meant for running systemd/init itself.
Solution 2:
The manpage for apache_selinux
mentions that # semanage permissive
can be used to allow specific processes to run in permissive mode.
# semanage permissive -a avahi_t
I suggest finding some more detailed info on its usage
Though, it might be wise to find a better solution than simply "allowing a service permissive" access controls;
especially when SELinux provides a vast number of config options to allow a given service permissions to do only the things you expect it to do, and nothing more!
Because of this vast number of control options, however, admins have to learn what options exist, and decide how/when/where to implement them efficaciously. As I mentioned, the first place to look is within the manpages on your system, as well as your audit log in /var/log/audit/audit.log
. To search for messages about avahi, for example, within your log files, execute:
# grep /usr/sbin/avahi /var/log/audit/audit.log
EDIT: to reflect updated question
msg=avc: denied { send_msg } for msgtype=method_return dest=:1.114
spid=731 tpid=14478 scontext=system_u:system_r:avahi_t:s0
tcontext=system_u:system_r:init_t:s0
Take a look at the Manpages
The following items in particular should be of interest to you:
-
system_dbusd_t
SELinux Type:$ man system_dbusd_selinux
-
avahi_t
SELinux Type:$ man avahi_selinux
- take a look at the
avahi_exec_t
-
avahi_initrc_exec_t
file contexts avahi_var_run_t
avahi_unit_file_t
- as well as the list of related booleans therein.
- take a look at the
Allright, as I'm not sure that you've noticed that last bit on avahi_exec_t
; and since I can't post comments :/ yet; here's the pertinent info from the manpage itself:
SELinux defines the file context types for the avahi, if you wanted to store files with these types in a diffent paths, you need to execute the semanage command to sepecify alternate labeling and then use restorecon to put the labels on disk.
semanage fcontext -a -t avahi_exec_t '/srv/avahi/content(/.*)?' restorecon -R -v /srv/myavahi_content Note: SELinux often uses regular expressions to specify labels that match multiple files. The following file types are defined for avahi: avahi_exec_t - Set files with the avahi_exec_t type, if you want to transition an executable to the avahi_t domain. Paths: /usr/sbin/avahi-daemon, /usr/sbin/avahi-autoipd, /usr/sbin/avahi-dnsconfd avahi_initrc_exec_t - Set files with the avahi_initrc_exec_t type, if you want to transition an executable to the avahi_initrc_t domain. avahi_unit_file_t - Set files with the avahi_unit_file_t type, if you want to treat the files as avahi unit content.
SELinux and Process Transitions
Head over to Dan Walsh's blog for some detailed discussion/information on SELinux, this post in particular mentions
A process transition says when process running as label a_t executes a file labeled b_exec_t it should execute the process as b_t An example of this would be service httpd start. In this case we have unconfined_t running an init script labeled initrc_exec_t and SELinux starts the process as initrc_t.
Aside from that, your best bet is to keep researching the tvheadend
program, as well as SELinux management. You can create a custom policy as suggested by the audit
log messages; something like:
# grep tvheadend /var/log/audit/audit.log | audit2allow -M mypol
# semodule -i mypol.pp
At least until a better solutions comes across, and/or tvheadend
makes its way to the fedora repos. Lastly, take a better look at the unit file (service file) you created for systemd
; check for errors, potential additions and changes.
Solution 3:
You could fix this using audit2allow to create a custom policy module
audit2allow -M custom_avhi <file_containing_AVC-denied messages
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i custom_avhi.pp