mirror of
https://github.com/Mbed-TLS/mbedtls-framework.git
synced 2026-06-05 21:15:09 +00:00
Support mutex API type being separate from the platform type
The way the mutex usage verification framework plugs into the library requires it to have access to the API type, which holds the state field. In the new threading API, the mutable function that the framework overrides now only receives a pointer to the platform object that is embedded in the API object. Hence we need to calculate a pointer to the containing API object when given a pointer to the platform object. It's ugly, but it works. A follow-up should clean this up by changing how the mutex usage verification framework plugs into the library. It should use a more normal hook function mechanism instead of replacing the function pointers. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
@@ -23,7 +23,32 @@
|
||||
#define mbedtls_mutex_free_ptr mbedtls_mutex_free
|
||||
#define mbedtls_mutex_lock_ptr mbedtls_mutex_lock
|
||||
#define mbedtls_mutex_unlock_ptr mbedtls_mutex_unlock
|
||||
#endif
|
||||
|
||||
typedef mbedtls_threading_mutex_t mbedtls_platform_mutex_t;
|
||||
#define mutex_container(platform_mutex) (platform_mutex)
|
||||
|
||||
#else /* MBEDTLS_THREADING_INTERNAL_VERSION >= 0x04000000 */
|
||||
|
||||
/* Historically, the mutex platform functions received a pointer to the
|
||||
* mbedtls_threading_mutex_t object, and the pthread implementation of
|
||||
* that type had a state field. Now the platform functions receive a pointer
|
||||
* to the mbedtls_platform_mutex_t object which is a field of the
|
||||
* mbedtls_threading_mutex_t object. Get a pointer to the containing
|
||||
* object which holds the state field.
|
||||
*
|
||||
* This weird arrangement was done to minimize changes when switching the
|
||||
* mutex usage framework to the separated platform/API types. In the future
|
||||
* we should clean up how the usage framework fits into the library.
|
||||
*/
|
||||
static mbedtls_threading_mutex_t *mutex_container(
|
||||
mbedtls_platform_mutex_t *platform_mutex)
|
||||
{
|
||||
unsigned char *field_address = (unsigned char *) platform_mutex;
|
||||
size_t offset = offsetof(mbedtls_threading_mutex_t, mutex);
|
||||
return (mbedtls_threading_mutex_t *) (field_address - offset);
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_THREADING_INTERNAL_VERSION */
|
||||
|
||||
#if defined(MBEDTLS_THREADING_PTHREAD)
|
||||
|
||||
@@ -148,10 +173,10 @@ enum value_of_mutex_state_field {
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
void (*init)(mbedtls_threading_mutex_t *);
|
||||
void (*free)(mbedtls_threading_mutex_t *);
|
||||
int (*lock)(mbedtls_threading_mutex_t *);
|
||||
int (*unlock)(mbedtls_threading_mutex_t *);
|
||||
void (*init)(mbedtls_platform_mutex_t *);
|
||||
void (*free)(mbedtls_platform_mutex_t *);
|
||||
int (*lock)(mbedtls_platform_mutex_t *);
|
||||
int (*unlock)(mbedtls_platform_mutex_t *);
|
||||
} mutex_functions_t;
|
||||
static mutex_functions_t mutex_functions;
|
||||
|
||||
@@ -171,7 +196,7 @@ static mutex_functions_t mutex_functions;
|
||||
* testing. This is not a situation that is likely to happen with normal
|
||||
* testing and we still have TSan to fall back on should this happen.
|
||||
*/
|
||||
mbedtls_threading_mutex_t mbedtls_test_mutex_mutex;
|
||||
mbedtls_platform_mutex_t mbedtls_test_mutex_mutex;
|
||||
|
||||
/**
|
||||
* The total number of calls to mbedtls_mutex_init(), minus the total number
|
||||
@@ -182,7 +207,7 @@ mbedtls_threading_mutex_t mbedtls_test_mutex_mutex;
|
||||
*/
|
||||
static int live_mutexes;
|
||||
|
||||
static void mbedtls_test_mutex_usage_error(mbedtls_threading_mutex_t *mutex,
|
||||
static void mbedtls_test_mutex_usage_error(mbedtls_platform_mutex_t *mutex,
|
||||
const char *msg)
|
||||
{
|
||||
(void) mutex;
|
||||
@@ -195,7 +220,7 @@ static void mbedtls_test_mutex_usage_error(mbedtls_threading_mutex_t *mutex,
|
||||
* mbedtls_test_mutex_usage_check() will mark it as failed. */
|
||||
}
|
||||
|
||||
static int mbedtls_test_mutex_can_test(mbedtls_threading_mutex_t *mutex)
|
||||
static int mbedtls_test_mutex_can_test(mbedtls_platform_mutex_t *mutex)
|
||||
{
|
||||
/* If we attempt to run tests on this mutex then we are going to run into a
|
||||
* couple of problems:
|
||||
@@ -203,20 +228,20 @@ static int mbedtls_test_mutex_can_test(mbedtls_threading_mutex_t *mutex)
|
||||
* reporting that failure, as we already hold the mutex at that point.
|
||||
* 2. Given the 'global' position of the initialization and free of this
|
||||
* mutex, it will be shown as leaked on the first test run. */
|
||||
if (mutex == mbedtls_test_get_info_mutex()) {
|
||||
if (mutex_container(mutex) == mbedtls_test_get_info_mutex()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void mbedtls_test_wrap_mutex_init(mbedtls_threading_mutex_t *mutex)
|
||||
static void mbedtls_test_wrap_mutex_init(mbedtls_platform_mutex_t *mutex)
|
||||
{
|
||||
mutex_functions.init(mutex);
|
||||
|
||||
if (mbedtls_test_mutex_can_test(mutex)) {
|
||||
if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
|
||||
mutex->state = MUTEX_IDLE;
|
||||
mutex_container(mutex)->state = MUTEX_IDLE;
|
||||
++live_mutexes;
|
||||
|
||||
mutex_functions.unlock(&mbedtls_test_mutex_mutex);
|
||||
@@ -224,17 +249,17 @@ static void mbedtls_test_wrap_mutex_init(mbedtls_threading_mutex_t *mutex)
|
||||
}
|
||||
}
|
||||
|
||||
static void mbedtls_test_wrap_mutex_free(mbedtls_threading_mutex_t *mutex)
|
||||
static void mbedtls_test_wrap_mutex_free(mbedtls_platform_mutex_t *mutex)
|
||||
{
|
||||
if (mbedtls_test_mutex_can_test(mutex)) {
|
||||
if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
|
||||
|
||||
switch (mutex->state) {
|
||||
switch (mutex_container(mutex)->state) {
|
||||
case MUTEX_FREED:
|
||||
mbedtls_test_mutex_usage_error(mutex, "free without init or double free");
|
||||
break;
|
||||
case MUTEX_IDLE:
|
||||
mutex->state = MUTEX_FREED;
|
||||
mutex_container(mutex)->state = MUTEX_FREED;
|
||||
--live_mutexes;
|
||||
break;
|
||||
case MUTEX_LOCKED:
|
||||
@@ -252,7 +277,7 @@ static void mbedtls_test_wrap_mutex_free(mbedtls_threading_mutex_t *mutex)
|
||||
mutex_functions.free(mutex);
|
||||
}
|
||||
|
||||
static int mbedtls_test_wrap_mutex_lock(mbedtls_threading_mutex_t *mutex)
|
||||
static int mbedtls_test_wrap_mutex_lock(mbedtls_platform_mutex_t *mutex)
|
||||
{
|
||||
/* Lock the passed in mutex first, so that the only way to change the state
|
||||
* is to hold the passed in and internal mutex - otherwise we create a race
|
||||
@@ -261,13 +286,13 @@ static int mbedtls_test_wrap_mutex_lock(mbedtls_threading_mutex_t *mutex)
|
||||
|
||||
if (mbedtls_test_mutex_can_test(mutex)) {
|
||||
if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
|
||||
switch (mutex->state) {
|
||||
switch (mutex_container(mutex)->state) {
|
||||
case MUTEX_FREED:
|
||||
mbedtls_test_mutex_usage_error(mutex, "lock without init");
|
||||
break;
|
||||
case MUTEX_IDLE:
|
||||
if (ret == 0) {
|
||||
mutex->state = MUTEX_LOCKED;
|
||||
mutex_container(mutex)->state = MUTEX_LOCKED;
|
||||
}
|
||||
break;
|
||||
case MUTEX_LOCKED:
|
||||
@@ -285,14 +310,14 @@ static int mbedtls_test_wrap_mutex_lock(mbedtls_threading_mutex_t *mutex)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mbedtls_test_wrap_mutex_unlock(mbedtls_threading_mutex_t *mutex)
|
||||
static int mbedtls_test_wrap_mutex_unlock(mbedtls_platform_mutex_t *mutex)
|
||||
{
|
||||
/* Lock the internal mutex first and change state, so that the only way to
|
||||
* change the state is to hold the passed in and internal mutex - otherwise
|
||||
* we create a race condition. */
|
||||
if (mbedtls_test_mutex_can_test(mutex)) {
|
||||
if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
|
||||
switch (mutex->state) {
|
||||
switch (mutex_container(mutex)->state) {
|
||||
case MUTEX_FREED:
|
||||
mbedtls_test_mutex_usage_error(mutex, "unlock without init");
|
||||
break;
|
||||
@@ -300,7 +325,7 @@ static int mbedtls_test_wrap_mutex_unlock(mbedtls_threading_mutex_t *mutex)
|
||||
mbedtls_test_mutex_usage_error(mutex, "unlock without lock");
|
||||
break;
|
||||
case MUTEX_LOCKED:
|
||||
mutex->state = MUTEX_IDLE;
|
||||
mutex_container(mutex)->state = MUTEX_IDLE;
|
||||
break;
|
||||
default:
|
||||
mbedtls_test_mutex_usage_error(mutex, "corrupted state");
|
||||
|
||||
Reference in New Issue
Block a user