Privacy Preferences Policy Control

With the release of macOS Mojave imminent, and a new Privacy Preferences Policy Control Payload, it is important to properly launch scripts from LaunchAgents or 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 LaunchAgent or LaunchDaemon.

If a LaunchAgent or LaunchDaemon does not explicitly use /usr/bin/python to execute the script, it uses the codesign details of /System/Library/Frameworks/Python.framework/Resources/Python.app.

This presents an issue as the codesign details for /usr/bin/python are different to those of /System/Library/Frameworks/Python.framework/Resources/Python.app.

[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 /System/Library/Frameworks/Python.framework/Resources/Python.app

executeshell.py privacy alert

To correctly launch this script so that any privacy profiles work, the ProgramArguments array must include the path to the python interpreter.

<?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.

python privacy alert

*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"'
Terminal controlling System Events

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.