diff options
| author | Arnaud Golfouse <53786772+arnaudgolfouse@users.noreply.github.com> | 2023-09-26 16:21:21 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-26 16:21:21 +0200 |
| commit | 962071619d70975878fe93964422f0d0ed93945d (patch) | |
| tree | c8161e3d3e48c7c23a472733113d4b62dd93369a | |
| parent | 2fd0291a8180cba8a6d503229eeef7bd1b744796 (diff) | |
Avoid plugin panics (#2232)
| -rwxr-xr-x | assets/files/plugin-oob.wasm | bin | 0 -> 396 bytes | |||
| -rw-r--r-- | crates/typst/src/eval/plugin.rs | 31 | ||||
| -rw-r--r-- | tests/typ/compiler/plugin-oob.typ | 14 |
3 files changed, 43 insertions, 2 deletions
diff --git a/assets/files/plugin-oob.wasm b/assets/files/plugin-oob.wasm Binary files differnew file mode 100755 index 00000000..6afb7436 --- /dev/null +++ b/assets/files/plugin-oob.wasm 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")) |
