Library not loaded after Runtime Hardened enabled

Hi there,

I am trying to notarize my macOS app. My app is embedded with some licensed libraries.

I studied document about how to notarize an app and followed steps, my app can be uploaded to Apple notarize services and exported to use, but when I run my app it crashed. Under Xcode it shows


dyld: Library not loaded: libMotionEngine-bundle.3.dylib
Referenced from: /Users/kensington/Library/Developer/Xcode/DerivedData/KensingtonWorks-dekfhdrucwmhfogmapgkwzsawyfm/Build/Products/Debug/KensingtonWorks for Ultimate Presenter.app/Contents/MacOS/KensingtonWorks for Ultimate Presenter
 Reason: image not found

I've tried several way to run my app successfully including make libraries Required/Optional under Linked Frameworks and Libraries and add my libraries to Embedded Binaries, unfortunately all failed. List conditions and environments below:


Xcode version: 10.3 / 11

macOS: 10.14.5/10.14.6

Libraries signed: No

Runtime Hardened chosen: Allow DYLD Environment Variables & Disable Library Validation

Below is piece of my library information:


Load command 8
  cmd LC_VERSION_MIN_MACOSX
  cmdsize 16
  version 10.11
  sdk 10.11
Load command 9
  cmd LC_SOURCE_VERSION
  cmdsize 16
  version 0.0
Load command 10
  cmd LC_LOAD_DYLIB
  cmdsize 56
  name libMotionEngine-core.3.dylib (offset 24)
  time stamp 2 Thu Jan 1 08:00:02 1970
  current version 3.1.4
compatibility version 3.0.0
Load command 11
  cmd LC_LOAD_DYLIB
  cmdsize 48
  name /usr/lib/libc++.1.dylib (offset 24)
  time stamp 2 Thu Jan 1 08:00:02 1970
  current version 120.1.0
compatibility version 1.0.0
Load command 12
  cmd LC_LOAD_DYLIB
  cmdsize 56
  name /usr/lib/libSystem.B.dylib (offset 24)
  time stamp 2 Thu Jan 1 08:00:02 1970
  current version 1226.10.1
compatibility version 1.0.0
Load command 13
  cmd LC_FUNCTION_STARTS
  cmdsize 16
  dataoff 54872
 datasize 320
Load command 14
  cmd LC_DATA_IN_CODE
  cmdsize 16
  dataoff 55192
 datasize 0
Load command 15
  cmd LC_CODE_SIGNATURE
  cmdsize 16
  dataoff 84352
 datasize 19696

Appreciate any suggestion/opinions!

Accepted Reply

On the library front, you wrote:

they are located in

/usr/local/bin
, I don't have source code

I recommend that you raise this issue with the library’s vendor. Installing libraries globally like this is problematic on a modern Mac because of library validation. The library has to be signed by someone, either you or the vendor:

  • If you sign it, only your apps will be able to load it, in which case you don’t want it installed in

    /usr/local/bin
    . Ideally you’d move it to
    Contents/Frameworks/
    within your app but, even if you don’t do that, you need to put it in
    /usr/local/MyProductName/bin
    so that you don’t conflict with other folks using the same library.
  • If the vendor signs it, apps with library validation enabled won’t be able to load it.

Unless the library is doing something particularly wacky, it should be feasible to move it to

Contents/Frameworks/
. You may be able to do that yourself using
install_name_tool
but I think you’d be better off working with the vendor to come up with an authorised solution.

With regards your HID problem, it’s likely you’re hitting one of the new restrictions around input monitoring. WWDC 2019 Session 701 Advances in macOS Security has the details.

Share and Enjoy

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

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

Replies

My app is embedded with some licensed libraries.

So, just to be clear, you got this library from a vendor and you’re shipping it to users within your app, right? If so:

  • Where have you placed the library? The usual location for such things is

    Contents/Frameworks/
    .
  • Did you re-sign it using your Developer ID? That’s pretty much required, and it makes sense when you step back and think about it. You’re shipping this code to customers, so you take on the responsibility for how it behaves, so you sign it as your code.

Share and Enjoy

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

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

Where have you placed the library? The usual location for such things is

Contents/Frameworks/
.

-->I'm afraid of this, the libraries are dependencies with each other, they are located in /usr/local/bin, I don't have source code and I find they should be inside here because I got these information by otool -L:

libhidapi.0.dylib:
  /usr/local/lib/libhidapi.0.dylib (compatibility version 1.0.0, current version 1.0.0)
  /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
  /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1349.8.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)

I tried change the path by using install_name_tool but I failed. My install package project installs these libraries in /usr/local/lib originally.


Did you re-sign it using your Developer ID? That’s pretty much required, and it makes sense when you step back and think about it. You’re shipping this code to customers, so you take on the responsibility for how it behaves, so you sign it as your code.

-->Yes I re-signed the library using my company's Developer ID application.


And there's update here...

I manually signed these libraries by codesign with developer ID, then I replace the original with these new signed files, there's no more "library not loaded" message shows, it seems running( but crashes on IOHIDManager api that's never happens on 10.14), but somehow when I move all files(application+libraries) to 10.14.6, the message "library not loaded" still appears...


So I got 2 difficult questions:

1. The "Library not loaded" seems resolved on 10.15 but still appears on 10.14.6

2. The IOHIDManager api will run fail on 10.15.


Thanks Quinn's time and helpful anwsers!


--Another discovery--

I found the built binary behavior are not the same between debug and deploy version. Here's a crash report comparison:

https://imgur.com/dF1qU5Z

I am wondering why? How do I make the environment the same? Thanks a lot!

On the library front, you wrote:

they are located in

/usr/local/bin
, I don't have source code

I recommend that you raise this issue with the library’s vendor. Installing libraries globally like this is problematic on a modern Mac because of library validation. The library has to be signed by someone, either you or the vendor:

  • If you sign it, only your apps will be able to load it, in which case you don’t want it installed in

    /usr/local/bin
    . Ideally you’d move it to
    Contents/Frameworks/
    within your app but, even if you don’t do that, you need to put it in
    /usr/local/MyProductName/bin
    so that you don’t conflict with other folks using the same library.
  • If the vendor signs it, apps with library validation enabled won’t be able to load it.

Unless the library is doing something particularly wacky, it should be feasible to move it to

Contents/Frameworks/
. You may be able to do that yourself using
install_name_tool
but I think you’d be better off working with the vendor to come up with an authorised solution.

With regards your HID problem, it’s likely you’re hitting one of the new restrictions around input monitoring. WWDC 2019 Session 701 Advances in macOS Security has the details.

Share and Enjoy

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

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

Thanks Quinn, finally I did it. Yes the key point is on how we handle these libraries...

Sort all my working out below:
1. The libraries all must be only embedded in Frameworks. So we should make LC_ID_DYLIB and LC_ID_DYLIB correct. A success Mach-O path content should be like this:

@executable_path/../Frameworks/<Library name itself>
  @loader_path/<Refer Library name> (compatibility version 3.0.0, current version 3.1.4)

The first line is the library itself execute path, and the second line is the path of other library referred by this library.

2. In the project setting, all library should choose “Embed and sign”. The library itself doesn’t need to be signed manually first. All of them will be auto signed when exporting to notarize service.


That’s it, due to some reason we have limited resource to be authorized from 3rd party again, but thanks Apple we still can use these libraries 🙂

Thank’s Quinn’s strong support!!