OpenSSH
[Top] [All Lists]

Re: sshd gets stuck: select() in packet_read_seqnr waits indefinitely

To: Matt Day <opensshbugs@fjarlq.com>
Subject: Re: sshd gets stuck: select() in packet_read_seqnr waits indefinitely
From: Darren Tucker <dtucker@zip.com.au>
Date: Thu, 15 Mar 2007 16:52:42 +1100
Cc: openssh-unix-dev@mindrot.org
Delivered-to: sp-com-lists@consult.net
Delivered-to: openssh-unix-dev-list1@securepoint.com
Delivered-to: openssh-unix-dev-tmda@mindrot.org
Delivered-to: openssh-unix-dev@mindrot.org
In-reply-to: <20070315032213.GA12369@gate.dtucker.net>
List-archive: <http://lists.mindrot.org/pipermail/openssh-unix-dev>
List-help: <mailto:openssh-unix-dev-request@mindrot.org?subject=help>
List-id: Development of portable OpenSSH <openssh-unix-dev.mindrot.org>
List-post: <mailto:openssh-unix-dev@mindrot.org>
List-subscribe: <http://lists.mindrot.org/mailman/listinfo/openssh-unix-dev>, <mailto:openssh-unix-dev-request@mindrot.org?subject=subscribe>
List-unsubscribe: <http://lists.mindrot.org/mailman/listinfo/openssh-unix-dev>, <mailto:openssh-unix-dev-request@mindrot.org?subject=unsubscribe>
References: <20070314185309.GA40932@fjarlq.com> <20070315001416.GA28880@gate.dtucker.net> <20070315011208.GA48513@fjarlq.com> <20070315024347.GA10841@gate.dtucker.net> <20070315025904.GA50787@fjarlq.com> <20070315032213.GA12369@gate.dtucker.net>
Reply-to: dtucker@zip.com.au
Sender: openssh-unix-dev-bounces+openssh-unix-dev-list1=securepoint.com@mindrot.org
User-agent: Mutt/1.5.11
On Thu, Mar 15, 2007 at 02:22:13PM +1100, Darren Tucker wrote:
> On Wed, Mar 14, 2007 at 08:59:04PM -0600, Matt Day wrote:
> > What about the timeout handling in packet_write_wait? Do you really
> > want to proceed with the write() and then possibly loop back around
> > to the select() call?
> 
> Yeah, that's a problem.  On platforms that return EAGAIN rather than
> EWOULDBLOCK it'll just spin through packet_write_poll() repeatedly.
> 
> Probably best to capture the return from select() explicitly test for
> a timeout.

Like so (still untested):

Index: packet.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh/packet.c,v
retrieving revision 1.146
diff -u -p -r1.146 packet.c
--- packet.c    17 Jan 2007 00:00:14 -0000      1.146
+++ packet.c    15 Mar 2007 05:51:19 -0000
@@ -136,6 +136,10 @@ static int server_side = 0;
 /* Set to true if we are authenticated. */
 static int after_authentication = 0;
 
+/* Set to the maximum time that we will wait to send or receive a packet */
+static struct timeval packet_wait_tv;
+static struct timeval *packet_wait_tvp = NULL;
+
 /* Session key information for Encryption and MAC */
 Newkeys *newkeys[MODE_MAX];
 static struct packet_state {
@@ -189,6 +193,21 @@ packet_set_connection(int fd_in, int fd_
        }
 }
 
+void
+packet_set_timeout(int timeout, int count)
+{
+       if (timeout == 0 && count == 0) {
+               packet_wait_tvp = NULL;
+               return;
+       }
+       if (LONG_MAX / count < timeout)
+               packet_wait_tv.tv_sec = LONG_MAX;
+       else
+               packet_wait_tv.tv_sec = timeout * count;
+       packet_wait_tv.tv_usec = 0;
+       packet_wait_tvp = &packet_wait_tv;
+}
+
 /* Returns 1 if remote host is connected via socket, 0 if not. */
 
 int
@@ -888,7 +907,7 @@ packet_send(void)
 int
 packet_read_seqnr(u_int32_t *seqnr_p)
 {
-       int type, len;
+       int type, len, ret;
        fd_set *setp;
        char buf[8192];
        DBG(debug("packet_read()"));
@@ -923,10 +942,15 @@ packet_read_seqnr(u_int32_t *seqnr_p)
                FD_SET(connection_in, setp);
 
                /* Wait for some data to arrive. */
-               while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 
&&
+               while ((ret = select(connection_in + 1, setp, NULL, NULL,
+                   packet_wait_tvp)) == -1 &&
                    (errno == EAGAIN || errno == EINTR))
                        ;
-
+               if (ret == 0) {
+                       logit("Connection to %.200s timed out",
+                           get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
                /* Read data from the socket. */
                len = read(connection_in, buf, sizeof(buf));
                if (len == 0) {
@@ -1441,6 +1465,7 @@ void
 packet_write_wait(void)
 {
        fd_set *setp;
+       int ret;
 
        setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS),
            sizeof(fd_mask));
@@ -1449,9 +1474,15 @@ packet_write_wait(void)
                memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
                    sizeof(fd_mask));
                FD_SET(connection_out, setp);
-               while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 
&&
+               while ((ret = select(connection_out + 1, NULL, setp, NULL,
+                   packet_wait_tvp)) == -1 &&
                    (errno == EAGAIN || errno == EINTR))
                        ;
+               if (ret == 0) {
+                       logit("Connection to %.200s timed out",
+                           get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
                packet_write_poll();
        }
        xfree(setp);
Index: packet.h
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh/packet.h,v
retrieving revision 1.47
diff -u -p -r1.47 packet.h
--- packet.h    26 Mar 2006 03:30:02 -0000      1.47
+++ packet.h    15 Mar 2007 04:01:39 -0000
@@ -21,6 +21,7 @@
 #include <openssl/bn.h>
 
 void     packet_set_connection(int, int);
+void     packet_set_timeout(int, int);
 void     packet_set_nonblocking(void);
 int      packet_get_connection_in(void);
 int      packet_get_connection_out(void);
Index: sshconnect.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh/sshconnect.c,v
retrieving revision 1.171
diff -u -p -r1.171 sshconnect.c
--- sshconnect.c        23 Oct 2006 17:02:24 -0000      1.171
+++ sshconnect.c        15 Mar 2007 04:04:50 -0000
@@ -158,6 +158,8 @@ ssh_proxy_connect(const char *host, u_sh
 
        /* Set the connection file descriptors. */
        packet_set_connection(pout[0], pin[1]);
+       packet_set_timeout(options.server_alive_interval,
+           options.server_alive_count_max);
 
        /* Indicate OK return */
        return 0;
@@ -386,6 +388,8 @@ ssh_connect(const char *host, struct soc
 
        /* Set the connection. */
        packet_set_connection(sock, sock);
+       packet_set_timeout(options.server_alive_interval,
+           options.server_alive_count_max);
 
        return 0;
 }
Index: sshd.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh/sshd.c,v
retrieving revision 1.362
diff -u -p -r1.362 sshd.c
--- sshd.c      25 Feb 2007 09:37:22 -0000      1.362
+++ sshd.c      15 Mar 2007 03:58:53 -0000
@@ -1708,6 +1708,8 @@ main(int ac, char **av)
         * not have a key.
         */
        packet_set_connection(sock_in, sock_out);
+       packet_set_timeout(options.client_alive_interval,
+           options.client_alive_count_max);
        packet_set_server();
 
        /* Set SO_KEEPALIVE if requested. */

-- 
Darren Tucker (dtucker at zip.com.au)
GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4  37C9 C982 80C7 8FF4 FA69
    Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
http://lists.mindrot.org/mailman/listinfo/openssh-unix-dev

<Prev in Thread] Current Thread [Next in Thread>