Search code examples
javajava-native-interfacefortify

How to resolve unsafe JNI error on fortify


I'm in trouble with the fortify error UNSAFE JNI.

I've a class that calls native methods into a second class.

The second class uses JNI.

When I run a fortify scan, I get an Unsafe JNI error.

I tried to resolve removing the pointer parameter from all the methods, but it doesn't work.

Any idea about the resolution? thanks.

Class 1.

public class SteamGameServer extends SteamInterface {

    public SteamGameServer(SteamGameServerCallback callback) {
        super(SteamGameServerAPINative.getSteamGameServerPointer(),
                SteamGameServerNative.createCallback(new SteamGameServerCallbackAdapter(callback)));
    }

    public void setProduct(String product) {
        SteamGameServerNative.setProduct(pointer, product);
    }

    public void setGameDescription(String gameDescription) {
        SteamGameServerNative.setGameDescription(pointer, gameDescription);
    }

    public void setModDir(String modDir) {
        SteamGameServerNative.setModDir(pointer, modDir);
    }

    public void setDedicatedServer(boolean dedicated) {
        SteamGameServerNative.setDedicatedServer(pointer, dedicated);
    }

    public void logOn(String token) {
        SteamGameServerNative.logOn(pointer, token);
    }

    public void logOnAnonymous() {
        SteamGameServerNative.logOnAnonymous(pointer);
    }

    public void logOff() {
        SteamGameServerNative.logOff(pointer);
    }

    public boolean isLoggedOn() {
        return SteamGameServerNative.isLoggedOn(pointer);
    }

    public boolean isSecure() {
        return SteamGameServerNative.isSecure(pointer);
    }

    public SteamID getSteamID() {
        return new SteamID(SteamGameServerNative.getSteamID(pointer));
    }

    public boolean wasRestartRequested() {
        return SteamGameServerNative.wasRestartRequested(pointer);
    }

    public void setMaxPlayerCount(int playersMax) {
        SteamGameServerNative.setMaxPlayerCount(pointer, playersMax);
    }

    public void setBotPlayerCount(int botplayers) {
        SteamGameServerNative.setBotPlayerCount(pointer, botplayers);
    }

    public void setServerName(String serverName) {
        SteamGameServerNative.setServerName(pointer, serverName);
    }

    public void setMapName(String mapName) {
        SteamGameServerNative.setMapName(pointer, mapName);
    }
}

Class 2. (With native methods)

class SteamGameServerNative {

    private SteamGameServerNative () {
        
    }
    
    // @off

    /*JNI
        #include "SteamGameServerCallback.h"
    */

    static native long createCallback(Object javaCallback); 
    
    static native void setProduct(long pointer, String product); 

    static native void setGameDescription(long pointer, String gameDescription);

    static native void setModDir(long pointer, String modDir);

    static native void setDedicatedServer(long pointer, boolean dedicated);

    static native void logOn(long pointer, String token);

    static native void logOnAnonymous(long pointer);
    
    static native void logOff(long pointer);

    static native boolean isLoggedOn(long pointer);

    static native boolean isSecure(long pointer);

    static native long getSteamID(long pointer);

}

Solution

  • Per Fortify, any use of JNI is automatically tagged with the "Unsafe JNI" error flag.

    "Unsafe JNI" errors occur when a Java application uses JNI to call code written in another programming language. Improper use of JNI can render Java applications vulnerable to security flaws in other languages.

    The only way to prevent Fortify from tagging Java code with "Unsafe JNI" errors is to remove all JNI use from your code. This is not a viable or realistic solution if you need to use JNI. JNI is typically safe to use when proper coding practices are in place.

    The "Unsafe JNI" error is NOT a positive indicator of an existing vulnerability or error.

    A "Unsafe JNI" error is not necessarily a code problem to remediate. Fortify scanning is simply incapable of determining whether any given use of JNI has appropriate vulnerability safeguards in place on both the Java and non-Java sides of the JNI workflow. Therefore, Fortify must tag every JNI use as "Unsafe JNI".

    "Unsafe JNI" is a flag indicating a manual audit of the JNI code section is required to ensure appropriate safeguards are in place. The audit should be a code review between software development and security auditor personnel. Once any identified missing safeguards are remediated, the auditor should manually suppress the "Unsafe JNI" error.

    Fortify recommends resolving "Unsafe JNI" via manual auditing:

    Audit all source code comprising a given application, including native methods implemented in other languages. During audits, ensure that differences in bounds checking and other behavior between Java and native code are accounted for and handled correctly. In particular, verify that shared objects are handled correctly at all stages: before they are passed to native code, while they are manipulated by native code, and after they are returned to the Java application.

    The Fortify "Unsafe JNI" error is derived from CWE-111, which also recommends a manual audit as the resolution:

    When a Java application uses the Java Native Interface (JNI) to call code written in another programming language, it can expose the application to weaknesses in that code, even if those weaknesses cannot occur in Java.

    Many safety features that programmers may take for granted do not apply for native code, so you must carefully review all such code for potential problems. The languages used to implement native code may be more susceptible to buffer overflows and other attacks. Native code is unprotected by the security features enforced by the runtime environment, such as strong typing and array bounds checking.