Skip to content
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

Add hardcoded paths to macOS frameworks for Big Sur compatibility. #1905

Merged
merged 9 commits into from Jul 19, 2020

Conversation

sheagcraig
Copy link
Contributor

@sheagcraig sheagcraig commented Jul 16, 2020

ctypes.util.find_library is checking for the presence of the framework
files, which will fail due to macOS Big Sur's "dynamic linker cache".
Since these files really can't be anywhere else, we just hardcode the
path and load them. (see #1904 )

See: https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11-beta-release-notes
(relevent excerpt provided below)

This update takes the approach of leaving the existing behavior as is
for macOS 10.8 (lowest supported version) through 10.15.

Allegedly Apple is going to number Big Sur as macOS 11, although right
now the beta returns a version of "10.16", so this code handles both as
being greater than or equal to "10.16".

| New in macOS Big Sur 11 beta, the system ships with a built-in dynamic
linker cache of all system-provided libraries. As part of this change,
copies of dynamic libraries are no longer present on the filesystem.
Code that attempts to check for dynamic library presence by looking for
a file at a path or enumerating a directory will fail. Instead, check
for library presence by attempting to dlopen() the path, which will
correctly check for the library in the cache. (62986286)

ctypes.util.find_library is checking for the presence of the framework
files, which will fail due to macOS Big Sur's "dynamic linker cache".
Since these files really can't be anywhere else, we just hardcode the
path and load them.

See: https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11-beta-release-notes
(relevent excerpt provided below)

This update takes the approach of leaving the existing behavior as is
for macOS 10.8 (lowest supported version) through 10.15.

Allegedly Apple is going to number Big Sur as macOS 11, although right
now the beta returns a version of "10.16", so this code handles both as
being greater than or equal to "10.16".

| New in macOS Big Sur 11 beta, the system ships with a built-in dynamic
linker cache of all system-provided libraries. As part of this change,
copies of dynamic libraries are no longer present on the filesystem.
Code that attempts to check for dynamic library presence by looking for
a file at a path or enumerating a directory will fail. Instead, check
for library presence by attempting to dlopen() the path, which will
correctly check for the library in the cache. (62986286)
@sheagcraig sheagcraig changed the title Add hardcoded paths to macOS frameworks for Big Sur compatibility. (#1904) Add hardcoded paths to macOS frameworks for Big Sur compatibility. Jul 16, 2020
Copy link
Member

@pquentin pquentin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah, thanks! How did you notice this issue? Are you running Big Sur and can confirm that this change works?

@sheagcraig
Copy link
Contributor Author

I do a lot with Saltstack's macOS working group, and I have a project for making requests Sessions that use the macOS keychain for mutual TLS and cert verification; there have been a lot of projects that use either PyObjC or ctypes directly to get at the macOS frameworks, and the failures are all pretty much due to checking for the existence of the files (which aren't there).

I have a Big Sur 10.16 beta2 machine on my desk that I tested this change out on.

I wanted to get this out there; obviously there's some time.

If anyone wants to direct me in any way, the version check and importing code could probably be cleaned up a bit. I mostly wanted to at least get a working POC out there.

@sethmlarson
Copy link
Member

Just chiming in to thank you for raising this issue to our attention and for providing a fix. We'll be sure to backport to 1.25-series and get a release out there before Big Sur is released.

@sheagcraig
Copy link
Contributor Author

👍🏻

I hate leaving it with a kind of speculative version check... May be 10.16, may be 11... wait until September!

@pquentin
Copy link
Member

According to this answer by an Apple engineer, it will be 11. But it's good if it works on the beta too, so we can leave 10.16 until the release.

@sethmlarson
Copy link
Member

@sheagcraig As long as the last released version we know of is 10.15 I'm fine with leaving the version check to be less restrictive. Sometimes with these things you have to cover all your bases. Another way we could go about this is only doing the version lookup after a failed find_library() call, I'm unsure what the overhead for that is.

@sheagcraig
Copy link
Contributor Author

Cool @pquentin. And yes @sethmlarson, that sounds like a plan.

I'll see if I can cut out some of the repetition. I wasn't sure initially if the linter would be cranky with me for having the version check earlier, so I'll give it a little polish.

@sheagcraig
Copy link
Contributor Author

I have a contact at Apple that I'll ask about this; maybe we could use the hardcoded paths back further due to SIP making it very unlikely that those paths are anything but what we expect.

This should never be anything but these paths. Instead of checking for
`os.path.isfile` with `ctypes.util.find_library`, we just try to load
with `ctypes.CDLL` and catch the `OSError` if it fails, add context, and
reraise.
@sheagcraig
Copy link
Contributor Author

Well try this on for size. So I looked through ctypes.util.find_library, which is really running macholib.dyld.dyld_find(). It follows a search path, performing an os.path.isfile() looking for a path that is actually a file. This obviously won't work on Big Sur.

But the paths have been the same for all of the versions supported by the existing code (10.8+), and shouldn't be anywhere else.

So I just cleaned out a lot of the version conditionals and went straight to trying to load the libraries. If it fails to load for some reason, we catch the OSError, add a more friendly message, and reraise.

I also added a check to make sure we're even on macOS before going any further through the module.

I'm super green on urllib3 proper; I've poked around in the secure transport code a fair bit... But I guess I don't know why this was causing tests to fail on non-macOS, as the new code should have had the same behavior as the old? Regardless, this last couple of commits sidesteps that issue.

@sheagcraig
Copy link
Contributor Author

If this looks good, I'll yank that new test file too, since it basically does nothing now.

Copy link
Member

@sethmlarson sethmlarson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thought from me, let me know what you think and if you could give it a test locally :)

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
import mock
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this test script now :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIth the changes to retain the pre-Big Sur behavior, do it still make sense to take the test out?

@sheagcraig
Copy link
Contributor Author

Hah; well I just put your suggested changes in. It's fine like that!

@sethmlarson
Copy link
Member

I went ahead and made some changes myself on the branch:

  • Fixed the imports so ImportError is raised on non-macOS as before.
  • Deleted the test script, it's not necessary since CI doesn't support macOS 10.16 yet anyways so we can't test the alternate load_cdll() code path either way. Knowing it works on your system is enough for me to be confident it'll work for most others since the functionality is fairly simple. :)

@codecov
Copy link

codecov bot commented Jul 19, 2020

Codecov Report

Merging #1905 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##            master     #1905   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           23        23           
  Lines         2049      2055    +6     
=========================================
+ Hits          2049      2055    +6     
Flag Coverage Δ
#unittests 99.51% <ø> (-0.05%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/urllib3/util/ssl_.py 100.00% <0.00%> (ø)
src/urllib3/connection.py 100.00% <0.00%> (ø)
src/urllib3/util/__init__.py 100.00% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fe1f73b...d57db89. Read the comment docs.

@pquentin
Copy link
Member

@sethmlarson can't merge myself until you dismiss your review. Thanks for finishing this!

@sethmlarson sethmlarson merged commit 6bd33f6 into urllib3:master Jul 19, 2020
@sethmlarson
Copy link
Member

Thanks for the review @pquentin :)

sethmlarson added a commit to sethmlarson/urllib3 that referenced this pull request Jul 19, 2020
…ity. (urllib3#1905)

ctypes.util.find_library is checking for the presence of the framework
files, which will fail due to macOS Big Sur's "dynamic linker cache".
Since these files really can't be anywhere else, we just hardcode the
path and load them.

See: https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11-beta-release-notes
(relevent excerpt provided below)

This update takes the approach of leaving the existing behavior as is
for macOS 10.8 (lowest supported version) through 10.15.

Allegedly Apple is going to number Big Sur as macOS 11, although right
now the beta returns a version of "10.16", so this code handles both as
being greater than or equal to "10.16".

Co-authored-by: Seth Michael Larson <sethmichaellarson@gmail.com>
@pquentin
Copy link
Member

Big Sur will be both 10.16 and 11.0, depending on context: https://eclecticlight.co/2020/07/21/big-sur-is-both-10-16-and-11-0-its-official/

sethmlarson added a commit that referenced this pull request Jul 22, 2020
…ity. (#1905)

ctypes.util.find_library is checking for the presence of the framework
files, which will fail due to macOS Big Sur's "dynamic linker cache".
Since these files really can't be anywhere else, we just hardcode the
path and load them.

See: https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11-beta-release-notes
(relevent excerpt provided below)

This update takes the approach of leaving the existing behavior as is
for macOS 10.8 (lowest supported version) through 10.15.

Allegedly Apple is going to number Big Sur as macOS 11, although right
now the beta returns a version of "10.16", so this code handles both as
being greater than or equal to "10.16".

Co-authored-by: Seth Michael Larson <sethmichaellarson@gmail.com>
Dobatymo pushed a commit to Dobatymo/urllib3 that referenced this pull request Mar 16, 2022
…rllib3#1905)

* Add hardcoded paths to macOS frameworks for Big Sur compatibility.

ctypes.util.find_library is checking for the presence of the framework
files, which will fail due to macOS Big Sur's "dynamic linker cache".
Since these files really can't be anywhere else, we just hardcode the
path and load them.

See: https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11-beta-release-notes
(relevent excerpt provided below)

This update takes the approach of leaving the existing behavior as is
for macOS 10.8 (lowest supported version) through 10.15.

Allegedly Apple is going to number Big Sur as macOS 11, although right
now the beta returns a version of "10.16", so this code handles both as
being greater than or equal to "10.16".

| New in macOS Big Sur 11 beta, the system ships with a built-in dynamic
linker cache of all system-provided libraries. As part of this change,
copies of dynamic libraries are no longer present on the filesystem.
Code that attempts to check for dynamic library presence by looking for
a file at a path or enumerating a directory will fail. Instead, check
for library presence by attempting to dlopen() the path, which will
correctly check for the library in the cache. (62986286)

* Raise an OSError if not on macOS and trying to import securetransport

* Just use hardcoded paths for Security and CoreFoundation libs.

This should never be anything but these paths. Instead of checking for
`os.path.isfile` with `ctypes.util.find_library`, we just try to load
with `ctypes.CDLL` and catch the `OSError` if it fails, add context, and
reraise.

* Updated to preserve pre-10.16 behavior.

* Bail early on non-macOS.

* Restore find_library import, OSError -> ImportError

* ImportError

* OSError

* Delete test_securetransport_big_sur.py

Co-authored-by: Seth Michael Larson <sethmichaellarson@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants