diff options
Diffstat (limited to 'src/libcharon/sa/tasks/child_rekey.c')
-rw-r--r-- | src/libcharon/sa/tasks/child_rekey.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c index fb3452efd..fdaaea4b8 100644 --- a/src/libcharon/sa/tasks/child_rekey.c +++ b/src/libcharon/sa/tasks/child_rekey.c @@ -75,6 +75,15 @@ struct private_child_rekey_t { * colliding task, may be delete or rekey */ task_t *collision; + + /** + * Indicate that peer destroyed the redundant child from collision. + * This happens if a peer's delete notification for the redundant + * child gets processed before the rekey job. If so, we must not + * touch the child created in the collision since it points to + * memory already freed. + */ + bool other_child_destroyed; }; /** @@ -239,9 +248,13 @@ static child_sa_t *handle_collision(private_child_rekey_t *this) DBG1(DBG_IKE, "CHILD_SA rekey collision won, " "deleting rekeyed child"); to_delete = this->child_sa; - /* disable close action for the redundand child */ - child_sa = other->child_create->get_child(other->child_create); - child_sa->set_close_action(child_sa, ACTION_NONE); + /* don't touch child other created, it has already been deleted */ + if (!this->other_child_destroyed) + { + /* disable close action for the redundand child */ + child_sa = other->child_create->get_child(other->child_create); + child_sa->set_close_action(child_sa, ACTION_NONE); + } } else { @@ -286,7 +299,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) DBG1(DBG_IKE, "peer seems to not support CHILD_SA rekeying, " "starting reauthentication"); this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - charon->processor->queue_job(charon->processor, + lib->processor->queue_job(lib->processor, (job_t*)rekey_ike_sa_job_create( this->ike_sa->get_id(this->ike_sa), TRUE)); return SUCCESS; @@ -316,7 +329,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) DBG1(DBG_IKE, "CHILD_SA rekeying failed, " "trying again in %d seconds", retry); this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - charon->scheduler->schedule_job(charon->scheduler, job, retry); + lib->scheduler->schedule_job(lib->scheduler, job, retry); } return SUCCESS; } @@ -380,6 +393,13 @@ static void collide(private_child_rekey_t *this, task_t *other) else if (other->get_type(other) == CHILD_DELETE) { child_delete_t *del = (child_delete_t*)other; + if (del->get_child(del) == this->child_create->get_child(this->child_create)) + { + /* peer deletes redundant child created in collision */ + this->other_child_destroyed = TRUE; + other->destroy(other); + return; + } if (del == NULL || del->get_child(del) != this->child_sa) { /* not the same child => no collision */ @@ -466,6 +486,7 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, this->spi = spi; this->collision = NULL; this->child_delete = NULL; + this->other_child_destroyed = FALSE; return &this->public; } |