How to configure SELinux to allow specific services to communicate with Avahi

avahifedorafedora-20selinux

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

Best Answer

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.