Description of problem: We have a situation where telnet is launched from a program. If this program then exits uncleanly, telnet ends up in a tight loop consuming all available CPU. Excerpt from strace: write(1, "\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\r"..., 47) = -1 EPIPE (Broken pipe) ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B600 opost isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) write(1, "\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\r"..., 47) = -1 EPIPE (Broken pipe) ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B600 opost isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) write(1, "\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\r"..., 47) = -1 EPIPE (Broken pipe) connecting with the debugger: (gdb) bt #0 0x0000002a95989d77 in tcsetattr () from /lib64/tls/libc.so.6 #1 0x000000552aab4587 in TerminalNewMode (f=-1) at sys_bsd.c:407 #2 0x000000552aab34b8 in tn (argc=-1073746416, argv=0x552abc1380) at commands.c:2487 #3 0x000000552aab387f in main (argc=0, argv=0x7fbffff870) at main.c:350 a few steps later: (gdb) bt #0 TerminalNewMode (f=-1) at sys_bsd.c:410 #1 0x000000552aab34b8 in tn (argc=-1073746416, argv=0x552abc1380) at commands.c:2487 #2 0x000000552aab387f in main (argc=0, argv=0x7fbffff870) at main.c:350 and it's in a tight loop... (gdb) next 407 tcsetattr(tin, TCSADRAIN, &tmp_tc); (gdb) next 409 old = ttyflush(SYNCHing|flushout); (gdb) next 410 } while (old < 0 || old > 1); (gdb) p old $3 = -1 (gdb) next 407 tcsetattr(tin, TCSADRAIN, &tmp_tc); Version-Release number of selected component (if applicable): telnet-0.17-31.EL4.3
After freeing up some space in /tmp, the loop looks a bit different, but the end result is the same.... strace shows: --- SIGPIPE (Broken pipe) @ 0 (0) --- rt_sigaction(SIGTSTP, {SIG_DFL}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_BLOCK, [], [PIPE], 8) = 0 rt_sigprocmask(SIG_SETMASK, [PIPE], [PIPE], 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {0x1000 /* B??? */ opost isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, SNDCTL_TMR_START or TCSETS, {0x1000 /* B??? */ opost isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, FIONBIO, [0]) = 0 ioctl(1, FIONBIO, [0]) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 close(3) = -1 EBADF (Bad file descriptor) rt_sigaction(SIGTSTP, {0x552aab48d0, [TSTP], SA_RESTORER|SA_RESTART, 0x2a958f92b0}, {SIG_DFL}, 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {0x1000 /* B??? */ opost -isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, SNDCTL_TMR_START or TCSETS, {0x1000 /* B??? */ opost -isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, FIONBIO, [1]) = 0 ioctl(1, FIONBIO, [1]) = 0 select(2, NULL, [1], NULL, NULL) = 1 (out [1]) rt_sigaction(SIGTSTP, {SIG_DFL}, {0x552aab48d0, [TSTP], SA_RESTORER|SA_RESTART, 0x2a958f92b0}, 8) = 0 rt_sigprocmask(SIG_BLOCK, [], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], [], 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {0x1000 /* B??? */ opost isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, SNDCTL_TMR_START or TCSETS, {0x1000 /* B??? */ opost isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, FIONBIO, [0]) = 0 ioctl(1, FIONBIO, [0]) = 0 rt_sigaction(SIGTSTP, {0x552aab48d0, [TSTP], SA_RESTORER|SA_RESTART, 0x2a958f92b0}, {SIG_DFL}, 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {0x1000 /* B??? */ opost -isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, SNDCTL_TMR_START or TCSETS, {0x1000 /* B??? */ opost -isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, FIONBIO, [1]) = 0 ioctl(1, FIONBIO, [1]) = 0 select(2, NULL, [1], NULL, NULL) = 1 (out [1]) rt_sigaction(SIGTSTP, {SIG_DFL}, {0x552aab48d0, [TSTP], SA_RESTORER|SA_RESTART, 0x2a958f92b0}, 8) = 0 rt_sigprocmask(SIG_BLOCK, [], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], [], 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {0x1000 /* B??? */ opost isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, SNDCTL_TMR_START or TCSETS, {0x1000 /* B??? */ opost isig -icanon -echo ...}) = -1 EINVAL (Invalid argument) ioctl(0, FIONBIO, [0]) = 0 ioctl(1, FIONBIO, [0]) = 0 write(2, "Connection closed by foreign hos"..., 36) = -1 EPIPE (Broken pipe) --- SIGPIPE (Broken pipe) @ 0 (0) --- rt_sigaction(SIGTSTP, {SIG_DFL}, {SIG_DFL}, 8) = 0
Looking closer, the change of behaviour is probably that in the latter case, the server had had time to close the connection... I'll stop spamming the bugzilla now (-:
Customer states problem resolved in RHEL 4.6. Looks like this BZ can be closed.
Fixed in telnet-0.17-31.EL4.5. Thanks for your help (-:
It would appear that the fix in telnet-0.17-31.EL4.5 is insufficient to the task. An strace reveals a similar pattern as before --- SIGPIPE (Broken pipe) @ 0 (0) --- rt_sigaction(SIGTSTP, {SIG_DFL}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_BLOCK, [], [PIPE], 8) = 0 rt_sigprocmask(SIG_SETMASK, [PIPE], [PIPE], 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0 ioctl(0, FIONBIO, [0]) = 0 ioctl(1, FIONBIO, [0]) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 close(3) = -1 EBADF (Bad file descriptor) rt_sigaction(SIGTSTP, {0x3f52dc, [TSTP], SA_RESTORER|SA_RESTART, 0x138898}, {SIG_DFL}, 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0 ioctl(0, FIONBIO, [1]) = 0 ioctl(1, FIONBIO, [1]) = 0 select(2, NULL, [1], NULL, NULL) = 1 (out [1]) rt_sigaction(SIGTSTP, {SIG_DFL}, {0x3f52dc, [TSTP], SA_RESTORER|SA_RESTART, 0x138898}, 8) = 0 rt_sigprocmask(SIG_BLOCK, [], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], [], 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0 ioctl(0, FIONBIO, [0]) = 0 ioctl(1, FIONBIO, [0]) = 0 rt_sigaction(SIGTSTP, {0x3f52dc, [TSTP], SA_RESTORER|SA_RESTART, 0x138898}, {SIG_DFL}, 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0 ioctl(0, FIONBIO, [1]) = 0 ioctl(1, FIONBIO, [1]) = 0 select(2, NULL, [1], NULL, NULL) = 1 (out [1]) rt_sigaction(SIGTSTP, {SIG_DFL}, {0x3f52dc, [TSTP], SA_RESTORER|SA_RESTART, 0x138898}, 8) = 0 rt_sigprocmask(SIG_BLOCK, [], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], [], 8) = 0 ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0 ioctl(0, FIONBIO, [0]) = 0 ioctl(1, FIONBIO, [0]) = 0 write(2, "Connection closed by foreign hos"..., 36) = -1 EPIPE (Broken pipe) --- SIGPIPE (Broken pipe) @ 0 (0) --- rt_sigaction(SIGTSTP, {SIG_DFL}, {SIG_DFL}, 8) = 0 ltrace just shows a string of SIGPIPE
Hmmm, something seems fishy here.... Indeed those strace shows the pattern that Martin describes. But if you don't strace the process, or when you exit your strace, the process exits immediately. Or am I missing something here?
This request was evaluated by Red Hat Product Management for inclusion, but this component is not scheduled to be updated in the current Red Hat Enterprise Linux release. If you would like this request to be reviewed for the next minor release, ask your support representative to set the next rhel-x.y flag to "?".
As RHEL-4.9 is last update for RHEL-4 and it is not suitable for new features and should address only security, performance and critical issues, I'm closing that bugzilla WONTFIX. If this functionality is still missing in RHEL-5, feel free to clone that bugzilla against it.