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 <thomas.egerer@secunet.com>
enumerator_t *enumerator;
child_sa_t *child_sa;
status_t status = SUCCESS;
enumerator_t *enumerator;
child_sa_t *child_sa;
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) &&
ike_sa->has_condition(ike_sa, COND_NAT_THERE))
{
if (ike_sa->supports_extension(ike_sa, EXT_MS_WINDOWS) &&
ike_sa->has_condition(ike_sa, COND_NAT_THERE))
* with an "invalid situation" error. We just close the CHILD_SA,
* Windows will reestablish it immediately if required. */
DBG1(DBG_CFG, "resyncing CHILD_SA using a delete");
* with an "invalid situation" error. We just close the CHILD_SA,
* Windows will reestablish it immediately if required. */
DBG1(DBG_CFG, "resyncing CHILD_SA using a delete");
- status = ike_sa->delete_child_sa(ike_sa,
- child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE),
+ status = ike_sa->delete_child_sa(ike_sa, info->protocol, info->spi,
FALSE);
}
else
{
DBG1(DBG_CFG, "resyncing CHILD_SA using a rekey");
FALSE);
}
else
{
DBG1(DBG_CFG, "resyncing CHILD_SA using a rekey");
- status = ike_sa->rekey_child_sa(ike_sa,
- child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE));
+ status = ike_sa->rekey_child_sa(ike_sa, info->protocol, info->spi);
}
if (status == DESTROY_ME)
{
}
if (status == DESTROY_ME)
{
}
}
enumerator->destroy(enumerator);
}
}
enumerator->destroy(enumerator);
+ children->destroy_function(children, free);
+