07 January 2015

gpsd stdout stderr silently killed by SELinux on Centos 7

Setting up gpsd with a new gps device, I usually run gpsd in the foreground with debug output so I can see if the gps is detected.

It looks like something like this:
[root@octobox3 gpsd]# gpsd -D99 -n -N /dev/ttyS0
gpsd:INFO: launching (Version 3.11~dev)
gpsd:IO: opening IPv4 socket
gpsd:SPIN: passivesock_af() -> 3
gpsd:IO: opening IPv6 socket
gpsd:SPIN: passivesock_af() -> 4
gpsd:INFO: listening on port gpsd
gpsd:PROG: NTPD shmat(0,0,0) succeeded, segment 0
gpsd:PROG: NTPD shmat(32769,0,0) succeeded, segment 1
gpsd:PROG: NTPD shmat(65538,0,0) succeeded, segment 2
gpsd:PROG: NTPD shmat(98307,0,0) succeeded, segment 3
gpsd:PROG: successfully connected to the DBUS system bus
gpsd:PROG: shmat() succeeded, segment 131076
gpsd:PROG: shared-segment creation succeeded,
gpsd:INFO: stashing device /dev/ttyS0 at slot 0
gpsd:INFO: opening GPS data source type 2 at '/dev/ttyS0'
gpsd:INFO: speed 115200, 8N1
gpsd:IO: => GPS: $PASHQ,RID*28\x0d\x0a
gpsd:IO: => GPS: @F0.3=1*67\x0d\x0a
gpsd:IO: => GPS: @F0.3=1*67\x0d\x0a
gpsd:IO: => GPS: @F2.2=1*64\x0d\x0a
gpsd:IO: => GPS: @F2.2=1*64\x0d\x0a
gpsd:IO: => GPS: GPS:GPGGA 1\x0d\x0a
gpsd:PROG: writing oncore control type Cj
gpsd:IO: => GPS: @@Cj)\x0d\x0aRID*28\x0d\x0a
gpsd:SPIN: open(/dev/ttyS0) -> 6 in gpsd_serial_open()
gpsd:PROG: Probing "Garmin USB binary" driver...
gpsd:PROG: Probe not found "Garmin USB binary" driver...
gpsd:PROG: Probing "GeoStar" driver...
So when I installed gpsd from EPEL on a Centos 7 box the other day I was surprised that running gpsd would not produce any output. even "gpsd -V" would not show the version number. I strace'd the gpsd -V run and could see that the write() to STDOUT (file descriptor 1) was actually going to device 1,3
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7fff7e13b4b0) = -1 ENOTTY (Inappropriate ioctl for device)
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa1e9502000
write(1, "gpsd: 3.11~dev (revision 3.10-5."..., 55) = 55
exit_group(0)                           = ?
+++ exited with 0 +++
[root@octobox3 gpsd]#
 Device 1,3 is /dev/null
[root@octobox3 gpsd]# ls -l /dev/null
crw-rw-rw-. 1 root root 1, 3 Dec 22 00:20 /dev/null
I searched /var/log and poked around in systemd (disabling gpsd, gpsdctl etc), journalctl etc. I ended up rebuilding the RPM and installing it... same problem. I built from the source tarball and ran the resulting executable... now it works!

So, I copied it to /usr/sbin over top of the existing /usr/sbin/gpsd. Didn't work again! After a few more cp+mv tests and rebuilds and it finally occurred to me. That the "copy" to /usr/sbin/gpsd resulted in the same permissions and SELinux contexts/attributes being applied to the file.

At this point I was convinced the problem was due to the SELinux context of the gpsd executable installed by the EPEL rpm. Googling this new info led me to this blog post.

In that post Dan Walsh explains the whole situation, including the fact that the tty restrictions are usually set by default to NOT produce an AVC message so you see nothing in the logs (and have no idea what's going on if you've never seen this before).

He also gives a solution:
setsebool allow_daemons_use_tty on
That will temporarily allow any daemon that is normally restricted from accessing STDOUT etc to actually use STDOUT. It won't survive a reboot in case I forget to set if back off, which is preferred in this case.