wasmi/engine/limits/engine.rs
1use core::fmt::{self, Display};
2
3/// An error that can occur upon parsing or compiling a Wasm module when [`EnforcedLimits`] are set.
4#[derive(Debug, Copy, Clone)]
5pub enum EnforcedLimitsError {
6 /// When a Wasm module exceeds the global variable limit.
7 TooManyGlobals { limit: u32 },
8 /// When a Wasm module exceeds the table limit.
9 TooManyTables { limit: u32 },
10 /// When a Wasm module exceeds the function limit.
11 TooManyFunctions { limit: u32 },
12 /// When a Wasm module exceeds the linear memory limit.
13 TooManyMemories { limit: u32 },
14 /// When a Wasm module exceeds the element segment limit.
15 TooManyElementSegments { limit: u32 },
16 /// When a Wasm module exceeds the data segment limit.
17 TooManyDataSegments { limit: u32 },
18 /// When a Wasm module exceeds the function parameter limit.
19 TooManyParameters { limit: usize },
20 /// When a Wasm module exceeds the function results limit.
21 TooManyResults { limit: usize },
22 /// When a Wasm module exceeds the average bytes per function limit.
23 MinAvgBytesPerFunction { limit: u32, avg: u32 },
24}
25
26impl Display for EnforcedLimitsError {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match self {
29 Self::TooManyGlobals { limit } => write!(
30 f,
31 "the Wasm module exceeds the limit of {limit} global variables"
32 ),
33 Self::TooManyTables { limit } => {
34 write!(f, "the Wasm module exceeds the limit of {limit} tables")
35 }
36 Self::TooManyFunctions { limit } => {
37 write!(f, "the Wasm modules exceeds the limit of {limit} functions")
38 }
39 Self::TooManyMemories { limit } => {
40 write!(f, "the Wasm module exceeds the limit of {limit} memories")
41 }
42 Self::TooManyElementSegments { limit } => write!(
43 f,
44 "the Wasm module exceeds the limit of {limit} active element segments"
45 ),
46 Self::TooManyDataSegments { limit } => write!(
47 f,
48 "the Wasm module exceeds the limit of {limit} active data segments",
49 ),
50 Self::TooManyParameters { limit } => {
51 write!(f, "a function type exceeds the limit of {limit} parameters",)
52 }
53 Self::TooManyResults { limit } => {
54 write!(f, "a function type exceeds the limit of {limit} results",)
55 }
56 Self::MinAvgBytesPerFunction { limit, avg } => write!(
57 f,
58 "the Wasm module failed to meet the minumum average bytes per function of {limit}: \
59 avg={avg}"
60 ),
61 }
62 }
63}
64
65/// Stores customizable limits for the [`Engine`] when parsing or compiling Wasm modules.
66///
67/// By default no limits are enforced.
68///
69/// [`Engine`]: crate::Engine
70#[derive(Debug, Default, Copy, Clone)]
71pub struct EnforcedLimits {
72 /// Number of global variables a single Wasm module can have at most.
73 ///
74 /// # Note
75 ///
76 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
77 /// - `None` means the limit is not enforced.
78 ///
79 /// [`Module::new`]: crate::Module::new
80 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
81 pub(crate) max_globals: Option<u32>,
82 /// Number of functions a single Wasm module can have at most.
83 ///
84 /// # Note
85 ///
86 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
87 /// - `None` means the limit is not enforced.
88 ///
89 /// [`Module::new`]: crate::Module::new
90 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
91 pub(crate) max_functions: Option<u32>,
92 /// Number of tables a single Wasm module can have at most.
93 ///
94 /// # Note
95 ///
96 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
97 /// - This is only relevant if the Wasm `reference-types` proposal is enabled.
98 /// - `None` means the limit is not enforced.
99 ///
100 /// [`Module::new`]: crate::Module::new
101 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
102 pub(crate) max_tables: Option<u32>,
103 /// Number of table element segments a single Wasm module can have at most.
104 ///
105 /// # Note
106 ///
107 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
108 /// - This is only relevant if the Wasm `reference-types` proposal is enabled.
109 /// - `None` means the limit is not enforced.
110 ///
111 /// [`Module::new`]: crate::Module::new
112 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
113 pub(crate) max_element_segments: Option<u32>,
114 /// Number of linear memories a single Wasm module can have.
115 ///
116 /// # Note
117 ///
118 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
119 /// - This is only relevant if the Wasm `multi-memories` proposal is enabled
120 /// which is not supported in Wasmi at the time of writing this comment.
121 /// - `None` means the limit is not enforced.
122 ///
123 /// [`Module::new`]: crate::Module::new
124 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
125 pub(crate) max_memories: Option<u32>,
126 /// Number of linear memory data segments a single Wasm module can have at most.
127 ///
128 /// # Note
129 ///
130 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
131 /// - This is only relevant if the Wasm `reference-types` proposal is enabled.
132 /// - `None` means the limit is not enforced.
133 ///
134 /// [`Module::new`]: crate::Module::new
135 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
136 pub(crate) max_data_segments: Option<u32>,
137 /// Limits the number of parameter of all functions and control structures.
138 ///
139 /// # Note
140 ///
141 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
142 /// - `None` means the limit is not enforced.
143 ///
144 /// [`Engine`]: crate::Engine
145 /// [`Module::new`]: crate::Module::new
146 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
147 pub(crate) max_params: Option<usize>,
148 /// Limits the number of results of all functions and control structures.
149 ///
150 /// # Note
151 ///
152 /// - This is only relevant if the Wasm `multi-value` proposal is enabled.
153 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
154 /// - `None` means the limit is not enforced.
155 ///
156 /// [`Engine`]: crate::Engine
157 /// [`Module::new`]: crate::Module::new
158 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
159 pub(crate) max_results: Option<usize>,
160 /// Minimum number of bytes a function must have on average.
161 ///
162 /// # Note
163 ///
164 /// - This is checked in [`Module::new`] or [`Module::new_unchecked`].
165 /// - This limitation might seem arbitrary but is important to defend against
166 /// malicious inputs targeting lazy compilation.
167 /// - `None` means the limit is not enforced.
168 ///
169 /// [`Module::new`]: crate::Module::new
170 /// [`Module::new_unchecked`]: crate::Module::new_unchecked
171 pub(crate) min_avg_bytes_per_function: Option<AvgBytesPerFunctionLimit>,
172}
173
174/// The limit for average bytes per function limit and the threshold at which it is enforced.
175#[derive(Debug, Copy, Clone)]
176pub struct AvgBytesPerFunctionLimit {
177 /// The number of Wasm module bytes at which the limit is actually enforced.
178 ///
179 /// This represents the total number of bytes of all Wasm function bodies in the Wasm module combined.
180 ///
181 /// # Note
182 ///
183 /// - A `req_funcs_bytes` of 0 always enforces the `min_avg_bytes_per_function` limit.
184 /// - The `req_funcs_bytes` field exists to filter out small Wasm modules
185 /// that cannot seriously be used to attack the Wasmi compilation.
186 pub req_funcs_bytes: u32,
187 /// The minimum number of bytes a function must have on average.
188 pub min_avg_bytes_per_function: u32,
189}
190
191impl EnforcedLimits {
192 /// A strict set of limits that makes use of Wasmi implementation details.
193 ///
194 /// This set of strict enforced rules can be used by Wasmi users in order
195 /// to safeguard themselves against malicious actors trying to attack the Wasmi
196 /// compilation procedures.
197 pub fn strict() -> Self {
198 Self {
199 max_globals: Some(1000),
200 max_functions: Some(10_000),
201 max_tables: Some(100),
202 max_element_segments: Some(1000),
203 max_memories: Some(1),
204 max_data_segments: Some(1000),
205 max_params: Some(32),
206 max_results: Some(32),
207 min_avg_bytes_per_function: Some(AvgBytesPerFunctionLimit {
208 // If all function bodies combined use a total of at least 1000 bytes
209 // the average bytes per function body limit is enforced.
210 req_funcs_bytes: 1000,
211 // Compiled and optimized Wasm modules usually average out on 100-2500
212 // bytes per Wasm function. Thus the chosen limit is way below this threshold
213 // and should not be exceeded for non-malicous Wasm modules.
214 min_avg_bytes_per_function: 40,
215 }),
216 }
217 }
218}