Package: nsca
Version: 2.9.1-2
Severity: important
Tags: patch upstream
Forwarded: http://tracker.nagios.org/view.php?id=296

I haven't heard back from upstream, so I hope this can at least be fixed
in the Debian package.  Also <https://dev.icinga.org/issues/2400>.

> There is a race condition in src/nsca.c:open_command_file between
> stat() and fopen().  If the command file exists at the point of
> stat(), but is then removed before fopen() (typically by the Nagios
> init script), nsca will create an empty file instead of a named pipe.
> In our case, this would happen at least once every 2-3 reboots.
>
> It would be safer to open() the file atomically, without the O_CREAT
> that is implicit in fopen(..., "w"). Other parts of the code already use
> open() and related headers, so this shouldn't affect portability.
>
> Patch attached.

> To expand a bit, here's the scenario step by step:
>
>  1. src/nsca.c:open_command_file checks whether the named pipe exists,
>     sees that it does, and decides not to use the alternate dump file:
>
>     /* command file doesn't exist - monitoring app probably isn't running... 
> */
>     if(stat(command_file,&statbuf)){
>
>  2. An instant later, "/etc/init.d/nagios3 start" removes the pipe:
> 
>     rm -f $NagiosCommandFile

("rm -f $nagiospipe" in the Debian version.)

>  3. src/nsca.c:open_command_file opens the named pipe with fopen(3),
>     either in "a" or "w" mode. Both of these imply open(2) with
>     O_CREAT, so the command file gets created as an ordinary file:
>
>     command_file_fp=fopen(command_file,(append_to_file==TRUE)?"a":"w");
>
>  4. Nagios calls mkfifo(3) from base/utils.c:open_command_file, gets
>     EEXIST because the path already exists, and dies ignominiously.
>
> If we make the first step atomic -- either an existing pipe is opened
> or not -- the problem goes away.

Thanks,

Matej
#! /bin/sh /usr/share/dpatch/dpatch-run
## 05_command_file_race.dpatch by Matej Vela <v...@debian.org>
##
## DP: Fix race condition when opening /var/lib/nagios3/rw/nagios.cmd.

@DPATCH@
diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' 
'--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' nsca-2.9.1~/src/nsca.c 
nsca-2.9.1/src/nsca.c
--- nsca-2.9.1~/src/nsca.c
+++ nsca-2.9.1/src/nsca.c
@@ -1302,14 +1302,21 @@
 

 /* opens the command file for writing */

 static int open_command_file(void){

-       struct stat statbuf;

+       int fd;

 

         /* file is already open */

         if(command_file_fp!=NULL && using_alternate_dump_file==FALSE)

                 return OK;

 

+        /* open the command file for writing or appending (without using

+         * O_CREAT like fopen() would)

+         */

+        do

+                
fd=open(command_file,O_WRONLY|((append_to_file==TRUE)?O_APPEND:0));

+        while(fd<0 && errno==EINTR);

+

        /* command file doesn't exist - monitoring app probably isn't 
running... */

-       if(stat(command_file,&statbuf)){

+       if(fd<0 && errno==ENOENT){

                

                if(debug==TRUE)

                        syslog(LOG_ERR,"Command file '%s' does not exist, 
attempting to use alternate dump file '%s' for 
output",command_file,alternate_dump_file);

@@ -1326,9 +1333,7 @@
                return OK;

                }

 

-        /* open the command file for writing or appending */

-        command_file_fp=fopen(command_file,(append_to_file==TRUE)?"a":"w");

-        if(command_file_fp==NULL){

+        if(fd<0 || 
(command_file_fp=fdopen(fd,(append_to_file==TRUE)?"a":"w"))==NULL){

                 if(debug==TRUE)

                         syslog(LOG_ERR,"Could not open command file '%s' for 
%s",command_file,(append_to_file==TRUE)?"appending":"writing");

                 return ERROR;

Reply via email to