JNA Library is not working sandbox environment macOS

2,276 views
Skip to first unread message

Samrat Mohanta

unread,
Jul 22, 2021, 3:01:27 AM7/22/21
to Java Native Access
I developed and Java based application to fetch system info. I bundled the Java application into an app using AppBundler. Just double clicking the app works fine in macOS. Now to upload the app in the macOS App Store I signed the app with entitlement. Once I signed the app it is not working. My JNA code snippet is as below:

import java.nio.charset.StandardCharsets;
import com.sun.jna.Native;
import com.sun.jna.platform.mac.IOKit.IORegistryEntry;
import com.sun.jna.platform.mac.IOKitUtil;
...
...
IORegistryEntry platformExpert = IOKitUtil.getMatchingService("IOPlatformExpertDevice");
        if (platformExpert != null) {
            byte[] data = platformExpert.getByteArrayProperty("manufacturer");
            if (data != null) {
                manufacturer = Native.toString(data, StandardCharsets.UTF_8);
            }
            data = platformExpert.getByteArrayProperty("model");
            if (data != null) {
                model = Native.toString(data, StandardCharsets.UTF_8);
            }
            serialNumber = platformExpert.getStringProperty("IOPlatformSerialNumber");
            uuid = platformExpert.getStringProperty("IOPlatformUUID");
            platformExpert.release();
        }

now when I'm running this app I'm getting below error in the terminal:

Jul 16, 2021 8:35:21 PM com.sun.jna.Native extractFromResourcePath
INFO: Looking in classpath from sun.misc.Launcher$AppClassLoader@5c647e05 for /com/sun/jna/darwin-x86-64/libjnidispatch.jnilib
Jul 16, 2021 8:35:21 PM com.sun.jna.Native extractFromResourcePath
INFO: Found library resource at jar:file:/Users/<username>/Desktop/app-macos-installer-builder_v3/macOS-x64/application/MyApp.app/Contents/Java/MyApp_lib/jna-5.8.0.jar!/com/sun/jna/darwin-x86-64/libjnidispatch.jnilib
Jul 16, 2021 8:35:21 PM com.sun.jna.Native extractFromResourcePath
INFO: Extracting library to /Users/ahs-cbe-pp/Library/Containers/com.pkg.MyApp/Data/Library/Caches/JNA/temp/jna5601997128572859092.tmp
Jul 16, 2021 8:35:21 PM com.sun.jna.Native loadNativeDispatchLibraryFromClasspath
INFO: Trying /Users/<username>/Library/Containers/com.pkg.MyApp/Data/Library/Caches/JNA/temp/jna5601997128572859092.tmp
Exception in thread "main" java.lang.UnsatisfiedLinkError: /Users/<username>/Library/Containers/com.pkg.MyApp/Data/Library/Caches/JNA/temp/jna5601997128572859092.tmp: dlopen(/Users/<username>/Library/Containers/com.pkg.MyApp/Data/Library/Caches/JNA/temp/jna5601997128572859092.tmp, 1): no suitable image found.  Did find:
    /Users/<username>/Library/Containers/com.pkg.MyApp/Data/Library/Caches/JNA/temp/jna5601997128572859092.tmp: code signature in (/Users/<username>/Library/Containers/com.pkg.MyApp/Data/Library/Caches/JNA/temp/jna5601997128572859092.tmp) not valid for use in process using Library Validation: library load disallowed by system policy
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1934)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1817)
    at java.lang.Runtime.load0(Runtime.java:810)
    at java.lang.System.load(System.java:1086)
    at com.sun.jna.Native.loadNativeDispatchLibraryFromClasspath(Native.java:1019)
    at com.sun.jna.Native.loadNativeDispatchLibrary(Native.java:989)
    at com.sun.jna.Native.<clinit>(Native.java:195)
    at com.sun.jna.platform.mac.IOKit.<clinit>(IOKit.java:51)
    at com.sun.jna.platform.mac.IOKitUtil.<clinit>(IOKitUtil.java:39)

I've given following entitlement:

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.print</key>
<true/>
<key>com.apple.security.scripting-targets</key>
<true/>
<key>com.apple.security.get-task-allow</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
</dict>
</plist>

Can anyone help me what is going wrong here?


Durchholz, Joachim

unread,
Jul 22, 2021, 6:01:27 AM7/22/21
to jna-...@googlegroups.com

There’s some Apple library policy that’s preventing the library from loading (code signature in (/Users/<username>/Library/Containers/com.pkg.MyApp/Data/Library/Caches/JNA/temp/jna5601997128572859092.tmp) not valid for use in process using Library Validation: library load disallowed by system policy).

 

A potential cause is that MacOS does not allow code created at runtime (which is typical malware behaviour), and that extracting a library at runtime looks like that code was created because it’s not visible outside the jar file in which it came.

I prepared for this scenario by pre-extracting the library and bundling it as part of the installer. I also had JNA load the pre-extracted library instead of letting it extract and load it.

 

I’d love to hear about your success. We don’t currently bundle JNA in our MacOS build, but eventually we will, and any data points will help us decide how to proceed.

 

Regards,

Jo

--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jna-users/e81b8ffc-b32f-4c87-8264-179d6bfa7899n%40googlegroups.com.

 

Sensitivity: C2 Internal

The content of this e-mail is intended only for the confidential use of the person addressed.
If you are not the intended recipient, please notify the sender and delete this e-mail immediately.
Thank you.

Tres Finocchiaro

unread,
Jul 22, 2021, 1:37:26 PM7/22/21
to jna-...@googlegroups.com
To add a bit to Jo's feedback, quoting the Loading Library section:

Library Loading 
 
When JNA classes are loaded, the native shared library (jnidispatch) is loaded as well. An attempt is made to load it from the any paths defined in jna.boot.library.path (if defined), then the system library path using System.loadLibrary(java.lang.String), unless jna.nosys=true. If not found, the appropriate library will be extracted from the class path (into a temporary directory if found within a jar file) and loaded from there, unless jna.noclasspath=true. If your system has additional security constraints regarding execution or load of files (SELinux, for example), you should probably install the native library in an accessible location and configure your system accordingly, rather than relying on JNA to extract the library from its own jar file. 
 
To avoid the automatic unpacking (in situations where you want to force a failure if the JNA native library is not properly installed on the system), set the system property jna.nounpack=true
 
While this class and its corresponding native library are loaded, the system property jna.loaded will be set. The property will be cleared when native support has been unloaded (i.e. the Native class and its underlying native support has been GC'd). 
 
NOTE: all native functions are provided within this class to ensure that all other JNA-provided classes and objects are GC'd and/or finalized/disposed before this class is disposed and/or removed from memory (most notably Memory and any other class which by default frees its resources in a finalizer).

So I would strongly suggest the following for a sandboxed application:

boolean sandboxed = System.getenv("APP_SANDBOX_CONTAINER_ID") != null;

// Some 3rd party apps install to the system and can cause crashes
System.setProperty("jna.nosys", "true");

if(sandboxed) {
// Don't unpack the libraries
System.setProperty("jna.nounpack", "true");
// Tell JNA where the native libraries are
System.setProperty("jna.boot.library.path", "<path to native libs>");
}

Some notes:
  1. The "<path to native libs>" will NOT be /Applications/My.app/Contents/,but rather something calculated at runtime.  Sandboxed apps actually run from a special directory, don't hard-code this, but calculate it based on teh path of your JAR, or some other resource.
  2. One could argue this above code would work on all Mac instances (not just sandboxed instances) since the logic would be infallible so as long as the libs were in the expected location.
  3. jna.nosys is a personal preference and has nothing to do with the question, but it's something that can cause issues when other software which uses JNA decides to pollute the library search path, something I've seen especially in Windows environments.
  4. I haven't tested the above yet. :)



Samrat Mohanta

unread,
Jul 23, 2021, 8:31:32 AM7/23/21
to Java Native Access
Thanks Tres. This worked. :)

Daniel Zanchi

unread,
Nov 5, 2024, 2:09:57 PM11/5/24
to Java Native Access

Hi, I am trying to achieve the same thing but I had no luck for now. 
I am building a macOS app for the App Store so it will be sandboxed. 
I did set this:
      System.setProperty("jna.debug_load.jna", "true");

      System.setProperty("jna.nosys", "true");

and I think i am having issues here:

   System.setProperty("jna.boot.library.path", "<path to native libs>");

What path should i add there? 
I know that the jna-5.10.0.jar is here:
    java.library.path

Because this:
LogUtility.log(System.getProperty("java.library.path"));

Prints this:

MyApp.app/Contents/app

And I see the .jar and other libs there if I expand the .app.

But if I boot the app i get this error:

/Volumes/MyApp/MyApp.app/Contents/app
Nov 05, 2024 8:07:06 PM com.sun.jna.Native loadNativeDispatchLibrary
INFO: Looking in /Users/danielzanchi/java.library.path/libjnidispatch.jnilib
Nov 05, 2024 8:07:06 PM com.sun.jna.Native loadNativeDispatchLibrary
INFO: Looking in /Users/danielzanchi/java.library.path/libjnidispatch.dylib
Nov 05, 2024 8:07:06 PM com.sun.jna.Native extractFromResourcePath
INFO: Looking in classpath from jdk.internal.loader.ClassLoaders$AppClassLoader@4b85612c for /com/sun/jna/darwin-aarch64/libjnidispatch.jnilib
Nov 05, 2024 8:07:06 PM com.sun.jna.Native extractFromResourcePath
INFO: Found library resource at jar:file:/Volumes/MyApp/MyApp.app/Contents/app/jna-5.10.0.jar!/com/sun/jna/darwin-aarch64/libjnidispatch.jnilib
Exception in thread "main" java.lang.UnsatisfiedLinkError: Could not find JNA native support
at com.sun.jna.Native.loadNativeDispatchLibraryFromClasspath(Native.java:1039)
at com.sun.jna.Native.loadNativeDispatchLibrary(Native.java:1015)
at com.sun.jna.Native.<clinit>(Native.java:221)
at com.sm.myapp.SH3DBridge.SH3DBridge.init(Unknown Source)
at com.a.myapp.analytics.AnalyticsObject$2.run(Unknown Source)
at com.a.myapp.analytics.AnalyticsObject.init(Unknown Source)
at com.a.myapp.analytics.AnalyticsManager.init(Unknown Source)
at com.a.myapp.myapp.init(Unknown Source)
at com.a.myapp.myapp.main(Unknown Source)
Failed to launch JVM


Thanks in advance


Tres Finocchiaro

unread,
Nov 5, 2024, 6:01:38 PM11/5/24
to jna-...@googlegroups.com
Daniel,

Sorry if this is not obvious in the accepted answer, but you will need to extract the native library and place it somewhere that your application can access.  Your logs suggest that it's still trying to locate the native library inside the JAR.



Daniel Zanchi

unread,
Nov 6, 2024, 8:54:44 AM11/6/24
to Java Native Access
Thanks, i solved it 

To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages