eap-simaka-pseudonym: Prevent corrupting hashtables during concurrent accesses

This also protects access to the RNG, which is not always thread-safe.

Fixes: edcb2dd35b ("Moved reauth/pseudonym functionality from eap-sim-file to separate plugins, usable by any SIM/AKA backend")
This commit is contained in:
Tobias Brunner
2026-07-23 10:26:08 +02:00
parent e53e2c7ff6
commit 0b5143ae04
@@ -18,6 +18,7 @@
#include <utils/debug.h> #include <utils/debug.h>
#include <collections/hashtable.h> #include <collections/hashtable.h>
#include <threading/rwlock.h>
typedef struct private_eap_simaka_pseudonym_provider_t private_eap_simaka_pseudonym_provider_t; typedef struct private_eap_simaka_pseudonym_provider_t private_eap_simaka_pseudonym_provider_t;
@@ -45,6 +46,11 @@ struct private_eap_simaka_pseudonym_provider_t {
* RNG for pseudonyms/reauth identities * RNG for pseudonyms/reauth identities
*/ */
rng_t *rng; rng_t *rng;
/**
* Lock for pseudonym mappings
*/
rwlock_t *lock;
}; };
/** /**
@@ -68,12 +74,14 @@ METHOD(simaka_provider_t, is_pseudonym, identification_t*,
{ {
identification_t *permanent; identification_t *permanent;
this->lock->read_lock(this->lock);
permanent = this->permanent->get(this->permanent, id); permanent = this->permanent->get(this->permanent, id);
if (permanent) if (permanent)
{ {
return permanent->clone(permanent); permanent = permanent->clone(permanent);
} }
return NULL; this->lock->unlock(this->lock);
return permanent;
} }
/** /**
@@ -98,6 +106,8 @@ METHOD(simaka_provider_t, gen_pseudonym, identification_t*,
{ {
identification_t *pseudonym, *permanent; identification_t *pseudonym, *permanent;
this->lock->write_lock(this->lock);
/* remove old entry */ /* remove old entry */
pseudonym = this->pseudonym->remove(this->pseudonym, id); pseudonym = this->pseudonym->remove(this->pseudonym, id);
if (pseudonym) if (pseudonym)
@@ -113,6 +123,7 @@ METHOD(simaka_provider_t, gen_pseudonym, identification_t*,
pseudonym = gen_identity(this); pseudonym = gen_identity(this);
if (!pseudonym) if (!pseudonym)
{ {
this->lock->unlock(this->lock);
DBG1(DBG_CFG, "failed to generate pseudonym"); DBG1(DBG_CFG, "failed to generate pseudonym");
return NULL; return NULL;
} }
@@ -121,8 +132,10 @@ METHOD(simaka_provider_t, gen_pseudonym, identification_t*,
id = id->clone(id); id = id->clone(id);
this->pseudonym->put(this->pseudonym, id, pseudonym); this->pseudonym->put(this->pseudonym, id, pseudonym);
this->permanent->put(this->permanent, pseudonym, id); this->permanent->put(this->permanent, pseudonym, id);
pseudonym = pseudonym->clone(pseudonym);
return pseudonym->clone(pseudonym); this->lock->unlock(this->lock);
return pseudonym;
} }
METHOD(eap_simaka_pseudonym_provider_t, destroy, void, METHOD(eap_simaka_pseudonym_provider_t, destroy, void,
@@ -148,7 +161,8 @@ METHOD(eap_simaka_pseudonym_provider_t, destroy, void,
this->pseudonym->destroy(this->pseudonym); this->pseudonym->destroy(this->pseudonym);
this->permanent->destroy(this->permanent); this->permanent->destroy(this->permanent);
this->rng->destroy(this->rng); this->lock->destroy(this->lock);
DESTROY_IF(this->rng);
free(this); free(this);
} }
@@ -172,16 +186,16 @@ eap_simaka_pseudonym_provider_t *eap_simaka_pseudonym_provider_create()
}, },
.destroy = _destroy, .destroy = _destroy,
}, },
.pseudonym = hashtable_create((void*)hash, (void*)equals, 0),
.permanent = hashtable_create((void*)hash, (void*)equals, 0),
.rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK), .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
); );
if (!this->rng) if (!this->rng)
{ {
free(this); destroy(this);
return NULL; return NULL;
} }
this->pseudonym = hashtable_create((void*)hash, (void*)equals, 0);
this->permanent = hashtable_create((void*)hash, (void*)equals, 0);
return &this->public; return &this->public;
} }