diff --git a/docs/docs/advanced/cpu-limits.md b/docs/docs/advanced/cpu-limits.md index c1f08ec3c..04e60c384 100644 --- a/docs/docs/advanced/cpu-limits.md +++ b/docs/docs/advanced/cpu-limits.md @@ -51,7 +51,7 @@ var thread = new Thread() { } }; thread.start(); -Thread.sleep(200); +thread.join(200); thread.interrupt(); ``` @@ -67,6 +67,7 @@ var future = service.submit(() -> function.apply()); try { future.get(100, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { + future.cancel(true); // handle the failure } ``` diff --git a/docs/docs/advanced/logging.md b/docs/docs/advanced/logging.md index 8d0f73861..50f10caf1 100644 --- a/docs/docs/advanced/logging.md +++ b/docs/docs/advanced/logging.md @@ -5,13 +5,13 @@ title: Logging --- # Logging -For maximum compatibility and to avoid external dependencies we use, by default, the JDK Platform Logging (JEP 264). -You can configure it by providing a `logging.properties` using the `java.util.logging.config.file` property and [here](https://docs.oracle.com/cd/E57471_01/bigData.100/data_processing_bdd/src/rdp_logging_config.html) you can find the possible configurations. +For maximum compatibility and to avoid external dependencies we use, by default, the JDK Platform Logging ([JEP 264](https://openjdk.org/jeps/264)). +The Platform Logging falls back to the [`java.util.logging` API](https://docs.oracle.com/en/java/javase/21/core/java-logging-overview.html) by default. For more advanced configuration scenarios we encourage you to provide an alternative, compatible, adapter: -- [slf4j](https://www.slf4j.org/manual.html#jep264) -- [log4j2](https://logging.apache.org/log4j/2.x/log4j-jpl.html) +- [SLF4J](https://www.slf4j.org/manual.html#jep264) +- [Log4j2](https://logging.apache.org/log4j/2.x/log4j-jpl.html) It's also possible to provide a custom `run.endive.log.Logger` implementation if JDK Platform Logging is not available or doesn't fit. diff --git a/docs/docs/advanced/memory-customization.md b/docs/docs/advanced/memory-customization.md index 9821c8e9b..3f6db6850 100644 --- a/docs/docs/advanced/memory-customization.md +++ b/docs/docs/advanced/memory-customization.md @@ -35,7 +35,11 @@ var instance = Instance.builder(module).withMemoryFactory(limits -> { }).build(); ``` -> **NOTE:** Since Endive 1.1.0, an optimized memory implementation called `ByteArrayMemory` is also available. We recommend plugging this implementation on all recent OpenJDK systems for enhanced performance. On different Java runtimes (in particular, on Android VMs) you should stick to `ByteBufferMemory`. +:::note +Endive provides two built-in Memory implementations: +- `ByteArrayMemory`: An optimized memory implementation, recommended for recent OpenJDK systems +- `ByteBufferMemory`: Recommended for different Java runtimes (in particular, on Android VMs) +::: -> *Note*: Functions in Wasm can return multiple values, hence the array. This function only returns one value, so we take the first value. +:::note +Functions in Wasm can return multiple values, hence the array. This function only returns one value, so we take the first value. +::: diff --git a/docs/docs/security/best-practices.md b/docs/docs/security/best-practices.md index 95cfd50ed..269ffe73c 100644 --- a/docs/docs/security/best-practices.md +++ b/docs/docs/security/best-practices.md @@ -21,7 +21,7 @@ HostFunction readMemory = (Instance instance, long... args) -> { // Validate bounds BEFORE accessing memory var memory = instance.memory(); - if (offset < 0 || length < 0 || offset + length > memory.pages() * 65536) { + if (offset < 0 || length < 0 || Math.addExact(offset, length) > memory.pages() * 65536) { throw new TrapException("out of bounds memory access"); } @@ -33,7 +33,7 @@ HostFunction readMemory = (Instance instance, long... args) -> { **Key rules:** - Validate all memory offsets and lengths before reading/writing -- Never use Wasm-provided values as array indices without bounds checking +- Never use Wasm-provided values as array indices without bounds checking; keep overflow in mind or use overflow-safe methods such as `Math#addExact` or `Objects#checkFromIndexSize` - Be cautious with string decoding β€” enforce maximum lengths - Avoid exposing file paths, SQL queries, or shell commands derived from Wasm input @@ -47,8 +47,8 @@ WASI file access does not enforce path sandboxing by default. Passing the host f ```java title="Example" var options = WasiOptions.builder() - // Use ZeroFS to restrict access to specific directories - .withDirectory("/guest/data", Path.of("/host/sandboxed/data")) + // Use ZeroFs to restrict access to specific directories + .withDirectory("/guest/data", zeroFs.getPath("/host/sandboxed/data")) .withStdout(myStdout) .withStderr(myStderr) .build(); @@ -80,7 +80,7 @@ See [CPU Limits](/docs/advanced/cpu-limits) for more patterns. The runtime and build-time compilers translate Wasm to JVM bytecode for performance. When running untrusted modules: - **Prefer the interpreter** for maximum sandbox assurance β€” it doesn't generate JVM bytecode -- **Protect compiler cache directories** with restrictive permissions (`chmod 700`) if using the directory cache +- **Protect compiler cache directories** with restrictive permissions (`chmod 700`) if using the [directory cache](/docs/execution/compiler-cache/#the-directory-cache) - **Set JVM heap limits** when compiling large untrusted modules to prevent resource exhaustion ## Dependency Supply Chain diff --git a/docs/docs/security/overview.md b/docs/docs/security/overview.md index a9bfcdc88..ed35bb4c3 100644 --- a/docs/docs/security/overview.md +++ b/docs/docs/security/overview.md @@ -47,13 +47,13 @@ The critical trust boundary is between **Wasm guest code** and **host functions* - **CPU limits**: Wasm modules can execute infinite loops. The host must enforce timeouts (see [CPU Limits](/docs/advanced/cpu-limits)). - **Memory growth limits**: Modules can request memory growth up to the declared maximum. The host should set appropriate limits. - **Post-compilation verification**: The build-time and runtime compilers translate Wasm to JVM bytecode without a separate verification pass. For maximum assurance with untrusted code, prefer the interpreter. -- **Cache integrity**: The directory-based compiler cache does not verify bytecode integrity on load. Protect cache directories with restrictive permissions. +- **Cache integrity**: The [directory-based compiler cache](/docs/execution/compiler-cache/#the-directory-cache) does not verify bytecode integrity on load. Protect cache directories with restrictive permissions. ## WASI and Capability-Based Security When using WASI, the host controls what capabilities the guest receives: -- **Filesystem access** is opt-in. Use a virtual filesystem (e.g., ZeroFS) to restrict access to specific directories. +- **Filesystem access** is opt-in. Use a virtual filesystem (e.g., [ZeroFs](https://github.com/roastedroot/zerofs)) to restrict access to specific directories. - **Environment variables** and **command-line arguments** are explicitly passed by the host. - **Standard I/O** streams are host-controlled. diff --git a/docs/docs/wasi/index.md b/docs/docs/wasi/index.md index 856555b3e..12a209ea3 100644 --- a/docs/docs/wasi/index.md +++ b/docs/docs/wasi/index.md @@ -6,7 +6,7 @@ title: Wasi Preview 1 # WASI Preview 1 :::warning[Security Consideration] -WASI file access does not enforce path sandboxing by default. Always use a virtual filesystem (e.g., ZeroFS or JimFS) to restrict guest access to pre-opened directories. Passing the host filesystem directly exposes all files the JVM process can access. See [Security Best Practices](/docs/security/best-practices). +WASI file access does not enforce path sandboxing by default. Always use a virtual filesystem (e.g., [ZeroFs](https://github.com/roastedroot/zerofs) or [Jimfs](https://github.com/google/jimfs)) to restrict guest access to pre-opened directories. Passing the host filesystem directly exposes all files the JVM process can access. See [Security Best Practices](/docs/security/best-practices). ::: Notice that it is always possible to connect standard output, standard input and standard error to the system's real streams. -For instance, in the case of stdout, you would write: +For instance, you would write: ```java var wasi = WasiOptions.builder().withStdout(System.out).withStderr(System.err).withStdin(System.in).build(); @@ -163,7 +165,10 @@ var wasi = WasiOptions.builder().withArguments(List.of("executable-name", "--mor To expose environment variables to your WASI module you can list them in the options: ```java -var wasi = WasiOptions.builder().withEnvironment("ENV_ONE_KEY", "my-one-key-value").withEnvironment("ENV_TWO_KEY", "my-two-key-value").build(); +var wasi = WasiOptions.builder(). + withEnvironment("ENV_ONE_KEY", "my-one-key-value"). + withEnvironment("ENV_TWO_KEY", "my-two-key-value"). + build(); ``` ## disk @@ -196,7 +201,7 @@ try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix().toBuilder().setAtt ## Supported Features -If your module calls a wasi function that we don't support, or uses a feature that we don't support, we will throw a `WasmRuntimeException`. +If your module calls a WASI function that we don't support, or uses a feature that we don't support, we will throw a `WasmRuntimeException`. For the most up-to-date info, and to see what specific functions we support, see the [WasiPreview1.java](https://github.com/bytecodealliance/endive/blob/main/wasi/src/main/java/run/endive/wasi/WasiPreview1.java) and the following table: diff --git a/wasi/README.md b/wasi/README.md index 7d462dd61..72051061f 100644 --- a/wasi/README.md +++ b/wasi/README.md @@ -5,4 +5,4 @@ This library contains code for instantiating and running WASI modules. by many of the compilers out there. This library implements the widely-available version 0.1 of the spec, also known as `wasip1`. -For further details see the [corresponding docs](https://endive.run/docs/usage/wasi) section +For further details see the [corresponding docs](https://endive.run/docs/usage/wasi) section.