Security Guide

This security guide provides information on the security model and features of Oracle GraalVM Enterprise Edition for developers and embedders who seek to build a secure application on top of it. It assumes that readers are familiar with the architecture of GraalVM Enterprise. It also provides security researchers with information on GraalVM’s security model.

This guide does not replace Java’s own security documentation but rather supplements it with aspects unique to GraalVM Enterprise.

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

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 later. Developers who implement security controls for their applications (such as access control) can rely on the correct execution of those instructions. Incorrect execution of security-critical code running on top of GraalVM Enterprise that allows such security controls to be bypassed is regarded as a security vulnerability.

Please Note

Experimental and early-adopter features are not for production use and may have security limitations not covered in the Security Guide.

Debug features should only be used in a trusted environment as they provide privileged access to an application, allowing users to inspect and change its state and behavior. Debug features may also open network sockets to allow debug clients to connect.

For every language implemented with the Truffle language implementation framework (henceforth “Truffle”), and 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. The languages implemented with Truffle are henceforth referenced as guest languages.

Guest Applications

GraalVM allows a host application written in a JVM-based language to create an execution context to run code written in one or more guest languages. 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. Note that this is currently only fully supported by Javascript.

File I/O

Access to files can be controlled via two means.

  1. The allowIO privilege grants the guest application unrestricted access to the host file system:
    Context context = Context.newBuilder().allowIO(true).build();
    
  2. Alternatively, the Truffle framework virtual file system can be installed that all guest file I/O will be routed through:
    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 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");

This 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.

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()

Computational Resource Limits

Oracle GraalVM Enterprise Edition allows users to control certain computational resources used by guest applications, such as CPU time, a number of threads that can be concurrently used by a context, etc. Those can be restricted with the sandbox options.

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.

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 it must be remembered that violations of memory safety are a frequent cause of 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 Enterprise. 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.

Native Image

The Native Image function generates a snapshot of an application after startup and bundles it in a binary executable.

By default, Native Image executes the static initializers of classes at build time and persists the state in the native image heap. This means that any information that is obtained or computed in static initializers becomes part of the native image executable. This can lead to unintentionally including properties of the build environment, such as environment variables in the image heap. This can either result in sensitive data ending up in the snapshot, or fixing initialization data that is supposed to be obtained at startup, such as random number seeds.

Developers can request static initializers that process sensitive information to be instead executed at runtime by either specifying the --initialize-at-run-time CLI parameter when building a native image, or making use of the RuntimeClassInitialization API.

In addition, developers can run Native Image in a dedicated environment, such as a container, that does not contain any sensitive information in the first place.

Security Manager and Untrusted Code

The OpenJDK vulnerability group strongly discourages running untrusted code under a security manager. This also applies to GraalVM Enterprise, which does not support untrusted code execution in Java. While GraalVM Enterprise’s ability to restrict the execution of guest language applications to a certain extent is not dependent on a security manager, it is not suited to be used as a sandbox for running untrusted code.

Native Image does not support a security manager in general. Attempting to set a security manager will trigger a runtime error.

The Truffle framework needs to be invoked with all permissions to make full use of its functionality - it provides its own controls to manage resources.

If untrusted and potentially malicious code is to be executed, we recommend GraalVM Enterprise 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 that allow for native code extensions, such as Python and Ruby.