brl-vgr Bug Report

dpk at BRL-VGR.ARPA dpk at BRL-VGR.ARPA
Fri Mar 8 08:08:55 AEST 1985


Subject: RSH can hang in rcmd()
Index:	ucb/rsh.c 4.2BSD Fix
	lib/libc/net/rcmd.c 4.2BSD Fix

Description:
	Rsh can hang indefinitly in rcmd for two reasons:

	1.  The accept for the second TCP connection can fail to complete
	    do to remote failure,

	2.  If the remote end fails at the right time, the local end
	    will never discover the failure if it has no data to send
	    (which results in the send side being shutdown).

Repeat-By:
	1.  Wait for rsh to connect to the remote end and send the name
	of the local reserved socket, and then have the daemon exit.
	The rcmd() subroutine will have gone into an accept waiting
	for the remote side to issue a connect() which it never will.

	2.  Difficult, but happened regularly with our rsh'ing of batch
	and unbatch for news.  Create an rsh connection where the local
	end only reads from the connection.  Kill the remote side.
	The rsh will not discover the fact.  The "right time" is when
	the local side has acked all the data received so far, and has
	yet to receive more.  In this state he is content forever unless
	he is doing keepalives.
Fix:
	1.  Add a sanity time in the startup code of rsh to about the program
	with an error indication if the rcmd function takes too long.  While
	I was modifing rsh.c, I removed an extraneous external definition for
	"error()" which does not exist.

	2.  In the rcmd() function, set keepalive on both of the sockets
	to the remote host to allow detection of a downed host.

---------------------------------------------

Context diffs follow for ucb/rsh.c and lib/libc/net/rcmd.c

RCS file: RCS/rsh.c,v
retrieving revision 1.2
diff -c -r1.2 rsh.c
*** /tmp/,RCSt1010538	Thu Mar  7 15:54:48 1985
--- rsh.c	Thu Mar  7 15:44:14 1985
***************
*** 19,25
   * rsh - remote shell
   */
  /* VARARGS */
- int	error();
  char	*index(), *rindex(), *malloc(), *getpass(), *sprintf(), *strcpy();
  
  struct	passwd *getpwuid();

--- 19,24 -----
   * rsh - remote shell
   */
  /* VARARGS */
  char	*index(), *rindex(), *malloc(), *getpass(), *sprintf(), *strcpy();
  
  struct	passwd *getpwuid();
***************
*** 28,33
  int	options;
  int	rfd2;
  int	sendsig();
  
  #define	mask(s)	(1 << ((s) - 1))
  

--- 27,33 -----
  int	options;
  int	rfd2;
  int	sendsig();
+ int	timeout();
  
  #define	mask(s)	(1 << ((s) - 1))
  
***************
*** 115,120
  		fprintf(stderr, "rsh: shell/tcp: unknown service\n");
  		exit(1);
  	}
          rem = rcmd(&host, sp->s_port, pwd->pw_name,
  	    user ? user : pwd->pw_name, args, &rfd2);
          if (rem < 0)

--- 115,122 -----
  		fprintf(stderr, "rsh: shell/tcp: unknown service\n");
  		exit(1);
  	}
+ 	signal (SIGALRM, timeout);
+ 	alarm(120);		/* Sanity timer */
          rem = rcmd(&host, sp->s_port, pwd->pw_name,
  	    user ? user : pwd->pw_name, args, &rfd2);
  	alarm(0);
***************
*** 117,122
  	}
          rem = rcmd(&host, sp->s_port, pwd->pw_name,
  	    user ? user : pwd->pw_name, args, &rfd2);
          if (rem < 0)
                  exit(1);
  	if (rfd2 < 0) {

--- 119,125 -----
  	alarm(120);		/* Sanity timer */
          rem = rcmd(&host, sp->s_port, pwd->pw_name,
  	    user ? user : pwd->pw_name, args, &rfd2);
+ 	alarm(0);
          if (rem < 0)
                  exit(1);
  	if (rfd2 < 0) {
***************
*** 218,221
  {
  
  	(void) write(rfd2, (char *)&signo, 1);
  }

--- 221,230 -----
  {
  
  	(void) write(rfd2, (char *)&signo, 1);
+ }
+ 
+ timeout()
+ {
+ 	fputs("rsh: rcmd: timeout\n", stderr);
+ 	exit(14);
  }

-------------------------------------------------------------------


RCS file: RCS/rcmd.c,v
retrieving revision 1.1
diff -c -r1.1 rcmd.c
*** /tmp/,RCSt1010907	Thu Mar  7 16:14:34 1985
--- rcmd.c	Fri Mar  1 01:00:01 1985
***************
*** 25,30
  	char c;
  	int lport = IPPORT_RESERVED - 1;
  	struct hostent *hp;
  
  	hp = gethostbyname(*ahost);
  	if (hp == 0) {

--- 25,31 -----
  	char c;
  	int lport = IPPORT_RESERVED - 1;
  	struct hostent *hp;
+ 	int on = 1;
  
  	hp = gethostbyname(*ahost);
  	if (hp == 0) {
***************
*** 54,59
  		perror(hp->h_name);
  		return (-1);
  	}
  	lport--;
  	if (fd2p == 0) {
  		write(s, "", 1);

--- 54,62 -----
  		perror(hp->h_name);
  		return (-1);
  	}
+ 	if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof on) < 0)
+ 		perror("setsockopt (SO_KEEPALIVE)");
+ 
  	lport--;
  	if (fd2p == 0) {
  		write(s, "", 1);
***************
*** 82,87
  			goto bad;
  		  }
  		}
  		*fd2p = s3;
  		from.sin_port = ntohs((u_short)from.sin_port);
  		if (from.sin_family != AF_INET ||

--- 82,89 -----
  			lport = 0;
  			goto bad;
  		}
+ 		if (setsockopt(s3, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof on) < 0)
+ 			perror("setsockopt (SO_KEEPALIVE)");
  		*fd2p = s3;
  		from.sin_port = ntohs((u_short)from.sin_port);
  		if (from.sin_family != AF_INET ||



More information about the Comp.unix.wizards mailing list