Why can an app create daemons on the fly without sudo permission and how to stop it?

First, I come from Linux so there are many things which confuse me such as daemons.

I installed VOX.app and it has some kind of agents and cloud-related processes which can be started automatically. There is no option in the VOX UI which can disable them. I tried the following to remove those daemons:

launchctl remove com.coppertino.VOXCloud
launchctl remove com.coppertino.VOXAgent

The above commands are weird already because I didn't need to use sudo. The most weird part is what I did is apparently useless since everytime I launch VOX.app, it can create them again and again. This is just crazy.

If this is the security model of macOS how can I understand things and perhaps control for this?


Solution 1:

The general security model is that normal users can add any startup items to their realm (user library for them) and not for the system, so don’t let people have admin accounts if you don’t trust them to not run software that installer system level startup items.

There is no easy way to stop an admin user from changing the system. You can enforce gatekeeper or signed apps, but most admin users can bypass that setting so at best, you slow down an uneducated admin user for a bit.

Per-user and Computer Wide Jobs

On macOS, launchd can manage background processes per-user and computer wide.

Per-user jobs exist within your user session. They start and stop with your logging in and out of the computer. If the jobs have associated job tickets, you will find them with the folder ~/Library/LaunchAgents and ~/Library/LaunchDaemons

Computer wide jobs start and stop with the computer. These jobs are stored in /Library/LaunchAgents and /Library/LaunchDaemons.

Computer wide jobs managed by Apple are stored in /System/Library/LaunchAgents and /System/Library/LaunchDaemons.

Per-user jobs do not need super user permission. Thus you did not need sudo to stop jobs installed at the user level by vox.app.

Disabling a launchd job

You can unload a launchd job to block it returning:

Usage: launchctl unload <service-path, service-path2, ...>

  • -w Additionally disables the service such that future load operations will result in a service which launchd tracks but cannot be launched or discovered in any way.
  • -S <session> Only unloads the services associated with the specified session.
  • -D <domain> Unloads launchd.plist(5) files from the specified domain. See the discussion regarding this same flag when given to the load subcommand for further details.

The -w causes the unload to be written to disk and to persist across sessions.

For more about stopping, unloading, and overriding jobs see:

  • Launchctl difference between load and start, unload and stop
  • Disable Services in OSX (services.msc)
  • launchctl - remove enabled/disabled override

Solution 2:

The general problem is handled in Graham Miln's answer. This answer is only a slight addition exercised upon the example application given:

Short version: macOS has a few special directories for this kind of behaviour. Those are the global and user /Library paths already mentioned in Graham's answer. But a less visible and hence less obvious path is within each Application bundle.

Some apps are too clever. Vox is a prime example of this. These agents are not well explained but often complained about and thus a potentially unwanted programme, application or software (PUPAS)

This application triggers a chain of events already when it is being copied to /Applications and again when first launched.

Inside the package bundle are LoginItems:

   /Volumes/VOX/VOX.app/Contents/Library/LoginItems
  ../Loop.app
  ../VOX Agent.app

Both are the copied/registered by the system's own DesktopServicesHelper as an "application helper login item". These kind of "helpers" are often found in other apps as well and are usually just bloat adding nuisances. They might be blocked preemptively from registering in the first place by handy little apps, like BlockBlock.

As these are still contained within the app bundle you would have to search or supply the path to within the app bundle!

A search for automatically launched programmes/helpers has to include /Applications and ~/Applications!

Another annoyance is then found within the app bundle:

 /Volumes/VOX/VOX.app/Contents/XPCServices 
 /Volumes/VOX/VOX.app/Contents/XPCServices/VOX\ Toolbox.xpc
 /Volumes/VOX/VOX.app/Contents/XPCServices/com.coppertino.Vox.GNTPClientService.xpc 

One way to disable these per-user processes from bothering you is outlined in Graham's answer, using launchctl.
You just need to search within /Applications as well.
Another method would be to go into the bundle and just delete these items. – Most of the time those apps start fine without them, just missing the respective functionality. Vox was once a nice little 'no-frills' music player. It does work for that without those annoyances present on disk.
Sometimes better designed applications offer you an option to prevent those shenanigans in their preference dialogue.

Personal favorite: In the case of the application in the example given, it would be best to delete the whole application.

To directly answer the quesion headline of

Why can an app create daemons on the fly without sudo permission and how to stop it?

Because a user launches the app with his privileges and daemons contained within that application bundle are then sometimes quite annoyingly designed to then register themselves quite intransparently as "autostart" within that user's context and with that user's rights. To unload or deregister no sudo/administrative rights or permissions are required. If the offender sits under /Applications then removal might depend on higher permissions.