--- Begin Message ---
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.
signature.asc
Description: Digital signature
--- End Message ---