Puppet's use of tempfiles for capturing use of subprocess I/O

Sean E. Millichamp sean at bruenor.org
Fri Sep 12 13:24:36 UTC 2008


I know this is long, please be patient as I detail the situation.  There
is a lot of Puppet-stuff initially to frame the question, but I promise
there is an SELinux question at the end :)

A common use-case in Puppet is for it to manage your system services,
restarting services as needed.  I noticed that when Puppet did this I
got SELinux violations.  Since we are trying to embrace SELinux (and
noisy logs don't help in that goal) I dug a bit deeper.

It turns out that Puppet creates a temp file in /tmp and sets the file
descriptor for that tempfile to the stdout/stderr of the process before
it exec()s (say) "/etc/init.d/setroubleshoot" (I've seen this happen
with a number of different services).

audit log messages: 
type=AVC msg=audit(1220897810.383:141): avc:  denied  { read write } for  pid=3452 comm="setroubleshootd" path="/tmp/puppet.3059.7" dev=md3 ino=6036 scontext=root:system_r:setroubleshootd_t:s0 tcontext=root:object_r:tmp_t:s0 tclass=file
type=AVC msg=audit(1220897810.383:141): avc:  denied  { read write } for  pid=3452 comm="setroubleshootd" path="/tmp/puppet.3059.7" dev=md3 ino=6036 scontext=root:system_r:setroubleshootd_t:s0 tcontext=root:object_r:tmp_t:s0 tclass=file
type=AVC msg=audit(1220897810.383:141): avc:  denied  { read write } for  pid=3452 comm="setroubleshootd" path="/tmp/puppet.3059.7" dev=md3 ino=6036 scontext=root:system_r:setroubleshootd_t:s0 tcontext=root:object_r:tmp_t:s0 tclass=file

Now, it seems that the domain that the init scripts transition to
(rightly) doesn't have access to the tmp_t domain of Puppet's temporary
file.  It seems that the two results of this are a) audit log noise and
b) If Puppet were to want to use the output it captures then there
wouldn't be any for confined services.

I created and submitted a patch to use Unix pipes instead of a temporary
file for capturing the output - figuring that this was the only way sure
to be SELinux-safe.  (See my bug report at
http://projects.reductivelabs.com/issues/show/1563 for a link to the
original bug, the patch, and more details.) They told me that Puppet
used to use pipes about a year ago but that there were occasionally
weird hanging problems where Puppet would block on IO reads forever so
the temporary file method was adopted and they didn't want to just go
back to a situation where Puppet might end up hanging forever on an IO
read.  Fair enough, I can't object to that. 

I downloaded Debian Etch and successfully reproduced the originally
reported problem with the pipes method.  Bottom line is that during the
package install a process is started, daemonizes, but not correctly and
never detaches from/closes stdout/stderr, causing the pipe to not close
and flush, resulting in Puppet blocking forever on the IO read.

I have now worked out another patch to Puppet which uses non-blocking
I/O.  This works but causes problems where the package doesn't finish
installing properly because Puppet can't know when to finish trying to
read from the pipe and if it closes the pipe before the package is
finished installing then the install doesn't complete.  At this point I
would say this is squarely a problem with the package containing the
poorly written daemon BUT, before I make that case on the bug report
with my new patch I want to know:

Is there a clean way of doing this using temporary files that will be
safe for all SELinux domain transition possibilities?  Perhaps a label I
could apply to the temporary file after creation but before the
fork()/exec() that would be permissible in any SELinux context current
or future?  Or some other deep Unix magic I don't know about?  I suspect
the answer is "no", but I figure I had to ask the experts before
declaring there was no other way in the Puppet bug report.

Thanks for sticking through reading all of this :)

Sean




More information about the fedora-selinux-list mailing list