From baa32218b0df8bd342da9bfe04f7ae678f2664ff Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 4 Dec 2011 05:27:29 +0800
Subject: [PATCH] - Make sure we don't use channel-specific data after it has
 been freed   with a ChanType->closehandler()

---
 channel.h        |  4 ++++
 common-channel.c | 21 ++++++++++++++-------
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/channel.h b/channel.h
index 5c63226b..d9e28946 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 5821b085..9eaba509 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);
-- 
GitLab