The writev allows only a limited number of entries to be present in the iovector. This number depends on the OS. If more entries are passed, the writev operation fails and the connection is closed.
This patch limits the size of the vector to the maximum number accepted by the OS. On some operating systems IOV_MAX is not defined, if this is the case UIO_MAXIOV is being used as the maximum value. In the problematic scenario the Linux box, running dropbear, has a slow uplink. If an ssh is done to the box and a command is executed that generates a lot of small fragments (for example a 'find .' in the root), a lot of small interactions are seen between dropbear and the shell process. The observation was that the amount of entries pending in the queue could go up to 7500. Since all entries present in the queue will be passed to writev an error will be returned since Linux only accepts 1024 entries to be present in the vector. The result is that the connection is being closed. Signed-off-by: Ronny Meeus <[email protected]> diff --git a/packet.c b/packet.c --- a/packet.c +++ b/packet.c @@ -64,13 +64,24 @@ void write_packet() { struct iovec *iov = NULL; int i; struct Link *l; + int iov_max_count; #endif TRACE2(("enter write_packet")) dropbear_assert(!isempty(&ses.writequeue)); #ifdef HAVE_WRITEV - iov = m_malloc(sizeof(*iov) * ses.writequeue.count); + +#ifndef IOV_MAX +#define IOV_MAX UIO_MAXIOV +#endif + + /* Make sure the size of the iov is below the maximum allowed by the OS. */ + iov_max_count = ses.writequeue.count; + if (iov_max_count > IOV_MAX) + iov_max_count = IOV_MAX; + + iov = m_malloc(sizeof(*iov) * iov_max_count); for (l = ses.writequeue.head, i = 0; l; l = l->link, i++) { writebuf = (buffer*)l->item; @@ -83,7 +94,7 @@ void write_packet() { iov[i].iov_base = buf_getptr(writebuf, len); iov[i].iov_len = len; } - written = writev(ses.sock_out, iov, ses.writequeue.count); + written = writev(ses.sock_out, iov, iov_max_count); if (written < 0) { if (errno == EINTR) { m_free(iov);
