Security Guide

This security guide provides developers and embedders with information on the security model and features of Oracle GraalVM Enterprise Edition, such that they can build a secure application on top of it. It assumes that readers are familiar with the architecture of GraalVM Enterprise. This guide does not replace but rather supplements the Java security documentation with aspects unique to GraalVM Enterprise. It also provides security researchers with information on GraalVM’s security model.

This guide does not (yet) cover security aspects specific to a language implementation, usage of the Instrument API or any APIs other than the Polyglot API.

Security Model

Oracle GraalVM Enterprise Edition is a runtime. It accepts instructions in a higher-level programming language (or an intermediate representation thereof) as input, which is executed at some point. Developers that that implement security controls for their applications (such as access control) in code that is being run by GraalVM Enterprise can rely on the correct execution of instructions. Incorrect execution of security-critical code running on top of GraalVM Enterprise that allows to bypass such a security control is regarded a security vulnerability.

Using the Truffle Language Implementation framework of GraalVM Enterprise, interpreters for guest languages can be implemented to execute guest applications written in languages such as Javascript, Python or Ruby on top of GraalVM. The execution context for these guest applications can be created with restricted privileges, to allow for the execution of less trusted guest applications. For example, an embedder writes an application server (the host application) that runs JavaScript guest applications from a less trusted source. GraalVM offers features to limit the privileges of the guest application to some extent.

For every guest language shipped with GraalVM, a launcher, e.g. (interactive) shell, is provided. These launchers behave in the same way and come with the same security guarantees as their “original” counterparts.

We appreciate reports of bugs that break the security model via the process outlined in the Reporting Vulnerabilities guide.

Guest Application Context

GraalVM allows a host application written in a JVM-based language to create an execution context to run code written in one or multiple guest language(s). When creating a context, the host application can control which resources the guest can access. By default access to all managed resources is denied and needs to be granted explicitly.

Beyond controlling access to these resources, the execution context also enables timeboxing of guest applications: a watchdog thread that runs in the host application can be configured to close a context after a given amount of time specified by the host application, freeing up the computing resources used by the context.

File I/O

Access to files can be controlled via two means. The allowIO privilege grants the guest application unrestricted access to the host file system:

Context context = Context.newBuilder().allowIO(true).build();

Alternatively the Truffle framework virtual file system that all guest file I/O will be routed through can be installed:

Context context = Context.newBuilder().fileSystem(FileSystem fs).build();

Threading

A guest application can only create new threads, if the context is created with the corresponding privilege:

Context context = Context.newBuilder().allowCreateThread(true).build()

Native Access

The Truffle framework native interface allows access to privileged native code. It needs to be granted to a guest application context via:

Context context = Context.newBuilder().allowNativeAccess(true).build()

Host Interoperability

GraalVM Enterprise allows exchanging objects between the host and the guest application. Since the guest application is potentially less trusted than the host application, multiple controls exist to tune the degree of interoperability between the guest and the host:

The host access policy has three different options:

The following example demonstrates how these configuration options work together:

 public class MyClass {
     @HostAccess.Export
     public int accessibleMethod() {
         return 42;
     }

     public static void main(String[] args) {
         try (Context context = Context.newBuilder() //
                         .allowHostClassLookup(c -> c.equals("myPackage.MyClass")) //
                         .build()) {
             int result = context.eval("js", "" +
                             "var MyClass = Java.type('myPackage.MyClass');" +
                             "new MyClass().accessibleMethod()").asInt();
             assert result == 42;
         }
     }
 }

This Java/JavaScript example

The guest can also pass objects back to the host. This is implemented by functions that return a value. For example,

Value a = Context.create().eval("js", "21 + 21");

returns a guest object representing the value “42”. When executing less trusted guest code, application developers need to take care when processing objects returned from the guest application – the host application should treat them as less trusted input and sanitize accordingly.

Managed Execution of Native Code

The Truffle framework also supports the LLVM intermediate representation (IR) as a guest language. Several native system programming languages, above all C/C++, can be compiled to LLVM IR with the LLVM compiler toolchain. Typically, these languages are not memory safe by themselves and violations of memory safety being a frequent cause for security vulnerabilities.

Oracle GraalVM Enterprise Edition supports a managed execution mode for LLVM IR code. In managed mode, all ties to the native level are abstracted and routed through GraalVM. In particular this means that:

Managed mode can be selected when creating a context (Context.create()) or when calling the bin/lli binary by specifying the --llvm.managed option. A “managed” context will adhere to any restrictions (e.g., allowIO) passed during context creation and does not need the allowNativeAccess privilege.

Security Caveats

In this section we address security caveats that are specific to GraalVM Enterprise.

Sharing Execution Engines

Application developers may choose to share execution engines among execution contexts for performance reasons. While the context holds the state of the executed code, the engine holds the code itself. Sharing of an execution engine among multiple contexts needs to be set up explicitly and can increase performance in scenarios where a number of contexts execute the same code. In scenarios where contexts that share an execution engine for common code also execute sensitive (i.e., private) code, the corresponding source objects can opt out from code sharing with:

Source.newBuilder(…).cached(false).build()

ScriptEngine Compatibility

For reasons of backward compatibility, certain guest languages also support Java’s ScriptEngine interface. For example, this allows GraalVM JavaScript to be used as a drop-in replacement for Nashorn. However, to maintain compatibility, the Nashorn GraalVM JavaScript ScriptEngine interface will create a context with all privileges granted to the script and should be used with extreme caution and only for trusted code.

Security Manager and Untrusted Code

The OpenJDK vulnerability group strongly discourages to running untrusted code under a security manager. This also applies to GraalVM, which does not support untrusted code execution in Java – GraalVM Native Image does not support a security manager in general. While GraalVM’s ability to restrict the execution of guest languages (languages implemented with Truffle framework) applications to a certain extent is not dependent on a security manager, it is also not suited to be used as a sandbox for running untrusted code.

If untrusted and potentially malicious code is to be executed, we recommend GraalVM customers who have an immediate requirement to execute untrusted and potentially adversarial code, adopt the appropriate isolation primitives to ensure the confidentiality and integrity of their application data.

GraalVM Enterprise to GraalVM Community Downgrade

GraalVM’s managed execution of native code is only available in GraalVM Enterprise. When downgrading to GraalVM Community, native code execution is only available with the allowNativeAccess privilege. This also applies to languages implemented with Truffle framework that allow for native code extensions, such as Python and Ruby.

Configuring Host Access

Running less trusted applications requires special attention to which host methods are exposed to the guest application. For example, if a Java method is exposed that calls System.exit then the guest application will be able to exit the host process. In order to avoid accidentally exposed methods, no host access is allowed by default and every public method or field needs to be annotated with @HostAccess.Export explicitly.

public class Employee {
    private final String name;
    Employee(String name) {this.name = name;}

    @HostAccess.Export
    public String getName() {
        return name;
    }
}

public class Services {
    @HostAccess.Export
    public Employee createEmployee(String name) {
        return new Employee(name);
    }

    public void exitVM() {
        System.exit(1);
    }
}

public static void main(String[] args) {
    try (Context context = Context.create()) {
        Services services = new Services();
        context.getBindings("js").putMember("services", services);
        String name = context.eval("js",
                "let emp = services.createEmployee('John Doe');" +
                "emp.getName()").asString();
        assert name.equals("John Doe");

        try {
            context.eval("js", "services.exitVM()");
            assert false;
        } catch (PolyglotException e) {
            assert e.getMessage().endsWith(
                    "Unknown identifier: exitVM");
        }
    }
}

In this code:

Host access is fully customizable by creating a custom HostAccess policy described in Host Interoperability section above.

Access Privilege Configuration

It is possible to configure fine-grained access privileges for guest applications. The configuration can be provided using the Context.Builder class when constructing a new context. The following access parameters may be configured:

Warning: Allowing access to class loading, native APIs or host IO must not be enabled for less trusted code as these privileges effectively allow all access.