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