From 2f54f483c5abcdfe20b699a8d2ec722073529653 Mon Sep 17 00:00:00 2001 From: Matthias Neugschwandtner Date: Wed, 5 Oct 2022 14:01:09 +0200 Subject: [PATCH] Restructure the security guide and update with Polyglot sandboxing --- .../embedding/sandbox-options.md | 335 ------------ .../native-image/Compatibility.md | 4 +- .../native-image/InspectTool.md | 55 +- docs/security/native-image.md | 104 ++++ docs/security/polyglot-sandbox.md | 512 ++++++++++++++++++ docs/security/sandbox_security_boundary.png | Bin 0 -> 9869 bytes docs/security/security-guide.md | 111 +--- .../org/graalvm/polyglot/SandboxPolicy.java | 5 +- 8 files changed, 647 insertions(+), 479 deletions(-) delete mode 100644 docs/reference-manual/embedding/sandbox-options.md create mode 100644 docs/security/native-image.md create mode 100644 docs/security/polyglot-sandbox.md create mode 100644 docs/security/sandbox_security_boundary.png diff --git a/docs/reference-manual/embedding/sandbox-options.md b/docs/reference-manual/embedding/sandbox-options.md deleted file mode 100644 index a82464c015c1..000000000000 --- a/docs/reference-manual/embedding/sandbox-options.md +++ /dev/null @@ -1,335 +0,0 @@ ---- -layout: docs -toc_group: embedding -link_title: Sandbox Resource Limits -permalink: /reference-manual/embed-languages/sandbox-resource-limits/ ---- - -## Oracle GraalVM Sandbox Resource Limits - -Oracle GraalVM provides the Sandbox Resource Limits feature that allows for the limiting of resources used by guest applications. -These resource limits are not available in GraalVM Community Edition. -The following document describes how to configure sandbox resource limits using options in GraalVM Polyglot API. - -In general all resource limit options are prefixed with `sandbox` option group and they can be listed using the help of any language launcher provided in GraalVM, e.g., `js --help:tools`. -Polyglot options can be provided through the language launcher, using the polyglot embedding API of the Graal SDK, or on the JVM using a system property. -For better understanding of the examples it is recommended to read the [polyglot embedding guide](embed-languages.md) of the reference manual first. - -Currently all sandbox options are experimental therefore in these examples it is assumed that experimental options are enabled (e.g., with `--experimental-options`). -The options are a best effort approach to limiting resource usage of guest applications. - -The resource limits may be configured using the following options: - - -- `--sandbox.AllocatedBytesCheckFactor=[0.0, inf)` : Specifies a factor of MaxHeapMemory the allocation of which triggers retained heap memory computation. When allocated bytes for an execution context reach the specified factor, computation of bytes retained in the heap by the context is initiated. Is set to '1.0' by default. -- `--sandbox.AllocatedBytesCheckInterval=[1, inf)ms|s|m|h|d` : Time interval to check allocated bytes for an execution context. Exceeding certain number of allocated bytes triggers computation of bytes retained in the heap by the context. Is set to '10ms' by default. Maximum interval is 1h. -- `--sandbox.MaxASTDepth=[1, inf)` : Maximum AST depth of a function (default: no limit). -- `--sandbox.MaxCPUTime=[1, inf)ms|s|m|h|d` : Limits the total maximum CPU time that was spent running the application. No limit is set by default. Example value: '100ms'. -- `--sandbox.MaxCPUTimeCheckInterval=[1, inf)ms|s|m|h|d` : Time interval to check the active CPU time for an execution context. Is set to '10ms' by default. Maximum interval is 1h. -- `--sandbox.MaxErrorStreamSize=[0, inf)B|KB|MB|GB` : Specifies the maximum size that the guest application can write to stderr. No limit is set by default. Example value: '10MB'. -- `--sandbox.MaxHeapMemory=[1, inf)B|KB|MB|GB` : Specifies the maximum heap memory that can be retained by the application during its run. Includes only data retained by the guest application, runtime allocated data is not included. No limit is set by default and setting the related expert options has no effect. Example value: '100MB'. -- `--sandbox.MaxOutputStreamSize=[0, inf)B|KB|MB|GB` : Specifies the maximum size that the guest application can write to stdout. No limit is set by default. Example value: '10MB'. -- `--sandbox.MaxStackFrames=[1, inf)` : Limits the maximum number of guest stack frames (default: no limit). -- `--sandbox.MaxStatements=[1, inf)` : Limits the maximum number of guest language statements executed. The execution is cancelled with an resource exhausted error when it is exceeded. -- `--sandbox.MaxStatementsIncludeInternal` : Configures whether to include internal sources in the max statements computation. -- `--sandbox.MaxThreads=[1, inf)` : Limits the number of threads that can be entered by a context at the same point in time (default: no limit). -- `--sandbox.RetainedBytesCheckFactor=[0.0, inf)` : Specifies a factor of total heap memory of the host VM the exceeding of which stops the world. When the total number of bytes allocated in the heap for the whole host VM exceeds the factor, the following process is initiated. Execution for all engines with at least one memory-limited execution context is paused. Retained bytes in the heap for each memory-limited context are computed. Contexts exceeding their limits are cancelled. The execution is resumed. Is set to '0.7' by default. Has no effect if 'UseLowMemoryTrigger' is 'false'. -- `--sandbox.RetainedBytesCheckInterval=[1, inf)ms|s|m|h|d` : Specifies the minimum time interval between two computations of retained bytes in the heap for a single execution context. Is set to '10ms' by default. Maximum value for the minimum interval is 1h. -- `--sandbox.ReuseLowMemoryTriggerThreshold=true|false` : Specifies whether an already set heap memory notification limit can be reused for the low memory trigger. When reusing is allowed and the usage threshold or the collection usage threshold of a heap memory pool has already been set, then the value of 'RetainedBytesCheckFactor' is ignored for that memory pool and threshold type and whatever threshold value has already been set is used. Is set to 'false' by default. -- `--sandbox.TraceLimits=true|false` : Records the maximum amount of resources used during execution, and reports a summary of resource limits to the log file upon application exit. Users may also provide limits to enforce while tracing. This flag can be used to estimate an application's optimal sandbox parameters, either by tracing the limits of a stress test or peak usage. -- `--sandbox.UseLowMemoryTrigger=true|false` : Specifies whether stopping the world is enabled. When enabled, engines with at least one memory limited execution context are paused when the total number of bytes allocated in the heap for the whole host VM exceeds the specified factor of total heap memory of the host VM. Is set to 'true' by default. - - -Different configurations may be provided for each polyglot embedding `Context` instance. -In addition to that the limits may be reset at any point of time during the execution. Resetting is only aplicable to `sandbox.MaxStatements` and `sandbox.MaxCPUTime`. - -A guest language might choose to create an inner context within the outer execution context. The limits are applied to the outer context and all inner contexts it spawns. -It is not possible to specify a separate limit for inner contexts and it is also not possible to escape any limit by creating an inner context. - -## Limiting the active CPU time - -The `sandbox.MaxCPUTime` option allows you to specify the maximum CPU time spent running the application. -The maximum [CPU time](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/ThreadMXBean.html#getThreadCpuTime\(long\)) specifies how long a context can be active until it is automatically cancelled and the context is closed. -By default the time limit is checked every 10 milliseconds. -This can be customized using the `sandbox.MaxCPUTimeCheckInterval` option. -Both maximum CPU time limit and check interval must be positive. -By default no CPU time limit is enforced. -If the time limit is exceeded then the polyglot context is cancelled and the execution stops by throwing a [`PolyglotException`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/PolyglotException.html) which returns `true` for `isResourceExhausted()`. -As soon as the time limit is triggered, no further application code can be executed with this context. -It will continuously throw a `PolyglotException` for any method of the polyglot context that will be invoked. - -The used CPU time of a context includes time spent in callbacks to host code. -This is also the case when running with [Polyglot Isolates]. - -The used CPU time of a context typically does not include time spent waiting for synchronization or IO. -The CPU time of all threads will be added and checked against the CPU time limit. -This can mean that if two threads execute the same context then the time limit will be exceeded twice as fast. - -The time limit is enforced by a separate high-priority thread that will be woken regularly. -There is no guarantee that the context will be cancelled within the accuracy specified. -The accuracy may be significantly missed, e.g. if the host VM causes a full garbage collection. -If the time limit is never exceeded then the throughput of the guest context is not affected. -If the time limit is exceeded for one context then it may slow down the throughput for other contexts with the same explicit engine temporarily. - -Available units to specify time durations are `ms` for milliseconds, `s` for seconds, `m` for minutes, `h` for hours and `d` for days. -It is not allowed specify negative values or no time unit with CPU time limit options. - -### Example Usage - -```java -try (Context context = Context.newBuilder("js") - .allowExperimentalOptions(true) - .option("sandbox.MaxCPUTime", "500ms") - .option("sandbox.MaxCPUTimeCheckInterval", "5ms") - .build();) { - context.eval("js", "while(true);"); - assert false; -} catch (PolyglotException e) { - // triggered after 500ms; - // context is closed and can no longer be used - // error message: Maximum CPU time limit of 500ms exceeded. - assert e.isCancelled(); - assert e.isResourceExhausted(); -} -``` - -## Limiting the number of executed statements - -Specifies the maximum number of statements a context may execute until the the context will be cancelled. -After the statement limit was triggered for a context, it is no longer usable and every use of the context will throw a `PolyglotException` that returns `true` for `PolyglotException.isCancelled()`. -The statement limit is independent of the number of threads executing and is applied per context. -It is also possible to specify this limit using the `[ResourceLimits]()` API of the polyglot embedding API. - -By default there is no statement limit applied. -The limit may be set to a negative number to disable it. -Whether this limit is applied internal sources only can be configured using `sandbox.MaxStatementsIncludeInternal`. -By default the limit does not include statements of sources that are marked internal. -If a shared engine is used then the same internal configuration must be used for all contexts of an engine. -The maximum statement limit can be configured for each context of an engine separately. - -Attaching a statement limit to a context reduces the throughput of all guest applications with the same engine. -The statement counter needs to be updated with every statement that is executed. -It is recommended to benchmark the use of the statement limit before it is used in production. - -The complexity of a single statement may not be constant time depending on the guest language. -For example, statements that execute JavaScript builtins, like `Array.sort`, may account for a single statement, but its execution time is dependent on the size of the array. -The statement count limit is therefore not suitable to perform time boxing and must be combined with other more reliable measures like the CPU time limit. - -```java -try (Context context = Context.newBuilder("js") - .allowExperimentalOptions(true) - .option("sandbox.MaxStatements", "2") - .option("sandbox.MaxStatementsIncludeInternal", "false") - .build();) { - context.eval("js", "purpose = 41"); - context.eval("js", "purpose++"); - context.eval("js", "purpose++"); // triggers max statements - assert false; -} catch (PolyglotException e) { - // context is closed and can no longer be used - // error message: Maximum statements limit of 2 exceeded. - assert e.isCancelled(); - assert e.isResourceExhausted(); -} -``` - -## Limiting the AST depth of functions - -A limit on the maximum expression depth of a guest language function. -Only instrumentable nodes count towards the limit. -If the limit is exceeded, evaluation of the code fails and the context is canceled. - -The AST depth can give an estimate of the complexity of a function as well as its stack frame size. -Limiting the AST depth can serve as a safeguard against arbitrary stack space usage by a single function. - -## Limiting the number of stack frames - -Specifies the maximum number of frames a context can push on the stack. -Exceeding the limit results in cancellation of the context. -A thread-local stack frame counter is incremented on function enter and decremented on function return. -Resetting resource limits does not affect the stack frame counter. - -The stack frame limit in itself can serve as a safeguard against infinite recursion. -If used together with the AST depth limit it can be used to estimate total stack space usage. - -## Limiting the number of active threads - -Limits the number of threads that can be used by a context at the same point in time. -By default, an arbitrary number of threads can be used. -If a set limit is exceeded, entering the context fails with a `PolyglotException` and the polyglot context is canceled. -Resetting resource limits does not affect thread limits. - -## Limiting the maximum heap memory - -The `sandbox.MaxHeapMemory` option allows you to specify the maximum heap memory the application is allowed to retain during its run. -`sandbox.MaxHeapMemory` must be positive. This option is only supported on a HotSpot-based VM. -Enabling this option in a native executable will result in a `PolyglotException`. -The option is also not supported with [Polyglot Isolates], which have different means of controlling memory consumption. -When exceeding of the limit is detected, the corresponding context is automatically cancelled and then closed. - -Only objects residing in the guest application count towards the limit - memory allocated during callbacks to host code does not. -The efficacy of this option (also) depends on the garbage collector used. - -#### Example Usage - -```java -try (Context context = Context.newBuilder("js") - .allowExperimentalOptions(true) - .option("sandbox.MaxHeapMemory", "100MB") - .build()) { - context.eval("js", "var r = {}; var o = r; while(true) { o.o = {}; o = o.o; };"); - assert false; -} catch (PolyglotException e) { - // triggered after the retained size is greater than 100MB; - // context is closed and can no longer be used - // error message: Maximum heap memory limit of 104857600 bytes exceeded. Current memory at least... - assert e.isCancelled(); - assert e.isResourceExhausted(); -} -``` - -#### Implementation details and expert options - -The limit is checked by retained size computation triggered either based on [allocated](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.management/com/sun/management/ThreadMXBean.html#getThreadAllocatedBytes\(long\)) bytes or on [low memory notification](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/MemoryMXBean.html). - -The allocated bytes are checked by a separate high-priority thread that will be woken regularly. -There is one such thread for each memory-limited context (one with `sandbox.MaxHeapMemory` set). -The retained bytes computation is done by yet another high-priority thread that is started from the allocated bytes checking thread as needed. -The retained bytes computation thread also cancels the context if the heap memory limit is exeeded. -Additionaly, when low memory trigger is invoked, all contexts on engines with at least one memory-limited context are paused together with their allocation checkers. -All individual retained size computations are cancelled. -Retained bytes in the heap for each memory-limited context are computed by a single high-priority thread. -Contexts exceeding their limits are cancelled, and then the execution is resumed. - -The main goal of the heap memory limits is to prevent heap memory depletion related errors in most cases and thus enable the host VM to run smoothly even in the presence of misbehaving contexts. -The implementation is best effort. This means that there is no guarantee on the accuracy of the heap memory limit. -There is also no guarantee that setting a heap memory limit will prevent the context from causing `OutOfMemory` errors. -Guest applications that allocate many objects in quick succession have a lower accuracy than applications which allocate objects rarely. -The guest code execution will only be paused if the host heap memory is exhausted and a low memory trigger of the host VM is invoked. -Note that the scope of the pause is an engine, so a context without the `sandbox.MaxHeapMemory` option set is also paused in case it shares the engine with other context that is memory-limited. -Also note that if one context is cancelled other contexts with the same explicit engine may be slowed down. How the size retained by a context is computed can be -customized using the expert options `sandbox.AllocatedBytesCheckInterval`, `sandbox.AllocatedBytesCheckEnabled`, `sandbox.AllocatedBytesCheckFactor`, `sandbox.RetainedBytesCheckInterval`, `sandbox.RetainedBytesCheckFactor`, and `sandbox.UseLowMemoryTrigger` described below. - -Retained size computation for a context is triggered when a retained bytes estimate exceeds a certain factor of specified `sandbox.MaxHeapMemory`. -The estimate is based on heap memory -[allocated](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.management/com/sun/management/ThreadMXBean.html#getThreadAllocatedBytes\(long\)) by threads where the context has been active. -More precisely, the estimate is the result of previous retained bytes computation, if available, plus bytes allocated since the start of the previous computation. -By default the factor of `sandbox.MaxHeapMemory` is 1.0 and it can be customized by the `sandbox.AllocatedBytesCheckFactor` option. -The factor must be positive. -For example, let `sandbox.MaxHeapMemory` be 100MB and `sandbox.AllocatedBytesCheckFactor` be 0.5. -The retained size computation is first triggered when allocated bytes reach 50MB. -Let the computed retained size be 25MB, then the next retained size computation is triggered when additional 25MB is allocated, etc. - -By default, allocated bytes are checked every 10 milliseconds. This can be configured by `sandbox.AllocatedBytesCheckInterval`. -The smallest possible interval is 1ms. Any smaller value is interpreted as 1ms. - -The beginnings of two retained size computations of the same context must be by default at least 10 milliseconds apart. -This can be configured by the `sandbox.RetainedBytesCheckInterval` option. The interval must be positive. - -The allocated bytes checking for a context can be disabled by the `sandbox.AllocatedBytesCheckEnabled` option. -By default it is enabled ("true"). If disabled ("false"), retained size checking for the context can be triggered only by the low memory trigger. - -When the total number of bytes allocated in the heap for the whole host VM exceeds a certain factor of the total heap memory of the VM, [low memory notification](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/MemoryMXBean.html) is invoked and initiates the following process. -The execution for all engines with at least one execution context which has the `sandbox.MaxHeapMemory` option set is paused, retained bytes in the heap for each memory-limited context are computed, contexts exceeding their limits are cancelled, and then the execution is resumed. -The default factor is 0.7. This can be configuted by the `sandbox.RetainedBytesCheckFactor` option. -The factor must be between 0.0 and 1.0. All contexts using the `sandbox.MaxHeapMemory` option must use the same value for `sandbox.RetainedBytesCheckFactor`. - -When the usage threshold or the collection usage threshold of any heap memory pool has already been set, then the low memory trigger cannot be used by default, because the limit specified by the `sandbox.RetainedBytesCheckFactor` cannot be implemented. -However, when `sandbox.ReuseLowMemoryTriggerThreshold` is set to true and the usage threshold or the collection usage threshold of a heap memory pool has already been set, then the value of `sandbox.RetainedBytesCheckFactor` is ignored for that memory pool and whatever limit has already been set is used. -That way the low memory trigger can be used together with libraries that also set the usage threshold or the collection usage threshold of heap memory pools. - -The described low memory trigger can be disabled by the `sandbox.UseLowMemoryTrigger` option. -By default it is enabled ("true"). If disabled ("false"), retained size checking for the execution context can be triggered only by the allocated bytes checker. -All contexts using the `sandbox.MaxHeapMemory` option must use the same value for `sandbox.UseLowMemoryTrigger`. - -If exceeding of the heap memory limit is detected then the polyglot context is cancelled and the execution stops by throwing a [`PolyglotException`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/PolyglotException.html) which returns `true` for `isResourceExhausted()`. -As soon as the memory limit is triggered, no further application code can be executed with this context. -It will continuously throw a `PolyglotException` for any method of the polyglot context that will be invoked. - -Available units to specify time durations are `ms` for milliseconds, `s` for seconds, `m` for minutes, `h` for hours and `d` for days. -It is not allowed to specify negative values or no time unit with max heap memory options. - -Available units to specify sizes are `B` for bytes, `KB` for kilobytes, `MB` for megabytes, and `GB` for gigabytes. -It is not allowed to specify negative values or no size unit with max heap memory options. - -Resetting resource limits using `Context.resetLimits` does not affect the heap memory limit. - -## Limiting the size of the output written to stdout/stderr - -Limits the size of the output that the application writes to standard output or standard error output during runtime. -If the limit is exceeded, evaluation of the code fails and the context is canceled. -Limiting the size of the output can serve as protection against denial-of-service attacks that flood the output. - -#### Example Usage -```java -try (Context context = Context.newBuilder("js") - .option("sandbox.MaxOutputStreamSize", "100KB") - .build()) { - context.eval("js", "while(true) { console.log('Log message') };"); - assert false; -} catch (PolyglotException e) { - // triggered after writing more than 100KB to stdout - // context is closed and can no longer be used - // error message: Maximum output stream size of 102400 exceeded. Bytes written 102408. - assert e.isCancelled(); - assert e.isResourceExhausted(); -} -``` -```java -try (Context context = Context.newBuilder("js") - .option("sandbox.MaxErrorStreamSize", "100KB") - .build()) { - context.eval("js", "while(true) { console.error('Error message') };"); - assert false; -} catch (PolyglotException e) { - // triggered after writing more than 100KB to stderr - // context is closed and can no longer be used - // error message: Maximum error stream size of 102400 exceeded. Bytes written 102410. - assert e.isCancelled(); - assert e.isResourceExhausted(); -} -``` - -## Determining Sandbox Resource Limits - -The sandbox.TraceLimits option allows you to trace a running process and record the maximum resource utilization. This can be used to estimate parameters to define a sandbox for the workload. For example, a web server's sandbox parameters could be obtained by enabling this option and either stress-testing the server, or letting the server run during peak usage. When this option is enabled, the report is saved to the log file after the workload completes. Users can change the location of the log file by using --log.file= with a language launcher or -Dpolyglot.log.file= when using a java launcher. Each resource limit in the report can be passed directly to a sandbox option in order to enforce the limit. - -See, for example, how to trace limits for a Python workload: - -``` -graalpy --log.file=limits.log --experimental-options --sandbox.TraceLimits=true workload.py - -limits.log: -[trace-limits] Sandbox Limits Statistics: -HEAP 12MB -CPU 7s -STATEMENTS 9441565 -STACKFRAMES 29 -THREADS 1 -ASTDEPTH 15 - -Sandbox Command Line Options: ---sandbox.MaxHeapMemory=12MB --sandbox.MaxCPUTime=7s --sandbox.MaxStatements=9441565 --sandbox.MaxStackFrames=29 --sandbox.MaxThreads=1 --sandbox.MaxASTDepth=15 -``` - -## Resetting Resource Limits - -With the polyglot embedding API it is possible to reset the limits at any point in time using the [`Context.resetLimits`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html#resetLimits--) method. -This can be useful if a known and trusted initialization script should be excluded from limit. Resetting the limits is not applicable to all limits. - -### Example Usage - -```java -try (Context context = Context.newBuilder("js") - .allowExperimentalOptions(true) - .option("sandbox.MaxCPUTime", "500ms") - .build();) { - context.eval("js", /*... initialization script ...*/); - context.resetLimits(); - context.eval("js", /*... user script ...*/); - assert false; -} catch (PolyglotException e) { - assert e.isCancelled(); - assert e.isResourceExhausted(); -} -``` diff --git a/docs/reference-manual/native-image/Compatibility.md b/docs/reference-manual/native-image/Compatibility.md index ee4ae1a67528..633be781d3a8 100644 --- a/docs/reference-manual/native-image/Compatibility.md +++ b/docs/reference-manual/native-image/Compatibility.md @@ -41,9 +41,7 @@ Note that `invokedynamic` use cases generated by `javac` for, for example, Java ### Security Manager -The Java security manager is no longer recommended as a way to isolate less trusted code from more trusted code in the same process. -This is because almost all typical hardware architectures are susceptible to side-channel attacks to access data that is restricted via the security manager. -Using separate processes is now recommended for these cases. +Native Image will not allow a Java Security Manager to be enabled because this functionality has deprecated since Java 17. ## Features That May Operate Differently in a Native Image diff --git a/docs/reference-manual/native-image/InspectTool.md b/docs/reference-manual/native-image/InspectTool.md index cf4b264edd35..62c420b43bc7 100644 --- a/docs/reference-manual/native-image/InspectTool.md +++ b/docs/reference-manual/native-image/InspectTool.md @@ -24,60 +24,7 @@ Native Image provides the `--enable-sbom` option to embed an SBOM into a native > Note: Embedding a Software Bill of Materials (SBOM) is not available in GraalVM Community Edition. The feature is currently experimental. -The CycloneDX format is supported and the default. -To embed a CycloneDX SBOM into a native executable, pass the `--enable-sbom` option to the `native-image` command. - -The implementation constructs the SBOM by recovering all version information observable in external library manifests for classes included in a native executable. -The SBOM is also compressed in order to limit the SBOM's impact on the native executable size. -Even though the tool is not yet supported on Windows, Windows users can still embed the SBOM with this experimental option. -The SBOM is stored in the `gzip` format with the exported `sbom` symbol referencing its start address and the `sbom_length` symbol its size. - -After embedding the compressed SBOM into the executable, the tool is able to extract the compressed SBOM using an optional `--sbom` parameter accessible through `$JAVA_HOME/bin/native-image-inspect --sbom ` and outputs the SBOM in the following format: - -```json -{ - "bomFormat": "CycloneDX", - "specVersion": "1.4", - "version": 1, - "components": [ - { - "type": "library", - "group": "io.netty", - "name": "netty-codec-http2", - "version": "4.1.76.Final", - "properties": [ - { - "name": "syft:cpe23", - "value": "cpe:2.3:a:codec:codec:4.1.76.Final:*:*:*:*:*:*:*" - }, - { - "name": "syft:cpe23", - "value": "cpe:2.3:a:codec:netty-codec-http2:4.1.76.Final:*:*:*:*:*:*:*" - }, - { - "name": "syft:cpe23", - "value": "cpe:2.3:a:codec:netty_codec_http2:4.1.76.Final:*:*:*:*:*:*:*" - }, - ... - ] - }, - ... - ], - "serialNumber": "urn:uuid:51ec305f-616e-4139-a033-a094bb94a17c" -} -``` - -The tool can extract the SBOM from both executables and shared libraries. -To scan for any vulnerable libraries, submit the SBOM to a vulnerability scanner. -For example, the popular [Anchore software supply chain management platform](https://anchore.com/) makes the `grype` scanner freely available. -You can check whether the libraries given in your SBOMs have known vulnerabilities documented in Anchore's database. -For this purpose, the output of the tool can be fed directly to the `grype` scanner to check for vulnerable libraries, using the command `$JAVA_HOME/bin/native-image-inspect --sbom | grype` which produces the following output: -```shell -NAME INSTALLED VULNERABILITY SEVERITY -netty-codec-http2 4.1.76.Final CVE-2022-24823 Medium -``` - -You can then use this report to update any vulnerable dependencies found in your executable. +The tool is able to extract the compressed SBOM using an optional `--sbom` parameter accessible through `$JAVA_HOME/bin/native-image-inspect --sbom `. ### Further Reading diff --git a/docs/security/native-image.md b/docs/security/native-image.md new file mode 100644 index 000000000000..0b14fb1033e7 --- /dev/null +++ b/docs/security/native-image.md @@ -0,0 +1,104 @@ +--- +layout: docs +toc_group: security-guide +link_title: Security Considerations in Native Image +permalink: /security-guide/native-image/ +--- +# Native Image + +The `native-image` builder generates a snapshot of an application after startup and bundles it in a binary executable. + +## Class Initialization + +The `native-image` builder may execute the static initializers of certain classes at build time (see [class initialization](../reference-manual/native-image/ClassInitialization.md) for more details). +Executing static initializers at build time persists the state after initialization in the image heap. +This means that any information that is obtained or computed in static initializers becomes part of a native executable. +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 executed at run time by specifying the `--initialize-at-run-time` CLI parameter when building a native executable, followed by a comma-separated list of packages and classes (and implicitly all of their subclasses) that must be initialized at runtime and not during image building. +Alternatively developers can make use of the [`RuntimeClassInitialization` API](https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.html). + +Developers should run the `native-image` builder in a dedicated environment, such as a container, that does not contain any sensitive information in the first place. + +## Software Bill of Materials + +GraalVM Native Image can embed a Software Bill of Materials (SBOM) at build time to detect any libraries that may be susceptible to known security vulnerabilities. +Native Image provides the `--enable-sbom` option to embed an SBOM into a native executable. + +> Note: Embedding a Software Bill of Materials (SBOM) is not available in GraalVM Community Edition. + +The CycloneDX format is supported and the default. +To embed a CycloneDX SBOM into a native executable, pass the `--enable-sbom` option to the `native-image` command. + +The implementation constructs the SBOM by recovering all version information observable in external library manifests for classes included in a native executable. +The SBOM is also compressed in order to limit the SBOM's impact on the native executable size. +The SBOM is stored in the `gzip` format with the exported `sbom` symbol referencing its start address and the `sbom_length` symbol its size. + +After embedding the compressed SBOM into the executable, the [native image inspect tool](../reference-manual/native-image/InspectTool.md) is able to extract the compressed SBOM using an optional `--sbom` parameter accessible through `$JAVA_HOME/bin/native-image-inspect --sbom ` from both executables and shared libraries. +It outputs the SBOM in the following format: + +```json +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "components": [ + { + "type": "library", + "group": "io.netty", + "name": "netty-codec-http2", + "version": "4.1.76.Final", + "properties": [ + { + "name": "syft:cpe23", + "value": "cpe:2.3:a:codec:codec:4.1.76.Final:*:*:*:*:*:*:*" + }, + { + "name": "syft:cpe23", + "value": "cpe:2.3:a:codec:netty-codec-http2:4.1.76.Final:*:*:*:*:*:*:*" + }, + { + "name": "syft:cpe23", + "value": "cpe:2.3:a:codec:netty_codec_http2:4.1.76.Final:*:*:*:*:*:*:*" + }, + ... + ] + }, + ... + ], + "serialNumber": "urn:uuid:51ec305f-616e-4139-a033-a094bb94a17c" +} +``` + +To scan for any vulnerable libraries, submit the SBOM to a vulnerability scanner. +For example, the popular [Anchore software supply chain management platform](https://anchore.com/) makes the `grype` scanner freely available. +You can check whether the libraries given in your SBOMs have known vulnerabilities documented in Anchore's database. +For this purpose, the output of the tool can be fed directly to the `grype` scanner to check for vulnerable libraries, using the command `$JAVA_HOME/bin/native-image-inspect --sbom | grype` which produces the following output: +```shell +NAME INSTALLED VULNERABILITY SEVERITY +netty-codec-http2 4.1.76.Final CVE-2022-24823 Medium +``` + +You can then use this report to update any vulnerable dependencies found in your executable. + +## Java serialization in Native Image + +Native Image supports Serialization to help users deserialize the constructors for classes, contained in a native executable. +Unless picked up by native image analysis automatically, [these classes have to be pre-specified](https://www.graalvm.org/22.0/reference-manual/native-image/Reflection/#manual-configuration), as classes not contained in a native executable cannot be deserialized. +Native Image cannot prevent exploitation of deserialization vulnerabilities in isolation. +The [serialization and deserialization Secure Coding Guidelines for Java SE](https://www.oracle.com/java/technologies/javase/seccodeguide.html#8) should be followed. + +## Miscellaneous + +Native Image provides multiple ways to specify a certificate file used to define the default TrustStore. +While the default behavior for `native-image` is to capture and use the default TrustStore from the build-time host environment, this can be changed at run time by setting the "javax.net.ssl.trustStore\*" system properties. +See the [documentation](../reference-manual/native-image/CertificateManagement.md) for more details. + +The directory containing the native executable is part of the search path when loading native libraries using `System.loadLibrary()` at run time. + +Native Image will not allow a Java Security Manager to be enabled because this functionality has now deprecated since Java 17. +Attempting to set a security manager will trigger a runtime error. + +## Related Documentation +- [Security Guide](security-guide.md) +- [Polyglot Sandboxing](polyglot-sandbox.md) \ No newline at end of file diff --git a/docs/security/polyglot-sandbox.md b/docs/security/polyglot-sandbox.md new file mode 100644 index 000000000000..3c552d263e0a --- /dev/null +++ b/docs/security/polyglot-sandbox.md @@ -0,0 +1,512 @@ +--- +layout: docs +toc_group: security-guide +link_title: Polyglot Sandboxing +permalink: /security-guide/polyglot-sandbox/ +--- +# Polyglot Sandboxing + +GraalVM allows a host application written in a JVM-based language to execute guest code written in Javascript via the [Polyglot Embedding API](../reference-manual/embedding/embed-languages.md). +Configured with a [sandbox policy](#sandbox-policies), a security boundary between a host application and guest code can be established. +For example, host code can execute untrusted guest code using the [UNTRUSTED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/SandboxPolicy.html#UNTRUSTED) policy. +Host code can also execute multiple mutually distrusting instances of guest code that will be protected from one another. +Used this way, polyglot sandboxing supports a multi-tenant scenario: + +![](sandbox_security_boundary.png) + +Use cases that benefit from introducing a security boundary are: +* Usage of third party code, i.e., pulling in a dependency. Third party code is typically trusted and scanned for vulnerabilities before use, but sandboxing them is an additional precaution against supply-chain attacks. +* User plugins. Complex applications might allow users to install community-written plugins. Traditionally, those plugins are considered trusted and often run with full privileges, but ideally they should not be able to interfere with the application except when intended. +* Server scripting. Allowing users to customize a server application with their own logic expressed in a general-purpose scripting language, for example, to implement custom data processing on a shared data source. + +## Sandbox Policies + +Depending on the use case and the associated acceptable security risk, a [SandboxPolicy](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/SandboxPolicy.html) can be chosen, ranging from [TRUSTED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/SandboxPolicy.html#TRUSTED) to [UNTRUSTED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/SandboxPolicy.html#UNTRUSTED), enabling and configuring an increasing range of restrictions and mitigations. +A `SandboxPolicy` serves two purposes: preconfiguration and validation of the final configuration. +It preconfigures context and engine to comply to a policy by default. +In case the configuration is further customized, validation of the policy will ensure that the custom configuration does not unacceptably weaken the policy. + +### Trusted Policy + +The [TRUSTED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/SandboxPolicy.html#TRUSTED) sandboxing policy is intended for guest code that is entirely trusted. +This is the default mode. +There are no restrictions to the context or engine configuration. + +Example: +```java +try (Context context = Context.newBuilder("js") + .sandbox(SandboxPolicy.TRUSTED) + .build();) { + context.eval("js", "print('Hello JavaScript!');"); +} +``` + +### Constrained Policy + +The [CONSTRAINED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/SandboxPolicy.html#CONSTRAINED) sandboxing policy is intended for trusted applications whose access to host resources should be regulated. +The CONSTRAINED policy: +* Requires the languages for a context to be set. +* Disallows [native access](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#allowNativeAccess-boolean-). +* Disallows [process creation](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#allowCreateProcess-boolean-). +* Disallows [system exit](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#useSystemExit-boolean-), prohibiting the guest code from terminating the entire VM where this is supported by the language. +* Requires redirection of the standard [output](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#out-java.io.OutputStream-) and [error](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#err-java.io.OutputStream-) streams. This is to mitigate risks where external components, such as log processing, may be confused by unexpected writes to output streams by guest code. +* Disallows [host file](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/io/IOAccess.Builder.html#allowHostFileAccess-boolean-) or [socket](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/io/IOAccess.Builder.html#allowHostSocketAccess-boolean-) access. Only custom [polyglot file system](https://www.graalvm.org/sdk/javadoc/index.html?org/graalvm/polyglot/io/FileSystem.html) implementations are allowed. +* Disallows [environment access](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#allowEnvironmentAccess-org.graalvm.polyglot.EnvironmentAccess-). +* Restricts host access: + * Disallows [host class loading](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#allowHostClassLoading-boolean-). + * Disallows [to all public host classes and methods by default](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#allowPublicAccess-boolean-). + * Disallows [access inheritance](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#allowAccessInheritance-boolean-). + * Disallows implementation of arbitrary host [classes](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#allowAllClassImplementations-boolean-) and [interfaces](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#allowAllImplementations-boolean-). + * Disallows implementation of `java.lang.FunctionalInterface`. + * Disallows host object mappings of [mutable target types](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#allowMutableTargetMappings-org.graalvm.polyglot.HostAccess.MutableTargetMapping...-). +The [HostAccess.CONSTRAINED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.html#CONSTRAINED) host access policy is preconfigured to fulfil the requirements for the CONSTRAINED sandboxing policy. + +Example: +```java +try (Context context = Context.newBuilder("js") + .sandbox(SandboxPolicy.CONSTRAINED) + .out(new ByteArrayOutputStream()) + .err(new ByteArrayOutputStream()) + .build()) { + context.eval("js", "print('Hello JavaScript!');"); +} +``` + +### Isolated Policy + +The [ISOLATED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/SandboxPolicy.html#ISOLATED) sandboxing policy builds on top of the CONSTRAINED policy and is intended for trusted applications that may misbehave because of implementation bugs or processing of untrusted input. +As the name already suggests, the ISOLATED policy enforces deeper isolation between host and guest code. +In particular, guest code running with the ISOLATED policy will be executed in their own virtual machine, on a separate heap. +This means that they no longer share runtime elements such as the JIT compiler or the garbage collector with the host application, making the host VM significantly more resilient against faults in the guest VM. + +In addition to the restrictions of the CONSTRAINED policy, the ISOLATED policy: +* Requires [method scoping](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#methodScoping-boolean-) to be enabled. This avoids cyclic dependencies between host and guest objects. The [HostAccess.ISOLATED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.html#ISOLATED) host access policy is preconfigured to fulfil the requirements for the ISOLATED sandboxing policy. +* Requires setting the maximum isolate heap size. This is the heap size that will be used by the guest VM. If the engine is shared by multiple contexts, execution of these contexts will share the isolate heap. +* Requires setting the host call stack headroom. This protects against host stack starving on upcalls to the host: the guest will be prohibited from performing an upcall if the remaining stack size drops below the specified value. +* Requires setting the maximum CPU time limit. This restricts the workload to execute within the given time frame. + +Example: +```java +try (Context context = Context.newBuilder("js") + .sandbox(SandboxPolicy.ISOLATED) + .out(new ByteArrayOutputStream()) + .err(new ByteArrayOutputStream()) + .option("engine.MaxIsolateMemory", "256MB") + .option("sandbox.MaxCPUTime", "2s") + .build()) { + context.eval("js", "print('Hello JavaScript!');"); +} +``` + +### Untrusted Policy + +The [UNTRUSTED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/SandboxPolicy.html#UNTRUSTED) sandboxing policy builds on top of the ISOLATED policy and is intended to mitigate risks from running actual untrusted code. +The attack surface of GraalVM when running untrusted code consists of the entire guest VM that executes the code as well as the host entry points made available to guest code. + +In addition to the restrictions of the ISOLATED policy, the UNTRUSTED policy: +* Requires redirection of the standard [input](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#in-java.io.InputStream-) stream. +* Requires setting the maximum memory consumption of the guest code. This is a limit in addition to the maximum isolate heap size backed by a mechanism that keeps track of the size of objects allocated by the guest code on the guest VM heap. This limit can be thought of as a "soft" memory limit, whereas the isolate heap size is the "hard" limit. +* Requires setting the maximum number of stack frames that can be pushed on the stack by guest code. This limit can protect against unbounded recursion to exhaust the stack. +* Requires setting the maximum AST depth of the guest code. Together with the stack frame limit, this puts a bound on the stack space consumed by guest code. +* Requires setting the maximum output and error stream sizes. As output and error streams have to be redirected, the receiving ends are on the host side. Limiting the output and error stream sizes protects against availability issues on the host. +* Requires untrusted code mitigations to be enabled. Untrusted code mitigations address risks from JIT spraying and speculative execution attacks. They include constant blinding as well as comprehensive use of speculative execution barriers. +* Further restricts host access to ensure there are no implicit entry points to host code. This means that guest-code access to host arrays, lists, maps, buffers, iterables and iterators is disallowed. The reason is that there may be various implementations of these APIs on the host side, resulting in implicit entry points. In addition, direct mappings of guest implementations to host interfaces via [HostAccess.Builder#allowImplementationsAnnotatedBy()] are disallowed. The [HostAccess.UNTRUSTED](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.html#UNTRUSTED) host access policy is preconfigured to fulfil the requirements for the UNTRUSTED sandboxing policy. + +Example: +```java +try (Context context = Context.newBuilder("js") + .sandbox(SandboxPolicy.UNTRUSTED) + .in(new ByteArrayInputStream("foobar".getBytes())) + .out(new ByteArrayOutputStream()) + .err(new ByteArrayOutputStream()) + .allowHostAccess(HostAccess.UNTRUSTED) + .option("engine.MaxIsolateMemory", "8MB") + .option("sandbox.MaxHeapMemory", "128MB") + .option("sandbox.MaxCPUTime","2s") + .option("sandbox.MaxStatements","50000") + .option("sandbox.MaxStackFrames","2") + .option("sandbox.MaxThreads","1") + .option("sandbox.MaxASTDepth","10") + .option("sandbox.MaxOutputStreamSize","32B") + .option("sandbox.MaxErrorStreamSize","0B"); + .build()) { + context.eval("js", "print('Hello JavaScript!');"); +} +``` + +For further information on how to set the resource limits, please refer to the corresponding [guidance](#resource-limits). + +## Host Access + +GraalVM allows exchanging objects between host and guest code and exposing host methods to guest code. +When exposing host methods to less privileged guest code, these methods become part of the attack surface of the more privileged host code. +Therefore the sandboxing policies already restrict host access in the CONSTRAINED policy to make host entry points explicit. + +`HostAccess.CONSTRAINED` is the pre-defined host access policy for the CONSTRAINED sandbox policy. +To expose a host class method, it has to be annotated with `@HostAccess.Export`. +This annotation is not inherited. +Service providers such as [polyglot file system](https://www.graalvm.org/sdk/javadoc/index.html?org/graalvm/polyglot/io/FileSystem.html) implementations or output stream recipients for standard output and error stream redirections are exposed to guest code invocations. + +Guest code can also implement a Java interface that has been annotated with `@Implementable`. +Host code using such an interface directly interacts with guest code. + +Host code that interacts with guest code has to be implemented in a robust manner: +* Input validation. All data passed from the guest, e.g. via parameters to an exposed method, is untrusted and should be thorougly validated by host code where applicable. +* Reentrancy. Exposed host code should be reentrant as guest code may invoke it at any time. Do note that simply applying the `synchronized` keyword to a code block does not necessarily make it reentrant. +* Thread-safety. Exposed host code should be thread-safe as guest code may invoke them from multiple threads at the same time. +* Resource consumption. Exposed host code should be aware of its resource consumption. In particular, constructs that allocate memory based on untrusted input data, either directly or indirectly, e.g. through recursion, should either be avoided altogether or implement limits. +* Privileged functionality. Restrictions enforced by the sandbox can be entirely bypassed by exposing host methods that provide restricted functionality. For example, guest code with a CONSTRAINED sandbox policy cannot perform host file IO operations. However, exposing a host method to the context that allows writing to arbitrary files effectively bypasses this restriction. +* Side channels. Depending on the guest language, guest code may have access to timing information. For example, in Javascript the `Date()` object provides fine-grained timing information. In the UNTRUSTED sandbox policy the granularity of Javascript timers is pre-configured to one second and can be lowered to 100 milliseconds. However, host code should be aware that guest code may time its execution, potentially discovering secret information if the host code performs secret-depending processing. + +Host code that is unaware of interacting with untrusted guest code should never be directly exposed to guest code without taking the aforementioned aspects into account. +As an example, an antipattern would be to implement a third party interface and forwarding all method invocations to guest code. + +## Resource Limits + +The ISOLATED and UNTRUSTED sandbox policies require setting resource limits for a context. +Different configurations can be provided for each context. +If a limit is exceeded, evaluation of the code fails and the context is canceled with a [`PolyglotException`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/PolyglotException.html) which returns `true` for `isResourceExhausted()`. +At this point, no more guest code can be executed in the context + +The `--sandbox.TraceLimits` option allows you to trace guest code and record the maximum resource utilization. +This can be used to estimate the parameters for the sandbox. +For example, a web server's sandbox parameters could be obtained by enabling this option and either stress-testing the server, or letting the server run during peak usage. +When this option is enabled, the report is saved to the log file after the workload completes. +Users can change the location of the log file by using `--log.file=` with a language launcher or `-Dpolyglot.log.file=` when using a `java` launcher. +Each resource limit in the report can be passed directly to a sandbox option to enforce the limit. + +See, for example, how to trace limits for a Python workload: + +``` +graalpy --log.file=limits.log --sandbox.TraceLimits=true workload.py + +limits.log: +Traced Limits: +Maximum Heap Memory: 12MB +CPU Time: 7s +Number of statements executed: 9441565 +Maximum active stack frames: 29 +Maximum number of threads: 1 +Maximum AST Depth: 15 +Size written to standard output: 4B +Size written to standard error output: 0B + +Recommended Programmatic Limits: +Context.newBuilder() + .option("sandbox.MaxHeapMemory", "2MB") + .option("sandbox.MaxCPUTime","10ms") + .option("sandbox.MaxStatements","1000") + .option("sandbox.MaxStackFrames","64") + .option("sandbox.MaxThreads","1") + .option("sandbox.MaxASTDepth","64") + .option("sandbox.MaxOutputStreamSize","1024KB") + .option("sandbox.MaxErrorStreamSize","1024KB") + .build(); + +Recommended Command Line Limits: +--sandbox.MaxHeapMemory=12MB --sandbox.MaxCPUTime=7s --sandbox.MaxStatements=9441565 --sandbox.MaxStackFrames=64 --sandbox.MaxThreads=1 --sandbox.MaxASTDepth=64 --sandbox.MaxOutputStreamSize=1024KB --sandbox.MaxErrorStreamSize=1024KB +``` + +Re-profiling may be required if the workload changes or when switching to a different major GraalVM version. + +Certain limits can be [reset](#resetting-resource-limits) at any point of time during the execution. + +### Limiting active CPU time + +The `sandbox.MaxCPUTime` option allows you to specify the maximum CPU time spent running guest code. +CPU time spent depends on the underlying hardware. +The maximum [CPU time](https://docs.oracle.com/en/java/javase/17/docs/api/java.management/java/lang/management/ThreadMXBean.html#getThreadCpuTime\(long\)) specifies how long a context can be active until it is automatically cancelled and the context is closed. +By default the time limit is checked every 10 milliseconds. +This can be customized using the `sandbox.MaxCPUTimeCheckInterval` option. + +As soon as the time limit is triggered, no further guest code can be executed with this context. +It will continuously throw a `PolyglotException` for any method of the polyglot context that will be invoked. + +The used CPU time of a context includes time spent in callbacks to host code. + +The used CPU time of a context typically does not include time spent waiting for synchronization or IO. +The CPU time of all threads will be added and checked against the CPU time limit. +This can mean that if two threads execute the same context then the time limit will be exceeded twice as fast. + +The time limit is enforced by a separate high-priority thread that will be woken regularly. +There is no guarantee that the context will be cancelled within the accuracy specified. +The accuracy may be significantly missed, e.g. if the host VM causes a full garbage collection. +If the time limit is never exceeded then the throughput of the guest context is not affected. +If the time limit is exceeded for one context then it may slow down the throughput for other contexts with the same explicit engine temporarily. + +Available units to specify time durations are `ms` for milliseconds, `s` for seconds, `m` for minutes, `h` for hours and `d` for days. +Both maximum CPU time limit and check interval must be positive followed by a time unit. + +```java +try (Context context = Context.newBuilder("js") + .option("sandbox.MaxCPUTime", "500ms") + .build();) { + context.eval("js", "while(true);"); + assert false; +} catch (PolyglotException e) { + // triggered after 500ms; + // context is closed and can no longer be used + // error message: Maximum CPU time limit of 500ms exceeded. + assert e.isCancelled(); + assert e.isResourceExhausted(); +} +``` + +### Limiting the number of executed statements + +Specifies the maximum number of statements a context may execute until it is cancelled. +After the statement limit was triggered for a context, it is no longer usable and every use of the context will throw a `PolyglotException` that returns `true` for `PolyglotException.isCancelled()`. +The statement limit is independent of the number of threads executing. + +The limit may be set to a negative number to disable it. +Whether this limit is applied internal sources only can be configured using `sandbox.MaxStatementsIncludeInternal`. +By default the limit does not include statements of sources that are marked internal. +If a shared engine is used then the same internal configuration must be used for all contexts of an engine. + +The complexity of a single statement may not be constant time depending on the guest language. +For example, statements that execute Javascript builtins, like `Array.sort`, may account for a single statement, but its execution time is dependent on the size of the array. + +```java +try (Context context = Context.newBuilder("js") + .option("sandbox.MaxStatements", "2") + .option("sandbox.MaxStatementsIncludeInternal", "false") + .build();) { + context.eval("js", "purpose = 41"); + context.eval("js", "purpose++"); + context.eval("js", "purpose++"); // triggers max statements + assert false; +} catch (PolyglotException e) { + // context is closed and can no longer be used + // error message: Maximum statements limit of 2 exceeded. + assert e.isCancelled(); + assert e.isResourceExhausted(); +} +``` + +### AST depth limit + +A limit on the maximum expression depth of a guest language function. +Only instrumentable nodes count towards the limit. + +The AST depth can give an estimate of the complexity of a function as well as its stack frame size. + +### Limiting the number of stack frames + +Specifies the maximum number of frames a context can push on the stack. +A thread-local stack frame counter is incremented on function enter and decremented on function return. + +The stack frame limit in itself serves as a safeguard against infinite recursion. +Together with the AST depth limit it can restrict total stack space usage. + +### Limiting the number of active threads + +Limits the number of threads that can be used by a context at the same point in time. +Multi-threading is not supported in the UNTRUSTED sandbox policy. + +### Heap memory limits + +The `sandbox.MaxHeapMemory` option specifies the maximum heap memory guest code is allowed to retain during its run. +Only objects residing in guest code count towards the limit - memory allocated during callbacks to host code does not. +This is not a hard limit as the efficacy of this option (also) depends on the garbage collector used. +This means that the limit may be exceeded by guest code. + +```java +try (Context context = Context.newBuilder("js") + .option("sandbox.MaxHeapMemory", "100MB") + .build()) { + context.eval("js", "var r = {}; var o = r; while(true) { o.o = {}; o = o.o; };"); + assert false; +} catch (PolyglotException e) { + // triggered after the retained size is greater than 100MB; + // context is closed and can no longer be used + // error message: Maximum heap memory limit of 104857600 bytes exceeded. Current memory at least... + assert e.isCancelled(); + assert e.isResourceExhausted(); +} +``` + +The limit is checked by retained size computation triggered either based on [allocated](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.management/com/sun/management/ThreadMXBean.html#getThreadAllocatedBytes\(long\)) bytes or on [low memory notification](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/MemoryMXBean.html). + +The allocated bytes are checked by a separate high-priority thread that will be woken regularly. +There is one such thread for each memory-limited context (one with `sandbox.MaxHeapMemory` set). +The retained bytes computation is done by yet another high-priority thread that is started from the allocated bytes checking thread as needed. +The retained bytes computation thread also cancels the context if the heap memory limit is exeeded. +Additionaly, when the low memory trigger is invoked, all contexts on engines with at least one memory-limited context are paused together with their allocation checkers. +All individual retained size computations are cancelled. +Retained bytes in the heap for each memory-limited context are computed by a single high-priority thread. + +The heap memory limit will not prevent the context from causing `OutOfMemory` errors. +Guest code that allocates many objects in quick succession has a lower accuracy compared to code that allocates objects rarely. + +Retained size computation for a context can be customized using the expert options `sandbox.AllocatedBytesCheckInterval`, `sandbox.AllocatedBytesCheckEnabled`, `sandbox.AllocatedBytesCheckFactor`, `sandbox.RetainedBytesCheckInterval`, `sandbox.RetainedBytesCheckFactor`, and `sandbox.UseLowMemoryTrigger` described below. + +Retained size computation for a context is triggered when a retained bytes estimate exceeds a certain factor of specified `sandbox.MaxHeapMemory`. +The estimate is based on heap memory +[allocated](https://docs.oracle.com/en/java/javase/17/docs/api/jdk.management/com/sun/management/ThreadMXBean.html#getThreadAllocatedBytes\(long\)) by threads where the context has been active. +More precisely, the estimate is the result of previous retained bytes computation, if available, plus bytes allocated since the start of the previous computation. +By default the factor of `sandbox.MaxHeapMemory` is 1.0 and it can be customized by the `sandbox.AllocatedBytesCheckFactor` option. +The factor must be positive. +For example, let `sandbox.MaxHeapMemory` be 100MB and `sandbox.AllocatedBytesCheckFactor` be 0.5. +The retained size computation is first triggered when allocated bytes reach 50MB. +Let the computed retained size be 25MB, then the next retained size computation is triggered when additional 25MB is allocated, etc. + +By default, allocated bytes are checked every 10 milliseconds. This can be configured by `sandbox.AllocatedBytesCheckInterval`. +The smallest possible interval is 1ms. Any smaller value is interpreted as 1ms. + +The beginnings of two retained size computations of the same context must be by default at least 10 milliseconds apart. +This can be configured by the `sandbox.RetainedBytesCheckInterval` option. The interval must be positive. + +The allocated bytes checking for a context can be disabled by the `sandbox.AllocatedBytesCheckEnabled` option. +By default it is enabled ("true"). If disabled ("false"), retained size checking for the context can be triggered only by the low memory trigger. + +When the total number of bytes allocated in the heap for the whole host VM exceeds a certain factor of the total heap memory of the VM, [low memory notification](https://docs.oracle.com/en/java/javase/17/docs/api/java.management/java/lang/management/MemoryMXBean.html) is invoked and initiates the following process. +The execution for all engines with at least one execution context which has the `sandbox.MaxHeapMemory` option set is paused, retained bytes in the heap for each memory-limited context are computed, contexts exceeding their limits are cancelled, and then the execution is resumed. +The default factor is 0.7. This can be configured by the `sandbox.RetainedBytesCheckFactor` option. +The factor must be between 0.0 and 1.0. All contexts using the `sandbox.MaxHeapMemory` option must use the same value for `sandbox.RetainedBytesCheckFactor`. + +When the usage threshold or the collection usage threshold of any heap memory pool has already been set, then the low memory trigger cannot be used by default, because the limit specified by the `sandbox.RetainedBytesCheckFactor` cannot be implemented. +However, when `sandbox.ReuseLowMemoryTriggerThreshold` is set to true and the usage threshold or the collection usage threshold of a heap memory pool has already been set, then the value of `sandbox.RetainedBytesCheckFactor` is ignored for that memory pool and whatever limit has already been set is used. +That way the low memory trigger can be used together with libraries that also set the usage threshold or the collection usage threshold of heap memory pools. + +The described low memory trigger can be disabled by the `sandbox.UseLowMemoryTrigger` option. +By default it is enabled ("true"). If disabled ("false"), retained size checking for the execution context can be triggered only by the allocated bytes checker. +All contexts using the `sandbox.MaxHeapMemory` option must use the same value for `sandbox.UseLowMemoryTrigger`. + +### Limiting the amount of data written to standard output and error streams + +Limits the size of the output that guest code writes to standard output or standard error output during runtime. +Limiting the size of the output can serve as protection against denial-of-service attacks that flood the output. + +```java +try (Context context = Context.newBuilder("js") + .option("sandbox.MaxOutputStreamSize", "100KB") + .build()) { + context.eval("js", "while(true) { console.log('Log message') };"); + assert false; +} catch (PolyglotException e) { + // triggered after writing more than 100KB to stdout + // context is closed and can no longer be used + // error message: Maximum output stream size of 102400 exceeded. Bytes written 102408. + assert e.isCancelled(); + assert e.isResourceExhausted(); +} +``` +```java +try (Context context = Context.newBuilder("js") + .option("sandbox.MaxErrorStreamSize", "100KB") + .build()) { + context.eval("js", "while(true) { console.error('Error message') };"); + assert false; +} catch (PolyglotException e) { + // triggered after writing more than 100KB to stderr + // context is closed and can no longer be used + // error message: Maximum error stream size of 102400 exceeded. Bytes written 102410. + assert e.isCancelled(); + assert e.isResourceExhausted(); +} +``` + +### Resetting Resource Limits + +It is possible to reset the limits at any point in time using the [`Context.resetLimits`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html#resetLimits--) method. +This can be useful if a known and trusted initialization script should be excluded from limit. +Only the statement, cpu time and output / error stream limits can be reset. + +```java +try (Context context = Context.newBuilder("js") + .option("sandbox.MaxCPUTime", "500ms") + .build();) { + context.eval("js", /*... initialization script ...*/); + context.resetLimits(); + context.eval("js", /*... user script ...*/); + assert false; +} catch (PolyglotException e) { + assert e.isCancelled(); + assert e.isResourceExhausted(); +} +``` + +## Runtime Defenses + +The main defense enforced by the ISOLATED and UNTRUSTED sandbox policy through the `engine.SpawnIsolate` option is that the Polyglot engine runs in a dedicated `native-image` isolate, moving execution of guest code to a VM-level fault domain separate from the host application, with its own heap, garbage collector and JIT compiler. + +Apart from setting a hard limit for the memory consumption of guest code via the guest's heap size, it also allows to focus runtime defenses just on guest code and not cause performance degredation of host code. +The runtime defenses are enabled by the `engine.UntrustedCodeMitigation` option. + +### Constant Blinding + +JIT compilers allow users to provide source code and, given the source code is valid, compile it to machine code. +From an attacker's perspective, JIT compilers compile attacker-controlled inputs to predictable bytes in executable memory. +In an attack called JIT spraying an attacker leverages the predictable compilation by feeding malicious input programs into the JIT compiler, thereby forcing it to emit code containing Return-Oriented Programming (ROP) gadgets. + +Constants in the input program are a particularly attractive target for such an attack, since JIT compilers often include them verbatim in the machine code. +Constant blinding aims to invalidate an attacker's predictions by introducing randomness into the compilation process. +Specifically, constant blinding encrypts constants with a random key at compile time and decrypts them at runtime at each occurrence. +Only the encrypted version of the constant appears verbatim in the machine code. +Absent knowledge of the random key, the attacker cannot predict the encrypted constant value and, therefore, can no longer predict the resulting bytes in executable memory. + +GraalVM blinds all immediate values and data embedded in code pages of runtime compiled guest code down to a size of four bytes. + +### Speculative Execution Attack Mitigations + +Speculative execution attacks such as Spectre exploit the fact that a CPU may transiently execute instructions based on branch prediction information. +In the case of a misprediction, the result of these instructions is discarded. +However, the execution may have caused side effects in the micro-architectural state of a CPU. +For example, data may have been pulled into the cache during transient execution - a side-channel that can be read by timing data access. + +GraalVM protects against Spectre attacks by inserting speculative execution barrier instructions in runtime compiled guest code to prevent attackers from crafting speculative execution gadgets. +A speculative execution barrier is placed at each target of a conditional branch to stop speculative execution based on the pattern history table (Spectre V1). +Speculative execution barriers are also placed at each possible indirect branch target to stop speculative execution based on the branch target buffer (Spectre V2). + +## Sharing Execution Engines + +Guest code of different trust domains has to be separated at the Polylgot engine level, i.e. only guest code of the same trust domain should share an engine. +When multiple context share an engine, all of them must have the same sandbox policy (the engine's sandbox policy). +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: +```java +Source.newBuilder(…).cached(false).build() +``` + +## Compatibility and Limitations + +Polyglot sandboxing is not available in GraalVM Community Edition. + +Depending on the sandboxing policy, only a subset of Truffle languages, instruments, and options are available. +In particular, sandboxing is currently only supported for the runtime's [default version](https://github.com/oracle/graaljs/blob/master/docs/user/JavaScriptCompatibility.md) of ECMAScript, i.e. ECMAScript 2022. +Sandboxing is also not supported from within GraalVM's Node.js. + +Polyglot sandboxing is not compatible with modifications to the VM setup via e.g. system properties that change the behavior of the VM. + +The sandboxing policy is subject to incompatible changes across major GraalVM releases to maintain a secure-by-default posture. + +Polyglot sandboxing cannot protect against vulnerabilities in its operating environment, i.e. vulnerabilities in the operating system or the underlying hardware. +We recommend to adopt the appropriate external isolation primitives to protect against corresponding risks. + +## Differentiation with Java Security Manager + +The Java Security Manager is deprecated in Java 17 with JEP-411. +The purpose of the security manager is stated as follows: "It allows an application to determine, before performing a possibly unsafe or sensitive operation, what the operation is and whether it is being attempted in a security context that allows the operation to be performed." + +The goal of the GraalVM sandbox is to allow the execution of untrusted guest code in a secure manner, meaning untrusted guest code should not be able to compromise the confidentiality, integrity or availability of the host code and its environment. + +The GraalVM sandbox differs from Security Managers in the following aspects: + +* *Security boundary*: The Java Security Manager features a flexible security boundary that depends on the actual calling context of a method. This makes "drawing the line" complex and error prone. A security-critical code block first needs to inspect the current calling stack to determine whether all frames on the stack have the authority to invoke the code. In the GraalVM sandbox, there is a straightforward, clear security boundary: the boundary between host and guest code, with guest code running on top of the Truffle framework, similar to how typical computer architectures distinguish between user mode and (privileged) kernel mode. +* *Isolation*: With the Java Security Manager, privileged code is almost on "equal footing" as untrusted code with respect to the language and runtime: + * *Shared language*: With the Java Security Manager, untrusted code is written in the same language as privileged code, with the advantage of straightforward interoperability between the two. In contrast, the GraalVM sandbox a guest application written in a Truffle language needs to pass an explicit boundary to host code written in Java. + * *Shared runtime*: With the Java Security Manager, untrusted code executes in the same JVM environment as trusted code, sharing JDK classes and runtime services such as the garbage collector or the compiler. In the GraalVM sandbox, untrusted code runs in dedicated VM instances (GraalVM isolates), separating services and JDK classes of host and guest by design. +* *Resource limits*: The Java Security Manager cannot restrict the usage of computational resources such as CPU time or memory, allowing untrusted code to DoS the JVM. The GraalVM sandbox offers controls to set limits on several computational resources (CPU time, memory, threads, processes), guest code may consume to address availability concerns. +* *Configuration*: Crafting a Java Security Manager policy was often found to be a complex and error-prone task, requiring a subject matter expert that knows exactly which parts of the program require what level of access. Configuring the GraalVM sandbox provides security profiles that focus on common sandboxing use cases and threat models. + +## Reporting vulnerabilities + +If you believe you have found a security vulnerability, please submit a report to secalert_us@oracle.com preferably with a proof of concept. +Please refer to [Reporting Vulnerabilities](https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html) for additional information including our public encryption key for secure email. +We ask that you do not contact project contributors directly or through other channels about a report. + + +### Related Documentation +- [Security Guide](security-guide.md) +- [Native Image Security Aspects](native-image.md) diff --git a/docs/security/sandbox_security_boundary.png b/docs/security/sandbox_security_boundary.png new file mode 100644 index 0000000000000000000000000000000000000000..3e36f080dbf5538ce3e7976ca58e972ba538d429 GIT binary patch literal 9869 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 Nqj^E2;Iwt{e*;y29-aUI literal 0 HcmV?d00001 diff --git a/docs/security/security-guide.md b/docs/security/security-guide.md index d39a6ff723ee..8dc877f9055b 100644 --- a/docs/security/security-guide.md +++ b/docs/security/security-guide.md @@ -15,13 +15,6 @@ It assumes that readers are familiar with the GraalVM architecture. This guide does not replace but rather supplements the Java security documentation with aspects unique to GraalVM. It also provides security researchers with information on GraalVM's security model. -* [Security Model](#security-model) -* [Language Launchers](#language-launchers) -* [Guest Applications](#guest-applications) -* [Native Image](#native-image) -* [Security Manager and Untrusted Code](#security-manager-and-untrusted-code) -* [Oracle GraalVM to GraalVM Community Downgrade](#graalvm-enterprise-to-graalvm-community-downgrade) - ## Security Model GraalVM is a shared runtime. It accepts instructions in a higher-level @@ -29,73 +22,43 @@ programming language (or an intermediate representation thereof) as input, which Developers that implement security controls for their applications (such as access control) in code that is being run by GraalVM can rely on the correct execution of instructions. Incorrect execution of security-critical code running on top of GraalVM that allows to bypass such a security control is regarded a security vulnerability. -GraalVM does not support execution of 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 external isolation primitives to ensure the confidentiality and integrity of their application data. - Debug features should only be used in a trusted environment as they provide privileged access to an application, allowing to inspect and change its state and behavior. They may further open network sockets to allow debug clients to connect. Experimental features in GraalVM are not for production use and may have security limitations not covered in the Security Guide. +GraalVM enables execution of untrusted code in an appropriately configured polyglot execution context (see [Polyglot Sandboxing](polyglot-sandbox.md)). + We appreciate reports of bugs that break the security model via the process outlined in the [Reporting Vulnerabilities guide](https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html). -## Language Launchers +## Polyglot Languages -For every language implemented with the Truffle framework, and shipped with GraalVM, a launcher, e.g., interactive shell, is provided. +For every Polyglot 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. -## Guest Applications - -GraalVM allows a host application written in a JVM-based language to execute guest applications written in a Truffle language via the [Polyglot API](../reference-manual/embedding/embed-languages.md). -When creating a context, the host application can control which resources the guest can access. -This mechanism is only fully supported for Javascript. -By default, access to all managed resources is denied and needs to be granted explicitly, following the principle of least privilege. - -### Host Interoperability - -GraalVM allows exchanging objects between the host and the guest application. -By default only methods of host classes that are explicitly annotated by the embedder are exposed to guest applications. - -By exposing security critical host methods, access restrictions can be bypassed. -For example, a guest application in a context that is created with `allowIO=false` cannot perform IO operations via the guest language's native API. -However, exposing a host method to the context that allows writing to arbitrary files effectively bypasses this restriction. - -### 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: -```java -Source.newBuilder(…).cached(false).build() -``` - -### Computational Resource Limits - -> Note: Available with Oracle GraalVM. +### Polyglot Sandboxing -Oracle GraalVM allows restricting certain computational resources used by guest applications, such as CPU time, heap memory or the number of threads that can be concurrently used by a context. -These [sandboxing options](../reference-manual/embedding/sandbox-options.md) are also available via the Polyglot embedding API. +Polyglot sandboxing can establish a security boundary between privileged host code and unprivileged guest code. +For further information please refer to the [Polyglot Sandboxing guide](polyglot-sandbox.md). ### 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. +For reasons of backward compatibility, certain Polyglot languages also support the [Java Scripting API](https://docs.oracle.com/javase/9/scripting/java-scripting-api.htm). +For example, this allows the GraalVM Javascript runtime 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 -> Note: Available with Oracle GraalVM. +Polyglot embedding also supports LLVM intermediate representation (IR) guest code. +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 unless using managed execution and it must be remembered that violations of memory safety are a frequent cause of security vulnerabilities. -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. - -In managed mode, all ties to the native level are abstracted and routed through Oracle GraalVM. In particular this means that: +In managed mode, all access to unmanaged code including the operating system is mediated by the language runtime. In particular this means that: * In regards to temporal and spatial memory safety, memory is allocated from the Java heap. This means that memory allocations are managed objects and all accesses are performed in a memory-safe manner (no arbitrary pointer arithmetics and no unchecked out-of-bounds accesses). * Regarding type safety, it is not possible to reinterpret a data pointer into a function pointer and execute arbitrary instructions (since these are distinct pointer types for LLVM runtime). -* System calls are intercepted and routed to the corresponding Truffle -APIs. For example, file IO is mapped to the Truffle `FileSystem` API. +* System calls are intercepted and routed to the corresponding Truffle APIs. For example, file IO is mapped to the Truffle `FileSystem` API. The set of currently supported system calls is very limited -- only syscalls that can safely be mapped to the Truffle API level are available. Since LLVM Runtime in managed mode always runs bitcode compiled for Linux/x86, it only needs to implement system calls for this platform. * All dependent libraries are executed in managed mode as well, removing all references to natively executed system libraries. This includes libraries that are provided by the LLVM Runtime, such as muslibc. @@ -103,47 +66,23 @@ Managed mode can be selected when creating a context `(Context.create())` or whe ## Native Image -The `native-image` builder generates a snapshot of an application after startup and bundles it in a binary executable. - -By default, the `native-image` builder executes the static initializers of classes at build time and persists the state in the image heap. -This means that any information that is obtained or computed in static initializers becomes part of a native 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 executable, or making use of the `RuntimeClassInitialization` API. - -Native-image provides multiple ways to specify the certificate file used to define the default TrustStore. -While the default behavior for native-image is to capture and use the default TrustStore from the buildtime host environment, this can be changed at runtime by setting the "javax.net.ssl.trustStore\*" system properties. -See the [documentation](../reference-manual/native-image/CertificateManagement.md) for more details. - -In addition, developers can run the `native-image` builder in a dedicated environment, such as a container, that does not contain any sensitive information in the first place. - -The directory containing the native image is part of the search path when loading native libraries using `System.loadLibrary()` at runtime. +With GraalVM native image, an application's state is captured after startup and all reachable code is compiled ahead of time to be bundled as a native executable. +For further information please refer to the [native image security guide](native-image.md). -### Serialization in Native Image - -Native Image supports Serialization to help users deserialize the constructors for classes, contained in a native executable in the first place. -These classes should be whitelisted in an additional specific configuration file, as other classes cannot be deserialized. -Deserialization support also adds optional object checksums, and only classes with the same checksum can be deserialized at runtime. -The checksum mechanism must not be used for security purposes and the deserialization of untrusted data is not supported. - -## Security Manager and Untrusted Code +## Security Manager +Security manager has been deprecated in [JEP-411](https://openjdk.java.net/jeps/411). The OpenJDK vulnerability group strongly discourages running untrusted code under a security manager. This also applies to GraalVM, which does not support untrusted code execution in Java. -While GraalVM'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. - -Note that security manager deprecation is an option in [JEP-411](https://openjdk.java.net/jeps/411). - -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. -## Oracle GraalVM to GraalVM Community Edition Downgrade +## GraalVM Community Edition Downgrade -> Note: Managed execution of native code is not available in GraalVM Community Edition. +Polyglot sandboxing is not available in GraalVM Community Edition. +Managed execution of native code is not available with GraalVM Community Edition. When downgrading to GraalVM Community Edition, native code execution is only possible with the `allowNativeAccess` privilege. This also applies to languages implemented with Truffle that allow for native code extensions, such as Python and Ruby. -Computational resource limit options are not recognized by GraalVM Community Edition. +### Related Documentation +- [Polyglot Sandboxing](polyglot-sandbox.md) +- [Native Image Security Aspects](native-image.md) diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SandboxPolicy.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SandboxPolicy.java index 613ffb75f171..4c97248f5549 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SandboxPolicy.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SandboxPolicy.java @@ -86,6 +86,9 @@ * changelog. *

* + * For further information on Polyglot Sandboxing, please refer to the + * security guide. + * * @see Context.Builder#sandbox(SandboxPolicy) * @see Engine.Builder#sandbox(SandboxPolicy) * @@ -153,7 +156,7 @@ public enum SandboxPolicy { *

*

* Constrained Context building example: - * + * *

      * ByteArrayOutputStream output = new ByteArrayOutputStream();
      * ByteArrayOutputStream errorOutput = new ByteArrayOutputStream();