summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-08-05 23:09:48 +1000
committerDamien Miller <djm@mindrot.org>2010-08-05 23:09:48 +1000
commit7d45718943e63ec649003d3a9b56e531da2193ea (patch)
tree2f5d4845c06f6c9ff4ad36a0843fd017e69c5a3a
parentb89e6b76be2842d7d91b186753af741a73465d71 (diff)
- djm@cvs.openbsd.org 2010/08/05 13:08:42
[channels.c] Fix a trio of bugs in the local/remote window calculation for datagram data channels (i.e. TunnelForward): Calculate local_consumed correctly in channel_handle_wfd() by measuring the delta to buffer_len(c->output) from when we start to when we finish. The proximal problem here is that the output_filter we use in portable modified the length of the dequeued datagram (to futz with the headers for !OpenBSD). In channel_output_poll(), don't enqueue datagrams that won't fit in the peer's advertised packet size (highly unlikely to ever occur) or which won't fit in the peer's remaining window (more likely). In channel_input_data(), account for the 4-byte string header in datagram packets that we accept from the peer and enqueue in c->output. report, analysis and testing 2/3 cases from wierbows AT us.ibm.com; "looks good" markus@
-rw-r--r--ChangeLog20
-rw-r--r--channels.c41
2 files changed, 46 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index c32b36627..68f204635 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -25,6 +25,26 @@
25 - djm@cvs.openbsd.org 2010/08/04 06:08:40 25 - djm@cvs.openbsd.org 2010/08/04 06:08:40
26 [ssh-keysign.c] 26 [ssh-keysign.c]
27 clean for -Wuninitialized (Id sync only; portable had this change) 27 clean for -Wuninitialized (Id sync only; portable had this change)
28 - djm@cvs.openbsd.org 2010/08/05 13:08:42
29 [channels.c]
30 Fix a trio of bugs in the local/remote window calculation for datagram
31 data channels (i.e. TunnelForward):
32
33 Calculate local_consumed correctly in channel_handle_wfd() by measuring
34 the delta to buffer_len(c->output) from when we start to when we finish.
35 The proximal problem here is that the output_filter we use in portable
36 modified the length of the dequeued datagram (to futz with the headers
37 for !OpenBSD).
38
39 In channel_output_poll(), don't enqueue datagrams that won't fit in the
40 peer's advertised packet size (highly unlikely to ever occur) or which
41 won't fit in the peer's remaining window (more likely).
42
43 In channel_input_data(), account for the 4-byte string header in
44 datagram packets that we accept from the peer and enqueue in c->output.
45
46 report, analysis and testing 2/3 cases from wierbows AT us.ibm.com;
47 "looks good" markus@
28 48
2920100903 4920100903
30 - (dtucker) [monitor.c] Bug #1795: Initialize the values to be returned from 50 - (dtucker) [monitor.c] Bug #1795: Initialize the values to be returned from
diff --git a/channels.c b/channels.c
index fd6244d48..1cd5004c4 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.308 2010/07/13 23:13:16 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.309 2010/08/05 13:08:42 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1644,13 +1644,14 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1644{ 1644{
1645 struct termios tio; 1645 struct termios tio;
1646 u_char *data = NULL, *buf; 1646 u_char *data = NULL, *buf;
1647 u_int dlen; 1647 u_int dlen, olen = 0;
1648 int len; 1648 int len;
1649 1649
1650 /* Send buffered output data to the socket. */ 1650 /* Send buffered output data to the socket. */
1651 if (c->wfd != -1 && 1651 if (c->wfd != -1 &&
1652 FD_ISSET(c->wfd, writeset) && 1652 FD_ISSET(c->wfd, writeset) &&
1653 buffer_len(&c->output) > 0) { 1653 buffer_len(&c->output) > 0) {
1654 olen = buffer_len(&c->output);
1654 if (c->output_filter != NULL) { 1655 if (c->output_filter != NULL) {
1655 if ((buf = c->output_filter(c, &data, &dlen)) == NULL) { 1656 if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
1656 debug2("channel %d: filter stops", c->self); 1657 debug2("channel %d: filter stops", c->self);
@@ -1669,7 +1670,6 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1669 1670
1670 if (c->datagram) { 1671 if (c->datagram) {
1671 /* ignore truncated writes, datagrams might get lost */ 1672 /* ignore truncated writes, datagrams might get lost */
1672 c->local_consumed += dlen + 4;
1673 len = write(c->wfd, buf, dlen); 1673 len = write(c->wfd, buf, dlen);
1674 xfree(data); 1674 xfree(data);
1675 if (len < 0 && (errno == EINTR || errno == EAGAIN || 1675 if (len < 0 && (errno == EINTR || errno == EAGAIN ||
@@ -1682,7 +1682,7 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1682 chan_write_failed(c); 1682 chan_write_failed(c);
1683 return -1; 1683 return -1;
1684 } 1684 }
1685 return 1; 1685 goto out;
1686 } 1686 }
1687#ifdef _AIX 1687#ifdef _AIX
1688 /* XXX: Later AIX versions can't push as much data to tty */ 1688 /* XXX: Later AIX versions can't push as much data to tty */
@@ -1724,10 +1724,10 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1724 } 1724 }
1725#endif 1725#endif
1726 buffer_consume(&c->output, len); 1726 buffer_consume(&c->output, len);
1727 if (compat20 && len > 0) {
1728 c->local_consumed += len;
1729 }
1730 } 1727 }
1728 out:
1729 if (compat20 && olen > 0)
1730 c->local_consumed += olen - buffer_len(&c->output);
1731 return 1; 1731 return 1;
1732} 1732}
1733 1733
@@ -2172,6 +2172,14 @@ channel_output_poll(void)
2172 2172
2173 data = buffer_get_string(&c->input, 2173 data = buffer_get_string(&c->input,
2174 &dlen); 2174 &dlen);
2175 if (dlen > c->remote_window ||
2176 dlen > c->remote_maxpacket) {
2177 debug("channel %d: datagram "
2178 "too big for channel",
2179 c->self);
2180 xfree(data);
2181 continue;
2182 }
2175 packet_start(SSH2_MSG_CHANNEL_DATA); 2183 packet_start(SSH2_MSG_CHANNEL_DATA);
2176 packet_put_int(c->remote_id); 2184 packet_put_int(c->remote_id);
2177 packet_put_string(data, dlen); 2185 packet_put_string(data, dlen);
@@ -2257,7 +2265,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2257{ 2265{
2258 int id; 2266 int id;
2259 char *data; 2267 char *data;
2260 u_int data_len; 2268 u_int data_len, win_len;
2261 Channel *c; 2269 Channel *c;
2262 2270
2263 /* Get the channel number and verify it. */ 2271 /* Get the channel number and verify it. */
@@ -2273,6 +2281,9 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2273 2281
2274 /* Get the data. */ 2282 /* Get the data. */
2275 data = packet_get_string_ptr(&data_len); 2283 data = packet_get_string_ptr(&data_len);
2284 win_len = data_len;
2285 if (c->datagram)
2286 win_len += 4; /* string length header */
2276 2287
2277 /* 2288 /*
2278 * Ignore data for protocol > 1.3 if output end is no longer open. 2289 * Ignore data for protocol > 1.3 if output end is no longer open.
@@ -2283,23 +2294,23 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2283 */ 2294 */
2284 if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) { 2295 if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {
2285 if (compat20) { 2296 if (compat20) {
2286 c->local_window -= data_len; 2297 c->local_window -= win_len;
2287 c->local_consumed += data_len; 2298 c->local_consumed += win_len;
2288 } 2299 }
2289 return; 2300 return;
2290 } 2301 }
2291 2302
2292 if (compat20) { 2303 if (compat20) {
2293 if (data_len > c->local_maxpacket) { 2304 if (win_len > c->local_maxpacket) {
2294 logit("channel %d: rcvd big packet %d, maxpack %d", 2305 logit("channel %d: rcvd big packet %d, maxpack %d",
2295 c->self, data_len, c->local_maxpacket); 2306 c->self, win_len, c->local_maxpacket);
2296 } 2307 }
2297 if (data_len > c->local_window) { 2308 if (win_len > c->local_window) {
2298 logit("channel %d: rcvd too much data %d, win %d", 2309 logit("channel %d: rcvd too much data %d, win %d",
2299 c->self, data_len, c->local_window); 2310 c->self, win_len, c->local_window);
2300 return; 2311 return;
2301 } 2312 }
2302 c->local_window -= data_len; 2313 c->local_window -= win_len;
2303 } 2314 }
2304 if (c->datagram) 2315 if (c->datagram)
2305 buffer_put_string(&c->output, data, data_len); 2316 buffer_put_string(&c->output, data, data_len);