ha: Perform child rekeying outside of CHILD_SA enumerator
When rekey_child_sa is called while enumerating the children of an IKE_SA, and the child to be rekeyed is redundant a QUICK_DELETE task is queued instead of a QUICK_MODE task. This alters the IKE_SA's list of children (ike_sa_t::child_sas) invalidating the current element of the child_sa_enumerator. The enumerate function of linked_list_t will then advance to an element with unpredictable contents most likely resulting in an segmentation violation. A similar behavior should be observed when delete_child_sa is called. This patch creates a list of protocol/spi values while holding the child_sa_enumerator and performs the rekeying (deletion of redundant) chlidren after releasing the enumerator. Signed-off-by: Thomas Egerer <[email protected]>
This commit is contained in:
committed by
Martin Willi
parent
5cc0b23886
commit
875f7be5fc
@@ -196,9 +196,26 @@ static status_t rekey_children(ike_sa_t *ike_sa)
|
|||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
status_t status = SUCCESS;
|
status_t status = SUCCESS;
|
||||||
|
linked_list_t *children;
|
||||||
|
struct {
|
||||||
|
protocol_id_t protocol;
|
||||||
|
u_int32_t spi;
|
||||||
|
} *info;
|
||||||
|
|
||||||
|
children = linked_list_create();
|
||||||
enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
|
enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
|
||||||
while (enumerator->enumerate(enumerator, (void**)&child_sa))
|
while (enumerator->enumerate(enumerator, &child_sa))
|
||||||
|
{
|
||||||
|
INIT(info,
|
||||||
|
.protocol = child_sa->get_protocol(child_sa),
|
||||||
|
.spi = child_sa->get_spi(child_sa, TRUE),
|
||||||
|
);
|
||||||
|
children->insert_last(children, info);
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
enumerator = children->create_enumerator(children);
|
||||||
|
while (enumerator->enumerate(enumerator, &info))
|
||||||
{
|
{
|
||||||
if (ike_sa->supports_extension(ike_sa, EXT_MS_WINDOWS) &&
|
if (ike_sa->supports_extension(ike_sa, EXT_MS_WINDOWS) &&
|
||||||
ike_sa->has_condition(ike_sa, COND_NAT_THERE))
|
ike_sa->has_condition(ike_sa, COND_NAT_THERE))
|
||||||
@@ -207,17 +224,13 @@ static status_t rekey_children(ike_sa_t *ike_sa)
|
|||||||
* with an "invalid situation" error. We just close the CHILD_SA,
|
* with an "invalid situation" error. We just close the CHILD_SA,
|
||||||
* Windows will reestablish it immediately if required. */
|
* Windows will reestablish it immediately if required. */
|
||||||
DBG1(DBG_CFG, "resyncing CHILD_SA using a delete");
|
DBG1(DBG_CFG, "resyncing CHILD_SA using a delete");
|
||||||
status = ike_sa->delete_child_sa(ike_sa,
|
status = ike_sa->delete_child_sa(ike_sa, info->protocol, info->spi,
|
||||||
child_sa->get_protocol(child_sa),
|
|
||||||
child_sa->get_spi(child_sa, TRUE),
|
|
||||||
FALSE);
|
FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "resyncing CHILD_SA using a rekey");
|
DBG1(DBG_CFG, "resyncing CHILD_SA using a rekey");
|
||||||
status = ike_sa->rekey_child_sa(ike_sa,
|
status = ike_sa->rekey_child_sa(ike_sa, info->protocol, info->spi);
|
||||||
child_sa->get_protocol(child_sa),
|
|
||||||
child_sa->get_spi(child_sa, TRUE));
|
|
||||||
}
|
}
|
||||||
if (status == DESTROY_ME)
|
if (status == DESTROY_ME)
|
||||||
{
|
{
|
||||||
@@ -225,6 +238,8 @@ static status_t rekey_children(ike_sa_t *ike_sa)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
children->destroy_function(children, free);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user