On Thursday 03 September 2009 22:38, Cathey, Jim wrote:
> >Let's try to simplify it. Try some (or all) of these:
> 
> Wilco.
> 
> >* Run inetd with the same config on your own x?86 desktop.
> 
> That would be hard.  Not impossible, but hard.  (Not using
> busybox at all there, is my development system and don't
> want to screw it up.)  Might do that a bit later.

Why it would be hard?

* build busybox: make defconfig; make

* create inetd.conf which runs telnetd from current dir:
  telnet stream tcp nowait.12 root ./busybox telnetd -i

* modify ./bury to connect locally:
  #!/bin/sh
  # Bury the target in telnets
  for i in 1 2 3 4 5 6 7 8 9 10; do
    for j  in 1 2 3 4 5 6 7 8 9 10; do
        ./busybox telnet 127.0.0.1 >/dev/null 2>&1 &
    done
  done
  wait

* run inetd applet, again using busybox in current dir:
  ./busybox inetd -f -e ./inetd.conf

* in another terminal, run
  while sleep 0.05; do ./bury; echo -n .; done

* in yet another terminal, run
  while sleep 1; do ls -l /proc/<PID_OF_INETD>/fd; echo; done


As you see, no modification to your system is needed.

I just did this test. I even ran two loops with ./bury;
after 20 minutes not a single fd has leaked.


> >* Does it happen if you start inetd, *don't* SIGHUP it,
> >  and repeatedly run ./bury against it?
> >  (is SIGHUPing a factor in reproducing it?)
> 
> Yes, it still leaks even with no HUP action.  Slowly.
> 
> >* Does it happen if you replace
> >  telnet stream tcp nowait.12 root /usr/sbin/telnetd telnetd -i
> >  with telnet stream tcp nowait.12 root /bin/true true
> >  (iow, if server prog just exits at once)?
> 
> Yes, still leaks.  Also leaks with false instead of true.
> Slowly.
> 
> It also leaks in the /bin/false case even when the .12 is
> removed from the nowait.

> Big evil happened in the /bin/false case when the nowait
> was changed to a wait.  ps shows no children, but the fd
> list was full up to 1023, and stayed that way.

Yes. It is expected. tcp services usually use nowait,
and will behave incorrectly with wait.

In this example, inetd spawn telnetd and expects it to
accept the connections on fd 0. But telnetd does not
understand this, it thinks it was given an accepted
connection. It tries to read from fd 0, gets EOF, exits,
inetd notices this, starts to wait for connections again -
and BINGO! - there is a connection (the same one,
still not accepted!) and all the fun repeats...

Hmm, but why do you get full fd list?

I modified .conf file as follows:

telnet stream tcp wait root ./busybox sleep 1

and then:

# strace -tt ./busybox inetd -f -e ./inetd.conf
00:25:10.656087 execve("./busybox", ["inetd", "-f", "-e", "./inetd.conf"], [/* 
32 vars */]) = 0
00:25:10.656725 ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig 
icanon echo ...}) = 0
00:25:10.657158 ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig 
icanon echo ...}) = 0
00:25:10.657562 getuid32()              = 0
00:25:10.657905 getuid32()              = 0
00:25:10.658267 open("/dev/null", O_RDWR|O_LARGEFILE) = 3
00:25:10.658635 close(3)                = 0
00:25:10.658970 getgid32()              = 0
00:25:10.659309 setgroups32(1, [0])     = 0
00:25:10.659566 open("/var/run/inetd.pid", 
O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
00:25:10.659930 fstat64(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
00:25:10.660252 getpid()                = 24449
00:25:10.660553 write(3, "24449\n", 6)  = 6
00:25:10.660861 close(3)                = 0
00:25:10.661170 getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024}) = 0
00:25:10.661454 rt_sigaction(SIGALRM, {0x8062e93, [HUP ALRM CHLD], SA_RESTORER, 
0x8048683}, NULL, 8) = 0
00:25:10.661768 rt_sigaction(SIGHUP, {0x8061e68, [HUP ALRM CHLD], SA_RESTORER, 
0x8048683}, NULL, 8) = 0
00:25:10.662085 rt_sigaction(SIGCHLD, {0x8061887, [HUP ALRM CHLD], SA_RESTORER, 
0x8048683}, NULL, 8) = 0
00:25:10.662388 rt_sigaction(SIGTERM, {0x8061833, [HUP ALRM CHLD], SA_RESTORER, 
0x8048683}, NULL, 8) = 0
00:25:10.662690 rt_sigaction(SIGINT, {0x8061833, [HUP ALRM CHLD], SA_RESTORER, 
0x8048683}, NULL, 8) = 0
00:25:10.663001 rt_sigaction(SIGPIPE, {SIG_IGN}, {SIG_DFL}, 8) = 0
00:25:10.663275 brk(0)                  = 0x8113000
00:25:10.663514 brk(0x8114000)          = 0x8114000
00:25:10.663769 open("./inetd.conf", O_RDONLY|O_LARGEFILE) = 3
00:25:10.664083 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0xffd74a68) = -1 ENOTTY 
(Inappropriate ioctl for device)
00:25:10.664396 read(3, "telnet stream tcp wait root ./bu"..., 1024) = 46
00:25:10.664688 rt_sigprocmask(SIG_BLOCK, [HUP ALRM CHLD], [], 8) = 0
00:25:10.664968 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
00:25:10.665242 open("/etc/services", O_RDONLY) = 5
00:25:10.665500 ioctl(5, SNDCTL_TMR_TIMEBASE or TCGETS, 0xffd74a38) = -1 ENOTTY 
(Inappropriate ioctl for device)
00:25:10.665797 read(5, "#\n# Network services, Internet s"..., 1024) = 1024
00:25:10.666106 read(5, "     # File Transfer [Control]\ns"..., 1024) = 1024
00:25:10.666382 close(5)                = 0
00:25:10.666631 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 5
00:25:10.666912 setsockopt(5, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
00:25:10.667191 bind(5, {sa_family=AF_INET, sin_port=htons(23), 
sin_addr=inet_addr("0.0.0.0")}, 16) = 0
00:25:10.667496 listen(5, 128)          = 0
00:25:10.667751 read(3, "", 1024)       = 0
00:25:10.668003 close(3)                = 0
00:25:10.668242 rt_sigprocmask(SIG_BLOCK, [HUP ALRM CHLD], [], 8) = 0
00:25:10.668515 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
00:25:10.668772 select(6, [5], NULL, NULL, NULL) = 1 (in [5])

I run "telnet 127.0.0.1" on antother console...

00:25:14.538979 rt_sigprocmask(SIG_BLOCK, [HUP ALRM CHLD], [], 8) = 0
00:25:14.539113 vfork()                 = 24451
00:25:14.539799 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
00:25:14.546151 select(1, [], NULL, NULL, NULL) = ? ERESTARTNOHAND (To be 
restarted)
   here it waits for child to exit - does not wait for connections,
   child is expected to do that. "sleep 1" of course does not...
   ... and here it exits.
00:25:15.539552 --- SIGCHLD (Child exited) @ 0 (0) ---
00:25:15.539655 wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, 
NULL) = 24451
00:25:15.539760 wait4(-1, 0xffd748b8, WNOHANG, NULL) = -1 ECHILD (No child 
processes)
00:25:15.539846 sigreturn()             = ? (mask now [])
00:25:15.539966 select(6, [5], NULL, NULL, NULL) = 1 (in [5])
00:25:15.540149 rt_sigprocmask(SIG_BLOCK, [HUP ALRM CHLD], [], 8) = 0
00:25:15.540245 vfork()                 = 24453
00:25:15.541335 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
00:25:15.541613 select(1, [], NULL, NULL, NULL) = ? ERESTARTNOHAND (To be 
restarted)
    again
00:25:16.540830 --- SIGCHLD (Child exited) @ 0 (0) ---
00:25:16.541055 wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, 
NULL) = 24453
00:25:16.541347 wait4(-1, 0xffd748b8, WNOHANG, NULL) = -1 ECHILD (No child 
processes)
00:25:16.541626 sigreturn()             = ? (mask now [])
00:25:16.541914 select(6, [5], NULL, NULL, NULL) = 1 (in [5])
00:25:16.542265 rt_sigprocmask(SIG_BLOCK, [HUP ALRM CHLD], [], 8) = 0
00:25:16.543139 vfork()                 = 24454
00:25:16.543762 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
   ....

No fd leaking.

What do *you* see when you do the same?

--
vda
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to