From deafaa811edfdc3cd753515c17eb2c3574001e91 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Mar 2019 07:09:26 +0000 Subject: [PATCH] ssh2_try_send: don't try sending if a channel is half-open. When ssh2_connection_filter_queue is _receiving_ messages about a channel from the other end, it carefully checks if the channel referred to is half-open. But we weren't exercising the same caution before beginning to _send_ channel data, and we should, because in that situation important fields like c->remwinsize aren't even initialised yet. This can come up, for example, due to typeahead in the main session window before the server has sent OPEN_CONFIRMATION. --- ssh2connection.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/ssh2connection.c b/ssh2connection.c index 5b17bc66..76c3ccfd 100644 --- a/ssh2connection.c +++ b/ssh2connection.c @@ -1060,30 +1060,32 @@ static size_t ssh2_try_send(struct ssh2_channel *c) PktOut *pktout; size_t bufsize; - while (c->remwindow > 0 && - (bufchain_size(&c->outbuffer) > 0 || - bufchain_size(&c->errbuffer) > 0)) { - bufchain *buf = (bufchain_size(&c->errbuffer) > 0 ? - &c->errbuffer : &c->outbuffer); + if (!c->halfopen) { + while (c->remwindow > 0 && + (bufchain_size(&c->outbuffer) > 0 || + bufchain_size(&c->errbuffer) > 0)) { + bufchain *buf = (bufchain_size(&c->errbuffer) > 0 ? + &c->errbuffer : &c->outbuffer); - ptrlen data = bufchain_prefix(buf); - if (data.len > c->remwindow) - data.len = c->remwindow; - if (data.len > c->remmaxpkt) - data.len = c->remmaxpkt; - if (buf == &c->errbuffer) { - pktout = ssh_bpp_new_pktout( - s->ppl.bpp, SSH2_MSG_CHANNEL_EXTENDED_DATA); - put_uint32(pktout, c->remoteid); - put_uint32(pktout, SSH2_EXTENDED_DATA_STDERR); - } else { - pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_DATA); - put_uint32(pktout, c->remoteid); + ptrlen data = bufchain_prefix(buf); + if (data.len > c->remwindow) + data.len = c->remwindow; + if (data.len > c->remmaxpkt) + data.len = c->remmaxpkt; + if (buf == &c->errbuffer) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_CHANNEL_EXTENDED_DATA); + put_uint32(pktout, c->remoteid); + put_uint32(pktout, SSH2_EXTENDED_DATA_STDERR); + } else { + pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_DATA); + put_uint32(pktout, c->remoteid); + } + put_stringpl(pktout, data); + pq_push(s->ppl.out_pq, pktout); + bufchain_consume(buf, data.len); + c->remwindow -= data.len; } - put_stringpl(pktout, data); - pq_push(s->ppl.out_pq, pktout); - bufchain_consume(buf, data.len); - c->remwindow -= data.len; } /*