libipsec: Make sure to expire the right SA

If an IPsec SA is actually replaced with a rekeying its entry in the
manager is freed. That means that when the hard expire is triggered a
new entry might be found at the cached pointer location.  So we have
to make sure we trigger the expire only if we found the right SA.

We could use SPI and addresses for the lookup, but this here requires
a bit less memory and is just a small change. Another option would be to
somehow cancel the queued job, but our scheduler doesn't allow that at
the moment.

Fixes #2399.
This commit is contained in:
Tobias Brunner 2017-08-14 16:03:54 +02:00
parent e138003de9
commit 6e861947a0
1 changed files with 9 additions and 2 deletions

View File

@ -106,6 +106,11 @@ typedef struct {
*/
ipsec_sa_entry_t *entry;
/**
* SPI of the expired entry
*/
uint32_t spi;
/**
* 0 if this is a hard expire, otherwise the offset in s (soft->hard)
*/
@ -314,8 +319,9 @@ static job_requeue_t sa_expired(ipsec_sa_expired_t *expired)
private_ipsec_sa_mgr_t *this = expired->manager;
this->mutex->lock(this->mutex);
if (this->sas->find_first(this->sas, NULL, (void**)&expired->entry))
{
if (this->sas->find_first(this->sas, NULL, (void**)&expired->entry) &&
expired->spi == expired->entry->sa->get_spi(expired->entry->sa))
{ /* only if we find the right SA at this pointer location */
uint32_t hard_offset;
hard_offset = expired->hard_offset;
@ -355,6 +361,7 @@ static void schedule_expiration(private_ipsec_sa_mgr_t *this,
INIT(expired,
.manager = this,
.entry = entry,
.spi = entry->sa->get_spi(entry->sa),
);
/* schedule a rekey first, a hard timeout will be scheduled then, if any */