diff options
| author | dequis <dx@dxzone.com.ar> | 2016-02-18 08:17:08 -0300 | 
|---|---|---|
| committer | dequis <dx@dxzone.com.ar> | 2016-02-18 08:17:08 -0300 | 
| commit | 242f280339195f878973dd7f1e8c3e9233d61c0a (patch) | |
| tree | 032780ae77033179b4129cb3f4159ed3cd2ad747 /lib/proxy.c | |
| parent | 94562555d64001fc5517b328d1c8b8493dfd09cd (diff) | |
Fix a double free when calling proxy_disconnect() inside phb->func()
Fixes trac ticket #1248
proxy_connected() calls phb->func(), then tries to do phb_free() directly
afterwards, but that might have been freed by a proxy_disconnect() call
during the execution of that callback.
This one happened to several different people because some AIM server
broke recently.
This commit fixes it by implementing a phb_connected() function that
removes the PHB from the hash table before calling phb->func(), which
ensures that any proxy_disconnect() calls just close the fd and nothing
else.
Diffstat (limited to 'lib/proxy.c')
| -rw-r--r-- | lib/proxy.c | 31 | 
1 files changed, 23 insertions, 8 deletions
diff --git a/lib/proxy.c b/lib/proxy.c index 61a89f59..44ab7f5d 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -86,6 +86,25 @@ static gboolean phb_free(struct PHB *phb, gboolean success)  	return FALSE;  } +/* calls phb->func safely by ensuring that the phb struct doesn't exist in the + * case that proxy_disconnect() is called down there */ +static gboolean phb_connected(struct PHB *phb, gint source) +{ +	/* save func and data here */ +	b_event_handler func = phb->func; +	gpointer data = phb->data; + +	/* free the struct so that it can't be freed by the callback */ +	phb_free(phb, TRUE); + +	/* if any proxy_disconnect() call happens here, it will use the +	 * fd (still open), look it up in the hash table, get NULL, and +	 * proceed to close the fd and do nothing else */ +	func(data, source, B_EV_IO_READ); + +	return FALSE; +} +  static gboolean proxy_connected(gpointer data, gint source, b_input_condition cond)  {  	struct PHB *phb = data; @@ -124,8 +143,7 @@ static gboolean proxy_connected(gpointer data, gint source, b_input_condition co  	if (phb->proxy_func) {  		phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ);  	} else { -		phb->func(phb->data, source, B_EV_IO_READ); -		phb_free(phb, TRUE); +		phb_connected(phb, source);  	}  	return FALSE; @@ -221,8 +239,7 @@ static gboolean http_canread(gpointer data, gint source, b_input_condition cond)  	if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) ||  	    (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { -		phb->func(phb->data, source, B_EV_IO_READ); -		return phb_free(phb, TRUE); +		return phb_connected(phb, source);  	}  	return phb_free(phb, FALSE); @@ -294,8 +311,7 @@ static gboolean s4_canread(gpointer data, gint source, b_input_condition cond)  	memset(packet, 0, sizeof(packet));  	if (read(source, packet, 9) >= 4 && packet[1] == 90) { -		phb->func(phb->data, source, B_EV_IO_READ); -		return phb_free(phb, TRUE); +		return phb_connected(phb, source);  	}  	return phb_free(phb, FALSE); @@ -383,8 +399,7 @@ static gboolean s5_canread_again(gpointer data, gint source, b_input_condition c  		return phb_free(phb, FALSE);  	} -	phb->func(phb->data, source, B_EV_IO_READ); -	return phb_free(phb, TRUE); +	return phb_connected(phb, source);  }  static void s5_sendconnect(gpointer data, gint source)  | 
