-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mbed TLS: threading support - DRAFT - Do not merge #3150
Conversation
Please send this to the master branch. I'll label this as "do not merge" for the time being. |
This is an implementation of mbed TLS threading abstraction layer using RTOS mutexes. Design decisions: - The is_valid flag is not checked in the init function, because it is a chance that an uninitialised variable has the value of one (it is a small chance, but it would result in incorrect behaviour) - The checks on the is_valid flag are not abbreviated because an uninitialised variable is nonzero in most of the cases - The type of a mutex is a pointer to void and not an incomplete struct, because we use definitions with mbedtls_threading_mutex_t in the library - There is a wrapper for mbedtls_threading_set_alt to make it more user friendly and to enable the use of static functions
4cfdf7e
to
66a97c7
Compare
I have retested after the rebase on a K64F manually. |
Defining threading support impacts application code, therefore the corresponding macros shouldn't be defined by default they should be turned on in the application specific configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't ready for merging yet and needs rework.
/* | ||
* Enable mbed TLS to use mbed OS mutexes | ||
*/ | ||
#if defined(MBEDTLS_THREADING) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With MBEDTLS_THREADING
we're effectively defining a new mbed OS macro to control mbed TLS. I would like to put it in a separate namespace from the normal mbed TLS configuration macros to make it more obvious.
Could we use something like TLS_CONFIG_XXXX
? I'm open to ideas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of separating the namespaces. If we decide to do it, then I think we should be careful and stay consistent while doing so. For example, we should rename the hardware acceleration macro accordingly (now it is still in the library's namespace MBEDTLS_HW_SUPPORT
)
I would suggest the MBED_TLS_
prefix. This way we can take into account that mbed TLS won't always be the TLS stack in an mbed OS application, respect the application developers choice and avoid confusions. I would omit the CONFIG
part, because feel it a little bit redundant, since the aim of all of these macros is to configure the mbed TLS library within mbed OS. Also I think that if the macro names are shorter, then they are less intimidating and easier to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to this, threading is turned off by default? While I can see some of the benefits for this to happen, I would prefer to have the opposite default behaviour. Furthermore, I am not sure why we need the MBEDTLS_THREADING
macro at all, it only seems to be a short hand for two defines i.e. MBEDTLS_THREADING_C
and MBEDTLS_THREADING_ALT
that would have to be declared somewhere anyways. I would prefer if the user just had to define/undefine the macros manually in the mbedtls user config. Also this would enable us to remove the MBEDTLS_THREADING
macro.
return; | ||
|
||
delete mutex->mutex; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to add mutex->mutex = NULL;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am sorry but I can't see any scenario where this would make any difference. Could you please give an example when it might be useful to set that pointer to NULL
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just good defensive programming, and shouldn't need justification.
However - a scenario - imagine initialising the library, then tearing it down, because the application software encounters an error. The software then tries restarting the library, and because the mutex is statically allocated it and is only zeroed at boot, it will still contain the pointer to the old mutex. On calling threading_mutex_init_mbed()
nothing is allocated because it's already non-zero - but the pointer is stale.
Now expect a failure.
This is artificial and may not work in real life - but the point remains - it's good practice to zero it after use.
{ | ||
if( mutex == NULL || mutex->is_valid != true ) | ||
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're checking if mutex
is NULL
, but you should also check if mutex->mutex
is NULL
just to be safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the only case mutex->mutex
can be NULL
is when
mutex
is uninitialised OR- the memory is corrupted / the structure has been accessed with some means other than these functions
In these cases if we suppose that the memory content is uniformly distributed, then the chance of not catching this with is_valid
is 1:2^8 and therefore detecting this by checking for NULL
is 1:2^40 or 1:2^72, depending on the architecture (it can be higher on architectures with smaller address space).
The check probably wouldn't help against an active adversary at all, because an active adversary would probably set the pointer value to something other than NULL
if he can.
I think if we want to make it more robust then changing the type of is_valid
to int
would be much more effective, than adding this check for NULL
.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this is defensive programming to me. However, the case for testing for NULL
is much weaker, because as you say, the chance of the pointer being NULL
is logically improbable. I can accept not making the change.
{ | ||
if( mutex == NULL || mutex->is_valid != true ) | ||
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, you're checking if mutex
is NULL
, but you should also check if mutex->mutex
is NULL
just to be safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a same concerns here as I had above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments as above.
return( 0 ); | ||
} | ||
|
||
void mbedtls_threading_set_mbed( void ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this function is confusingly named, and I'd prefer we didn't have it. Really the library should self-configure and this function causes life time issues, because now something has to call it during initialisation to allow the library to use the primitives. Currently the caller would be the mbed OS application developer - and that is unacceptable as it means we're adding a breaking API change that extends the mbed TLS library interface, but is also outside the library.
This is a library problem, which I'll raise separately and will need to be fixed elsewhere before we can merge this PR.
Back to the point - while we have to have the function, can we call it something like mbedtls_rtx_threading_init()
?
_rtx_
because we're using the RTX primitives, and _init
because it's more natural than _set_alt()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As @sbutcher-arm mentioned, this is needed because of a library problem and should be fixed before the threading PR is merged.
/* | ||
* Enable mbed TLS to use mbed OS mutexes | ||
*/ | ||
#if defined(MBEDTLS_THREADING) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to this, threading is turned off by default? While I can see some of the benefits for this to happen, I would prefer to have the opposite default behaviour. Furthermore, I am not sure why we need the MBEDTLS_THREADING
macro at all, it only seems to be a short hand for two defines i.e. MBEDTLS_THREADING_C
and MBEDTLS_THREADING_ALT
that would have to be declared somewhere anyways. I would prefer if the user just had to define/undefine the macros manually in the mbedtls user config. Also this would enable us to remove the MBEDTLS_THREADING
macro.
void* mutex; | ||
char is_valid; | ||
} mbedtls_threading_mutex_t; | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add the comment next to the #endif
with the condition of the matching #if
?
*/ | ||
#if defined(MBEDTLS_THREADING) | ||
#define MBEDTLS_THREADING_C | ||
#define MBEDTLS_THREADING_ALT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to point out that defining MBEDTLS_THREADING_ALT
also defines MUTEX_INIT
which might not be what we want, and perhaps should be handled?
return( 0 ); | ||
} | ||
|
||
void mbedtls_threading_set_mbed( void ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As @sbutcher-arm mentioned, this is needed because of a library problem and should be fixed before the threading PR is merged.
@yanesca wondering what the status of this is. Any updates? Please close if not planning to complete or if it will be completed in a different version. |
There are no updates yet, but we are going to complete it. In case there will be a decision to complete it in a different version, I will close this PR down. |
please reopen when unblocked. |
Description
This is an implementation of mbed TLS threading abstraction layer using RTOS mutexes: The application developer has to call the
mbedtls_threading_set_mbed()
function before calling any mbed TLS functions and the library will use RTOS mutexes to provide thread safety where it is sopported. (see the corresponding Knowledge Base article).Status
IN DEVELOPMENT
Migrations
This PR does not change any existing behaviour:
NO
Todos
Description:
This is an implementation of mbed TLS threading abstraction layer
using RTOS mutexes.
Design decisions:
chance that an uninitialised variable has the value of one (it is a
small chance, but it would result in incorrect behaviour)
uninitialised variable is nonzero in most of the cases
because we use definitions with mbedtls_threading_mutex_t in the
library
friendly and to enable the use of static functions