Swift libraries not loading when running as root on earlier operating systems

I have a helper app that must, occasionally, run as root. I've spent the last year added a bunch of functionality in Swift and testing it on Big Sur without any problem.

I just now tried installing it on High Sierra (10.13.6), and when the helper is launch as the regular user is runs just fine. But when launched as root, I get

dyld: warning, LC_RPATH @executable_path/../Frameworks in /Users/USER/Library/Application Support/MyApp/Helper.app/Contents/MacOS/Helper being ignored in restricted program because of @executable_path

dyld: Library not loaded: @rpath/libswiftCore.dylib

  Referenced from: /Users/USER/Library/Application Support/MyApp/Helper.app/Contents/MacOS/Helper

  Reason: image not found

Abort trap: 6

So what do I need to do to get the Swift runtime libraries to load?

Accepted Reply

Thank you all for the excellent information. I knew about "dylib insertion" threats, but our application is signed (DeveloperID), notarized, and stapled, so I couldn't figure out why it wouldn't be trusted. It does use Hardened Runtime, but ultimately that wasn't the problem.

As usual, it was our fault. The ancient (circa OS X 10.4) code that installs the copy of the helper app in the Application Support folder was changing some of the access flags on the resource files. This, in turn, invalidated the app package. But until we added Dylibs to the package, this went unnoticed for years.

Once we figured out what was going on, the solution was to simply replace the copy hack with a single, modern, copy folder call and now everything works as expected. The installed helper app passes codesign validation, and the Swift libraries load even when run as root.

Thanks again, and apologies for the noise...

Replies

There is a concept in security call "dylib hijacking" where an attacker runs a program and swaps in an alternate dylib. There are a couple of ways to do the swap, including using @rpath. For that reason processes with elevated privileges (such as running as root) are blocked from using @rpath. That is the warning you are seeing and why the load of that dylib is failing.

Two solutions are:

  1. use swift 5 with the stable ABI which requires macOS 10.14.4 as you min deployment. With swift 5, the swift support dylibs are in the OS at a fixed path and don't need @rpath.
  2. codesign your helper app with "Library Validation". This will alter the security model for the process such that only dylibs loaded by the same signer (and team ID) or dylibs in the OS can be loaded. This security check thwarts dylib hijacking, so @rpath is supported.

In this case I suspect the the app has hardened runtime enabled but doesn't have Library Validation explicitly enabled. Hardened Runtime was introduced in 10.14 and so enabling Hardened Runtime would not provide Library Validation in 10.13.6. You can use "-o library" in your "Other Signing Flags" in Xcode or added do your codesign invocation.

Thank you all for the excellent information. I knew about "dylib insertion" threats, but our application is signed (DeveloperID), notarized, and stapled, so I couldn't figure out why it wouldn't be trusted. It does use Hardened Runtime, but ultimately that wasn't the problem.

As usual, it was our fault. The ancient (circa OS X 10.4) code that installs the copy of the helper app in the Application Support folder was changing some of the access flags on the resource files. This, in turn, invalidated the app package. But until we added Dylibs to the package, this went unnoticed for years.

Once we figured out what was going on, the solution was to simply replace the copy hack with a single, modern, copy folder call and now everything works as expected. The installed helper app passes codesign validation, and the Swift libraries load even when run as root.

Thanks again, and apologies for the noise...