Search code examples
javajvmjna

JNA does not work on safe mode without networking, GetIfTable failed


I created new Maven project on intellij. Added this code to main:

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Advapi32;
import com.sun.jna.platform.win32.Winsvc;
public class Main {
    public static void main(String[] args) throws InterruptedException {
        registerHandler();
        System.out.println(1);
        Thread.sleep(60000);
    }
    public static void registerHandler(){
        Winsvc.SERVICE_STATUS_HANDLE service_status_handle = Advapi32.INSTANCE.RegisterServiceCtrlHandlerEx("hvldlpxpa", new Winsvc.HandlerEx() {
            @Override
            public int callback(int i, int i1, Pointer pointer, Pointer pointer1) {
                return i;
            }
        }, Pointer.NULL);
    }
    public static void stopService(String[] args) throws Exception {
        System.exit(0);
    }
}

MAVEN FILE:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.example</groupId>
   <artifactId>jnaReg</artifactId>
   <version>1.0-SNAPSHOT</version>
   <dependencies>
      <dependency>
         <groupId>net.java.dev.jna</groupId>
         <artifactId>jna-platform</artifactId>
         <version>5.12.1</version>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <executions>
               <execution>
                  <phase>package</phase>
                  <goals>
                     <goal>single</goal>
                  </goals>
               </execution>
            </executions>
            <configuration>
               <descriptorRefs>
                  <descriptorRef>jar-with-dependencies</descriptorRef>
               </descriptorRefs>
               <archive>
                  <manifest>
                     <mainClass>Main</mainClass>
                  </manifest>
               </archive>
               <finalName>JNA</finalName>
            </configuration>
         </plugin>
      </plugins>
   </build>
</project>

Executed with:

setlocal
set JARS="C:\Users\bunsal\Downloads\JNA-jar-with-dependencies.jar"
set MAINCLASS=Main

java.exe -cp %JARS% %MAINCLASS%
endlocal

Booted into safe mode minimal. This error happens:

Exception in thread "main" java.lang.Error: IP Helper Library GetIfTable function failed
    at java.net.NetworkInterface.getAll(Native Method)
    at java.net.NetworkInterface.getNetworkInterfaces(NetworkInterface.java:355)
    at sun.security.provider.SeedGenerator.addNetworkAdapterInfo(SeedGenerator.java:233)
    at sun.security.provider.SeedGenerator.access$000(SeedGenerator.java:80)
    at sun.security.provider.SeedGenerator$1.run(SeedGenerator.java:183)
    at sun.security.provider.SeedGenerator$1.run(SeedGenerator.java:168)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.security.provider.SeedGenerator.getSystemEntropy(SeedGenerator.java:168)
    at sun.security.provider.SecureRandom$SeederHolder.<clinit>(SecureRandom.java:201)
    at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:221)
    at java.security.SecureRandom.nextBytes(SecureRandom.java:468)
    at java.security.SecureRandom.next(SecureRandom.java:491)
    at java.util.Random.nextLong(Random.java:424)
    at java.io.File$TempDirectory.generateFile(File.java:1905)
    at java.io.File.createTempFile(File.java:2010)
    at com.sun.jna.Native.extractFromResourcePath(Native.java:1174)
    at com.sun.jna.Native.loadNativeDispatchLibraryFromClasspath(Native.java:1036)
    at com.sun.jna.Native.loadNativeDispatchLibrary(Native.java:1015)
    at com.sun.jna.Native.<clinit>(Native.java:221)
    at com.sun.jna.platform.win32.Advapi32.<clinit>(Advapi32.java:70)
    at Main.registerHandler(Main.java:11)
    at Main.main(Main.java:6)

In safe mode with networking it works perfectly (outputs 1 and sleeps for 60 seconds). Winapi docs does not provide much help. I also searched on jna issues on GitHub.

Provide complete information about the problem

  1. Version of JNA and related jars 5.12.1

  2. Version and vendor of the Java virtual machine Oracle, 1.8.0_251

  3. Operating system Windows 10 Build 19041

  4. System architecture (CPU type, bitness of the JVM) 64 bit

  5. Complete description of the problem -> Already discussed

  6. Steps to reproduce -> Already discussed


Solution

  • The error occurs when JNA is extracting its native library to a temporary directory and uses the JDK’s methods for creating a randomly named temporary file, which internally invokes the random number generator.

    However, the bug is not in JNA, it's in the JDK's java.io.File.createTempFile() method as shown in the stack trace.

    The root problem is a bug in the JDK introduced in jdk8, JDK-8066931:

    When running a Java website on Azure you don't have access to the network interfaces. Since http://hg.openjdk.java.net/jdk8u/jdk8u20/jdk/rev/c6836440c427 the way SecureRandom works is to add the network addresses to the seed hash which causes the application to not work when deployed on Azure. Because no a lot of applications use the SecureRandom class they cannot be used as an Azure web site with the current JDK version.

    It was fixed in JDK18 with better exception handling in JDK-8275319.

    Your options to resolve this:

    1. Upgrade to JDK 18 or newer. It does not look like the fix has been backported to earlier JDKs.
    2. Pre-extract the JNA native library (jnidispatch) to a location of your choice and point JNA to it via jna.boot.library.path parameter, or put it in your system library path. See the "Loading JNA" section of the Overview.
    3. Make sure you have at least one network interface.

    Alternately you might experiment with newer versions of the JDK; while the underlying root cause may not have been fixed until JDK 18, there may have been other methods used in temporary file generation that worked around this known issue.

    The JDK 8 version you're using was released nearly 3 years ago and there have been 4 Oracle active support releases since then (up to 291) with security support versions up to 361 if you are constrained to using Oracle's JDK.