-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
[RC1 Sodium] Properly handle libcrypto library search on macOS. #56958
Conversation
macOS has been steadily moving towards requiring programmers to directly link against the library version they prefer and forbidding linking against unversioned libraries. With Catalina this has moved from simply logging a warning when a programmer links against an unversioned library (typically a stub) to outright crashing with a pretty clear error. In an effort to honor Apple's intentions but not completely reimplement their dlopen methods, this change takes advantage of Apple's library naming scheme to load the most recent versioned dylib while ignoring the unversioned stub. Fixes: #55084 Signed-off-by: Thomas J. Gallen <kaori.hinata@gmail.com>
As an addendum regarding testing, the only tests available for pycrypto are simple functionality tests at this time, and as this involves a hard crash, we may be better served by adding Catalina to CI some time in the near future. |
This needs a test to make sure it's getting the right lib location on OSX |
Hi, @twangboy. (Edit: Fixed crude wording that probably would make more sense had it not been text.) |
I ask because, if the wrong library was loaded, we would hard crash before I ever had the chance to test the result. Any library that loads successfully based on the given globs would essentially be the correct library (at least, correct enough to satisfy any of the other checks in that file.) |
I've tested a pytest run without the patch and, as pytest doesn't isolate the python instance it's using to run tests from the tests themselves, a hard crash interrupts the entire testing process. As the testing is currently being done, I don't think we can write a test that would adequately handle this situation. |
If it's possible, I would suggest running tests on macOS Catalina as well (or change |
@kaorihinata You would probably have to split out that code into another function and test that function. Something like |
Correct, but then the code for macOS would be more thoroughly tested than the surrounding code (which I would be reorganizing), and I would be splitting |
_load_libcrypto has been split into _find_libcrypto and _load_libcrypto so as to allow for easier testing. _load_libcrypto is now actually a 1 liner. Signed-off-by: Thomas J. Gallen <kaori.hinata@gmail.com>
I forgot to either wrap find_library in a list or pop off the first glob result, and after already wrapping the short name for Windows, switching to just popping off the first glob result just felt less dirty. Signed-off-by: Thomas J. Gallen <kaori.hinata@gmail.com>
After exhausting every reasonable avenue to try to make the
If you do all of that, then you should now be able to run just the test cases for The problem after that is that, once you reverse the last item on the list, it's not possible for the search component to ever return "/usr/lib/libcrypto.dylib" again on Darwin/macOS, and even if it could, this wouldn't allow a full test load to run because the first thing the tests do overall (and repeats multiple times later) is launch master and minion instances. This will make use of the How do we want to proceed? |
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.
@kaorihinata Salt does not expect you to write tests for functions you did not change. You just need to write tests for “_load_libcrypto” and “_find_libcrypto”. In reality you don’t need to mock anything. You can test for what your function returns. For example ”check if your on Windows and then see if “_find_libcrytpto” returns “"libeay32"”. When testing “_load_libcrypot” see if it returns a ctype and it has the members it needs for that platform. For unsupported platforms check that the OSError gets raised.
Sure. The issue is that you cannot test on darwin/macOS for the bug I was fixing. If you're okay with me making tests that cannot test the issue I originally set out to fix then sure, I'll write some general tests. |
Add tests for both _find_libcrypto and _load_libcrypto. Mocking was used for the OSError test as it's possible to pass _find_libcrypto with as little as a find_library call. As a caveat, there is currently no way to catch an unversioned dylib being passed to _load_libcrypto on Darwin (from _find_libcrypto) as that would require we parse Mach-O binaries, so for the moment we'll assume that Apple will continue to name libraries sensibly. Signed-off-by: Thomas J. Gallen <kaori.hinata@gmail.com>
It would seem like there are some issues with CI, but tests should be completed. I'll await results from some of the non-errored jobs and fix anything that needs to be fixed. |
The pre-commit step does things I basically already do anyway but I forgot to consult pylint this time, sorry about that! Signed-off-by: Thomas J. Gallen <kaori.hinata@gmail.com>
Imports need to be identical between the test target and source or you end up calling the orignal callable and not the patched one. Has now been debugged and tested on a Fedora 32 VM. Signed-off-by: Thomas J. Gallen <kaori.hinata@gmail.com>
As I'm writing this all on macOS 10.15 (Catalina) and the long standing issues with timelib have yet to be solved, I can't actually use the pre-commit hooks as intended. That means that, unfortunately, I need to add pre-commit hooks, run them/commit, remove pre-commit hooks, then actually commit. Would be nice to get that fixed. Signed-off-by: Thomas J. Gallen <kaori.hinata@gmail.com>
ci/py3/fedora32 and ci/py3/ubuntu2004 seem to be broken. Let me know if you'd like anything done differently. (Edit: Codecov isn't moving anywhere without mocking to test all supported platforms as well though.) |
@kaorihinata can you pull master again? |
@weswhet All green, except for what looks like a CI issue for |
@kaorihinata thanks for the PR it looks good! Should get merged here soon. |
Welp this didn't age well. Currently broken on macOS Big Sur. with 3001 |
Hah! You must be really eager to try it out! I just watched the keynote this morning. It's probably not too hard to fix, but I'd have to find a copy of Big Sur somehow. How is it currently failing? Have they changed the naming scheme for libcrypto finally? |
WWDC is Christmas in June :) yeah |
Well, good time to test out the fallback then. Homebrew may just refuse to operate right now, but once you install openssl (or openssl 1.1) via Homebrew the patched section should actually pick it up just fine. Edit: Does it correctly bomb by saying that it can't find libcrypto right now? |
yeah it fails as intended, might need to update this to support the |
Sure. My ability to test it will be limited to Catalina for the time being, but it's a simple 1 liner. Should the order of precedence be:
...then? |
yeah, that sounds good, the only other thing I can think of is the |
I'm gonna see if I can get the rsax931.py file modified to work on Big Sur. |
Last I checked timelib is still broken and requires a manual fix if you want to install via You should be able to to just add the path to the beginning of the second block that checks for non-Apple paths. Should work fine. |
I've expanded the package and 3001 doesn't appear to include a dylib that |
I was just looking at that as well. I'm seeing the same. I'm looking to see if we can compile |
ahh looks like my open PR here will include the necessary shared lib. :) #57607 |
Oh. That's good. Should this do it then? diff --git a/salt/utils/rsax931.py b/salt/utils/rsax931.py
index c60ef6ba0e..0a1e0d4e3a 100644
--- a/salt/utils/rsax931.py
+++ b/salt/utils/rsax931.py
@@ -61,8 +61,10 @@ def _find_libcrypto():
# Sort so as to prefer the newest version.
lib = list(reversed(sorted(lib)))
else:
+ # Find library symlink in Salt locations.
+ lib = glob.glob("/opt/salt/lib/libcrypto.dylib")
# Find library symlinks in Homebrew locations.
- lib = glob.glob("/usr/local/opt/openssl/lib/libcrypto.dylib")
+ lib = lib or glob.glob("/usr/local/opt/openssl/lib/libcrypto.dylib")
lib = lib or glob.glob("/usr/local/opt/openssl@*/lib/libcrypto.dylib")
lib = lib[0] if lib else None
if not lib: |
Here we go. Sorry about that. Edit: Added changes to tests. diff --git a/salt/utils/rsax931.py b/salt/utils/rsax931.py
index c60ef6ba0e..4a9a589ab9 100644
--- a/salt/utils/rsax931.py
+++ b/salt/utils/rsax931.py
@@ -53,6 +53,14 @@ def _find_libcrypto():
else:
lib = glob.glob("/opt/freeware/lib/libcrypto.so*")
lib = lib[0] if lib else None
+ elif salt.utils.platform.is_darwin():
+ # If no library (or library symlink) was found at all on
+ # Darwin (macOS), attempt to find one in Salt locations.
+ lib = glob.glob("/opt/salt/lib/libcrypto.dylib")
+ # Find library symlinks in Homebrew locations.
+ lib = lib or glob.glob("/usr/local/opt/openssl/lib/libcrypto.dylib")
+ lib = lib or glob.glob("/usr/local/opt/openssl@*/lib/libcrypto.dylib")
+ lib = lib[0] if lib else None
elif salt.utils.platform.is_darwin():
# Find versioned libraries in system locations, being careful
# to avoid the unversioned stub which is no longer permitted.
diff --git a/tests/unit/utils/test_rsax931.py b/tests/unit/utils/test_rsax931.py
index 85d5e4e32f..1b6bf584a0 100644
--- a/tests/unit/utils/test_rsax931.py
+++ b/tests/unit/utils/test_rsax931.py
@@ -181,6 +181,7 @@ class RSAX931Test(TestCase):
lib_path = _find_libcrypto()
passed = False
for i in (
+ "/opt/salt/lib/libcrypto.so",
"/usr/lib/libcrypto.*.dylib",
"/usr/local/opt/openssl/lib/libcrypto.dylib",
"/usr/local/opt/openssl@*/lib/libcrypto.dylib", |
I've updated the patch to check Homebrew locations in both instances, and updated the applicable tests as well. |
@kaorihinata thanks! On the newer build |
Serves me right for lazily copy/pasting. I'll fix the above snippet just for correctness. Go for it. |
As a side note, very technically, if someone deleted the Apple libraries on purpose for some reason (and SIP didn't cover |
macOS has been steadily moving towards requiring programmers to directly
link against the library version they prefer and forbidding linking against
unversioned libraries. With Catalina this has moved from simply logging a
warning when a programmer links against an unversioned library (typically a
stub) to outright crashing with a pretty clear error.
In an effort to honor Apple's intentions but not completely reimplement
their dlopen methods, this change takes advantage of Apple's library
naming scheme to load the most recent versioned dylib while ignoring the
unversioned stub.
Fixes: #55084
Signed-off-by: Thomas J. Gallen kaori.hinata@gmail.com
What does this PR do?
This PR fixes issue #55084 caused by salt's use of an unversioned dylib stub on macOS which is no longer allowed.
What issues does this PR fix or reference?
Fixes: #55084
Previous Behavior
Any salt application which results in a call to
_load_libcrypto
would cause a hard crash of the python interpreter follow by a message from macOS indicating that python had attempted to load an unversioned dylib which is no longer supported.New Behavior
Any salt application which results in a call to
_load_libcrypto
should now operate normally.Merge requirements satisfied?
[NOTICE] Bug fixes or features added to Salt require tests.
Regarding docs, besides no longer crashing, there should be no user facing changes that need to be documented.
Regarding the changelog, I didn't see anything about it in the contributing guide, please let me know how I should go about this, or if I should considering how small the change is.
Regarding tests, I don't believe any changes need to be made, as any test that would catch an exception from
_load_libcrypto
should still catch it.Commits signed with GPG?
No
Please review Salt's Contributing Guide for best practices.
See GitHub's page on GPG signing for more information about signing commits with GPG.