JEP 472, Prepare to Restrict the Use of JNI, has been promoted to Proposed to Target. This JEP proposes issuing warnings for the use of the Java Native Interface (JNI) and adjusting the Foreign Function & Memory (FFM) API to issue consistent warnings. This prepares developers for a future release that ensures integrity by default by uniformly restricting JNI and the FFM API. This proposal builds on the long-term efforts to enhance the security and performance of the Java Platform, following the examples of JEP 454, Foreign Function & Memory API; JEP 471, Deprecate the Memory-Access Methods of sun.misc.Unsafe; and JEP 451, Prepare to Restrict the Dynamic Loading of Agents. The main goal is to ensure that any use of JNI and the FFM API in future releases will require explicit approval from the application's developer at startup.
The JNI, introduced in JDK 1.1, has been a standard way for Java code to interoperate with native code. However, any interaction between Java code and native code can compromise the integrity of applications and the Java Platform itself. For example, calling native code can lead to unpredictable issues, including JVM crashes, that cannot be handled by the Java runtime or caught with exceptions. These issues can disrupt the normal operation of the Java Platform and the applications running on it.
For example, consider the following C function that takes a long
value passed from Java code and treats it as an address in memory, storing a value at that address:
void Java_pkg_C_setPointerToThree__J(jlong ptr) {
*(int*)ptr = 3; // Potential memory corruption
}
Additionally, exchanging data through direct byte buffers, which are not managed by the JVM's garbage collector, can expose Java code to invalid memory regions, leading to undefined behavior. Furthermore, native code can bypass JVM access checks and modify fields or call methods, potentially violating the integrity of Java code, such as by mutating String objects.
JEP 472 proposes a staged approach to restrict JNI usage to mitigate these risks. Initially, warnings will be issued for operations that load and link native libraries uniformly in both JNI and the FFM API.
Developers can avoid warnings by enabling native access for specific Java code at startup. The command-line option --enable-native-access=ALL-UNNAMED
enables native access to all codes on the classpath. For specific modules, developers can pass a comma-separated list of module names, such as java --enable-native-access=M1,M2,...
.
Code that calls native methods declared in another module does not need to have native access enabled. However, code that calls System::loadLibrary, System::load, Runtime::loadLibrary
, or Runtime::load
, or declares a native method is affected by native access restrictions. When a restricted method is called from a module for which native access is not enabled, the JVM runs the method but, by default, issues a warning that identifies the caller:
WARNING: A restricted method in java.lang.System has been called
WARNING: System::load has been called by com.foo.Server in module com.foo (file:/path/to/com.foo.jar)
WARNING: Use --enable-native-access=com.foo to avoid a warning for callers in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
Developers can avoid these warnings and future restrictions by explicitly enabling native access for specific code at startup using the --enable-native-access
command-line option. This option can be applied globally or selectively to specific modules on the module path.
The impact of native access restrictions can be controlled using the --illegal-native-access
option. Its modes include:
allow
: Allows the restricted operation without warnings.warn
: Issues a warning for the first occurrence of illegal native access in a module (default in the upcoming release).deny
: Throws anIllegalCallerException
for every illegal native access operation (planned default for a future release).
The long-term goal is to transition the default behavior to deny
, enforcing stricter security measures by default. This change aligns with broader efforts to achieve integrity across the Java Platform by default, enhancing security and performance.
Developers are encouraged to use the deny
mode to proactively identify code that requires native access and make necessary adjustments. Additionally, a new tool, jnativescan
, will be introduced to help identify libraries using JNI.
In conclusion, JEP 472 marks a significant step towards a more secure Java Platform. While the transition to stricter JNI restrictions may require some adjustments, the resulting benefits in terms of security and integrity are expected to be substantial. Developers can ensure a smooth transition and contribute to a more robust Java ecosystem by preparing for these changes.