-
-
Notifications
You must be signed in to change notification settings - Fork 11k
crypto/init.c: do not try to load itself when linked statically #6725
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
Conversation
The leak-one-reference trick for keeping the crypto module loaded is pointless when the program has already statically linked OpenSSL. It can be also dangerous, because DSO_dsobyaddr will try to load the main program itself. In Linux, for example, trying to load an executable file will generate an error and be ignored, but bad things will happen when the main program is compiled and linked with PIE hardening. Because the PIE-hardened program acts more like a shared object, it can be accidentally dlopen() and loaded into memory again, mess up the mapping and flush the global state. CLA: trivial
The statically linked program should not try to keep loaded by dlopen trick. Fixes: nodejs#21845 Refs: openssl/openssl#6725
|
Ping? |
|
You seem to have fixed it for nodejs, can we ask you to create a PR for OpenSSL proper as well? |
|
I assume, btw, that this is an issue both in master and in the 1.1.0 branch, correct? |
Emmmm yes, sir. But I don't understand, this is a PR, isn't it? Please correct me if there is anything wrong.
Correct. So far there is nothing that checks Lines 118 to 128 in b50c9f3
|
|
D'oh, you're right, this is indeed a PR. I have no idea how I missed that earlier today. My apologies... |
|
Uhmmmm, I gotta ask, what is it that would cause |
Sorry, could you explain more about your question? I'd like to make a short summary here, for your information:
|
|
Sorry, I mixed up It seems a bit uncertain how this gets addressed... after all, we create a static library even when building the shared library (except on Windows 'cause reasons), and that might end up in the application as well and still cause your issue. On the other hand, it may also be linked into another shared library. But awright, this is a specific use case and we can treat it as such. |
|
Note that I'm approving with a bit of trepidation... |
|
I'm unconvinced but not to the point of rejecting this. Not having static engines doesn't mean OpenSSL is statically linked, it just means that OpenSSL doesn't have any built in engines. It can be either statically or dynamically linked in such a case. I'm having difficulties trying to work out how a library could detect if it is statically linked or dynamically loaded. The best that comes to mind is a comparison of returns from |
|
How about this? Let the build script
Sure, detecting at runtime will be better. |
Note that this won't cover when a static library is linked into another shared library. I assume that's not a common thing to do, but it's still perfectly possible, given a build with -fPIC or similar... Anyway, this will require creating separate object files for shared library and for static library, which our build system currently doesn't support (it's in the planning for the next major release, but nothing really stops us from introducing it earlier... however, considering where we are in the release cycle for the moment, it's probably much too late to get this in for 1.1.1).
Can this be done? How? |
I would suggest using |
No idea.
That's quite interesting. In fact, I'm wondering why libcrypto.so tries to prevent itself from unloading. I assume that is for improving performance. Normally, a program "linked a shared library" loads the library by A program "linked a static library" will never call the unload handler until the program itself is going to exit, so adding reference count is also a no-op, or in fact not permitted by system or letting PIE program to be reloaded. This is a chain, all libraries actually (recursively) "linked" with the main program always stay with the living process, regardless of "static" or "shared". Programs or libraries which NOT link libcrypto.so but "dlopen" it during runtime, may "dlclose" it and "dlopen" it again soon. If we leak a reference, libcrypto.so will stay there. I think this might be (one of) the case(s) that it should leak a reference. Am I correct? Now, consider a library was statically linked into another library, say libpassword-manager.so. Now the same pattern here: a program "dlopen" libpassword-manager.so and "dlclose" it soon. Shall we force libpassword-manager.so to leak one reference? What if the parts outside of libcrypto.a want to be unloaded (e.g. to synchronize files, to clean buffers, to disconnect sockets) as the "dlclose" of the main program implies? So my conclusion is |
If you agree with the comment above, that a static library shouldn't do the "nodelete" no matter it was linked into a program or another library, preventing the static library from doing this does simply cover all the situations in my opinion. |
|
The no-delete thing was added to cover for another issue, our use of |
|
On many Unix systems, there is a concept of a dtor (destructor) list which corresponds to the ctor (constructor) one but runs on library/program unload. I'd be surprised in Windows didn't have something similar. |
Sure... and they don't necessarily look the same. This is completely undefined by POSIX. So there is that portability bit...
One word: |
"The most portable" mechanism is Most of UNIX-like system also implemented An incomplete list of compilers support
IBM XL C/C++ for AIX does not support As I described above, If we don't use "no-delete" things, I think the most general method will be |
|
I know that ELF is quite popular these days, and that certainly simplifies things... but OpenSSL doesn't count on being built on ELF only. I'll throw in a curve ball: ftp://ftp.mrynet.com/os/HP-MPE/docs.hp.com/en/11782/LinkerOnliinehelp0709/libraryroutines.htm |
|
Initialisers and finalisers are present here. Albeit using a different method.
Still, the point is made. We can’t rely on them being present.
Pauli
… On 6 Sep 2018, at 4:27 pm, Richard Levitte ***@***.***> wrote:
I know that ELF is quite popular these days, and that certainly simplifies things... but OpenSSL doesn't count on being built on ELF only.
I'll throw in a curve ball: ftp://ftp.mrynet.com/os/HP-MPE/docs.hp.com/en/11782/LinkerOnliinehelp0709/libraryroutines.htm
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#6725 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/ARFiwQ1j17hu8nboBQIbRivhCBL6SUkcks5uYMBQgaJpZM4VR-DK>.
|
Exactly, hence portability problems that will need to be resolved should we decide to adopt this route. Personally, I would have much preferred to use the initializers and finalizers, but the choice that was made does reflect that we couldn't be sure we covered all the bases. |
|
Emm... Using one method to try to workaround all the platforms (except Windows) is neat and does keep the code small. However, will preprocessor branches work better for the portability issue? Branches for |
|
Yeah, I can see us doing that. It will require some careful coding and should therefore not be rushed. I don't think it's likely to go into 1.1.1, but probably in a subsequent update, unless this is seen as a showstopper. @mattcaswell, what are your thoughts on the matter? |
Absolutely not to be rushed and not a showstopper for 1.1.1 IMO. |
|
Could this be looked at again? |
The |
Specifying the "no-pinshared" option to Configure will cause that define to be specified. |
|
Ok, I overlooked that. I looked for a more "automatic" way, like when building only static. But it is probably hard to detect for many cases, by "automatic" means. |
|
This issue is in a state where it requires action by @openssl/committers but the last update was 363 days ago |
|
Closing as this is already handled by the no-pinshared option. |
The leak-one-reference trick for keeping the crypto module loaded is
pointless when the program has already statically linked OpenSSL.
It can be also dangerous, because DSO_dsobyaddr will try to load
the main program itself.
In Linux, for example, trying to load an executable file will generate an
error and be ignored, but bad things will happen when the main program is
compiled and linked with PIE hardening. Because the PIE-hardened program acts
more like a shared object, it can be accidentally dlopen() and loaded into
memory again, mess up the mapping and flush the global state.