-
Notifications
You must be signed in to change notification settings - Fork 865
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
Protect Crypspr initialisation with a mutex #2425
Conversation
Multiple threads can be initialising the SPR at one time. This is a particular problem with the MbedTLS implementation as there is some additional static initialisation performed for this SPR which can lead to a crash.
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.
Serious? turning CRYSPR to C++ to use sync. Sorry I cannot review this. I am biased, being 100% with Linus Torvalds about C++, and then incompetent to approve or reject.
You'd better get rid of all the other C++ files in your library then... :o) Seriously, if you have an alternative suggestion to a mutex in that piece of code, then I'm all ears. |
@jeandube : there wouldn't be a problem with turning scoped locking into explicit lock/unlock calls, but the problem is with a lazy initialization of the global-static mutex object; nice if you can find some solution for it. Hmm... pthread_setspecific, or whatever it was...? @oviano : what you wrote (with the static mutex) might be likely not a problem in C++11, but SRT is allowed also in C++03, which knows nothing about threads, and therefore there are concerns as to whether a lazy initialization of a local static variable in a multithreaded environment can be safely done in this standard. Likely not. |
Ah ok, I did search for another precedent in the code actually and found a similar example of a static srt::sync::mutex in the function srt::sync::genRandomInt. So I figured it was ok, but I understand. |
Yes, but I don't think you read the comment in this function ;D |
No, I didn't read it properly, you're right. However, I still don't fully understand - shouldn't that mutex in genRandomInt be inside the HAVE_CX11 then if it's useless in earlier versions? Anyway, I don't really know the best solution, just that you need some sort of sync to prevent the issues I was getting before I added the mutex. |
The current situation is that in C++11 you can use the static variables with no problems. In C++03, and in C, there's no good method for this; the global variables get then initialization through the The problem is, even in cryspr this must be done portable way and include the C++11 version of sync. So, there could be simply a global variable for a mutex like this, done appropriate way for particular standard (check the sync version flag, not just C++11), and expose only functions for locking and unlocking it, as extern "C" so that they can be used in cryspr, plus a startup/cleanup functions that will be called from |
I am thinking of a slight variation to the above:
The advantage is it encapsulates the change into just the CCryptoControl class, and we don't need any extern global variables etc. Just the two function calls to init and cleanup. Does that tick all the boxes, or have I missed another flaw...? |
I don't exactly like it by one reason - you are locking way more execution steps than needed. But on the other hand, the frequency of the call to You don't have to create the whole big facility for a global variable. The |
Ok, makes sense. In terms of execution steps, do you mean the extra steps due to moving it up a level into CCyptoControl where it calls the function, or do think even as it was before with the first proposal it was locking too much? Two threads calling this function at the same time is a problem, they'd both be accessing the same static data.
|
Right, but the lock at |
It’s just locking the call to receive the instance, which either just returns it or initialises it? Anyway I’ll update the PR, as maybe it’s not clear from my description. |
I like this direction most. I guess |
Even simpler - but are you happy to initialise it even though it might not be used? |
Wait - so the problem wasn't about simultaneous access to the statically shared data when creating new crypter context, but with the lazy global initialization of the internal data of mbedtls? If so, then of course, it should be done in |
So basically you guys need to decide if it’s: A. Global mutex, accessed by crypto to lock getting instance. Crypto only initialised when first used. Small mutex overhead. B. Startup code calls crypto initialisation (calls get instance). No mutex required but initialisation code always runs regardless of whether crypto ever required. Happy to change it to B, let me know. |
My last comment here #2412 explained the issue as best as I could. |
If B really solves the problem, this is the best solution. I don't think it's costly to initialize the encryption library, even if the application doesn't use encryption (unless SRT is compiled with disabled encryption, see conditional macros). Of course, @maxsharabayko please confirm if so. |
I vote for "B. Startup code calls crypto initialisation (calls get instance). No mutex required but initialisation code always runs regardless of whether crypto ever required." I even think it makes much more sense to initialize the crypto library at the startup, to not put a performance burden on the connection establishment. @jeandube should also be pleased with this solution 😄 |
Ok, I've changed it to B. I have placed the call to HaiCryptCryspr_Get_Instance inside a CCryptoControl::globalInit() function as this seemed slightly cleaner as 1) it is the class that normally calls the HaiCryptCryspr_Get_Instance 2) it leaves a logical place for any future further initializations required. But if you prefer to call HaiCryptCryspr_Get_Instance directly from startup then I can change it. Main thing is no mutex, and any Linus fans aren't offended... |
Unsure as to whether any further global init would be required in the future, but still, it's cleaner to have a This still won't stop the Linux kernel from being written in C++ some day. ;) |
Multiple threads can be initialising the SPR at one time. This is a particular problem with the MbedTLS implementation as there is some additional static initialisation performed for this SPR which can lead to a crash.