changeset 29659:df9de37e0274

gnutls/nss: Don't call the handshake functions synchronously. Fixes #11525 If the handshake callbacks are called sychronously and they fail (e.g. passing GnuTLS a bad priority string or doing voodoo with NSS, see #11524 for details), the error_cb is called and the gsc destroyed, but this happens /before/ the assignment to, e.g., js->gsc happens (see jabber.c:tls_init). Thus, js->gsc is assigned a (now invalid) pointer and jabber_close tries to free it (again).
author Paul Aurich <paul@darkrain42.org>
date Thu, 01 Apr 2010 05:26:44 +0000
parents 89de871ecffc
children fc4bacb35cbc
files ChangeLog libpurple/plugins/ssl/ssl-gnutls.c libpurple/plugins/ssl/ssl-nss.c
diffstat 3 files changed, 39 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Apr 01 04:58:17 2010 +0000
+++ b/ChangeLog	Thu Apr 01 05:26:44 2010 +0000
@@ -6,6 +6,9 @@
 	* Changed GLib minimum version requirement to 2.12.0.
 	* Using the --disable-nls argument to configre now works properly. You
 	  will no longer be forced to have intltool to configure and build.
+	* Fix two related crashes in the GnuTLS and NSS plugins when they
+	  suffer internal errors immediately upon attempting to establish
+	  an SSL connection.
 	* Added support for PURPLE_GNUTLS_PRIORITIES environment variable.
 	  This can be used to specify GnuTLS priorities on a per-host basis.
 	  The format is "host=priority;host2=priority;...".  The default
--- a/libpurple/plugins/ssl/ssl-gnutls.c	Thu Apr 01 04:58:17 2010 +0000
+++ b/libpurple/plugins/ssl/ssl-gnutls.c	Thu Apr 01 05:26:44 2010 +0000
@@ -36,6 +36,7 @@
 {
 	gnutls_session session;
 	guint handshake_handler;
+	guint handshake_timer;
 } PurpleSslGnutlsData;
 
 #define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data)
@@ -367,6 +368,19 @@
 
 }
 
+static gboolean
+start_handshake_cb(gpointer data)
+{
+	PurpleSslConnection *gsc = data;
+	PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc);
+
+	purple_debug_info("gnutls", "Starting handshake with %s\n", gsc->host);
+
+	gnutls_data->handshake_timer = 0;
+
+	ssl_gnutls_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ);
+	return FALSE;
+}
 
 static void
 ssl_gnutls_connect(PurpleSslConnection *gsc)
@@ -410,10 +424,8 @@
 	gnutls_data->handshake_handler = purple_input_add(gsc->fd,
 		PURPLE_INPUT_READ, ssl_gnutls_handshake_cb, gsc);
 
-	purple_debug_info("gnutls", "Starting handshake with %s\n", gsc->host);
-
 	/* Orborde asks: Why are we configuring a callback, then
-	   immediately calling it?
+	   (almost) immediately calling it?
 
 	   Answer: gnutls_handshake (up in handshake_cb) needs to be called
 	   once in order to get the ball rolling on the SSL connection.
@@ -424,7 +436,8 @@
 	   and subsequent calls, we'll just fire the callback immediately to
 	   accomplish this.
 	*/
-	ssl_gnutls_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ);
+	gnutls_data->handshake_timer = purple_timeout_add(0, start_handshake_cb,
+	                                                  gsc);
 }
 
 static void
@@ -437,6 +450,8 @@
 
 	if(gnutls_data->handshake_handler)
 		purple_input_remove(gnutls_data->handshake_handler);
+	if (gnutls_data->handshake_timer)
+		purple_timeout_remove(gnutls_data->handshake_timer);
 
 	gnutls_bye(gnutls_data->session, GNUTLS_SHUT_RDWR);
 
--- a/libpurple/plugins/ssl/ssl-nss.c	Thu Apr 01 04:58:17 2010 +0000
+++ b/libpurple/plugins/ssl/ssl-nss.c	Thu Apr 01 05:26:44 2010 +0000
@@ -51,7 +51,7 @@
 	PRFileDesc *fd;
 	PRFileDesc *in;
 	guint handshake_handler;
-
+	guint handshake_timer;
 } PurpleSslNssData;
 
 #define PURPLE_SSL_NSS_DATA(gsc) ((PurpleSslNssData *)gsc->private_data)
@@ -368,6 +368,18 @@
 	}
 }
 
+static gboolean
+start_handshake_cb(gpointer data)
+{
+	PurpleSslConnection *gsc = data;
+	PurpleSslNssData *nss_data = PURPLE_SSL_NSS_DATA(gsc);
+
+	nss_data->handshake_timer = 0;
+
+	ssl_nss_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ);
+	return FALSE;
+}
+
 static void
 ssl_nss_connect(PurpleSslConnection *gsc)
 {
@@ -438,7 +450,7 @@
 	nss_data->handshake_handler = purple_input_add(gsc->fd,
 		PURPLE_INPUT_READ, ssl_nss_handshake_cb, gsc);
 
-	ssl_nss_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ);
+	nss_data->handshake_timer = purple_timeout_add(0, start_handshake_cb, gsc);
 }
 
 static void
@@ -460,6 +472,9 @@
 	if (nss_data->handshake_handler)
 		purple_input_remove(nss_data->handshake_handler);
 
+	if (nss_data->handshake_timer)
+		purple_timeout_remove(nss_data->handshake_timer);
+
 	g_free(nss_data);
 	gsc->private_data = NULL;
 }