Ensuring own Framework continues to be loadable by other apps, which may be Hardened and/or Sandboxed

Hi,


My software installs frameworks in the local domain (/Library/Frameworks) that are accessed from third-party apps. Some of these apps are simply code-signed, others are sandboxed. They are obviously signed by other companies, and so far there have been no problems on the part of DYLD in loading and executing code inside our frameworks. The loader is happy to continue looking for our framework outside the app container, in the case of sandboxed apps.


What changes are necessary to ensure that our frameworks remain accessible from hardened apps? Hardened Runtime, to the best of my understanding, only allows executables to load code that has been code-signed by the same team, or by Apple. I also think that hardened runtime affects only executables, and yet when I enable the ENABLE_HARDENED_RUNTIME setting in Xcode on my framework targets (via xcconfig) it clearly influences the way they are signed, and suddenly these "hardened frameworks" fail to be loaded by third-party apps, even if these apps aren't yet hardened themselves. In what its perhaps the key to solving this issue, how can one mark non-app targets to enable the library-validation exception? Why would a non-hardened app fail to load code whose only difference may be a simple flag (kill,runtime) in its signature?


Maybe I'm wrong to assume that non-app targets deserve any special treatment, but the fact remains that when I enable hardened runtime, our code simply stops being "seen" and loaded by DYLD, with all other variables remaining identical.


Thank you!

Gabe

Replies

Hello,


I'm having the same problem. Built a piece of code as an external framework which can be optionally installed (in Library/Frameworks).


This worked fine until I've enable hardened runtime in my mac os app (even with the "Disable Library Validation" option set).


Both app and framework have the LC_VERSION_MIN set to 10.9, as suggested in this thread:

https://forums.developer.apple.com/thread/115451


Both app and framework are signed by me. The application is not sandboxed.


Any suggestions?

See my response to your other post.

Oh, while I’m here, I thought I’d post an update on this issue…

I worked with FxFactory in a different context to uncover the root cause of their problem. It turns out that this was a

LC_VERSION_MIN
issue, although not one they can fix directly because the libraries in question come from Apple’s own FXPlug SDK. The fix will require Apple to ship an update to the FXPlug SDK, that is, something later than the current version of 3.1.1 (r. 44639232).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hey Quinn,


Has the issue been resolved?

I'm trying to enable hardened runtime in FxPlug 4 examples, then notiarize them, and they stop working (disappear from Motion/FCPX). When hardened runtime is not enforced, they work OK.

As a follow up, looks like in my case the problem is related to entitlement: com.apple.security.get-task-allow.

As soon as it is stripped by a codesign it no longer works in Motion/FCPX.

Same happens if I change the build settings to disable "Code Signing Inject Base Entitlements".

From what I'm reading this entitlement is used for debugging, but is it in some way needed by Motion/FCPX to comunicate with the pluginkit? If so, then it means that the plugin cannot be notarized.

Hi hateom,


In most cases, you should never have to explicitly add that entitlement to your targets. AFAIK Xcode automatically injects that entitlement when you begin a Debug session for that target. And since you don't need software that you are debugging to be notarized, this is perfectly fine. (I assume you are already codesigning to run locally)


From my experience, as long as:

- you are using the most recent version of FxPlug and PlugInManager, embedded as appropriate inside your PlugInKit container

- you are codesigning with the hardened runtime flag

- your loadable code is linked against a recent version of the macOS SDK


You should be able to build plugins that are loaded by Final Cut Pro / Motion and that can be notarized.

I agree with everything you mentioned. But, when you download FxPlug 4 - the examples have "Code Signing Inject Base Entitlements" enabled by default (I'm trying FxSimpleColorCorrector), and just by disabling "Code Signing Inject Base Entitlements" the filters no longer work. Filters are not visible by Motion/FCPX. This one build setting change, nothing else, make the filters disappear. Everything else is straight from the FxPlug 4 SDK.

I verified that with "codesign -d --entitlements :- *.pluginkit" command - as long as com.apple.security.get-task-allow entitlement exists Motion sees the filter. Once it's stripped, filter disappears in Motion.

Not sure what I'm doing wrong.

Try re-signing the FxPlug framework with your own identity (the same one you are using to sign the target, which may be different in Debug/Release configuration).


So... disable automatic code signing in the Copy Files phase, where you are probably copying the FxPlug framework to its final location inside your bundle. Next, add a build script which resigns that framework with your own identity:


codesign --force --timestamp --options runtime --sign "${CODE_SIGN_IDENTITY}" "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/FxPlug.framework"


As a side note, I have "Code Signing Inject Base Entitlements" ON in my Debug configuration, and OFF for Release. I'm not sure what’s going on on your system, but I don't think that option is *directly* affecting your ability to load the filters. It is more a case that when you have that option on, a bunch of stuff that doesn't pass GateKeeper validation gets a free pass.

I was finally able to make it work.

Looks like the PluginManager.framework was not embeded and signed properly in the XPC component.

Once I fixed that everything else worked.

Thanks for help!

  • Can you share the details of how you made sure the PluginManager.framework is embedded properly into your XPC?

    Our pluginkit targets use: xattr -cr "$CODESIGNING_FOLDER_PATH" codesign --force --timestamp --options runtime --sign "${CODE_SIGN_IDENTITY}" "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/PluginManager.framework"

    We're still seeing "The binary uses an SDK older than the 10.9 SDK." or "The signature algorithm used is too weak."

    messages when trying to notarize the XPC.

Add a Comment

@fuseaudiolabs the error message "The binary uses an SDK older than the 10.9 SDK." suggests to me that you might be using an older version of the SDK, or at least that the PluginManager.framework that you are copying to your built products is from an older SDK.

With any recent version of the FxPlug SDK and Xcode, it is no longer necessary to add custom build phases to get plugins recognized and loaded by the host app. You can simply link with the frameworks, and under the General → Frameworks and Libraries section of your project configuration, select the "Embed & Sign" option. Under Build Phases, the part where the SDK frameworks are copied to the Frameworks directory inside your bundle should have the Code Sign on Copy option enabled.

First, I would make sure you have the very latest version of the FxPlug SDK. This message thread pre-dates the reorganization of the SDK, following Apple’s newest conventions. Besides letting the FxPlug SDK install the "FxPlug.sdk" folder where it wants, you could make your own local copy (so it's part of your repository) and add a build configuration setting so that Xcode can locate it when building your target, for example:

ADDITIONAL_SDKS = "$(PROJECT_DIR)/SDK/FxPlug/FxPlug.sdk"

@FxFactory thanks for the feedback. There seems to be an older version of the SDK in "/Library/Developer/Frameworks/PluginManager.framework/" indeed. I have installed the latest SDK though (v4.2.4). It's weird though, that the example targets from the latest SDK still point to the old versions of the frameworks. I have tried pointing our project to the newer version which is located under /Library/Developer/SDKs/FxPlug.sdk/Library/Frameworks. However, code signing fails in that case with the following error message: "bundle format unrecognized, invalid, or unsuitable. Command CodeSign failed with a nonzero exit code". This is mentioned as a known issue in the release notes for version 4.0 in which case a manual copy/sign step via a run script phase is recommended. We did just that but the exact error persists in the manual code signing step so we're stuck :-(

I also tried going the route you suggested, but unfortunately it yields the same issues, eventually.

For posterity, if you follow some of the previous advice in this thread and use the ADDITIONAL_SDKS build setting to tell Xcode about your local copy of the "FxPlug.sdk" folder, you'll have to include this additional line in your xcconfig file*:

FRAMEWORK_SEARCH_PATHS = $(inherited) "/Library/Frameworks"

This is because the FxPlug.sdk folder does not contain the frameworks at its root. The FxPlug.framework and PlugInManager.framework are nested in /Library/Frameworks

  • You don't have to use xcconfig files, strictly speaking... both the ADDITIONAL_SDKS and FRAMEWORK_SEARCH_PATHS build settings are available through Xcode’s Build Settings UI.