fixed a use-after-free bug in dpd_timeout()
authorAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 10 Mar 2009 21:13:18 +0000 (21:13 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 10 Mar 2009 21:13:18 +0000 (21:13 -0000)
src/pluto/connections.c
src/pluto/ipsec_doi.c
src/pluto/state.c

index 941c6ad..0dbabd9 100644 (file)
@@ -2995,6 +2995,8 @@ terminate_connection(const char *nm)
            c->policy &= ~POLICY_UP;
            flush_pending_by_connection(c);
            delete_states_by_connection(c, FALSE);
+           if (c->kind == CK_INSTANCE)
+               delete_connection(c, FALSE);
            reset_cur_connection();
        }
        c = n;
index d680005..b59fe3c 100644 (file)
@@ -5592,6 +5592,7 @@ dpd_timeout(struct state *st)
     struct state *newest_phase1_st;
     struct connection *c = st->st_connection;
     int action = st->st_connection->dpd_action;
+    char cname[BUF_LEN];
 
     passert(action == DPD_ACTION_HOLD
         || action == DPD_ACTION_CLEAR
@@ -5622,20 +5623,30 @@ dpd_timeout(struct state *st)
         * leak traffic.  Also, being in %trap means new packets will
         * force an initiation of the conn again.
         */
-       loglog(RC_LOG_SERIOUS, "DPD: Putting connection into %%trap");
+       loglog(RC_LOG_SERIOUS, "DPD: Putting connection \"%s\" into %%trap", c->name);
+       if (c->kind == CK_INSTANCE)
+           delete_connection(c, TRUE);
        break;
     case DPD_ACTION_CLEAR:
        /* dpdaction=clear - Wipe the SA & eroute - everything */
-        loglog(RC_LOG_SERIOUS, "DPD: Clearing connection");
+        loglog(RC_LOG_SERIOUS, "DPD: Clearing connection \"%s\"", c->name);
         unroute_connection(c);
+       if (c->kind == CK_INSTANCE)
+           delete_connection(c, TRUE);
        break;
     case DPD_ACTION_RESTART:
        /* dpdaction=restart - Restart connection,
         * except if roadwarrior connection
         */
-       loglog(RC_LOG_SERIOUS, "DPD: Restarting connection");
+       loglog(RC_LOG_SERIOUS, "DPD: Restarting connection \"%s\"", c->name);
        unroute_connection(c);
-       initiate_connection(c->name, NULL_FD);
+
+       /* caching the connection name before deletion */
+       strncpy(cname, c->name, BUF_LEN);
+
+       if (c->kind == CK_INSTANCE)
+           delete_connection(c, TRUE);
+       initiate_connection(cname, NULL_FD);
        break;
     default:
        loglog(RC_LOG_SERIOUS, "DPD: unknown action");
index 273038f..d1587a1 100644 (file)
@@ -464,12 +464,7 @@ delete_states_by_connection(struct connection *c, bool relations)
        passert(sr->routing != RT_ROUTED_TUNNEL);
        sr = sr->next;
     }
-
-    if (ck == CK_INSTANCE)
-    {
-       c->kind = ck;
-       delete_connection(c, relations);
-    }
+    c->kind = ck;
 }
 
 /* Walk through the state table, and delete each state whose phase 1 (IKE)
@@ -506,6 +501,8 @@ delete_states_by_peer(ip_address *peer)
                         , peerstr
                         , c->name);
                    delete_states_by_connection(c, TRUE);
+                   if (c->kind == CK_INSTANCE)
+                       delete_connection(c, TRUE);
                    break;      /* can only delete it once */
                }
            }