mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 04:07:12 -06:00
Security: bounded flattening, plug-in budgets and caches, loaded textures, Revolve paint copies, color book names and ICC names
CodeRabbit findings #4, #34, #46, #51, #77, #101, #170, #171, #188: - `vectorcraft_geom::flatten`: kurbo's flatten with each curve's tolerance raised so it makes at most ~4096 segments (non-finite curves become a line); the canvas outline and variable-width strokes use it. - Plug-ins: a heavy filter's budget is the host's `Limits::heavy_fuel`/`heavy_wall_time_ms`, never more; a start function runs on one fuel slice; the effect cache holds at most ~1M anchors of inputs and results, and doesn't keep a result past a quarter of that. - Loaded textures are cached by their PNG (base64 spacing doesn't matter), and live textures hold at most 512 MB together. - Revolve draws the source path when the faces' paint copies would pass 256 MB. - Color books: names with prefix and suffix take at most 64 MB. - ICC: localized-name (`mluc`) records over 1 MB together are refused before moxcms copies them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Opus 5.5
parent
a608838ba2
commit
e2a870e602
@@ -46,6 +46,11 @@ pub struct Limits {
|
||||
/// Wall-clock budget for one run, in milliseconds. Native builds only: the web build has no
|
||||
/// monotonic clock in `std`, so the fuel budget alone bounds it there.
|
||||
pub wall_time_ms: u64,
|
||||
/// The most a heavy filter ([`crate::Budget::Heavy`]) is given instead of `fuel_base` and
|
||||
/// `wall_time_ms`: what the host allows, which the module's manifest can ask for but never
|
||||
/// raise. Set them to `fuel_base` and `wall_time_ms` to give heavy filters nothing more.
|
||||
pub heavy_fuel: u64,
|
||||
pub heavy_wall_time_ms: u64,
|
||||
}
|
||||
|
||||
impl Default for Limits {
|
||||
@@ -58,6 +63,8 @@ impl Default for Limits {
|
||||
fuel_per_byte: 4_000,
|
||||
max_recursion_depth: 1024,
|
||||
wall_time_ms: 60_000,
|
||||
heavy_fuel: HEAVY_FUEL,
|
||||
heavy_wall_time_ms: HEAVY_WALL_TIME_MS,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,11 +177,11 @@ impl Plugin {
|
||||
e => e,
|
||||
})?;
|
||||
p.manifest = Manifest::parse(&text)?;
|
||||
// A heavy filter's runs get the larger budget, which the host lets the user allow or
|
||||
// refuse before installing it.
|
||||
// A heavy filter's runs get the larger budget the host allows for one, which the host
|
||||
// lets the user allow or refuse before installing it.
|
||||
if p.manifest.budget == crate::Budget::Heavy {
|
||||
p.limits.fuel_base = p.limits.fuel_base.max(HEAVY_FUEL);
|
||||
p.limits.wall_time_ms = p.limits.wall_time_ms.max(HEAVY_WALL_TIME_MS);
|
||||
p.limits.fuel_base = p.limits.fuel_base.max(p.limits.heavy_fuel);
|
||||
p.limits.wall_time_ms = p.limits.wall_time_ms.max(p.limits.heavy_wall_time_ms);
|
||||
}
|
||||
// The other exports must exist with the right types.
|
||||
live.func::<i32, i32>("vc_alloc")?;
|
||||
@@ -217,8 +224,9 @@ impl Plugin {
|
||||
StoreLimitsBuilder::new().memory_size(self.limits.max_memory_bytes).memories(1).tables(4).table_elements(100_000).instances(1).build();
|
||||
let mut store = Store::new(&self.engine, limits);
|
||||
store.limiter(|l| l);
|
||||
// The start function (if any) runs on this fuel.
|
||||
store.set_fuel(self.limits.fuel_base).map_err(wasm_err)?;
|
||||
// The start function (if any) runs on one slice of fuel: it runs before `call` can check
|
||||
// the deadline or a cancel between slices, so a heavy budget would let it run for minutes.
|
||||
store.set_fuel(self.limits.fuel_base.min(FUEL_SLICE)).map_err(wasm_err)?;
|
||||
let linker = Linker::<StoreLimits>::new(&self.engine);
|
||||
let instance = linker.instantiate_and_start(&mut store, &self.module).map_err(wasm_err)?;
|
||||
let memory =
|
||||
|
||||
Reference in New Issue
Block a user