remote vs local window discrepancy

Damien Miller djm at mindrot.org
Fri Jul 23 10:58:47 EST 2010


On Thu, 22 Jul 2010, David Wierbowski wrote:

> Damien,
> 
> Thanks for the quick response.  I am on a platform that uses the
> output filter function in openbsd-compat/port-tun.c.  I had briefly
> looked at the sys_tun_outfilter function and was suspicious when I saw
> that it decremented dlen.  I think you might be on to the source of the
> discrepancy.

If I'm right, then this should fix it:

Index: channels.c
===================================================================
RCS file: /var/cvs/openssh/channels.c,v
retrieving revision 1.299
diff -u -p -r1.299 channels.c
--- channels.c	16 Jul 2010 03:58:37 -0000	1.299
+++ channels.c	23 Jul 2010 00:52:07 -0000
@@ -1644,7 +1644,7 @@ channel_handle_wfd(Channel *c, fd_set *r
 {
 	struct termios tio;
 	u_char *data = NULL, *buf;
-	u_int dlen;
+	u_int dlen, wlen;
 	int len;
 
 	/* Send buffered output data to the socket. */
@@ -1652,7 +1652,8 @@ channel_handle_wfd(Channel *c, fd_set *r
 	    FD_ISSET(c->wfd, writeset) &&
 	    buffer_len(&c->output) > 0) {
 		if (c->output_filter != NULL) {
-			if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
+			if ((buf = c->output_filter(c, &data, &dlen,
+			    &wlen)) == NULL) {
 				debug2("channel %d: filter stops", c->self);
 				if (c->type != SSH_CHANNEL_OPEN)
 					chan_mark_dead(c);
@@ -1662,15 +1663,16 @@ channel_handle_wfd(Channel *c, fd_set *r
 			}
 		} else if (c->datagram) {
 			buf = data = buffer_get_string(&c->output, &dlen);
+			wlen = dlen;
 		} else {
 			buf = data = buffer_ptr(&c->output);
-			dlen = buffer_len(&c->output);
+			dlen = wlen = buffer_len(&c->output);
 		}
 
 		if (c->datagram) {
 			/* ignore truncated writes, datagrams might get lost */
 			c->local_consumed += dlen + 4;
-			len = write(c->wfd, buf, dlen);
+			len = write(c->wfd, buf, wlen);
 			xfree(data);
 			if (len < 0 && (errno == EINTR || errno == EAGAIN ||
 			    errno == EWOULDBLOCK))
@@ -1687,10 +1689,10 @@ channel_handle_wfd(Channel *c, fd_set *r
 #ifdef _AIX
 		/* XXX: Later AIX versions can't push as much data to tty */
 		if (compat20 && c->wfd_isatty)
-			dlen = MIN(dlen, 8*1024);
+			wlen = MIN(wlen, 8*1024);
 #endif
 
-		len = write(c->wfd, buf, dlen);
+		len = write(c->wfd, buf, wlen);
 		if (len < 0 &&
 		    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
 			return 1;
@@ -1709,7 +1711,7 @@ channel_handle_wfd(Channel *c, fd_set *r
 			return -1;
 		}
 #ifndef BROKEN_TCGETATTR_ICANON
-		if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
+		if (compat20 && c->isatty && wlen >= 1 && buf[0] != '\r') {
 			if (tcgetattr(c->wfd, &tio) == 0 &&
 			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
 				/*
@@ -2172,6 +2174,14 @@ channel_output_poll(void)
 
 					data = buffer_get_string(&c->input,
 					    &dlen);
+					if (dlen > c->remote_window ||
+					    dlen > c->remote_maxpacket) {
+						debug("channel %d: datagram "
+						    "too big for channel",
+						    c->self);
+						xfree(data);
+						continue;
+					}
 					packet_start(SSH2_MSG_CHANNEL_DATA);
 					packet_put_int(c->remote_id);
 					packet_put_string(data, dlen);
Index: channels.h
===================================================================
RCS file: /var/cvs/openssh/channels.h,v
retrieving revision 1.97
diff -u -p -r1.97 channels.h
--- channels.h	21 May 2010 04:57:10 -0000	1.97
+++ channels.h	23 Jul 2010 00:52:30 -0000
@@ -64,7 +64,8 @@ typedef void channel_open_fn(int, int, v
 typedef void channel_callback_fn(int, void *);
 typedef int channel_infilter_fn(struct Channel *, char *, int);
 typedef void channel_filter_cleanup_fn(int, void *);
-typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *);
+typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *,
+    u_int *);
 
 /* Channel success/failure callbacks */
 typedef void channel_confirm_cb(int, struct Channel *, void *);
Index: openbsd-compat/port-tun.c
===================================================================
RCS file: /var/cvs/openssh/openbsd-compat/port-tun.c,v
retrieving revision 1.14
diff -u -p -r1.14 port-tun.c
--- openbsd-compat/port-tun.c	19 May 2008 05:28:36 -0000	1.14
+++ openbsd-compat/port-tun.c	23 Jul 2010 00:55:53 -0000
@@ -245,7 +245,7 @@ sys_tun_infilter(struct Channel *c, char
 }
 
 u_char *
-sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
+sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen, u_int *wlen)
 {
 	u_char *buf;
 	u_int32_t *af;
@@ -254,9 +254,10 @@ sys_tun_outfilter(struct Channel *c, u_c
 	if (*dlen < sizeof(*af))
 		return (NULL);
 	buf = *data;
+	*wlen = *dlen;
 
 #if defined(SSH_TUN_PREPEND_AF)
-	*dlen -= sizeof(u_int32_t);
+	*wlen -= sizeof(u_int32_t);
 	buf = *data + sizeof(u_int32_t);
 #elif defined(SSH_TUN_COMPAT_AF)
 	af = ntohl(*(u_int32_t *)buf);
Index: openbsd-compat/port-tun.h
===================================================================
RCS file: /var/cvs/openssh/openbsd-compat/port-tun.h,v
retrieving revision 1.4
diff -u -p -r1.4 port-tun.h
--- openbsd-compat/port-tun.h	5 Aug 2006 04:07:21 -0000	1.4
+++ openbsd-compat/port-tun.h	23 Jul 2010 00:58:24 -0000
@@ -27,7 +27,7 @@ int	  sys_tun_open(int, int);
 #if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF)
 # define SSH_TUN_FILTER
 int	 sys_tun_infilter(struct Channel *, char *, int);
-u_char	*sys_tun_outfilter(struct Channel *, u_char **, u_int *);
+u_char	*sys_tun_outfilter(struct Channel *, u_char **, u_int *, u_int *);
 #endif
 
 #endif


More information about the openssh-unix-dev mailing list