diff options
author | Damien Miller <djm@mindrot.org> | 2010-08-05 23:09:48 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2010-08-05 23:09:48 +1000 |
commit | 7d45718943e63ec649003d3a9b56e531da2193ea (patch) | |
tree | 2f5d4845c06f6c9ff4ad36a0843fd017e69c5a3a | |
parent | b89e6b76be2842d7d91b186753af741a73465d71 (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-- | ChangeLog | 20 | ||||
-rw-r--r-- | channels.c | 41 |
2 files changed, 46 insertions, 15 deletions
@@ -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 | ||
29 | 20100903 | 49 | 20100903 |
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); |