MacOS 14.4 ServiceManagement, cannot install sandboxed daemon from sandboxed main application anymore

I have made an app that requires a daemon to run. For this I use the ServiceManagement framework and the SMAppService.register to register the daemon.

The macOS 14.4 update broke the installation process and the daemon cannot be installed anymore and instead returns an error when trying to install the helper. The installation works on MacOS 14.3.1 or lower.

I have narrowed the error to the main app being sandboxed. Both the daemon and the main app are sandboxed (as MacOS 14.2 introduced the restriction that a sandboxed app can only run/install a sandboxed daemon, https://developer.apple.com/documentation/macos-release-notes/macos-14_2-release-notes#ServiceManagement).

I have been able to confirm that removing the sandbox on the main application results in the register function working again on MacOS 14.4. However, the release notes of 14.4 do not mention anything regarding the ServiceManagement API or something related. So my question is, what has changed in MacOS 14.4 so that the register function for a daemon causes an error when the main app is sandboxed? And moreover, how can I prevent this error without removing the sandbox

-- Information regarding the error:

The .register function returns the following error:

Error Domain=SMAppServiceErrorDomain Code=22 "Invalid argument" UserInfo={NSLocalizedFailureReason=Invalid argument

I have also created a log file according to the procedure at the link below and attached it to this post: https://forums.developer.apple.com/forums/thread/707482#716553022

It appears from the log file and from observing the logs in the Console app, that the error "plist changed between client and smd" causes the issue but I don't understand what causes this error

--

(I already use the com.apple.security.temporary-exception.sbpl entitlement in the daemon such that it can write to a specific file that the pmset command write to when invoked. This to indicate that I would prefer to keep the main app sandboxed as well. As I could also just remove the sandbox but I don't want to do that)

Replies

what has changed in MacOS 14.4 so that the register function for a daemon causes an error when the main app is sandboxed?

This was a deliberate change. We added code to SMAppService to explicitly require that, when a sandboxed app registers a daemon, that daemon must be sandboxed.

Is your app targeting the Mac App Store?

ps You wrote:

I already use the com.apple.security.temporary-exception.sbpl entitlement

To be be clear, that entitlement is not documented for third-party use.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you for the reply!

Great to hear indeed that the SMAppService returns an error now when the daemon isn't sandboxed, which wasn't the case on 14.2 indeed. In my case I had already sandboxed the daemon since 14.2 so that wasn't the issue I encountered.

I have been able to identify and solve the issue. The 14.4 update imposed new restrictions where sandboxed daemons are not allowed to set StandardInputPath, StandardOutputPath and StandardErrorPath's anymore. Removing these from the daemon plist file solved the issue for me.

--

Is your app targeting the Mac App Store?

I hope at some point in the future the answer will be yes. At this moment in time, the app requires privilege escalation to change the energy mode. Which can only be done via the pmset command, if I am correct. This unfortunately requires root privileges. I have tried NSAppleScript (by trying the order of privilege escalation mentioned here https://forums.developer.apple.com/forums/thread/708765) but have been unable to find a way to store such some sort of authorization for it, requiring either the user to enter their password every time or storing their password (which is something I definitely don't want to do).

--

To be clear, that entitlement is not documented for third-party use.

Yes I was somewhat aware of this as there was no documentation of it online. The functionality was only mentioned rarely on some forums online. I checked how it was used by other apps and by finding examples of the syntax online.

I used this entitlement as using the pmset command to change the energy mode from a sandboxed daemon isn't possible (it will write to a preference file which violates normal sandboxing restrictions). This left me with the option to either 1) remove the sandbox from the daemon, which after macOS 14.2 would require the removal of the sandbox from the main application, or 2) I could include this, undocumented, entitlement. I opted for the last as it allowed me to keep the sandboxing in both the daemon and main application. I included a file-write to only allow writing to the specific preference file pmset uses. I personally prefer this over removing the sandbox from both the daemon and main application (especially since the app only needs to be able to change the energy mode)