Local Network Privacy breaks Application

With the new macOS 15, Apple introduced the new Local Network Privacy feature. This is causing issues for our customers as - even though they granted the required permission for our software - connections to a server in their local network are being blocked. The situation is not fixed by recent macOS updates.

As far as I know, this issue exists for machines running on Apple Silicon. Systems running macOS versions (e.g. Sonoma) are not affected.

Currently, the workaround is to re-enable the permission under Settings > Privacy & Security > Local Network. The list shows our application with an enabled checkbox. Users now have to de-select the box and then re-select it again for the application to work. They have to do this after each and every reboot of their system, which is slightly annoying (so at the moment we recommend to not upgrade macOS to Sequoia, if possible)

I did some research and saw that other products are also affected by this bug. Is there a solution to this issue or any plans to fix it?

Answered by DTS Engineer in 819713022

And I believe you've found the problem:

This means, that all gui apps that are part of our application share the same executable (there's separate instances of the file on disk, but they all have the same UUID).

This is a bad idea. The issue here is that, in general, the system "primary" executable identifier is bundle id. So, two apps are "the same" if the bundle ID and "different" if they have different bundle IDs. However, the problem here is that there are cases where it cannot/does not use the bundle ID. As a few examples:

  1. Crash logs are correlated/identified based on build UUID. Part of this is technical, since the crash collection system can only rely on information that's already in-process and it's possible for a process to crash before it "knows" it's bundle id (assuming it has one at all). Part of this is also practical, since crash logs need to be tied to specific "builds", not just apps.

  2. Parts of the TCC system rely on build UUIDs (as well as code signature data), since permission grants need to be more tightly "bound" than JUST the bundle ID.

  3. Part of the networking system also use build UUIDs, though there isn't a strong technical requirement (like most of the other cases). I think it was originally done this way partly because the network API usage is very broad (so it needs to work in processes that don't have bundle IDS) and partly to try and avoid circular dependencies between the low level networking layer and Foundation/CoreFoundation.

Obviously 2 & 3 are an issue for your app, but the larger issue here is that it's simply a bad ideas to ship different apps with non-unique build UUIDs. It's the kind of detail that won't cause and immediate/obvious failure, but will instead cause odd problems "later" which won't have any obvious connection to the build UUID. Those kind of bugs are a nightmare to try and sort out.

That leads to here:

You're correct, we're using some launcher technology. To package and install our application, we're using a tool called Install4j.

Basically, I think you need to contact them and they need to fix this. Their tool should be generating unique UUIDs for the objects it generates to avoid exactly these issues.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Have you filed a bug on this? If so, what's the bug number?

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you for your reply - and the help on filing a bug report. I created one now: FB16112111

Thank you for your reply - and the help on filing a bug report. I created one now: FB16112111

Looking over your bug, the one thing that did jump out at me is that this is a Java application. Java application tend to use "launcher" architecture, where the executable (often a shell script) the system is initially launching is NOT what actually end "running". It's possible that you're bundle is laid out in a way that's causing the system to incorrectly treat your app as a "new" app every time it's restarted. What does the console log show when you launch post-restart and the system denies authorization?

Also does, is your app quit before the restart occurs or is it running when you start the restart process? If it's the second case, make sure the issue still happens if you specifically quit your app before the restart.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware.

I see nothing interesting in Console logs (but then I don't know what I would be looking for). Before every reboot, I quit the application.

You're correct, we're using some launcher technology. To package and install our application, we're using a tool called Install4j. That tool 'generates' a launcher, that is then the main executable of our gui applications. This means, that all gui apps that are part of our application share the same executable (there's separate instances of the file on disk, but they all have the same UUID).

I did an experiment to check, if this might be part of the problem:

  1. Experiment:
  • created a simple Java app that let's you enter IP and port and then opens a TCP connection
  • packaged that app in an installer with exactly one launcher
  • ran the app and allowed local network
  • was able to connect to a server on the local network
  • quit app and rebooted machine
  • was still able to connect to local network after reboot without toggling the permission
  1. Experiment
  • used stuff from first experiment, added a second app that only displays a hello-world-gui without anything network related
  • packaged that in an installer, now with two launchers (both using the 'JavaApplicationStub' from Install4j)
  • ran both apps and allowed local network
  • was able to connect to a server on the local network
  • quit app and rebooted machine
  • no longer able to connect to local network. had to turn permission off and on again

Side note: as a preparation for the experiments, I made sure that no other application on my machine were using Install4j technology (so I uninstalled our real-world application and also my development instance of Install4j) and then rebooted my machine before I installed the experiment-applications...

So for now I'm assuming, the UUID, which is shared across multiple GUI applications is confusing the network privacy system somehow. Which is something I cannot fix, because not only does our application have multiple executables with the same UUID, but on a customer machine, there might be other applications installed also using Install4j for packaging ...

Accepted Answer

And I believe you've found the problem:

This means, that all gui apps that are part of our application share the same executable (there's separate instances of the file on disk, but they all have the same UUID).

This is a bad idea. The issue here is that, in general, the system "primary" executable identifier is bundle id. So, two apps are "the same" if the bundle ID and "different" if they have different bundle IDs. However, the problem here is that there are cases where it cannot/does not use the bundle ID. As a few examples:

  1. Crash logs are correlated/identified based on build UUID. Part of this is technical, since the crash collection system can only rely on information that's already in-process and it's possible for a process to crash before it "knows" it's bundle id (assuming it has one at all). Part of this is also practical, since crash logs need to be tied to specific "builds", not just apps.

  2. Parts of the TCC system rely on build UUIDs (as well as code signature data), since permission grants need to be more tightly "bound" than JUST the bundle ID.

  3. Part of the networking system also use build UUIDs, though there isn't a strong technical requirement (like most of the other cases). I think it was originally done this way partly because the network API usage is very broad (so it needs to work in processes that don't have bundle IDS) and partly to try and avoid circular dependencies between the low level networking layer and Foundation/CoreFoundation.

Obviously 2 & 3 are an issue for your app, but the larger issue here is that it's simply a bad ideas to ship different apps with non-unique build UUIDs. It's the kind of detail that won't cause and immediate/obvious failure, but will instead cause odd problems "later" which won't have any obvious connection to the build UUID. Those kind of bugs are a nightmare to try and sort out.

That leads to here:

You're correct, we're using some launcher technology. To package and install our application, we're using a tool called Install4j.

Basically, I think you need to contact them and they need to fix this. Their tool should be generating unique UUIDs for the objects it generates to avoid exactly these issues.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Also, please take a look TN3178 for more details about this issue.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you!

We have the same scenario, but with just a shell script launching our java app. When we do a build of our app, a set of jar files are placed in a dir, and a lancher bash script is generated, which looks like:

#!/bin/bash

## Define the classpath with all external jar dependencies and the class files
CLASSPATH=/path/to/Foo.jar:\
/path/to/Bar.jar:\
/path/to/other

## Call the Java runtime, passing the classpath, the main class, and all script arguments
MAIN_CLASS=xx.yy.zz.Main
java -cp $CLASSPATH $MAIN_CLASS "$@"

The java app itself opens a TCP connection to a database. But when the launcher shell script is executed from the command line, it never elicits the OS prompt for "Do you want to allow <Your App> to access local network?". Instead I just get "No route to host" error message.

The exact same java app runs correctly inside the IDE, which was granted local network access.

How do we facilitate shell script launchers or similar homemade cli utilities that need network connections like this?

Local Network Privacy breaks Application
 
 
Q