Security Guide
This security guide provides developers and embedders with information on thesecurity model and features of GraalVM, such that they can build a secureapplication on top of it. It assumes that readers are familiar with the GraalVMarchitecture. This guide does not replace but rather supplements the Javasecurity documentation with aspects unique to GraalVM. It also provides securityresearchers with information on GraalVM’s security model.
This guide does not (yet) cover security aspects specific to a languageimplementation, usage of the Instrument API or any APIs other than the PolyglotAPI.
Security Model
GraalVM is a shared runtime. It accepts instructions in a higher-levelprogramming language (or an intermediate representation thereof) as input, whichis executed at some point. Developers that implement security controls for theirapplications (such as access control) in code that is being run by GraalVM canrely on the correct execution of instructions. Incorrect execution ofsecurity-critical code running on top of GraalVM that allows to bypass such asecurity control is regarded a security vulnerability.
Using the Truffle Language Implementation framework,interpreters for guest languages can be implemented to execute guestapplications written in languages such as Javascript, Python, Ruby or R on top ofGraalVM. The execution context for these guest applications can be created withrestricted privileges, to allow for the execution of less trusted guestapplications. For example, an embedder writes an application server (the hostapplication) that runs JavaScript guest applications from a less trusted source.GraalVM offers features to limit the privileges of the guestapplication 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 thesame security guarantees as their “original” counterparts.
Warning: GraalVM provides only experimental support for Python, R and Ruby languages.
We appreciate reports of bugs that break the security model via the processoutlined in the Reporting Vulnerabilities guide.
Guest Application Context
GraalVM allows a host application written in a JVM-based language to create anexecution context to run code written in one or multiple guest language(s). Whencreating a context, the host application can control which resources the guestcan access. By default access to all managed resources is denied and needs to begranted explicitly.
Beyond controlling access to these resources, the execution context also enablestimeboxing of guest applications: a watchdog thread that runs in the hostapplication can be configured to close a context after a given amount of timespecified by the host application, freeing up the computing resources used bythe context.
File I/O
Access to files can be controlled via two means. The allowIO
privilege grantsthe 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 allows exchanging objects between the host and the guestapplication. Since the guest application is potentially less trusted than thehost application, multiple controls exist to tune the degree of interoperabilitybetween the guest and the host:
allowHostAccess(policy)
– configures which public constructors, methods or fields of public classes of the host can be accessed by the guestallowHostClassLookup(Predicate<String> classFilter)
– allows the guest application to look up the host application classes specified in the classFilter viaJava.type
. For example, a Javascript context can create a Java ArrayList, provided that ArrayList is whitelisted by the classFilter and access is permitted by the host access policy:context.eval("js", "var array = Java.type('java.util.ArrayList')")
allowHostClassLoading(true/false)
- allows the guest application to access the host’s class loader to load new classes. Classes are only accessible if access to them is granted by the host access policy.
The host access policy has three different options:
ALL
- all public constructors, methods or fields of public classes of the host can be accessed by the guest.NONE
- no constructors, methods or fields of the host can be accessed by the guest.EXPLICIT
- only public constructors, methods and fields of public classes that are annotated with@HostAccess.Export
can be accessed by the guest.
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
- creates a new context with the permission to look up the class
myPackage.MyClass
in the guest applicationevaluates a JavaScript code snippet that accesses the Java classmyPackage.MyClass
using theJava.type
builtin provided by the JavaScript language implementation - creates a new instance of the Java class
MyClass
by using the JavaScriptnew
keyword - calls the method
accessibleMethod()
which returns “42”. The method is accessible to the guest language because because the enclosing class and the declared method are public, as well as annotated with the@HostAccess.Export
annotation.
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 trustedguest code, application developers need to take care when processing objectsreturned from the guest application – the host application should treat them asless trusted input and sanitize accordingly.
Managed Execution of Native Code
The Truffle framework also supports the LLVM intermediate representation (IR) asa guest language. Several native system programming languages, above all C/C++,can be compiled to LLVM IR with the LLVM compiler toolchain. Typically, theselanguages are not memory safe by themselves and violations of memory safetybeing a frequent cause for security vulnerabilities.
The GraalVM Enterprise Edition adds support for a managed execution mode for LLVM IRcode. In managed mode, all ties to the native level are abstracted and routedthrough GraalVM. In particular this means that:
- Temporal and spatial memory safety. Memory is allocated from the Java heap. Thismeans that memory allocations are managed objects and all accesses are performedin a memory-safe manner (no arbitrary pointer arithmetics, no uncheckedout-of-bounds accesses).
- Type safety. It is not possible to reinterpret a data pointer into a functionpointer and execute arbitrary instructions (since these are distinct pointertypes for LLVM Runtime).
- System calls are intercepted and routed to the corresponding Truffle frameworkAPIs. For example, file IO is mapped to the Truffle framework FileSystem API.The set of currently supported system calls is very limited – only syscallsthat can safely be mapped to the Truffle API level are available. Since LLVMruntime in managed mode always runs bitcode compiled for Linux/x86, it onlyneeds to implement system calls for this platform.
- All dependent libraries are executed in managed mode as well, removing allreferences to natively executed system libraries. This includes libraries thatare provided by the LLVM Runtime, such as muslibc.
Managed mode can be selected when creating a context (Context.create())
orwhen calling the bin/lli
binary by specifying the —llvm.managed
option. A“managed” context will adhere to any restrictions (e.g., allowIO
) passedduring context creation and does not need the allowNativeAccess
privilege.
Security Caveats
In this section we address security caveats that are specific to GraalVM Enterprise Edition.
Sharing Execution Engines
Application developers may choose to share execution engines among executioncontexts for performance reasons. While the context holds the state of theexecuted code, the engine holds the code itself. Sharing of an execution engineamong multiple contexts needs to be set up explicitly and can increaseperformance in scenarios where a number of contexts execute the same code. Inscenarios where contexts that share an execution engine for common code alsoexecute sensitive (i.e., private) code, the corresponding source objects can optout from code sharing with:
Source.newBuilder(…).cached(false).build()
ScriptEngine Compatibility
For reasons of backward compatibility, certain guest languages also supportJava’s ScriptEngine interface. For example, this allows GraalVM JavaScript to beused as a drop-in replacement for Nashorn. However, to maintain compatibility,the Nashorn GraalVM JavaScript ScriptEngine interface will create a context withall privileges granted to the script and should be used with extreme caution andonly for trusted code.
Security Manager and Untrusted Code
The OpenJDK vulnerability group strongly discourages to running untrusted codeunder a security manager. This also applies to GraalVM, which does not supportuntrusted code execution in Java – GraalVM Native Image does not support asecurity manager in general. While GraalVM’s ability to restrict the executionof guest languages (languages implemented with Truffle framework) applicationsto a certain extent is not dependent on a security manager, it is also notsuited to be used as a sandbox for running untrusted code.
If untrusted and potentially malicious code is to be executed, we recommendGraalVM customers who have an immediate requirement to execute untrusted andpotentially adversarial code, adopt the appropriate isolation primitives toensure 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 GraalVMEnterprise. When downgrading to GraalVM Community, native code execution is onlyavailable with the allowNativeAccess
privilege. This also applies to languagesimplemented with Truffle framework that allow for native code extensions, suchas Python and Ruby.