From 390ae7a2c2f899122e722241cb261f53dfc81b9a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 8 Jul 2015 15:28:46 +0200 Subject: [PATCH] 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. --- src/libcharon/sa/ike_sa_manager.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 938f784..987260d 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -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 * @@ -384,6 +384,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 */ bool reuse_ikesa; @@ -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); -- 2.4.6