changeset 29762:b0bc67f42027

Fix a possible use-after-free. If the user initiated a file transfer while a display pic transfer was in progress, and that transfer finished before the user selected a file, then the MsnSlpLink to that user could be used after it's freed. Also, if there were a conversation open to that user, then the slplink would not be freed, so the FT must be started from the buddy list. Fixes #6453.
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Tue, 20 Apr 2010 00:05:34 +0000
parents 4ebecacf2fbb
children 57a482217ee1
files libpurple/protocols/msn/msn.c libpurple/protocols/msn/slplink.c libpurple/protocols/msn/slplink.h
diffstat 3 files changed, 46 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/msn/msn.c	Mon Apr 19 23:55:03 2010 +0000
+++ b/libpurple/protocols/msn/msn.c	Tue Apr 20 00:05:34 2010 +0000
@@ -589,6 +589,14 @@
 {
 	MsnSlpLink *slplink = xfer->data;
 	msn_slplink_request_ft(slplink, xfer);
+	msn_slplink_unref(slplink);
+}
+
+static void
+t_msn_xfer_cancel_send(PurpleXfer *xfer)
+{
+	MsnSlpLink *slplink = xfer->data;
+	msn_slplink_unref(slplink);
 }
 
 static PurpleXfer*
@@ -603,9 +611,10 @@
 
 	g_return_val_if_fail(xfer != NULL, NULL);
 
-	xfer->data = msn_session_get_slplink(session, who);
+	xfer->data = msn_slplink_ref(msn_session_get_slplink(session, who));
 
 	purple_xfer_set_init_fnc(xfer, t_msn_xfer_init);
+	purple_xfer_set_cancel_send_fnc(xfer, t_msn_xfer_cancel_send);
 
 	return xfer;
 }
--- a/libpurple/protocols/msn/slplink.c	Mon Apr 19 23:55:03 2010 +0000
+++ b/libpurple/protocols/msn/slplink.c	Tue Apr 20 00:05:34 2010 +0000
@@ -78,7 +78,7 @@
 	session->slplinks =
 		g_list_append(session->slplinks, slplink);
 
-	return slplink;
+	return msn_slplink_ref(slplink);
 }
 
 void
@@ -94,6 +94,11 @@
 	if (slplink->swboard != NULL)
 		slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink);
 
+	if (slplink->refs > 1) {
+		slplink->refs--;
+		return;
+	}
+
 	session = slplink->session;
 
 #if 0
@@ -115,6 +120,31 @@
 }
 
 MsnSlpLink *
+msn_slplink_ref(MsnSlpLink *slplink)
+{
+	g_return_val_if_fail(slplink != NULL, NULL);
+
+	slplink->refs++;
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "slplink ref (%p)[%d]\n", slplink, slplink->refs);
+
+	return slplink;
+}
+
+void
+msn_slplink_unref(MsnSlpLink *slplink)
+{
+	g_return_if_fail(slplink != NULL);
+
+	slplink->refs--;
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "slplink unref (%p)[%d]\n", slplink, slplink->refs);
+
+	if (slplink->refs == 0)
+		msn_slplink_destroy(slplink);
+}
+
+MsnSlpLink *
 msn_session_find_slplink(MsnSession *session, const char *who)
 {
 	GList *l;
--- a/libpurple/protocols/msn/slplink.h	Mon Apr 19 23:55:03 2010 +0000
+++ b/libpurple/protocols/msn/slplink.h	Tue Apr 20 00:05:34 2010 +0000
@@ -43,6 +43,8 @@
 	MsnSession *session;
 	MsnSwitchBoard *swboard;
 
+	int refs;
+
 	char *remote_user;
 
 	int slp_seq_id;
@@ -55,6 +57,9 @@
 	GQueue *slp_msg_queue;
 };
 
+MsnSlpLink *msn_slplink_ref(MsnSlpLink *slplink);
+void msn_slplink_unref(MsnSlpLink *slplink);
+
 void msn_slplink_destroy(MsnSlpLink *slplink);
 
 /**