From joelh@beastie.mayfield.hp.com  Fri Jul  7 18:53:48 2000
Return-Path: <joelh@beastie.mayfield.hp.com>
Received: from palrel1.hp.com (palrel1.hp.com [156.153.255.242])
	by hub.freebsd.org (Postfix) with ESMTP id EC20F37B552
	for <FreeBSD-gnats-submit@freebsd.org>; Fri,  7 Jul 2000 18:53:33 -0700 (PDT)
	(envelope-from joelh@beastie.mayfield.hp.com)
Received: from beastie.mayfield.hp.com (beastie.mayfield.hp.com [15.37.242.90])
	by palrel1.hp.com (Postfix) with ESMTP id D0291CB9
	for <FreeBSD-gnats-submit@freebsd.org>; Fri,  7 Jul 2000 18:53:33 -0700 (PDT)
Received: (from joelh@localhost)
	by beastie.mayfield.hp.com (8.9.3/8.9.3) id WAA07069;
	Fri, 7 Jul 2000 22:42:10 -0700 (PDT)
	(envelope-from joelh)
Message-Id: <200007080542.WAA07069@beastie.mayfield.hp.com>
Date: Fri, 7 Jul 2000 22:42:10 -0700 (PDT)
From: joelh@gnu.org
Sender: joelh@beastie.mayfield.hp.com
Reply-To: joelh@gnu.org
To: FreeBSD-gnats-submit@freebsd.org
Subject: [PATCH] telnet infinite loop depending on how fds are closed
X-Send-Pr-Version: 3.2

>Number:         19773
>Category:       bin
>Synopsis:       [patch] telnet(1) infinite loop depending on how fds are closed
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jul 07 19:00:01 PDT 2000
>Closed-Date:    Tue Sep 07 11:35:21 UTC 2010
>Last-Modified:  Tue Sep 07 11:35:21 UTC 2010
>Originator:     Joel Ray Holveck
>Release:        FreeBSD 4.0-STABLE i386
>Organization:
none
>Environment:

FreeBSD 4.0, Pentium 90, nothing extraordinary here that seems relevant

>Description:

The telnet client can get into an infinite loop if the pipe going to
stdout and stderr is closed before the pipe going to stdin.  This is
because, on a SIGPIPE, it will assume that the remote has closed its
connection.  It longjmp()'s out of the signal handler, and reports this
to the user on stdout or stderr (not sure which, doesn't really matter),
generating another SIGPIPE.  Now, that SIGPIPE will try the same longjmp.
telnet tries to report again, gets another SIGPIPE... ad infinitum.

>How-To-Repeat:

Compile and run the following program.  (I'm not sure how necessary the
sleeps are, and this has a few minor bugs, but it demonstrates the
problem.)  After the process closes the pipe from "me->telnet", then the
telnet process (find it with top or ps, sorry) will go into the
aforementioned infinite loop.  Note that the telnet sticks around after
the calling program exits; find it with top or ps and kill it yourself.

#include <stdio.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    int topipe[2];
    int frompipe[2];
    pipe(&topipe);
    pipe(&frompipe);
    if (!fork()) {
	close(topipe[1]);
	close(frompipe[0]);
	dup2(topipe[0], 0);
	dup2(frompipe[1], 1);
	dup2(frompipe[1], 2);
	execlp("/usr/bin/telnet", "telnet", "localhost", NULL);
	abort();
    }
    close(topipe[0]);
    close(frompipe[1]);
    printf("forked\n");
    sleep(5);
    printf("closing telnet->me\n");
    close(frompipe[0]);
    sleep(3);
    printf("closing me->telnet\n");
    close(topipe[1]);
    sleep(2);
    printf("bye\n");
    exit(0);
}


>Fix:

Here's the fix for crypto/telnet/telnet/sys_bsd.c.  I haven't looked at the
other telnets, but I would assume they would be similar.  Caveat: I've
tested this precisely twice.

--- sys_bsd.c.orig      Fri Jul  7 21:35:57 2000
+++ sys_bsd.c   Fri Jul  7 21:50:59 2000
@@ -941,9 +941,17 @@
     void
 sys_telnet_init()
 {
+    struct sigaction act;
     (void) signal(SIGINT, intr);
     (void) signal(SIGQUIT, intr2);
-    (void) signal(SIGPIPE, deadpeer);
+    /* We only want deadpeer to be called once, 'cause if there's a broken
+     * pipe on stdout, we can't handle a SIGPIPE while reporting the
+     * dropped connection.
+     */
+    act.sa_handler = deadpeer;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = SA_RESETHAND;
+    (void) sigaction(SIGPIPE, &act, NULL);
 #ifdef SIGWINCH
     (void) signal(SIGWINCH, sendwin);
 #endif

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->feedback 
State-Changed-By: mike 
State-Changed-When: Sat Jul 21 22:01:47 PDT 2001 
State-Changed-Why:  

Does this problem still occur in newer versions of FreeBSD, 
such as 4.3-RELEASE? 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=19773 

From: Mike Barcroft <mike@FreeBSD.org>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: bin/19773: [PATCH] telnet infinite loop depending on how fds are closed
Date: Mon, 23 Jul 2001 12:23:23 -0400

 Adding to Audit-Trail.
 
 ----- Forwarded message from Joel Ray Holveck <joelh@gnu.org> -----
 
 Delivered-To: mike@freebsd.org
 To: <mike@FreeBSD.org>
 Cc: freebsd-bugs@FreeBSD.org
 Subject: Re: bin/19773: [PATCH] telnet infinite loop depending on how fds are closed
 From: Joel Ray Holveck <joelh@gnu.org>
 Precedence: first-class
 Date: 23 Jul 2001 00:41:48 -0700
 In-Reply-To: <mike@FreeBSD.org>'s message of "Sat, 21 Jul 2001 22:02:02 -0700 (PDT)"
 X-Mailer: Gnus v5.7/Emacs 20.7
 
 > Synopsis: [PATCH] telnet infinite loop depending on how fds are closed
 > State-Changed-From-To: open->feedback
 > State-Changed-By: mike
 > State-Changed-When: Sat Jul 21 22:01:47 PDT 2001
 > State-Changed-Why: 
 > Does this problem still occur in newer versions of FreeBSD,
 > such as 4.3-RELEASE?
 > http://www.FreeBSD.org/cgi/query-pr.cgi?pr=19773
 
 I used the reproduction code in the bug report to test it under
 4.3-STABLE, and it does still occur.
 
 (There's technically a bug in the reproduction code-- the args to pipe
 shouldn't have &s-- but the repro code still does its job for most
 compilers.)
 
 joelh
 
 -- 
 Joel Ray Holveck - joelh@gnu.org
    Fourth law of programming:
    Anything that can go wrong wi
 sendmail: segmentation violation - core dumped
 
 ----- End forwarded message -----
State-Changed-From-To: feedback->suspended 
State-Changed-By: mike 
State-Changed-When: Mon Jul 23 16:55:30 PDT 2001 
State-Changed-Why:  

This is still a problem in 4.3-STABLE.  Awaiting fix and committer. 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=19773 
Responsible-Changed-From-To: freebsd-bugs->markm 
Responsible-Changed-By: johan 
Responsible-Changed-When: Thu Aug 22 18:16:24 PDT 2002 
Responsible-Changed-Why:  
Let our telnet maintainer have a look at this. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=19773 

From: Joel Ray Holveck <joelh@piquan.org>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: bin/19773: [PATCH] telnet infinite loop depending on how fds are closed
Date: 16 Aug 2003 12:34:34 -0700

 Just for fun, I retested this under FreeBSD 5.1-STABLE.  It still has
 the same problem.
 
 -- 
 Joel Ray Holveck - joelh@piquan.org
    Fourth law of programming:
    Anything that can go wrong wi
 sendmail: segmentation violation - core dumped

From: "Nissen, Andy" <Andy_Nissen@securecomputing.com>
To: <bug-followup@FreeBSD.org>, <joelh@gnu.org>
Cc:  
Subject: Re: bin/19773: [PATCH] telnet infinite loop depending on how fds are closed
Date: Sun, 10 Sep 2006 14:48:08 -0500

 I ran into this problem recently with a similar script:
 
 cat << __EOF__ > telnet_spin.py
 #! /usr/contrib/bin/python
 import os
 
 # Change IP and port to suit needs - This happens to work in my
 configuration.
 CMD =3D ['/usr/bin/telnet', '10.69.181.121', '80']
 GET =3D 'GET http://www.example.com HTTP/1.0\n\n'
 
 stdin, stdout, stderr =3D os.popen3(CMD)
 stdin.write(GET)
 __EOF__
 
 This is on FreeBSD 6.0-RELEASE.  My fix is comparable, but also catches =
 the
 longjmp from netflush.
 
 __FBSDID("$FreeBSD: src/contrib/telnet/telnet/commands.c,v 1.35 =
 2005/02/28
 12:46:52 tobez Exp $");
 
 ***************
 
 *** 2494,2499 ****
 --- 2494,2507 ----
       if (setjmp(peerdied) =3D=3D 0)
         telnet(user);
       (void) NetClose(net);
 +=20
 +     /*
 +      *  Since ExitString does a write, if SIGPIPE is left going to
 deadpeer, we
 +      *  may end up in a loop.   Since longjump restores the signal =
 mask,
 we break
 +      *  the tie here.
 +      */
 +     signal(SIGPIPE, SIG_IGN);
 +=20
       ExitString("Connection closed by foreign host.\n",1);
       /*NOTREACHED*/
    fail:
 
 Andy

From: Jason Fesler <jfesler@yahoo-inc.com>
To: bug-followup@FreeBSD.org, joelh@gnu.org
Cc:  
Subject: Re: bin/19773: [PATCH] telnet infinite loop depending on how fds are closed
Date: Fri, 15 Feb 2008 11:31:57 -0800

 Still happens in 6.3
 
 Easiest and most painfully frequent way I run into it, is :
 
 ssh somehost telnet otherhost port
 
 And then killing the SSH process.
 
 I've worked around it by calling:
 ssh somehost 'ssh -c "limit -t 10 ; telnet otherhost port"'
 
 so that when (not if) the process spins, it gets killed  
 automatically.  Also, I try to gracefully tell telnet to close (send  
 ^], close) first - except when debugging this cleanup doesn't always  
 get called.
 
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/19773: commit references a PR
Date: Fri, 30 Apr 2010 19:53:18 +0000 (UTC)

 Author: jilles
 Date: Fri Apr 30 19:52:35 2010
 New Revision: 207449
 URL: http://svn.freebsd.org/changeset/base/207449
 
 Log:
   telnet: Fix infinite loop if local output generates SIGPIPE.
   
   Instead of catching SIGPIPE and jumping out of the signal handler with
   longjmp, ignore it and handle write errors to the local output by exiting
   from there. I have changed the error message to mention the local output
   instead of NetBSD's wrong "Connection closed by foreign host". Write errors
   to the network were already handled by exiting immediately and this now
   applies to EPIPE too.
   
   The code assumed that SIGPIPE could only be generated by the network
   connection; if it was generated by the local output, it would longjmp out of
   the signal handler and write an error message which caused another SIGPIPE.
   
   PR:		19773
   Obtained from:	NetBSD
   MFC after:	1 week
 
 Modified:
   head/contrib/telnet/telnet/commands.c
   head/contrib/telnet/telnet/externs.h
   head/contrib/telnet/telnet/network.c
   head/contrib/telnet/telnet/sys_bsd.c
   head/contrib/telnet/telnet/telnet.c
   head/contrib/telnet/telnet/terminal.c
 
 Modified: head/contrib/telnet/telnet/commands.c
 ==============================================================================
 --- head/contrib/telnet/telnet/commands.c	Fri Apr 30 19:40:37 2010	(r207448)
 +++ head/contrib/telnet/telnet/commands.c	Fri Apr 30 19:52:35 2010	(r207449)
 @@ -2491,8 +2491,7 @@ tn(int argc, char *argv[])
  	env_export("USER");
      }
      (void) call(status, "status", "notmuch", 0);
 -    if (setjmp(peerdied) == 0)
 -	telnet(user);
 +    telnet(user); 
      (void) NetClose(net);
      ExitString("Connection closed by foreign host.\n",1);
      /*NOTREACHED*/
 
 Modified: head/contrib/telnet/telnet/externs.h
 ==============================================================================
 --- head/contrib/telnet/telnet/externs.h	Fri Apr 30 19:40:37 2010	(r207448)
 +++ head/contrib/telnet/telnet/externs.h	Fri Apr 30 19:52:35 2010	(r207449)
 @@ -233,7 +233,6 @@ extern void
      SetNetTrace(char *);	/* Function to change where debugging goes */
  
  extern jmp_buf
 -    peerdied,
      toplevel;		/* For error conditions. */
  
  extern void
 
 Modified: head/contrib/telnet/telnet/network.c
 ==============================================================================
 --- head/contrib/telnet/telnet/network.c	Fri Apr 30 19:40:37 2010	(r207448)
 +++ head/contrib/telnet/telnet/network.c	Fri Apr 30 19:52:35 2010	(r207449)
 @@ -158,7 +158,7 @@ netflush(void)
  	    perror(hostname);
  	    (void)NetClose(net);
  	    ring_clear_mark(&netoring);
 -	    longjmp(peerdied, -1);
 +	    ExitString("Connection closed by foreign host.\n", 1);
  	    /*NOTREACHED*/
  	}
  	n = 0;
 
 Modified: head/contrib/telnet/telnet/sys_bsd.c
 ==============================================================================
 --- head/contrib/telnet/telnet/sys_bsd.c	Fri Apr 30 19:40:37 2010	(r207448)
 +++ head/contrib/telnet/telnet/sys_bsd.c	Fri Apr 30 19:52:35 2010	(r207449)
 @@ -809,14 +809,6 @@ NetNonblockingIO(int fd, int onoff)
   */
  
  /* ARGSUSED */
 -static SIG_FUNC_RET
 -deadpeer(int sig __unused)
 -{
 -	setcommandmode();
 -	longjmp(peerdied, -1);
 -}
 -
 -/* ARGSUSED */
  SIG_FUNC_RET
  intr(int sig __unused)
  {
 @@ -884,7 +876,7 @@ sys_telnet_init(void)
  {
      (void) signal(SIGINT, intr);
      (void) signal(SIGQUIT, intr2);
 -    (void) signal(SIGPIPE, deadpeer);
 +    (void) signal(SIGPIPE, SIG_IGN);
  #ifdef	SIGWINCH
      (void) signal(SIGWINCH, sendwin);
  #endif
 
 Modified: head/contrib/telnet/telnet/telnet.c
 ==============================================================================
 --- head/contrib/telnet/telnet/telnet.c	Fri Apr 30 19:40:37 2010	(r207448)
 +++ head/contrib/telnet/telnet/telnet.c	Fri Apr 30 19:52:35 2010	(r207449)
 @@ -146,7 +146,6 @@ unsigned char telopt_environ = TELOPT_NE
  #endif
  
  jmp_buf	toplevel;
 -jmp_buf	peerdied;
  
  int	flushline;
  int	linemode;
 
 Modified: head/contrib/telnet/telnet/terminal.c
 ==============================================================================
 --- head/contrib/telnet/telnet/terminal.c	Fri Apr 30 19:40:37 2010	(r207448)
 +++ head/contrib/telnet/telnet/terminal.c	Fri Apr 30 19:52:35 2010	(r207449)
 @@ -111,7 +111,8 @@ init_terminal(void)
  }
  
  /*
 - *		Send as much data as possible to the terminal.
 + *		Send as much data as possible to the terminal, else exits if
 + *		it encounters a permanent failure when writing to the tty.
   *
   *		Return value:
   *			-1: No useful work done, data waiting to go out.
 @@ -152,8 +153,19 @@ ttyflush(int drop)
  	}
  	ring_consumed(&ttyoring, n);
      }
 -    if (n < 0)
 +    if (n < 0) {
 +	if (errno == EAGAIN || errno == EINTR) {
 +	    return -1;
 +	} else {
 +	    ring_consumed(&ttyoring, ring_full_count(&ttyoring));
 +	    setconnmode(0);
 +	    setcommandmode();
 +	    NetClose(net);
 +	    fprintf(stderr, "Write error on local output.\n");
 +	    exit(1);
 +	}
  	return -1;
 +    }
      if (n == n0) {
  	if (n0)
  	    return -1;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: suspended->patched 
State-Changed-By: jilles 
State-Changed-When: Fri Apr 30 20:06:48 UTC 2010 
State-Changed-Why:  
Fixed in 9-CURRENT. 


Responsible-Changed-From-To: markm->jilles 
Responsible-Changed-By: jilles 
Responsible-Changed-When: Fri Apr 30 20:06:48 UTC 2010 
Responsible-Changed-Why:  
Take. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=19773 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/19773: commit references a PR
Date: Fri,  7 May 2010 20:59:08 +0000 (UTC)

 Author: jilles
 Date: Fri May  7 20:58:50 2010
 New Revision: 207758
 URL: http://svn.freebsd.org/changeset/base/207758
 
 Log:
   MFC r207449: telnet: Fix infinite loop if local output generates SIGPIPE.
   
   Instead of catching SIGPIPE and jumping out of the signal handler with
   longjmp, ignore it and handle write errors to the local output by exiting
   from there. I have changed the error message to mention the local output
   instead of NetBSD's wrong "Connection closed by foreign host". Write errors
   to the network were already handled by exiting immediately and this now
   applies to EPIPE too.
   
   The code assumed that SIGPIPE could only be generated by the network
   connection; if it was generated by the local output, it would longjmp out of
   the signal handler and write an error message which caused another SIGPIPE.
   
   PR:		19773
   Obtained from:	NetBSD
 
 Modified:
   stable/8/contrib/telnet/telnet/commands.c
   stable/8/contrib/telnet/telnet/externs.h
   stable/8/contrib/telnet/telnet/network.c
   stable/8/contrib/telnet/telnet/sys_bsd.c
   stable/8/contrib/telnet/telnet/telnet.c
   stable/8/contrib/telnet/telnet/terminal.c
 Directory Properties:
   stable/8/contrib/telnet/   (props changed)
 
 Modified: stable/8/contrib/telnet/telnet/commands.c
 ==============================================================================
 --- stable/8/contrib/telnet/telnet/commands.c	Fri May  7 20:46:22 2010	(r207757)
 +++ stable/8/contrib/telnet/telnet/commands.c	Fri May  7 20:58:50 2010	(r207758)
 @@ -2491,8 +2491,7 @@ tn(int argc, char *argv[])
  	env_export("USER");
      }
      (void) call(status, "status", "notmuch", 0);
 -    if (setjmp(peerdied) == 0)
 -	telnet(user);
 +    telnet(user); 
      (void) NetClose(net);
      ExitString("Connection closed by foreign host.\n",1);
      /*NOTREACHED*/
 
 Modified: stable/8/contrib/telnet/telnet/externs.h
 ==============================================================================
 --- stable/8/contrib/telnet/telnet/externs.h	Fri May  7 20:46:22 2010	(r207757)
 +++ stable/8/contrib/telnet/telnet/externs.h	Fri May  7 20:58:50 2010	(r207758)
 @@ -233,7 +233,6 @@ extern void
      SetNetTrace(char *);	/* Function to change where debugging goes */
  
  extern jmp_buf
 -    peerdied,
      toplevel;		/* For error conditions. */
  
  extern void
 
 Modified: stable/8/contrib/telnet/telnet/network.c
 ==============================================================================
 --- stable/8/contrib/telnet/telnet/network.c	Fri May  7 20:46:22 2010	(r207757)
 +++ stable/8/contrib/telnet/telnet/network.c	Fri May  7 20:58:50 2010	(r207758)
 @@ -158,7 +158,7 @@ netflush(void)
  	    perror(hostname);
  	    (void)NetClose(net);
  	    ring_clear_mark(&netoring);
 -	    longjmp(peerdied, -1);
 +	    ExitString("Connection closed by foreign host.\n", 1);
  	    /*NOTREACHED*/
  	}
  	n = 0;
 
 Modified: stable/8/contrib/telnet/telnet/sys_bsd.c
 ==============================================================================
 --- stable/8/contrib/telnet/telnet/sys_bsd.c	Fri May  7 20:46:22 2010	(r207757)
 +++ stable/8/contrib/telnet/telnet/sys_bsd.c	Fri May  7 20:58:50 2010	(r207758)
 @@ -809,14 +809,6 @@ NetNonblockingIO(int fd, int onoff)
   */
  
  /* ARGSUSED */
 -static SIG_FUNC_RET
 -deadpeer(int sig __unused)
 -{
 -	setcommandmode();
 -	longjmp(peerdied, -1);
 -}
 -
 -/* ARGSUSED */
  SIG_FUNC_RET
  intr(int sig __unused)
  {
 @@ -884,7 +876,7 @@ sys_telnet_init(void)
  {
      (void) signal(SIGINT, intr);
      (void) signal(SIGQUIT, intr2);
 -    (void) signal(SIGPIPE, deadpeer);
 +    (void) signal(SIGPIPE, SIG_IGN);
  #ifdef	SIGWINCH
      (void) signal(SIGWINCH, sendwin);
  #endif
 
 Modified: stable/8/contrib/telnet/telnet/telnet.c
 ==============================================================================
 --- stable/8/contrib/telnet/telnet/telnet.c	Fri May  7 20:46:22 2010	(r207757)
 +++ stable/8/contrib/telnet/telnet/telnet.c	Fri May  7 20:58:50 2010	(r207758)
 @@ -146,7 +146,6 @@ unsigned char telopt_environ = TELOPT_NE
  #endif
  
  jmp_buf	toplevel;
 -jmp_buf	peerdied;
  
  int	flushline;
  int	linemode;
 
 Modified: stable/8/contrib/telnet/telnet/terminal.c
 ==============================================================================
 --- stable/8/contrib/telnet/telnet/terminal.c	Fri May  7 20:46:22 2010	(r207757)
 +++ stable/8/contrib/telnet/telnet/terminal.c	Fri May  7 20:58:50 2010	(r207758)
 @@ -111,7 +111,8 @@ init_terminal(void)
  }
  
  /*
 - *		Send as much data as possible to the terminal.
 + *		Send as much data as possible to the terminal, else exits if
 + *		it encounters a permanent failure when writing to the tty.
   *
   *		Return value:
   *			-1: No useful work done, data waiting to go out.
 @@ -152,8 +153,19 @@ ttyflush(int drop)
  	}
  	ring_consumed(&ttyoring, n);
      }
 -    if (n < 0)
 +    if (n < 0) {
 +	if (errno == EAGAIN || errno == EINTR) {
 +	    return -1;
 +	} else {
 +	    ring_consumed(&ttyoring, ring_full_count(&ttyoring));
 +	    setconnmode(0);
 +	    setcommandmode();
 +	    NetClose(net);
 +	    fprintf(stderr, "Write error on local output.\n");
 +	    exit(1);
 +	}
  	return -1;
 +    }
      if (n == n0) {
  	if (n0)
  	    return -1;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/19773: commit references a PR
Date: Thu, 13 May 2010 15:28:54 +0000 (UTC)

 Author: jilles
 Date: Thu May 13 15:28:34 2010
 New Revision: 208029
 URL: http://svn.freebsd.org/changeset/base/208029
 
 Log:
   MFC r207449: telnet: Fix infinite loop if local output generates SIGPIPE.
   
   Instead of catching SIGPIPE and jumping out of the signal handler with
   longjmp, ignore it and handle write errors to the local output by exiting
   from there. I have changed the error message to mention the local output
   instead of NetBSD's wrong "Connection closed by foreign host". Write errors
   to the network were already handled by exiting immediately and this now
   applies to EPIPE too.
   
   The code assumed that SIGPIPE could only be generated by the network
   connection; if it was generated by the local output, it would longjmp out of
   the signal handler and write an error message which caused another SIGPIPE.
   
   PR:		19773
   Obtained from:	NetBSD
 
 Modified:
   stable/7/contrib/telnet/telnet/commands.c
   stable/7/contrib/telnet/telnet/externs.h
   stable/7/contrib/telnet/telnet/network.c
   stable/7/contrib/telnet/telnet/sys_bsd.c
   stable/7/contrib/telnet/telnet/telnet.c
   stable/7/contrib/telnet/telnet/terminal.c
 Directory Properties:
   stable/7/contrib/telnet/   (props changed)
 
 Modified: stable/7/contrib/telnet/telnet/commands.c
 ==============================================================================
 --- stable/7/contrib/telnet/telnet/commands.c	Thu May 13 12:08:11 2010	(r208028)
 +++ stable/7/contrib/telnet/telnet/commands.c	Thu May 13 15:28:34 2010	(r208029)
 @@ -2491,8 +2491,7 @@ tn(int argc, char *argv[])
  	env_export("USER");
      }
      (void) call(status, "status", "notmuch", 0);
 -    if (setjmp(peerdied) == 0)
 -	telnet(user);
 +    telnet(user); 
      (void) NetClose(net);
      ExitString("Connection closed by foreign host.\n",1);
      /*NOTREACHED*/
 
 Modified: stable/7/contrib/telnet/telnet/externs.h
 ==============================================================================
 --- stable/7/contrib/telnet/telnet/externs.h	Thu May 13 12:08:11 2010	(r208028)
 +++ stable/7/contrib/telnet/telnet/externs.h	Thu May 13 15:28:34 2010	(r208029)
 @@ -233,7 +233,6 @@ extern void
      SetNetTrace(char *);	/* Function to change where debugging goes */
  
  extern jmp_buf
 -    peerdied,
      toplevel;		/* For error conditions. */
  
  extern void
 
 Modified: stable/7/contrib/telnet/telnet/network.c
 ==============================================================================
 --- stable/7/contrib/telnet/telnet/network.c	Thu May 13 12:08:11 2010	(r208028)
 +++ stable/7/contrib/telnet/telnet/network.c	Thu May 13 15:28:34 2010	(r208029)
 @@ -158,7 +158,7 @@ netflush(void)
  	    perror(hostname);
  	    (void)NetClose(net);
  	    ring_clear_mark(&netoring);
 -	    longjmp(peerdied, -1);
 +	    ExitString("Connection closed by foreign host.\n", 1);
  	    /*NOTREACHED*/
  	}
  	n = 0;
 
 Modified: stable/7/contrib/telnet/telnet/sys_bsd.c
 ==============================================================================
 --- stable/7/contrib/telnet/telnet/sys_bsd.c	Thu May 13 12:08:11 2010	(r208028)
 +++ stable/7/contrib/telnet/telnet/sys_bsd.c	Thu May 13 15:28:34 2010	(r208029)
 @@ -809,14 +809,6 @@ NetNonblockingIO(int fd, int onoff)
   */
  
  /* ARGSUSED */
 -static SIG_FUNC_RET
 -deadpeer(int sig __unused)
 -{
 -	setcommandmode();
 -	longjmp(peerdied, -1);
 -}
 -
 -/* ARGSUSED */
  SIG_FUNC_RET
  intr(int sig __unused)
  {
 @@ -884,7 +876,7 @@ sys_telnet_init(void)
  {
      (void) signal(SIGINT, intr);
      (void) signal(SIGQUIT, intr2);
 -    (void) signal(SIGPIPE, deadpeer);
 +    (void) signal(SIGPIPE, SIG_IGN);
  #ifdef	SIGWINCH
      (void) signal(SIGWINCH, sendwin);
  #endif
 
 Modified: stable/7/contrib/telnet/telnet/telnet.c
 ==============================================================================
 --- stable/7/contrib/telnet/telnet/telnet.c	Thu May 13 12:08:11 2010	(r208028)
 +++ stable/7/contrib/telnet/telnet/telnet.c	Thu May 13 15:28:34 2010	(r208029)
 @@ -146,7 +146,6 @@ unsigned char telopt_environ = TELOPT_NE
  #endif
  
  jmp_buf	toplevel;
 -jmp_buf	peerdied;
  
  int	flushline;
  int	linemode;
 
 Modified: stable/7/contrib/telnet/telnet/terminal.c
 ==============================================================================
 --- stable/7/contrib/telnet/telnet/terminal.c	Thu May 13 12:08:11 2010	(r208028)
 +++ stable/7/contrib/telnet/telnet/terminal.c	Thu May 13 15:28:34 2010	(r208029)
 @@ -111,7 +111,8 @@ init_terminal(void)
  }
  
  /*
 - *		Send as much data as possible to the terminal.
 + *		Send as much data as possible to the terminal, else exits if
 + *		it encounters a permanent failure when writing to the tty.
   *
   *		Return value:
   *			-1: No useful work done, data waiting to go out.
 @@ -152,8 +153,19 @@ ttyflush(int drop)
  	}
  	ring_consumed(&ttyoring, n);
      }
 -    if (n < 0)
 +    if (n < 0) {
 +	if (errno == EAGAIN || errno == EINTR) {
 +	    return -1;
 +	} else {
 +	    ring_consumed(&ttyoring, ring_full_count(&ttyoring));
 +	    setconnmode(0);
 +	    setcommandmode();
 +	    NetClose(net);
 +	    fprintf(stderr, "Write error on local output.\n");
 +	    exit(1);
 +	}
  	return -1;
 +    }
      if (n == n0) {
  	if (n0)
  	    return -1;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
Responsible-Changed-From-To: jilles->freebsd-bugs 
Responsible-Changed-By: jilles 
Responsible-Changed-When: Thu May 13 15:40:37 UTC 2010 
Responsible-Changed-Why:  
This is fixed in 7.x/8.x/9.x. I'm not interested in 6.x. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=19773 
State-Changed-From-To: patched->closed 
State-Changed-By: maxim 
State-Changed-When: Tue Sep 7 11:34:49 UTC 2010 
State-Changed-Why:  
It looks like the fix was merged to all supported branches.  Close the PR. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=19773 
>Unformatted:
