Fix crashes and memory leaks when receiving malformed voice release-2.x.y
authorMark Doliner <markdoliner@pidgin.im>
Tue, 06 Dec 2011 07:06:01 +0000
branchrelease-2.x.y
changeset15eb0e242206 pushlog
parent 883a1b407408
child 4fff920c6493
Fix crashes and memory leaks when receiving malformed voice
and video requests. Thanks to Thijs Alkemade for reporting this!
ChangeLog
libpurple/protocols/jabber/jingle/jingle.c
libpurple/protocols/jabber/jingle/rtp.c
libpurple/protocols/jabber/jingle/session.c
     1.1 --- a/ChangeLog
     1.2 +++ b/ChangeLog
     1.3 @@ -18,6 +18,10 @@
     1.4  	* Fix a leak when admitting UTF-8 text with a non-UTF-8 primary
     1.5  	  encoding.  (#14700)
     1.6  
     1.7 +	Jabber:
     1.8 +	* Fix crashes and memory leaks when receiving malformed voice
     1.9 +	  and video requests.  Thanks to Thijs Alkemade for reporting this!
    1.10 +
    1.11  	Sametime:
    1.12  	* Separate "username" and "server" when adding new Sametime accounts.
    1.13  	  (#14608)
     2.1 --- a/libpurple/protocols/jabber/jingle/jingle.c
     2.2 +++ b/libpurple/protocols/jabber/jingle/jingle.c
     2.3 @@ -126,7 +126,7 @@
     2.4  		if (local_content != NULL) {
     2.5  			const gchar *senders = xmlnode_get_attrib(content, "senders");
     2.6  			gchar *local_senders = jingle_content_get_senders(local_content);
     2.7 -			if (strcmp(senders, local_senders))
     2.8 +			if (!purple_strequal(senders, local_senders))
     2.9  				jingle_content_modify(local_content, senders);
    2.10  			g_free(local_senders);
    2.11  		} else {
     3.1 --- a/libpurple/protocols/jabber/jingle/rtp.c
     3.2 +++ b/libpurple/protocols/jabber/jingle/rtp.c
     3.3 @@ -590,6 +590,16 @@
     3.4  	senders = jingle_content_get_senders(content);
     3.5  	transport = jingle_content_get_transport(content);
     3.6  
     3.7 +	if (media_type == NULL) {
     3.8 +		g_free(name);
     3.9 +		g_free(remote_jid);
    3.10 +		g_free(senders);
    3.11 +		g_free(params);
    3.12 +		g_object_unref(transport);
    3.13 +		g_object_unref(session);
    3.14 +		return FALSE;
    3.15 +	}
    3.16 +
    3.17  	if (JINGLE_IS_RAWUDP(transport))
    3.18  		transmitter = "rawudp";
    3.19  	else if (JINGLE_IS_ICEUDP(transport))
    3.20 @@ -598,17 +608,17 @@
    3.21  		transmitter = "notransmitter";
    3.22  	g_object_unref(transport);
    3.23  
    3.24 -	is_audio = !strcmp(media_type, "audio");
    3.25 +	is_audio = g_str_equal(media_type, "audio");
    3.26  
    3.27 -	if (!strcmp(senders, "both"))
    3.28 -		type = is_audio == TRUE ? PURPLE_MEDIA_AUDIO
    3.29 +	if (purple_strequal(senders, "both"))
    3.30 +		type = is_audio ? PURPLE_MEDIA_AUDIO
    3.31  				: PURPLE_MEDIA_VIDEO;
    3.32 -	else if ((strcmp(senders, "initiator") == 0) ==
    3.33 +	else if (purple_strequal(senders, "initiator") ==
    3.34  			jingle_session_is_initiator(session))
    3.35 -		type = is_audio == TRUE ? PURPLE_MEDIA_SEND_AUDIO
    3.36 +		type = is_audio ? PURPLE_MEDIA_SEND_AUDIO
    3.37  				: PURPLE_MEDIA_SEND_VIDEO;
    3.38  	else
    3.39 -		type = is_audio == TRUE ? PURPLE_MEDIA_RECV_AUDIO
    3.40 +		type = is_audio ? PURPLE_MEDIA_RECV_AUDIO
    3.41  				: PURPLE_MEDIA_RECV_VIDEO;
    3.42  
    3.43  	params =
    3.44 @@ -616,7 +626,17 @@
    3.45  			NULL, NULL, &num_params);
    3.46  
    3.47  	creator = jingle_content_get_creator(content);
    3.48 -	if (!strcmp(creator, "initiator"))
    3.49 +	if (creator == NULL) {
    3.50 +		g_free(name);
    3.51 +		g_free(media_type);
    3.52 +		g_free(remote_jid);
    3.53 +		g_free(senders);
    3.54 +		g_free(params);
    3.55 +		g_object_unref(session);
    3.56 +		return FALSE;
    3.57 +	}
    3.58 +
    3.59 +	if (g_str_equal(creator, "initiator"))
    3.60  		is_creator = jingle_session_is_initiator(session);
    3.61  	else
    3.62  		is_creator = !jingle_session_is_initiator(session);
    3.63 @@ -625,6 +645,8 @@
    3.64  	if(!purple_media_add_stream(media, name, remote_jid,
    3.65  			type, is_creator, transmitter, num_params, params)) {
    3.66  		purple_media_end(media, NULL, NULL);
    3.67 +		/* TODO: How much clean-up is necessary here? (does calling
    3.68 +		         purple_media_end lead to cleaning up Jingle structs?) */
    3.69  		return FALSE;
    3.70  	}
    3.71  
    3.72 @@ -646,9 +668,22 @@
    3.73  	const char *encoding_name,*id, *clock_rate;
    3.74  	PurpleMediaCodec *codec;
    3.75  	const gchar *media = xmlnode_get_attrib(description, "media");
    3.76 -	PurpleMediaSessionType type =
    3.77 -			!strcmp(media, "video") ? PURPLE_MEDIA_VIDEO :
    3.78 -			!strcmp(media, "audio") ? PURPLE_MEDIA_AUDIO : 0;
    3.79 +	PurpleMediaSessionType type;
    3.80 +
    3.81 +	if (media == NULL) {
    3.82 +		purple_debug_warning("jingle-rtp", "missing media type\n");
    3.83 +		return NULL;
    3.84 +	}
    3.85 +
    3.86 +	if (g_str_equal(media, "video")) {
    3.87 +		type = PURPLE_MEDIA_VIDEO;
    3.88 +	} else if (g_str_equal(media, "audio")) {
    3.89 +		type = PURPLE_MEDIA_AUDIO;
    3.90 +	} else {
    3.91 +		purple_debug_warning("jingle-rtp", "unknown media type: %s\n",
    3.92 +				media);
    3.93 +		return NULL;
    3.94 +	}
    3.95  
    3.96  	for (codec_element = xmlnode_get_child(description, "payload-type") ;
    3.97  		 codec_element ;
    3.98 @@ -769,19 +804,19 @@
    3.99  	switch (action) {
   3.100  		case JINGLE_SESSION_ACCEPT:
   3.101  		case JINGLE_SESSION_INITIATE: {
   3.102 -			JingleSession *session = jingle_content_get_session(content);
   3.103 -			JingleTransport *transport = jingle_transport_parse(
   3.104 -					xmlnode_get_child(xmlcontent, "transport"));
   3.105 -			xmlnode *description = xmlnode_get_child(xmlcontent, "description");
   3.106 -			GList *candidates = jingle_rtp_transport_to_candidates(transport);
   3.107 -			GList *codecs = jingle_rtp_parse_codecs(description);
   3.108 -			gchar *name = jingle_content_get_name(content);
   3.109 -			gchar *remote_jid =
   3.110 -					jingle_session_get_remote_jid(session);
   3.111 +			JingleSession *session;
   3.112 +			JingleTransport *transport;
   3.113 +			xmlnode *description;
   3.114 +			GList *candidates;
   3.115 +			GList *codecs;
   3.116 +			gchar *name;
   3.117 +			gchar *remote_jid;
   3.118  			PurpleMedia *media;
   3.119  
   3.120 +			session = jingle_content_get_session(content);
   3.121 +
   3.122  			if (action == JINGLE_SESSION_INITIATE &&
   3.123 -					jingle_rtp_init_media(content) == FALSE) {
   3.124 +					!jingle_rtp_init_media(content)) {
   3.125  				/* XXX: send error */
   3.126  				jabber_iq_send(jingle_session_terminate_packet(
   3.127  						session, "general-error"));
   3.128 @@ -789,6 +824,14 @@
   3.129  				break;
   3.130  			}
   3.131  
   3.132 +			transport = jingle_transport_parse(
   3.133 +					xmlnode_get_child(xmlcontent, "transport"));
   3.134 +			description = xmlnode_get_child(xmlcontent, "description");
   3.135 +			candidates = jingle_rtp_transport_to_candidates(transport);
   3.136 +			codecs = jingle_rtp_parse_codecs(description);
   3.137 +			name = jingle_content_get_name(content);
   3.138 +			remote_jid = jingle_session_get_remote_jid(session);
   3.139 +
   3.140  			media = jingle_rtp_get_media(session);
   3.141  			purple_media_set_remote_codecs(media,
   3.142  					name, remote_jid, codecs);
     4.1 --- a/libpurple/protocols/jabber/jingle/session.c
     4.2 +++ b/libpurple/protocols/jabber/jingle/session.c
     4.3 @@ -288,7 +288,7 @@
     4.4  	if (!js->sessions) {
     4.5  		purple_debug_info("jingle",
     4.6  				"Creating hash table for sessions\n");
     4.7 -		js->sessions = g_hash_table_new(g_str_hash, g_str_equal);
     4.8 +		js->sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
     4.9  	}
    4.10  	purple_debug_info("jingle",
    4.11  			"inserting session with key: %s into table\n", sid);
    4.12 @@ -411,26 +411,24 @@
    4.13  			xmlnode_new("jingle");
    4.14  	gchar *local_jid = jingle_session_get_local_jid(session);
    4.15  	gchar *remote_jid = jingle_session_get_remote_jid(session);
    4.16 +	gchar *sid = jingle_session_get_sid(session);
    4.17  
    4.18  	xmlnode_set_namespace(jingle, JINGLE);
    4.19  	xmlnode_set_attrib(jingle, "action", jingle_get_action_name(action));
    4.20  
    4.21  	if (jingle_session_is_initiator(session)) {
    4.22 -		xmlnode_set_attrib(jingle, "initiator",
    4.23 -				jingle_session_get_local_jid(session));
    4.24 -		xmlnode_set_attrib(jingle, "responder",
    4.25 -				jingle_session_get_remote_jid(session));
    4.26 +		xmlnode_set_attrib(jingle, "initiator", local_jid);
    4.27 +		xmlnode_set_attrib(jingle, "responder", remote_jid);
    4.28  	} else {
    4.29 -		xmlnode_set_attrib(jingle, "initiator",
    4.30 -				jingle_session_get_remote_jid(session));
    4.31 -		xmlnode_set_attrib(jingle, "responder",
    4.32 -				jingle_session_get_local_jid(session));
    4.33 +		xmlnode_set_attrib(jingle, "initiator", remote_jid);
    4.34 +		xmlnode_set_attrib(jingle, "responder", local_jid);
    4.35  	}
    4.36  
    4.37 +	xmlnode_set_attrib(jingle, "sid", sid);
    4.38 +
    4.39  	g_free(local_jid);
    4.40  	g_free(remote_jid);
    4.41 -
    4.42 -	xmlnode_set_attrib(jingle, "sid", jingle_session_get_sid(session));
    4.43 +	g_free(sid);
    4.44  
    4.45  	return jingle;
    4.46  }
    4.47 @@ -508,11 +506,16 @@
    4.48  JingleContent *
    4.49  jingle_session_find_content(JingleSession *session, const gchar *name, const gchar *creator)
    4.50  {
    4.51 -	GList *iter = session->priv->contents;
    4.52 +	GList *iter;
    4.53 +
    4.54 +	if (name == NULL)
    4.55 +		return NULL;
    4.56 +
    4.57 +	iter = session->priv->contents;
    4.58  	for (; iter; iter = g_list_next(iter)) {
    4.59  		JingleContent *content = iter->data;
    4.60  		gchar *cname = jingle_content_get_name(content);
    4.61 -		gboolean result = !strcmp(name, cname);
    4.62 +		gboolean result = g_str_equal(name, cname);
    4.63  		g_free(cname);
    4.64  
    4.65  		if (creator != NULL) {
    4.66 @@ -530,11 +533,16 @@
    4.67  JingleContent *
    4.68  jingle_session_find_pending_content(JingleSession *session, const gchar *name, const gchar *creator)
    4.69  {
    4.70 -	GList *iter = session->priv->pending_contents;
    4.71 +	GList *iter;
    4.72 +
    4.73 +	if (name == NULL)
    4.74 +		return NULL;
    4.75 +
    4.76 +	iter = session->priv->pending_contents;
    4.77  	for (; iter; iter = g_list_next(iter)) {
    4.78  		JingleContent *content = iter->data;
    4.79  		gchar *cname = jingle_content_get_name(content);
    4.80 -		gboolean result = !strcmp(name, cname);
    4.81 +		gboolean result = g_str_equal(name, cname);
    4.82  		g_free(cname);
    4.83  
    4.84  		if (creator != NULL) {