diff options
author | Matt Johnston <matt@ucc.asn.au> | 2011-12-04 05:27:29 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2011-12-04 05:27:29 +0800 |
commit | d7ea701658b0a8a546071af890589d17d77ec588 (patch) | |
tree | 9ec84783d9a9f51451e2ea211c155fac02e154a5 | |
parent | 8f150e2bf4b6e821e3c21f69b17ee1e7f16618a4 (diff) | |
download | dropbear-d7ea701658b0a8a546071af890589d17d77ec588.tar.gz |
- Make sure we don't use channel-specific data after it has been freed
with a ChanType->closehandler()
-rw-r--r-- | channel.h | 4 | ||||
-rw-r--r-- | common-channel.c | 21 |
2 files changed, 18 insertions, 7 deletions
@@ -69,6 +69,10 @@ struct Channel { int sent_close, recv_close; int recv_eof, sent_eof; + /* Set after running the ChanType-specific close hander + * to ensure we don't run it twice (nor type->checkclose()). */ + int close_handler_done; + int initconn; /* used for TCP forwarding, whether the channel has been fully initialised */ diff --git a/common-channel.c b/common-channel.c index 5821b08..9eaba50 100644 --- a/common-channel.c +++ b/common-channel.c @@ -138,6 +138,7 @@ struct Channel* newchannel(unsigned int remotechan, newchan->index = i; newchan->sent_close = newchan->recv_close = 0; newchan->sent_eof = newchan->recv_eof = 0; + newchan->close_handler_done = 0; newchan->remotechan = remotechan; newchan->transwindow = transwindow; @@ -270,7 +271,9 @@ static void check_close(struct Channel *channel) { cbuf_getused(channel->writebuf), channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) - if (!channel->flushing && channel->type->check_close + if (!channel->flushing + && !channel->close_handler_done + && channel->type->check_close && channel->type->check_close(channel)) { channel->flushing = 1; @@ -281,7 +284,8 @@ static void check_close(struct Channel *channel) { channel, to ensure that the shell has exited (and the exit status retrieved) before we close things up. */ if (!channel->type->check_close - || channel->type->check_close(channel)) { + || channel->close_handler_done + || channel->type->check_close(channel)) { close_allowed = 1; } @@ -363,9 +367,11 @@ static void check_in_progress(struct Channel *channel) { /* Send the close message and set the channel as closed */ static void send_msg_channel_close(struct Channel *channel) { - TRACE(("enter send_msg_channel_close")) - if (channel->type->closehandler) { + TRACE(("enter send_msg_channel_close %p", channel)) + if (channel->type->closehandler + && !channel->close_handler_done) { channel->type->closehandler(channel); + channel->close_handler_done = 1; } CHECKCLEARTOWRITE(); @@ -568,16 +574,17 @@ void recv_msg_channel_request() { struct Channel *channel; - TRACE(("enter recv_msg_channel_request")) - channel = getchannel(); + TRACE(("enter recv_msg_channel_request %p", channel)) + if (channel->sent_close) { TRACE(("leave recv_msg_channel_request: already closed channel")) return; } - if (channel->type->reqhandler) { + if (channel->type->reqhandler + && !channel->close_handler_done) { channel->type->reqhandler(channel); } else { send_msg_channel_failure(channel); |