summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaud Golfouse <53786772+arnaudgolfouse@users.noreply.github.com>2023-09-26 16:21:21 +0200
committerGitHub <noreply@github.com>2023-09-26 16:21:21 +0200
commit962071619d70975878fe93964422f0d0ed93945d (patch)
treec8161e3d3e48c7c23a472733113d4b62dd93369a
parent2fd0291a8180cba8a6d503229eeef7bd1b744796 (diff)
Avoid plugin panics (#2232)
-rwxr-xr-xassets/files/plugin-oob.wasmbin0 -> 396 bytes
-rw-r--r--crates/typst/src/eval/plugin.rs31
-rw-r--r--tests/typ/compiler/plugin-oob.typ14
3 files changed, 43 insertions, 2 deletions
diff --git a/assets/files/plugin-oob.wasm b/assets/files/plugin-oob.wasm
new file mode 100755
index 00000000..6afb7436
--- /dev/null
+++ b/assets/files/plugin-oob.wasm
Binary files differ
diff --git a/crates/typst/src/eval/plugin.rs b/crates/typst/src/eval/plugin.rs
index 11576080..ee64ec5f 100644
--- a/crates/typst/src/eval/plugin.rs
+++ b/crates/typst/src/eval/plugin.rs
@@ -120,11 +120,19 @@ struct Repr {
/// Owns all data associated with the WebAssembly module.
type Store = wasmi::Store<StoreData>;
+/// If there was an error reading/writing memory, keep the offset + length to
+/// display an error message.
+struct MemoryError {
+ offset: u32,
+ length: u32,
+ write: bool,
+}
/// The persistent store data used for communication between store and host.
#[derive(Default)]
struct StoreData {
args: Vec<Bytes>,
output: Vec<u8>,
+ memory_error: Option<MemoryError>,
}
#[scope]
@@ -245,6 +253,14 @@ impl Plugin {
let mut code = wasmi::Value::I32(-1);
func.call(store.as_context_mut(), &lengths, std::slice::from_mut(&mut code))
.map_err(|err| eco_format!("plugin panicked: {err}"))?;
+ if let Some(MemoryError { offset, length, write }) =
+ store.data_mut().memory_error.take()
+ {
+ return Err(eco_format!(
+ "plugin tried to {kind} out of bounds: pointer {offset:#x} is out of bounds for {kind} of length {length}",
+ kind = if write { "write" } else { "read" }
+ ));
+ }
// Extract the returned data.
let output = std::mem::take(&mut store.data_mut().output);
@@ -294,7 +310,14 @@ fn wasm_minimal_protocol_write_args_to_buffer(mut caller: Caller<StoreData>, ptr
let arguments = std::mem::take(&mut caller.data_mut().args);
let mut offset = ptr as usize;
for arg in arguments {
- memory.write(&mut caller, offset, arg.as_slice()).unwrap();
+ if memory.write(&mut caller, offset, arg.as_slice()).is_err() {
+ caller.data_mut().memory_error = Some(MemoryError {
+ offset: offset as u32,
+ length: arg.len() as u32,
+ write: true,
+ });
+ return;
+ }
offset += arg.len();
}
}
@@ -308,6 +331,10 @@ fn wasm_minimal_protocol_send_result_to_host(
let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
let mut buffer = std::mem::take(&mut caller.data_mut().output);
buffer.resize(len as usize, 0);
- memory.read(&caller, ptr as _, &mut buffer).unwrap();
+ if memory.read(&caller, ptr as _, &mut buffer).is_err() {
+ caller.data_mut().memory_error =
+ Some(MemoryError { offset: ptr, length: len, write: false });
+ return;
+ }
caller.data_mut().output = buffer;
}
diff --git a/tests/typ/compiler/plugin-oob.typ b/tests/typ/compiler/plugin-oob.typ
new file mode 100644
index 00000000..4bc16212
--- /dev/null
+++ b/tests/typ/compiler/plugin-oob.typ
@@ -0,0 +1,14 @@
+// Test Out Of Bound read/write in WebAssembly plugins communication.
+// Ref: false
+
+---
+#let p = plugin("/files/plugin-oob.wasm")
+
+// Error: 2-14 plugin tried to read out of bounds: pointer 0x40000000 is out of bounds for read of length 1
+#p.read_oob()
+
+---
+#let p = plugin("/files/plugin-oob.wasm")
+
+// Error: 2-27 plugin tried to write out of bounds: pointer 0x40000000 is out of bounds for write of length 3
+#p.write_oob(bytes("xyz"))