With the release of macOS Mojave imminent, and a new Privacy Preferences Policy Control Payload, it is important to properly launch scripts from
LaunchDaemons to ensure the correct process is identified when the script runs, so that macOS uses the correct
codesign requirements; this is especially true for
python scripts as there are different requirements depending on how the
python script is run from the
LaunchDaemon does not explicitly use
/usr/bin/python to execute the script, it uses the
codesign details of
This presents an issue as the
codesign details for
/usr/bin/python are different to those of
[testuser@blackbird]:Desktop # codesign -dr - /usr/bin/python Executable=/usr/bin/python designated => identifier "com.apple.python" and anchor apple
[testuser@blackbird]:Desktop # codesign -dr - /System/Library/Frameworks/Python.framework/Resources/Python.app
Executable=/System/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python designated => identifier "org.python.python" and anchor apple
An example of a
LaunchAgent that will not work (as at time of writing), is:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.example.pythonScript</string> <key>ProgramArguments</key> <array> <string>/Users/testuser/Desktop/executeshell.py</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist>
When this is launched by
launchd , any privacy alerts triggered by the script will show
executeshell.py as the parent process*. It appears that in this example, macOS uses the
codesign details of
To correctly launch this script so that any privacy profiles work, the
ProgramArguments array must include the path to the
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.example.pythonScript</string> <key>ProgramArguments</key> <array>
<string>/usr/bin/python</string> <string>/Users/testuser/Desktop/executeshell.py</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist>
With the adjusted file, the script will have the correct parent process if it triggers any privacy alerts. It appears in this case that the
codesign details of
/usr/bin/python are used, which is what the privacy management system is expecting.
This is important, because the shebang in a script does not always appear to be evaluated correctly when
launchd launches the script.
*A note about parent processes in relation to whitelisting:
This article only discusses behaviour observed in testing profiles to whitelist apps/scripts.
Based on testing, to successfully whitelist scripts that interact with files/folders that are protected by the new privacy protections in macOS Mojave, or automation events that try to control macOS, the item being whitelisted must be the parent process.
For example, if you open up
Terminal.app and run the below
osascript, you will be prompted to allow Terminal to control System Events.
osascript -e 'tell app "System Events" to display dialog "Hello World"'
In this example, the parent process is the Terminal application, so to allow
Terminal to control System Events, you would need to create a profile with an
AppleEvents Privacy Preferences Policy Control Payload that whitelists the Terminal application.
Other examples include using outset to manage the execution of scripts, profile installs, etc during login or boot time. In this instance,
python is the parent process of any scripts/profile installs that occur, so
/usr/bin/python would need to be whitelisted in appropriate Privacy Preferences Policy Control Payloads in order for
outset to be run any scripts without triggering privacy alerts.