1use anyhow::bail;
6use move_core_types::{
7 account_address::AccountAddress,
8 annotated_value as A,
9 annotated_visitor::{self, StructDriver, ValueDriver, VecDriver, Visitor},
10 language_storage::TypeTag,
11 u256::U256,
12};
13use once_cell::sync::Lazy;
14use tracing::info;
15
16pub struct BoundedVisitor {
21 bound: usize,
23}
24
25#[derive(thiserror::Error, Debug)]
26pub enum Error {
27 #[error(transparent)]
28 Visitor(#[from] annotated_visitor::Error),
29
30 #[error("Deserialized value too large")]
31 OutOfBudget,
32}
33
34const MAX_BOUND_VAR_NAME: &str = "MAX_ANNOTATED_VALUE_SIZE";
38
39const DEFAULT_MAX_BOUND: usize = 1024 * 1024;
42
43static MAX_BOUND: Lazy<usize> = Lazy::new(|| {
59 let max_bound_opt = std::env::var(MAX_BOUND_VAR_NAME)
60 .ok()
61 .and_then(|s| s.parse().ok());
62 if let Some(max_bound) = max_bound_opt {
63 info!(
64 "Using custom value for '{}' max bound: {}",
65 MAX_BOUND_VAR_NAME, max_bound
66 );
67 max_bound
68 } else {
69 info!(
70 "Using default value for '{}' -- max bound: {}",
71 MAX_BOUND_VAR_NAME, DEFAULT_MAX_BOUND
72 );
73 DEFAULT_MAX_BOUND
74 }
75});
76
77impl BoundedVisitor {
78 fn new(bound: usize) -> Self {
79 Self { bound }
80 }
81
82 pub fn deserialize_value(
86 bytes: &[u8],
87 layout: &A::MoveTypeLayout,
88 ) -> anyhow::Result<A::MoveValue> {
89 let mut visitor = Self::default();
90 A::MoveValue::visit_deserialize(bytes, layout, &mut visitor)
91 }
92
93 pub fn deserialize_struct(
97 bytes: &[u8],
98 layout: &A::MoveStructLayout,
99 ) -> anyhow::Result<A::MoveStruct> {
100 let mut visitor = Self::default();
101 let A::MoveValue::Struct(struct_) =
102 A::MoveStruct::visit_deserialize(bytes, layout, &mut visitor)?
103 else {
104 bail!("Expected to deserialize a struct");
105 };
106 Ok(struct_)
107 }
108
109 fn debit(&mut self, size: usize) -> Result<(), Error> {
112 if self.bound < size {
113 Err(Error::OutOfBudget)
114 } else {
115 self.bound -= size;
116 Ok(())
117 }
118 }
119
120 fn debit_type_size(&mut self, tag: &TypeTag) -> Result<(), Error> {
125 use TypeTag as TT;
126 let mut frontier = vec![tag];
127 while let Some(tag) = frontier.pop() {
128 match tag {
129 TT::Bool
130 | TT::U8
131 | TT::U16
132 | TT::U32
133 | TT::U64
134 | TT::U128
135 | TT::U256
136 | TT::Address
137 | TT::Signer => self.debit(8)?,
138
139 TT::Vector(inner) => {
140 self.debit(8)?;
141 frontier.push(inner);
142 }
143
144 TT::Struct(tag) => {
145 self.debit(8 + AccountAddress::LENGTH + tag.module.len() + tag.name.len())?;
146 frontier.extend(tag.type_params.iter());
147 }
148 }
149 }
150
151 Ok(())
152 }
153}
154
155impl<'b, 'l> Visitor<'b, 'l> for BoundedVisitor {
156 type Value = A::MoveValue;
157 type Error = Error;
158
159 fn visit_u8(
160 &mut self,
161 _driver: &ValueDriver<'_, 'b, 'l>,
162 value: u8,
163 ) -> Result<Self::Value, Self::Error> {
164 Ok(A::MoveValue::U8(value))
165 }
166
167 fn visit_u16(
168 &mut self,
169 _driver: &ValueDriver<'_, 'b, 'l>,
170 value: u16,
171 ) -> Result<Self::Value, Self::Error> {
172 Ok(A::MoveValue::U16(value))
173 }
174
175 fn visit_u32(
176 &mut self,
177 _driver: &ValueDriver<'_, 'b, 'l>,
178 value: u32,
179 ) -> Result<Self::Value, Self::Error> {
180 Ok(A::MoveValue::U32(value))
181 }
182
183 fn visit_u64(
184 &mut self,
185 _driver: &ValueDriver<'_, 'b, 'l>,
186 value: u64,
187 ) -> Result<Self::Value, Self::Error> {
188 Ok(A::MoveValue::U64(value))
189 }
190
191 fn visit_u128(
192 &mut self,
193 _driver: &ValueDriver<'_, 'b, 'l>,
194 value: u128,
195 ) -> Result<Self::Value, Self::Error> {
196 Ok(A::MoveValue::U128(value))
197 }
198
199 fn visit_u256(
200 &mut self,
201 _driver: &ValueDriver<'_, 'b, 'l>,
202 value: U256,
203 ) -> Result<Self::Value, Self::Error> {
204 Ok(A::MoveValue::U256(value))
205 }
206
207 fn visit_bool(
208 &mut self,
209 _driver: &ValueDriver<'_, 'b, 'l>,
210 value: bool,
211 ) -> Result<Self::Value, Self::Error> {
212 Ok(A::MoveValue::Bool(value))
213 }
214
215 fn visit_address(
216 &mut self,
217 _driver: &ValueDriver<'_, 'b, 'l>,
218 value: AccountAddress,
219 ) -> Result<Self::Value, Self::Error> {
220 Ok(A::MoveValue::Address(value))
221 }
222
223 fn visit_signer(
224 &mut self,
225 _driver: &ValueDriver<'_, 'b, 'l>,
226 value: AccountAddress,
227 ) -> Result<Self::Value, Self::Error> {
228 Ok(A::MoveValue::Signer(value))
229 }
230
231 fn visit_vector(
232 &mut self,
233 driver: &mut VecDriver<'_, 'b, 'l>,
234 ) -> Result<Self::Value, Self::Error> {
235 let mut elems = vec![];
236 while let Some(elem) = driver.next_element(self)? {
237 elems.push(elem);
238 }
239
240 Ok(A::MoveValue::Vector(elems))
241 }
242
243 fn visit_struct(
244 &mut self,
245 driver: &mut StructDriver<'_, 'b, 'l>,
246 ) -> Result<Self::Value, Self::Error> {
247 let tag = driver.struct_layout().type_.clone().into();
248
249 self.debit_type_size(&tag)?;
250 for field in driver.struct_layout().fields.iter() {
251 self.debit(field.name.len())?;
252 }
253
254 let mut fields = vec![];
255 while let Some((field, elem)) = driver.next_field(self)? {
256 fields.push((field.name.clone(), elem));
257 }
258
259 let TypeTag::Struct(type_) = tag else {
260 unreachable!("SAFETY: tag was derived from a StructTag.");
261 };
262
263 Ok(A::MoveValue::Struct(A::MoveStruct {
264 type_: *type_,
265 fields,
266 }))
267 }
268
269 fn visit_variant(
270 &mut self,
271 driver: &mut annotated_visitor::VariantDriver<'_, 'b, 'l>,
272 ) -> Result<Self::Value, Self::Error> {
273 let type_ = driver.enum_layout().type_.clone().into();
274
275 self.debit_type_size(&type_)?;
276 self.debit(driver.variant_name().len())?;
277
278 for field in driver.variant_layout() {
279 self.debit(field.name.len())?;
280 }
281
282 let mut fields = vec![];
283 while let Some((field, elem)) = driver.next_field(self)? {
284 fields.push((field.name.clone(), elem));
285 }
286
287 let TypeTag::Struct(type_) = type_ else {
288 unreachable!("SAFETY: type_ was derived from a StructTag.");
289 };
290
291 Ok(A::MoveValue::Variant(A::MoveVariant {
292 type_: *type_,
293 fields,
294 variant_name: driver.variant_name().to_owned(),
295 tag: driver.tag(),
296 }))
297 }
298}
299
300impl Default for BoundedVisitor {
301 fn default() -> Self {
302 Self::new(*MAX_BOUND)
303 }
304}
305
306#[cfg(test)]
307pub(crate) mod tests {
308 use std::str::FromStr;
309
310 use expect_test::expect;
311 use move_core_types::{identifier::Identifier, language_storage::StructTag};
312
313 use super::*;
314
315 #[test]
316 fn test_success() {
317 use A::{MoveTypeLayout as T, MoveValue as V};
318
319 let type_layout = layout_(
320 "0x0::foo::Bar",
321 vec![
322 ("a", T::U64),
323 ("b", T::Vector(Box::new(T::U64))),
324 ("c", layout_("0x0::foo::Baz", vec![("d", T::U64)])),
325 ],
326 );
327
328 let value = value_(
329 "0x0::foo::Bar",
330 vec![
331 ("a", V::U64(42)),
332 ("b", V::Vector(vec![V::U64(43)])),
333 ("c", value_("0x0::foo::Baz", vec![("d", V::U64(44))])),
334 ],
335 );
336
337 let bytes = serialize(value.clone());
338
339 let mut visitor = BoundedVisitor::new(1000);
340 let deser = A::MoveValue::visit_deserialize(&bytes, &type_layout, &mut visitor).unwrap();
341 assert_eq!(value, deser);
342 }
343
344 #[test]
345 fn test_env_variable_override() {
346 use A::{MoveTypeLayout as T, MoveValue as V};
347
348 let type_layout = layout_(
349 "0x0::foo::Bar",
350 vec![
351 ("a", T::U64),
352 ("b", T::Vector(Box::new(T::U64))),
353 ("c", layout_("0x0::foo::Baz", vec![("d", T::U64)])),
354 ],
355 );
356
357 let value = value_(
358 "0x0::foo::Bar",
359 vec![
360 ("a", V::U64(42)),
361 ("b", V::Vector(vec![V::U64(43)])),
362 ("c", value_("0x0::foo::Baz", vec![("d", V::U64(44))])),
363 ],
364 );
365
366 let bytes = serialize(value.clone());
367
368 let before_value = std::env::var(MAX_BOUND_VAR_NAME).ok();
369
370 std::env::set_var(MAX_BOUND_VAR_NAME, "10");
371 let mut visitor = BoundedVisitor::default();
372 let err = A::MoveValue::visit_deserialize(&bytes, &type_layout, &mut visitor).unwrap_err();
373 let expect = expect!["Deserialized value too large"];
374 expect.assert_eq(&err.to_string());
375
376 std::env::set_var(MAX_BOUND_VAR_NAME, "1000");
378 let mut visitor = BoundedVisitor::default();
379 let err = A::MoveValue::visit_deserialize(&bytes, &type_layout, &mut visitor).unwrap_err();
380 let expect = expect!["Deserialized value too large"];
381 expect.assert_eq(&err.to_string());
382
383 if let Some(previous_value) = before_value {
386 std::env::set_var(MAX_BOUND_VAR_NAME, previous_value);
387 } else {
388 std::env::remove_var(MAX_BOUND_VAR_NAME);
389 }
390
391 let mut visitor = BoundedVisitor::default();
393 let err = A::MoveValue::visit_deserialize(&bytes, &type_layout, &mut visitor).unwrap_err();
394 let expect = expect!["Deserialized value too large"];
395 expect.assert_eq(&err.to_string());
396 }
397
398 #[test]
399 fn test_too_deep() {
400 use A::{MoveTypeLayout as T, MoveValue as V};
401
402 let mut layout = T::U64;
403 let mut value = V::U64(42);
404
405 const DEPTH: usize = 10;
406 for _ in 0..DEPTH {
407 layout = layout_("0x0::foo::Bar", vec![("f", layout)]);
408 value = value_("0x0::foo::Bar", vec![("f", value)]);
409 }
410
411 let bound = DEPTH * (8 + 32 + "foo".len() + "Bar".len() + "f".len());
412 let bytes = serialize(value.clone());
413
414 let mut visitor = BoundedVisitor::new(bound);
415 let deser = A::MoveValue::visit_deserialize(&bytes, &layout, &mut visitor).unwrap();
416 assert_eq!(deser, value);
417
418 let mut visitor = BoundedVisitor::new(bound - 1);
419 let err = A::MoveValue::visit_deserialize(&bytes, &layout, &mut visitor).unwrap_err();
420
421 let expect = expect!["Deserialized value too large"];
422 expect.assert_eq(&err.to_string());
423 }
424
425 #[test]
426 fn test_too_wide() {
427 use A::{MoveTypeLayout as T, MoveValue as V};
428
429 const WIDTH: usize = 10;
430 let mut idents = vec![];
431 let mut fields = vec![];
432 let mut values = vec![];
433
434 for i in 0..WIDTH {
435 idents.push(format!("f{}", i));
436 }
437
438 for (i, id) in idents.iter().enumerate() {
439 let layout = layout_("0x0::foo::Baz", vec![("f", T::U64)]);
440 let value = value_("0x0::foo::Baz", vec![("f", V::U64(i as u64))]);
441
442 fields.push((id.as_str(), layout));
443 values.push((id.as_str(), value));
444 }
445
446 let layout = layout_("0x0::foo::Bar", fields);
447 let value = value_("0x0::foo::Bar", values);
448
449 let outer = 8 + 32 + "foo".len() + "Bar".len();
450 let inner = WIDTH * ("fx".len() + 8 + 32 + "foo".len() + "Baz".len() + "f".len());
451 let bound = outer + inner;
452
453 let bytes = serialize(value.clone());
454
455 let mut visitor = BoundedVisitor::new(bound);
456 let deser = A::MoveValue::visit_deserialize(&bytes, &layout, &mut visitor).unwrap();
457 assert_eq!(deser, value);
458
459 let mut visitor = BoundedVisitor::new(bound - 1);
460 let err = A::MoveValue::visit_deserialize(&bytes, &layout, &mut visitor).unwrap_err();
461
462 let expect = expect!["Deserialized value too large"];
463 expect.assert_eq(&err.to_string());
464 }
465
466 #[test]
467 fn test_big_types() {
468 use A::{MoveTypeLayout as T, MoveValue as V};
469
470 let big_mod_ = "m".repeat(128);
471 let big_name = "T".repeat(128);
472 let big_type = format!("0x0::{big_mod_}::{big_name}");
473
474 let layout = layout_(big_type.as_str(), vec![("f", T::U64)]);
475 let value = value_(big_type.as_str(), vec![("f", V::U64(42))]);
476
477 let bound = 8 + 32 + big_mod_.len() + big_name.len() + "f".len();
478 let bytes = serialize(value.clone());
479
480 let mut visitor = BoundedVisitor::new(bound);
481 let deser = A::MoveValue::visit_deserialize(&bytes, &layout, &mut visitor).unwrap();
482 assert_eq!(deser, value);
483
484 let mut visitor = BoundedVisitor::new(bound - 1);
485 let err = A::MoveValue::visit_deserialize(&bytes, &layout, &mut visitor).unwrap_err();
486
487 let expect = expect!["Deserialized value too large"];
488 expect.assert_eq(&err.to_string());
489 }
490
491 type Variant<'s> = (&'s str, u16);
492 type FieldLayout<'s> = (&'s str, A::MoveTypeLayout);
493
494 fn ident_(name: &str) -> Identifier {
495 Identifier::new(name).unwrap()
496 }
497
498 pub(crate) fn value_(rep: &str, fields: Vec<(&str, A::MoveValue)>) -> A::MoveValue {
500 let type_ = StructTag::from_str(rep).unwrap();
501 let fields = fields
502 .into_iter()
503 .map(|(name, value)| (ident_(name), value))
504 .collect();
505
506 A::MoveValue::Struct(A::MoveStruct::new(type_, fields))
507 }
508
509 pub(crate) fn layout_(rep: &str, fields: Vec<FieldLayout<'_>>) -> A::MoveTypeLayout {
511 let type_ = StructTag::from_str(rep).unwrap();
512 let fields = fields
513 .into_iter()
514 .map(|(name, layout)| A::MoveFieldLayout::new(ident_(name), layout))
515 .collect();
516
517 A::MoveTypeLayout::Struct(Box::new(A::MoveStructLayout { type_, fields }))
518 }
519
520 pub(crate) fn variant_(
522 rep: &str,
523 name: &str,
524 tag: u16,
525 fields: Vec<(&str, A::MoveValue)>,
526 ) -> A::MoveValue {
527 let type_ = StructTag::from_str(rep).unwrap();
528 let fields = fields
529 .into_iter()
530 .map(|(name, value)| (ident_(name), value))
531 .collect();
532
533 A::MoveValue::Variant(A::MoveVariant {
534 type_,
535 variant_name: ident_(name),
536 tag,
537 fields,
538 })
539 }
540
541 pub(crate) fn enum_(
543 rep: &str,
544 variants: Vec<(Variant<'_>, Vec<FieldLayout<'_>>)>,
545 ) -> A::MoveTypeLayout {
546 let type_ = StructTag::from_str(rep).unwrap();
547 let variants = variants
548 .into_iter()
549 .map(|((name, tag), fields)| {
550 let fields = fields
551 .into_iter()
552 .map(|(name, layout)| A::MoveFieldLayout::new(ident_(name), layout))
553 .collect();
554 ((ident_(name), tag), fields)
555 })
556 .collect();
557
558 A::MoveTypeLayout::Enum(Box::new(A::MoveEnumLayout { type_, variants }))
559 }
560
561 fn serialize(value: A::MoveValue) -> Vec<u8> {
563 value.clone().undecorate().simple_serialize().unwrap()
564 }
565}