Blob Blame History Raw
Tue Jun 15 15:00:40 2010  James Cameron  <quozl@laptop.org>

	* pptp_ctrl.c (pptp_conn_is_dead): immediately destroying the
	connection and freeing the structure has led to segmentation
	faults on more recent heap implementations, since we use the
	structure after it has been freed.

	Defer the free of the structure until after all uses of it have
	ceased, by adding a connection state for dead and terminating the
	main loop once it is detected.

--- pptp_callmgr.c	2008-05-14 07:33:55.000000000 +0100
+++ pptp_callmgr.c	2010-06-15 14:32:00.478100392 +0100
@@ -167,6 +170,7 @@
     do {
         int rc;
         fd_set read_set = call_set, write_set;
+        if (pptp_conn_is_dead(conn)) break;
         FD_ZERO (&write_set);
         if (pptp_conn_established(conn)) {
 	  FD_SET (unix_sock, &read_set);
@@ -294,6 +298,7 @@
 	}
         /* with extreme prejudice */
         pptp_conn_destroy(conn);
+        pptp_conn_free(conn);
         vector_destroy(call_list);
     }
 cleanup:
--- pptp_ctrl.c	2008-05-14 07:33:55.000000000 +0100
+++ pptp_ctrl.c	2010-06-15 14:32:00.480100647 +0100
@@ -58,8 +62,11 @@
 struct PPTP_CONN {
     int inet_sock;
     /* Connection States */
-    enum { 
-        CONN_IDLE, CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY, CONN_ESTABLISHED 
+    enum {
+      CONN_IDLE,
+      CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY,
+      CONN_ESTABLISHED,
+      CONN_DEAD
     } conn_state; /* on startup: CONN_IDLE */
     /* Keep-alive states */
     enum { 
@@ -448,6 +457,16 @@
     close(conn->inet_sock);
     /* deallocate */
     vector_destroy(conn->call);
+    conn->conn_state = CONN_DEAD;
+}
+
+int pptp_conn_is_dead(PPTP_CONN * conn)
+{
+    return conn->conn_state == CONN_DEAD;
+}
+
+void pptp_conn_free(PPTP_CONN * conn)
+{
     free(conn);
 }
 
@@ -1038,11 +1059,13 @@
     int i;
     /* "Keep Alives and Timers, 1": check connection state */
     if (global.conn->conn_state != CONN_ESTABLISHED) {
-        if (global.conn->conn_state == CONN_WAIT_STOP_REPLY) 
+        if (global.conn->conn_state == CONN_WAIT_STOP_REPLY) {
             /* hard close. */
             pptp_conn_destroy(global.conn);
-        else /* soft close */
-            pptp_conn_close(global.conn, PPTP_STOP_NONE);
+            return;
+        }
+        /* soft close */
+        pptp_conn_close(global.conn, PPTP_STOP_NONE);
     }
     /* "Keep Alives and Timers, 2": check echo status */
     if (global.conn->ka_state == KA_OUTSTANDING) {
--- pptp_ctrl.h	2008-05-14 07:33:55.000000000 +0100
+++ pptp_ctrl.h	2010-06-15 14:32:00.864975405 +0100
@@ -33,6 +33,8 @@
 void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call);
 /* hard close. */
 void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call);
+int pptp_conn_is_dead(PPTP_CONN * conn);
+void pptp_conn_free(PPTP_CONN * conn);
 /* soft close.  Will callback on completion. */
 void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason);
 /* hard close */