Advanced tools: playing with Java Native Access

This post results from a recent deep diving in the source code of Elasticsearch, which uses JNA mainly for memory management when configuring the mlockall. I will present you how to use JNA in a very simple example: how to check the user who has launched the JVM.

Note
Remember that when you are thinking about solution using OS native calls, you must deal and depend with platform librairies. So use it carefully and only for specific needs.

First of all, we need JNA:

<dependency>
  <groupId>net.java.dev.jna</groupId>
  <artifactId>jna</artifactId>
  <optional>true</optional>
  <version>3.2.3</version>
</dependency>

Now let’s encapsulate the JNA calls in 2 dedicated classes, a specific JNA class using the C library and a facade for all native calls using JNA:

public final class JNANatives {

    /** no instantiation */
    private JNANatives() {}

    /**
     * Returns true if user is root, false if not, or if we don't know
     */
    public static boolean isRunningAsRoot() {
        return getUid() == 0;
    }

    public static int getUid() {
        if (System.getProperty("os.name").startsWith("Windows")) {
            return -1; // don't know
        }
        try {
            return JNACLibrary.geteuid();
        } catch (UnsatisfiedLinkError e) {
            return -1;
        }
    }
}
import com.sun.jna.Native;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public static final class JNACLibrary {

    static {
        try {
            Native.register("c");
        } catch (UnsatisfiedLinkError e) {
            log.warn("Unable to link C library, native methods (geteuid) are disabled.", e);
        }
    }

    static native int geteuid();

    private JNACLibrary() {
    }
}

Now with a simple test:

public class RootTest {

    @Test
    public void test() {

        System.err.println("Running with uid: " + JNANatives.getUid() + " (is root? -> " + JNANatives.isRunningAsRoot() + ")");
        Assert.assertFalse(JNANatives.isRunningAsRoot());
    }
}

When running this test with my profile:

$ whoami
devil
$ cat /etc/passwd | grep devil
devil:x:1000:1000:devil,,,:/home/devil:/usr/bin/zsh

the result is:

Running with uid: 1000 (is root? -> false)
$ whoami
root
$ cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/zsh

the result is:

Running with uid: 0 (is root? -> true)

Credits:
– by Markus Spiske, licensed under CC0 1.0

Related Posts

Leave a comment