ike-sa-manager: Safely access the RNG instance with an rwlock

Threads might still be allocating SPIs (e.g. triggered by an acquire or
an inbound message) while the main thread calls flush().  If there is a
context switch right after such a thread successfully checked this->rng
in get_spi() and the main thread destroys the RNG instance right then,
that worker thread will cause a segmentation fault when it continues and
attempts to call get_bytes().

Fixes #1014.
This commit is contained in:
Tobias Brunner 2015-07-08 15:28:46 +02:00
parent 856ea64129
commit 390ae7a2c2
1 changed files with 16 additions and 5 deletions

View File

@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2011 Martin Willi
* Copyright (C) 2011 revosec AG
* Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2008-2015 Tobias Brunner
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@ -383,6 +383,11 @@ struct private_ike_sa_manager_t {
*/
rng_t *rng;
/**
* Lock to access the RNG instance
*/
rwlock_t *rng_lock;
/**
* reuse existing IKE_SAs in checkout_by_config
*/
@ -943,12 +948,14 @@ static u_int64_t get_spi(private_ike_sa_manager_t *this)
{
u_int64_t spi;
if (this->rng &&
this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi))
this->rng_lock->read_lock(this->rng_lock);
if (!this->rng ||
!this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi))
{
return spi;
spi = 0;
}
return 0;
this->rng_lock->unlock(this->rng_lock);
return spi;
}
/**
@ -2055,8 +2062,10 @@ METHOD(ike_sa_manager_t, flush, void,
charon->bus->set_sa(charon->bus, NULL);
unlock_all_segments(this);
this->rng_lock->write_lock(this->rng_lock);
this->rng->destroy(this->rng);
this->rng = NULL;
this->rng_lock->unlock(this->rng_lock);
}
METHOD(ike_sa_manager_t, destroy, void,
@ -2081,6 +2090,7 @@ METHOD(ike_sa_manager_t, destroy, void,
free(this->connected_peers_segments);
free(this->init_hashes_segments);
this->rng_lock->destroy(this->rng_lock);
free(this);
}
@ -2138,6 +2148,7 @@ ike_sa_manager_t *ike_sa_manager_create()
free(this);
return NULL;
}
this->rng_lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
this->ikesa_limit = lib->settings->get_int(lib->settings,
"%s.ikesa_limit", 0, lib->ns);