[PATCH] fix for Linux hang on exit bug in 2.9.9p2

John Bowman bowman at math.ualberta.ca
Sat Sep 29 07:10:47 EST 2001


As you are now probably aware, the portability team for openssh still
has not fixed the hang-on-exit bug in the 2.9.9p2 release.

Attached is a patch for 2.9.9p2 that fixes the hang-on-exit bug for Linux
systems. It also adds a useful exit delay feature that has also not yet been
incorporated into the main sources.

For more information, see the SNFS (secure NFS) web page:
http://www.math.ualberta.ca/imaging/snfs

-- John Bowman
University of Alberta

diff -u openssh-2.9.9p2/channels.c openssh-2.9.9p2J/channels.c
--- openssh-2.9.9p2/channels.c	Mon Sep 17 23:53:12 2001
+++ openssh-2.9.9p2J/channels.c	Thu Sep 27 22:12:43 2001
@@ -1527,8 +1527,18 @@
 		c = channels[i];
 		if (c == NULL)
 			continue;
-		if (ftab[c->type] != NULL)
+		if (ftab[c->type] != NULL) {
+			if(c->istate == CHAN_INPUT_OPEN && c->rfd == -1) {
+			  int type=c->type;
+			  c->type=SSH_CHANNEL_CLOSED;
+			  if(channel_find_open() == -1)
+			    shutdown(packet_get_connection_out(),
+				     SHUT_RDWR);
+			  c->type=type;
+			  continue;
+			}
 			(*ftab[c->type])(c, readset, writeset);
+		}
 		if (chan_is_dead(c)) {
 			/*
 			 * we have to remove the fd's from the select mask
diff -u openssh-2.9.9p2/channels.h openssh-2.9.9p2J/channels.h
--- openssh-2.9.9p2/channels.h	Mon Sep 17 23:51:14 2001
+++ openssh-2.9.9p2J/channels.h	Thu Sep 27 22:16:44 2001
@@ -219,6 +219,7 @@
 void	 chan_mark_dead(Channel *);
 void 	 chan_init_iostates(Channel *);
 void	 chan_init(void);
+void	 chan_shutdown_read(Channel *);
 
 typedef void    chan_event_fn(Channel *);
 
diff -u openssh-2.9.9p2/clientloop.c openssh-2.9.9p2J/clientloop.c
--- openssh-2.9.9p2/clientloop.c	Mon Sep 17 23:51:14 2001
+++ openssh-2.9.9p2J/clientloop.c	Fri Sep 28 12:47:09 2001
@@ -84,6 +84,7 @@
 
 /* import options */
 extern Options options;
+extern int no_tty_flag;
 
 /* Flag indicating that stdin should be redirected from /dev/null. */
 extern int stdin_null_flag;
@@ -122,7 +123,8 @@
 static int connection_in;	/* Connection to server (input). */
 static int connection_out;	/* Connection to server (output). */
 static int need_rekeying;	/* Set to non-zero if rekeying is requested. */
-static int session_closed = 0;	/* In SSH2: login session closed. */
+enum SessionStatus {SessionOpen, SessionClose, SessionWait};
+static int session_status = SessionOpen; /* In SSH2: login session closed. */
 
 static void client_init_dispatch(void);
 int	session_ident = -1;
@@ -320,6 +322,10 @@
 client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
     int *maxfdp, int *nallocp, int rekeying)
 {
+	struct timeval timer;
+	struct timeval *timerp;
+	int rc;
+	
 	/* Add any selections by the channel mechanism. */
 	channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying);
 
@@ -343,11 +349,12 @@
 			FD_SET(fileno(stderr), *writesetp);
 	} else {
 		/* channel_prepare_select could have closed the last channel */
-		if (session_closed && !channel_still_open()) {
+		if ((session_status == SessionClose)
+		    && !channel_still_open()) {
 			if (!packet_have_data_to_write())
 				return;
 		} else {
-			FD_SET(connection_in, *readsetp);
+		    FD_SET(connection_in, *readsetp);
 		}
 	}
 
@@ -364,7 +371,17 @@
 	 * SSH_MSG_IGNORE packet when the timeout expires.
 	 */
 
-	if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {
+	if((session_status == SessionWait && options.sleep > 0) ||
+	    (no_tty_flag && options.sleep == -1)) {
+		timer.tv_sec=options.sleep > 0 ? options.sleep : 0;
+		timer.tv_usec=0;
+		timerp=&timer;
+	} else {
+		timerp=NULL;
+	}
+	
+	rc=select((*maxfdp)+1, *readsetp, *writesetp, NULL, timerp);
+	if (rc < 0) {
 		char buf[100];
 
 		/*
@@ -381,7 +398,8 @@
 		snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
 		buffer_append(&stderr_buffer, buf, strlen(buf));
 		quit_pending = 1;
-	}
+	} else if (rc == 0 && session_status == SessionWait)
+		session_status=SessionClose;
 }
 
 static void
@@ -442,9 +460,12 @@
 		len = read(connection_in, buf, sizeof(buf));
 		if (len == 0) {
 			/* Received EOF.  The remote host has closed the connection. */
+/* This message duplicates the one already in client_loop(). */
+#if 0 
 			snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
 				 host);
 			buffer_append(&stderr_buffer, buf, strlen(buf));
+#endif
 			quit_pending = 1;
 			return;
 		}
@@ -753,7 +774,7 @@
 	if (id != session_ident)
 		error("client_channel_closed: id %d != session_ident %d",
 		    id, session_ident);
-	session_closed = 1;
+	session_status = (options.sleep >= 0) ? SessionWait : SessionClose;
 	if (in_raw_mode())
 		leave_raw_mode();
 }
@@ -778,6 +799,7 @@
 	start_time = get_current_time();
 
 	/* Initialize variables. */
+	if(!have_pty) session_status=SessionWait;
 	escape_pending = 0;
 	last_was_cr = 1;
 	exit_status = -1;
@@ -842,7 +864,8 @@
 		/* Process buffered packets sent by the server. */
 		client_process_buffered_input_packets();
 
-		if (compat20 && session_closed && !channel_still_open())
+		if (compat20 && (session_status == SessionClose)
+		    && !channel_still_open())
 			break;
 
 		rekeying = (xxx_kex != NULL && !xxx_kex->done);
diff -u openssh-2.9.9p2/nchan.c openssh-2.9.9p2J/nchan.c
--- openssh-2.9.9p2/nchan.c	Thu Sep 20 13:33:33 2001
+++ openssh-2.9.9p2J/nchan.c	Thu Sep 27 22:09:31 2001
@@ -81,7 +81,7 @@
 
 /* helper */
 static void	chan_shutdown_write(Channel *);
-static void	chan_shutdown_read(Channel *);
+void		chan_shutdown_read(Channel *);
 
 /*
  * SSH1 specific implementation of event functions
@@ -524,7 +524,7 @@
 			    c->self, c->wfd, strerror(errno));
 	}
 }
-static void
+void
 chan_shutdown_read(Channel *c)
 {
 	if (compat20 && c->type == SSH_CHANNEL_LARVAL)
diff -u openssh-2.9.9p2/readconf.c openssh-2.9.9p2J/readconf.c
--- openssh-2.9.9p2/readconf.c	Wed Sep 19 18:57:56 2001
+++ openssh-2.9.9p2J/readconf.c	Thu Sep 27 22:17:56 2001
@@ -115,7 +115,7 @@
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
-	oClearAllForwardings
+	oClearAllForwardings, oSleep
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -186,6 +186,7 @@
 	{ "bindaddress", oBindAddress },
 	{ "smartcarddevice", oSmartcardDevice },
 	{ "clearallforwardings", oClearAllForwardings }, 
+ 	{ "sleep", oSleep },
 	{ NULL, 0 }
 };
 
@@ -523,6 +524,10 @@
 		intptr = &options->connection_attempts;
 		goto parse_int;
 
+	case oSleep:
+		intptr = &options->sleep;
+		goto parse_int;
+
 	case oCipher:
 		intptr = &options->cipher;
 		arg = strdelim(&s);
@@ -793,6 +798,7 @@
 	options->preferred_authentications = NULL;
 	options->bind_address = NULL;
 	options->smartcard_device = NULL;
+ 	options->sleep = -1;
 }
 
 /*
diff -u openssh-2.9.9p2/readconf.h openssh-2.9.9p2J/readconf.h
--- openssh-2.9.9p2/readconf.h	Wed Sep 19 18:57:56 2001
+++ openssh-2.9.9p2J/readconf.h	Thu Sep 27 22:01:07 2001
@@ -101,6 +101,7 @@
 	int     num_remote_forwards;
 	Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
 	int	clear_forwardings;
+        int     sleep;		/* Exit delay in seconds */
 }       Options;
 
 
diff -u openssh-2.9.9p2/session.c openssh-2.9.9p2J/session.c
--- openssh-2.9.9p2/session.c	Sun Sep 16 16:17:15 2001
+++ openssh-2.9.9p2J/session.c	Thu Sep 27 22:01:07 2001
@@ -1906,6 +1906,9 @@
 	 */
 	if (c->ostate != CHAN_OUTPUT_CLOSED)
 		chan_write_failed(c);
+	if (c->istate == CHAN_INPUT_OPEN && compat20) {
+		chan_shutdown_read(c);
+	}
 	s->chanid = -1;
 }
 
diff -u openssh-2.9.9p2/ssh.c openssh-2.9.9p2J/ssh.c
--- openssh-2.9.9p2/ssh.c	Mon Sep 24 16:04:03 2001
+++ openssh-2.9.9p2J/ssh.c	Thu Sep 27 22:04:49 2001
@@ -195,6 +195,7 @@
 	fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", __progname);
 	fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
 	fprintf(stderr, "  -D port     Enable dynamic application-level port forwarding.\n");
+ 	fprintf(stderr, "  -S delay    Set exit delay (in seconds; 0 means wait forever).\n");
 	fprintf(stderr, "  -C          Enable compression.\n");
 	fprintf(stderr, "  -N          Do not execute a shell or command.\n");
 	fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");
@@ -320,7 +321,7 @@
 
 again:
 	while ((opt = getopt(ac, av,
-	    "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) {
+	    "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:S:TVX")) != -1) {
 		switch (opt) {
 		case '1':
 			options.protocol = SSH_PROTO_1;
@@ -495,7 +496,13 @@
 				add_remote_forward(&options, fwd_port, buf,
 				     fwd_host_port);
 			break;
-
+		case 'S':
+			options.sleep = atoi(optarg);
+			if (options.sleep < 0) {
+				fprintf(stderr, "Bad delay value '%s'\n", optarg);
+				exit(1);
+			}
+			break;
 		case 'D':
 			fwd_port = a2port(optarg);
 			if (fwd_port == 0) {



More information about the openssh-unix-dev mailing list