Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8331672

Implement JEP 472: Prepare to Restrict the Use of JNI

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 24
    • core-libs
    • None
    • low
    • Hide
      After enabling native access as appropriate or allowing illegal native access, the program will run exactly as before.

      Without doing one of the above, the program will emit a warning (or potentially several if the module path is used) to the standard error. This could impact programs that are sensitive to their console output.
      Show
      After enabling native access as appropriate or allowing illegal native access, the program will run exactly as before. Without doing one of the above, the program will emit a warning (or potentially several if the module path is used) to the standard error. This could impact programs that are sensitive to their console output.
    • Java API, add/remove/modify command line option
    • SE

      Summary

      Issue warnings about uses of the Java Native Interface (JNI). These warnings aim to prepare developers for a future release that restricts the use of JNI by default in order to improve integrity by default. The warnings issued in this release, and the exceptions thrown in that future release, can be avoided by selectively enabling native access. Adjust the Foreign Function & Memory API (JEP 454) to issue warnings in a consistent manner.

      Problem

      Any interaction at all between Java code and native code is risky because it can compromise the integrity of applications and of the Java Platform itself. According to the policy of integrity by default, all JDK features that are capable of breaking integrity must obtain explicit approval from the application's developer.

      Solution

      The FFM API restricts the ability to load native libraries and to obtain method handles for native code; it does not restrict the ability to call native code. We propose here to do the same for JNI, by restricting the loading of native libraries and the binding of native methods; we will not restrict the calling of native methods. As with the FFM API, these restrictions can be lifted for specific modules by enabling native access for those modules. We will strengthen the effects of the restrictions over time, starting with warnings and proceeding gradually to unavoidable exceptions.

      Specification

      Enabling native access

      You can lift the native-access restrictions for selected modules, in effect acknowledging your application's need to load native libraries and bind native methods, in the same way as for the FFM API. At startup, use the command line option

      $ java --enable-native-access=M,... ...

      where M,... is a comma-separated list of modules that should be allowed to perform restricted operations. To lift restrictions on code on the class path, use

      $ java --enable-native-access=ALL-UNNAMED ...

      As an alternative to the --enable-native-access option, you can add this attribute to the manifest of an executable JAR file, i.e., a JAR file that is launched via the java -jar option:

      Enable-Native-Access: ALL-UNNAMED

      ALL-UNNAMED is the only supported value; other module names cause an exception to be thrown.

      When a module is created programmatically, you can enable native access for it via the <code class="prettyprint" data-shared-secret="1741789421827-0.40386687429455803">ModuleLayer.Controller::enableNativeAccess</code> method, which is itself a restricted method.

      The JNI Invocation API allows a native application to embed a JVM in its own process. A native application which uses the JNI Invocation API can enable native access for modules in the embedded JVM by passing the --enable-native-access option when creating the JVM.

      Code can test, at runtime, whether or not its module has native access enabled with the method Module.isNativeAccessEnabled.

      Controlling the consequences of illegal native access

      Performing a restricted operation in a module that does not have native access is deemed illegal. What action the Java runtime takes when such an operation is attempted is controlled by a new command line option, --illegal-native-access, which is similar in spirit and form to the --illegal-access option introduced by JEP 261 in JDK 9. It works as follows:

      • --illegal-native-access=allow allows the operation to proceed.

      • --illegal-native-access=warn allows the operation but issues a warning the first time that illegal native access occurs in a particular module. At most one warning per module is issued.

        This mode is the default in JDK 24. It will be phased out in a future release and, eventually, removed.

      • --illegal-native-access=deny throws an IllegalCallerException exception for every illegal native access operation.

        This mode will become the default in a future release.

      When deny becomes the default mode then allow will be removed but warn will remain supported for at least one release.

      Aligning the FFM API

      In prior releases, if one or more modules were granted native access via the --enable-native-access option then attempts to call restricted FFM methods from any other module would cause an IllegalCallerException to be thrown.

      To align the FFM API with JNI, we will relax this behavior so that illegal native access operations are treated exactly the same by the FFM API as in JNI. This means that, in JDK NN, such operations will result in warnings rather than exceptions.

      Applications currently using the FFM API can get the old behavior with this combination of options:

      $ java --enable-native-access=M,... --illegal-native-access=deny

      Warnings on loading native libraries

      Native libraries are loaded via the <code class="prettyprint" data-shared-secret="1741789421827-0.40386687429455803">load</code> and <code class="prettyprint" data-shared-secret="1741789421827-0.40386687429455803">loadLibrary</code> methods of the java.lang.Runtime class. (The identically named convenience methods <code class="prettyprint" data-shared-secret="1741789421827-0.40386687429455803">load</code> and <code class="prettyprint" data-shared-secret="1741789421827-0.40386687429455803">loadLibrary</code> of the java.lang.System class merely invoke the corresponding methods of the system-wide Runtime instance.)

      The methods java.lang.Runtime.load, java.lang.System.load, java.lang.Runtime.loadLibrary, and java.lang.System.loadLibrary are annotated with @Restricted.

      When a restricted method is called from a module that has not been granted native access via the --enable-native-access option, 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 an unnamed module (file:/path/to/comfoo.jar)
      WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
      WARNING: Restricted methods will be blocked in a future release unless native access is enabled

      The warning is written to the standard error stream. At most one such warning is issued for any particular module, and only if a native-access warning has not yet been issued for that module. (The unnamed module, mentioned in this example warning, is the module containing code on the class path.)

      Warnings on binding native methods

      When a native method in Java code is first called, the method is linked to the corresponding native code in a native library. This operation is called binding the native method. (The correspondence between the native method and the native code is described here.)

      Binding a native method is a restricted operation, just as obtaining a downcall handle via the FFM API’s <code class="prettyprint" data-shared-secret="1741789421827-0.40386687429455803">Linker::downcallHandle</code> method is restricted. When a native method is bound in a module that has not been granted native access via the --enable-native-access option, the JVM binds 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 is declared in module foomod (file:/path/to/comfoo.jar)
      WARNING: Use --enable-native-access=foomod to avoid a warning for callers in this module
      WARNING: Restricted methods will be blocked in a future release unless native access is enabled

      At most one such warning is issued for any particular module. Specifically:

      • The warning is issued only when a native method is bound, which happens the first time that the native method is called. The warning is not issued every time that the native method is called.

      • The warning is issued the first time that any native method declared in a particular module is bound, unless a native-access warning has already been issued for that module.

      Identifying the use of native code

      • The JFR events jdk.NativeLibraryLoad and jdk.NativeLibraryUnload track the loading and unloading of native libraries.

      • To help identify libraries that use JNI, a new JDK tool, jnativescan, statically scans code in a provided module/class path and reports use of restricted methods as well as classes declaring native methods. The tool is described in the CSR JDK-8334569.

      Documentation

      Man page diff

      \f[V]--enable-native-access\f[R] \f[I]module\f[R][\f[V],\f[R]\f[I]module\f[R]...]
      Native access involves access to code or data outside the Java runtime.
      This is generally unsafe and, if done incorrectly, might crash the JVM
      or result in memory corruption.
      Native access can occur as a result of calling a method that is either
      \f[B]restricted\f[R] https://openjdk.org/jeps/454#Safety, or
      \f[V]native\f[R].
      This option allows code in the specified modules to perform native
      access.
      Native access occurring in a module that has not been explicitly enabled
      is deemed \f[I]illegal\f[R].
      .RS
      .PP
      \f[I]module\f[R] can be a module name, or \f[V]ALL-UNNAMED\f[R] to
      indicate code on the class path.
      .RE
      .TP
      -\f[V]--illegal-native-access=\f[R]\f[I]parameter\f[R]
      This option specifies a mode for how illegal native access is handled:
      .RS
      .RS
      .PP
      \f[B]Note:\f[R] This option will be removed in a future release.
      .RE
      .IP \[bu] 2
      \f[V]allow\f[R]: This mode allows illegal native access in all modules,
      without any warings.
      .IP \[bu] 2
      \f[V]warn\f[R]: This mode is identical to \f[V]allow\f[R] except that a
      warning message is issued for the first illegal native access found in a
      module.
      This mode is the default for the current JDK but will change in a future
      release.
      .IP \[bu] 2
      \f[V]deny\f[R]: This mode disables all illegal native access except for
      those modules enabled by the \f[V]--enable-native-access\f[R]
      command-line option.
      That is, any illegal native access causes an
      \f[V]IllegalCallerException\f[R].
      This mode will become the default in a future release.
      .PP
      To verify that your application is ready for a future version of the
      JDK, run it with \f[V]--illegal-native-access=deny\f[R] along with any
      necessary \f[V]--enable-native-access\f[R] options.

        1. api_spec_diff_v1.zip
          6.28 MB
        2. jni_design_spec_diff.txt
          4 kB
        3. jni_intro_spec_diff.txt
          3 kB
        4. Runtime-report.html
          89 kB
        5. System-report.html
          118 kB

            rpressler Ron Pressler
            rpressler Ron Pressler
            Alan Bateman, Maurizio Cimadamore
            Votes:
            1 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: