dyld_insert_libraries ignored when calling application through bash

bash, macos, shared-libraries

Solution

This is a security feature of recent macOS versions.

The system `bash` executable has been marked as "restricted", disabling the DYLD_* features. To work around this, you can make a copy of `bash` and use that instead.

By looking for the following details in the implementations of `dyld`, I see that this restriction goes back at least to 10.6.

In the macOS 10.13 `dyld` implementation this logic is in `pruneEnvironmentVariables`, with the comment:

// For security, setuid programs ignore DYLD_* environment variables.
// Additionally, the DYLD_* enviroment variables are removed
// from the environment, so that any child processes don't see them.

However the actual logic to set the restriction is in `configureProcessRestrictions`:

// any processes with setuid or setgid bit set or with __RESTRICT segment is restricted
if ( issetugid() || hasRestrictedSegment(mainExecutableMH) ) {
    gLinkContext.processIsRestricted = true;
}
...
if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
    // On OS X CS_RESTRICT means the program was signed with entitlements
    if ( ((flags & CS_RESTRICT) == CS_RESTRICT) && usingSIP ) {
        gLinkContext.processIsRestricted = true;
    }
    // Library Validation loosens searching but requires everything to be code signed
    if ( flags & CS_REQUIRE_LV ) {
        gLinkContext.processIsRestricted = false;
...

As you can see, it depends on, `issetugid`, `hasRestrictedSegment`, and the `CS_RESTRICT` / SIP entitlements. You might be able to test for restricted status directly, or you could probably construct a function to test for these conditions yourself based on this information.

Problem

For my application, I am using DYLD_INSERT_LIBRARIES to switch libraries. I am running Mac OS X, El Capitan. If I set these environment variables in my shell: ``` export PYTHONHOME=${HOME}/anaconda export DYLD_INSERT_LIBRARIES=${HOME}/anaconda/lib/libpython2.7.dylib:${HOME}/anaconda/lib/libmkl_rt.dylib ``` If I launch my application directly, it works properly. However, if I call it through a bash script I have written, the `DYLD_INSERT_LIBRARIES` is ignored. If I add the same 2 lines to my bash script, my application works again. It looks like `DYLD_INSERT_LIBRARIES` is being unset when the bash script is called, as proven by this test script. ``` #!/bin/bash set -e echo ${DYLD_INSERT_LIBRARIES} ``` Is there any way to let the bash script inherit and pass down `DYLD_INSERT_LIBRARIES`?

Original source