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