Package: xinetd
Version: 2.3.13-3

I noticed that sometimes services started failing. I tracked this down to
the fact that xinetd passed a closed file as stdout.

The next piece of strace log demonstrates the problem:
[ I did try to make it a bit more readable ]

The trace starts by xinetd waiting for a connection:

1988  select(25, [3 5 8 9 10 22 23 24], NULL, NULL, NULL <unfinished ...>
20950 <... rt_sigaction resumed> {SIG_IGN}, 8) = 0
20950 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
20950 close(3)                          = 0
20950 close(4)                          = 0
20950 close(0)                          = 0
20950 close(1)                          = 0
20950 close(2)                          = 0
20950 setgid32(0)                       = 0
20950 setgroups32(0, [])                = 0
20950 setuid32(0)                       = 0
20950 rt_sigaction(SIGALRM, .......
20950 getsockname(6, {sa_family=AF_INET, sin_port=htons(21),
                             sin_addr=inet_addr("193.1.1.3")}, [16]) = 0
20950 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 0
20950 bind(0, {sa_family=AF_INET, sin_port=htons(0),
                             sin_addr=inet_addr("193.1.1.3")}, 16) = 0
20950 fcntl64(0, F_SETFD, FD_CLOEXEC)   = 0
20950 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
20950 alarm(30)                         = 0
20950 connect(0, {sa_family=AF_INET, sin_port=htons(113),
                            sin_addr=inet_addr("193.1.1.170")}, 128) = 0
20950 write(0, "7909,21\r\n", 9)        = 9
20950 read(0, 0x8067240, 1024)          = -1 ECONNRESET
20950 time([1133858142])                = 1133858142
20950 getpid()                          = 20950
20950 rt_sigaction(SIGPIPE, {0x40160210, [], SA_RESTORER,
                           0x400b56f8}, {SIG_DFL}, 8) = 0
----> Here is where the trouble starts. syslog has been restarted and the
      syslog socket is no longer connected! So xinetd closes down the old
      connection and opens a new one. Very good... except for the fact
      that the descriptors 0-2 were already closed in preparation of starting
      the service!
 
20950 send(7, "<27>Dec  6 09:35:42 xinetd[20950"..., 79, 0) = -1 ENOTCONN
20950 close(7)                          = 0
20950 socket(PF_FILE, SOCK_DGRAM, 0)    = 1
20950 fcntl64(1, F_SETFD, FD_CLOEXEC)   = 0
20950 connect(1, {sa_family=AF_FILE, path="/dev/log"}, 16) = 0
20950 send(1, "<27>Dec  6 09:35:42 xinetd[20950"..., 79, 0) = 79
20950 rt_sigaction(SIGPIPE, {SIG_DFL}, NULL, 8) = 0
20950 alarm(0)                          = 30
20950 rt_sigaction(SIGALRM, {SIG_DFL}, {0x804f410, [ALRM],
                          SA_RESTORER|SA_RESTART, 0x400b56f8}, 8) = 0
20950 close(0)                          = 0
20950 fcntl64(6, F_SETFD, 0)            = 0
20950 dup2(6, 0)                        = 0
20950 dup2(6, 1)                        = 1
20950 dup2(6, 2)                        = 2
20950 setrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024}) = 0
20950 close(6)                          = 0
20950 setsid()                          = 20950

------> Now watch it! This is the msg_suspend() function in action. It
        closes the log socket which now happens to be stdout for the ftp
        service....

20950 close(1)                          = 0
20950 execve("/usr/sbin/in.ftpd", ["in.ftpd"], [/* 243 vars */]) = 0
20950 uname({sys="Linux", node="ah1039", ...}) = 0
20950 brk(0)                            = 0x805be6c



So the problem is that there is a period that the so carefully closed 
filedescriptors can be re-used. I tried to prevent it by the following
patch. The trick is to reopen them to /dev/null. So all history is
abandoned but the descriptors cannot be recaimed.

==== Patch =====

Index: child.c
===================================================================
--- child.c     (revision 4)
+++ child.c     (revision 17)
@@ -271,6 +271,7 @@
    connection_s            *cp  = SERVER_CONNECTION( serp ) ;
    struct service_config   *scp = SVC_CONF( sp ) ;
    const char              *func = "child_process" ;
+   int                     fd, null_fd;
 
    signal_default_state();
 
@@ -283,11 +284,24 @@
    signals_pending[0] = -1;
    signals_pending[1] = -1;
 
-   Sclose(0);
-   Sclose(1);
-   Sclose(2);
+   if ( ( null_fd = open( "/dev/null", O_RDONLY ) ) == -1 )
+   {
+      msg( LOG_ERR, func, "open('/dev/null') failed: %m") ;
+      _exit( 1 ) ;
+   }
 
+   for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ )
+   {
+      if ( fd != null_fd && dup2( null_fd, fd ) == -1 )
+      {
+         msg( LOG_ERR, func, "dup2(%d, %d) failed: %m") ;
+         _exit( 1 ) ;
+      }
+   }
+   if ( null_fd > MAX_PASS_FD )
+      (void) Sclose( null_fd ) ;
 
+
 #ifdef DEBUG_SERVER
    if ( debug.on )
    {


Regards,

Leo Weppelman.

Attachment: signature.asc
Description: Digital signature

Reply via email to