From Keith.White@site.uottawa.ca  Wed Jul 19 11:32:24 2000
Return-Path: <Keith.White@site.uottawa.ca>
Received: from mail.site.uottawa.ca (mail.site.uottawa.ca [137.122.24.142])
	by hub.freebsd.org (Postfix) with ESMTP id C2E4F37BFFE
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 19 Jul 2000 11:32:20 -0700 (PDT)
	(envelope-from Keith.White@site.uottawa.ca)
Received: (from kwhite@localhost)
	by mail.site.uottawa.ca (8.9.3/8.9.3) id OAA22009;
	Wed, 19 Jul 2000 14:32:14 -0400 (EDT)
Message-Id: <200007191832.OAA22009@mail.site.uottawa.ca>
Date: Wed, 19 Jul 2000 14:32:14 -0400 (EDT)
From: kwhite@uottawa.ca
Sender: Keith.White@site.uottawa.ca
Reply-To: kwhite@uottawa.ca
To: FreeBSD-gnats-submit@freebsd.org
Subject: "rsh -t" doesn't timeout if rcmd(3) never returns [patch included]
X-Send-Pr-Version: 3.2

>Number:         20042
>Category:       bin
>Synopsis:       "rsh -t" doesn't timeout if rcmd(3) never returns [patch included]
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    iedowse
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jul 19 11:40:01 PDT 2000
>Closed-Date:    Mon Aug 26 12:51:58 PDT 2002
>Last-Modified:  Mon Aug 26 12:51:58 PDT 2002
>Originator:     Keith White
>Release:        FreeBSD 4.0-RELEASE i386
>Organization:
SITE, University of Ottawa
>Environment:

Any release up to and including 4.0.

$ ident /usr/bin/rsh
/usr/bin/rsh:
     $FreeBSD: src/usr.bin/rsh/rsh.c,v 1.21 2000/02/24 21:06:19 markm Exp $

>Description:

The documentation for rsh(1) leads you to believe that you can use
the "-t" flag to timeout if nothing happens for the specified
number of seconds.  This doesn't always work.

The rcmd(3) call will never return if the target machine is in a hung
state.  The rsh commmand will wait forever, even with the "-t" flag.

>How-To-Repeat:

Place a machine (server, say) in a hung state.  On another machine
(client, say) execute an rsh -t.  Notice that the rsh never times out.

        client$ rsh -t 60 server
        wait...

>Fix:
	
The following patch fixes the problem.  You'll need to add
considerable salt and pepper to taste...

$ ident /usr/src/usr.bin/rsh/rsh.c
/usr/src/usr.bin/rsh/rsh.c:
     $FreeBSD: src/usr.bin/rsh/rsh.c,v 1.21 2000/02/24 21:06:19 markm Exp $

---cut here---
*** rsh.c.orig	Thu Feb 24 16:06:19 2000
--- rsh.c	Wed Jul 19 14:27:01 2000
***************
*** 89,94 ****
--- 89,97 ----
  
  char   *copyargs __P((char **));
  void	sendsig __P((int));
+ #ifndef NOKSW
+ void	connect_timeout __P((int));
+ #endif
  void	talk __P((int, long, pid_t, int, int));
  void	usage __P((void));
  
***************
*** 283,290 ****
--- 286,305 ----
  			      &rfd2, family);
  	}
  #else
+ #ifndef NOKSW
+ 	if (timeout) {
+ 		signal(SIGALRM, connect_timeout);
+ 		alarm(timeout);
+ 	}
+ #endif
  	rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
  		      family);
+ #ifndef NOKSW
+ 	if (timeout) {
+ 		signal(SIGALRM, SIG_DFL);
+ 		alarm(0);
+ 	}
+ #endif
  #endif
  
  	if (rem < 0)
***************
*** 445,450 ****
--- 460,474 ----
  		}
  	} while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
  }
+ 
+ #ifndef NOKSW
+ void
+ connect_timeout(sig)
+ 	int sig;
+ {
+ 	errx(1, "timeout reached before connection completed.");
+ }
+ #endif
  
  void
  sendsig(sig)
---cut here---

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->feedback 
State-Changed-By: iedowse 
State-Changed-When: Fri Aug 9 16:44:37 PDT 2002 
State-Changed-Why:  

It isn't safe to call errx() from a signal handler - would you 
like to suggest a better patch that uses only functions that are 
documented in sigaction(2) as being safe to call? You can also 
remove the #ifdef's from around the new code. 

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

From: Keith White <Keith.White@site.uottawa.ca>
To: Ian Dowse <iedowse@FreeBSD.org>
Cc: kwhite@uottawa.ca, <freebsd-bugs@FreeBSD.org>,
	<bug-followup@FreeBSD.org>
Subject: Re: bin/20042: "rsh -t" doesn't timeout if rcmd(3) never returns
 [patch included]
Date: Tue, 13 Aug 2002 11:53:53 -0400 (EDT)

 On Fri, 9 Aug 2002, Ian Dowse wrote:
 
 > Synopsis: "rsh -t" doesn't timeout if rcmd(3) never returns [patch included]
 >
 > State-Changed-From-To: open->feedback
 > State-Changed-By: iedowse
 > State-Changed-When: Fri Aug 9 16:44:37 PDT 2002
 > State-Changed-Why:
 >
 > It isn't safe to call errx() from a signal handler - would you
 > like to suggest a better patch that uses only functions that are
 > documented in sigaction(2) as being safe to call? You can also
 > remove the #ifdef's from around the new code.
 >
 > http://www.freebsd.org/cgi/query-pr.cgi?pr=20042
 
 My initial bug report didn't include an easy way to demonstrate the
 problem.  This will.
 
 server# kill -STOP `cat /var/run/inetd.pid`
 
 client$ rsh -t 5 server who
         ...wait, rsh doesn't return after 5 seconds...
 
 after patching rsh
 client$ rsh -t 5 server who
         timeout reached before connection completed.
 
 server# kill -CONT `cat /var/run/inetd.pid`
 
 The following patch should fulfill the criteria:
 
 ---cut here---
 --- rsh.c.orig	Sun Mar  4 04:01:45 2001
 +++ rsh.c	Tue Aug 13 09:57:06 2002
 @@ -89,6 +89,7 @@
 
  char   *copyargs __P((char **));
  void	sendsig __P((int));
 +void	connect_timeout __P((int));
  void	talk __P((int, long, pid_t, int, int));
  void	usage __P((void));
 
 @@ -283,8 +284,22 @@
  			      &rfd2, family);
  	}
  #else
 +
 +/*
 + * it is possible that the rcmd() will never return -- perhaps because the
 + * remote machine is hung -- so add an alarm just in case
 + */
 +
 +	if (timeout) {
 +		signal(SIGALRM, connect_timeout);
 +		alarm(timeout);
 +	}
  	rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
  		      family);
 +	if (timeout) {
 +		signal(SIGALRM, SIG_DFL);
 +		alarm(0);
 +	}
  #endif
 
  	if (rem < 0)
 @@ -446,6 +461,19 @@
  				(void)write(1, buf, cc);
  		}
  	} while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
 +}
 +
 +void
 +connect_timeout(sig)
 +	int sig;
 +{
 +	char message[] = "timeout reached before connection completed.\n";
 +/*
 + * why not use errx()? -- we're in a signal handler so must restrict ourselves
 + * to those functions listed in sigaction(2)
 + */
 +	write(STDERR_FILENO, message, sizeof(message)-1);
 +	_exit(1);
  }
 
  void
 ---cut here---
 
 ...keith
 -- 
 Keith White, EITI/SITE, University of Ottawa
 kwhite@site.uottawa.ca [+1 613 562 5800 x6681] FAX [+1 613 562 5664]
 
State-Changed-From-To: feedback->patched 
State-Changed-By: iedowse 
State-Changed-When: Tue Aug 13 09:28:57 PDT 2002 
State-Changed-Why:  

Committed (with minor adjustments) to -current, awaiting MFC. Thanks! 


Responsible-Changed-From-To: freebsd-bugs->iedowse 
Responsible-Changed-By: iedowse 
Responsible-Changed-When: Tue Aug 13 09:28:57 PDT 2002 
Responsible-Changed-Why:  

My MFC reminder. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=20042 
State-Changed-From-To: patched->closed 
State-Changed-By: iedowse 
State-Changed-When: Mon Aug 26 12:51:27 PDT 2002 
State-Changed-Why:  

Now fixed in -STABLE too. 

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