summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2011-12-04 05:27:29 +0800
committerMatt Johnston <matt@ucc.asn.au>2011-12-04 05:27:29 +0800
commitd7ea701658b0a8a546071af890589d17d77ec588 (patch)
tree9ec84783d9a9f51451e2ea211c155fac02e154a5
parent8f150e2bf4b6e821e3c21f69b17ee1e7f16618a4 (diff)
downloaddropbear-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.h4
-rw-r--r--common-channel.c21
2 files changed, 18 insertions, 7 deletions
diff --git a/channel.h b/channel.h
index 5c63226..d9e2894 100644
--- a/channel.h
+++ b/channel.h
@@ -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);