1use std::{collections::BTreeMap, error::Error, num::NonZeroU64};
17
18use iota_types::{
19 GENESIS_BRIDGE_ADDRESS, IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS,
20 authenticator_state::AUTHENTICATOR_STATE_MODULE_NAME,
21 clock::CLOCK_MODULE_NAME,
22 deny_list_v1::{DENY_LIST_CREATE_FUNC, DENY_LIST_MODULE},
23 error::{ExecutionError, VMMVerifierErrorSubStatusCode},
24 id::OBJECT_MODULE_NAME,
25 iota_system_state::IOTA_SYSTEM_MODULE_NAME,
26 randomness_state::RANDOMNESS_MODULE_NAME,
27};
28use move_abstract_interpreter::absint::{
29 AbstractDomain, AbstractInterpreter, FunctionContext, JoinResult, TransferFunctions,
30};
31use move_abstract_stack::AbstractStack;
32use move_binary_format::{
33 errors::PartialVMError,
34 file_format::{
35 Bytecode, CodeOffset, CompiledModule, FunctionDefinitionIndex, FunctionHandle, LocalIndex,
36 StructDefinition, StructFieldInformation,
37 },
38};
39use move_bytecode_verifier_meter::{Meter, Scope};
40use move_core_types::{
41 account_address::AccountAddress, ident_str, identifier::IdentStr, vm_status::StatusCode,
42};
43
44use crate::{
45 TEST_SCENARIO_MODULE_NAME, check_for_verifier_timeout, to_verification_timeout_error,
46 verification_failure,
47};
48pub(crate) const JOIN_BASE_COST: u128 = 10;
49pub(crate) const JOIN_PER_LOCAL_COST: u128 = 5;
50pub(crate) const STEP_BASE_COST: u128 = 15;
51
52#[derive(Clone, Copy, Debug, Eq, PartialEq)]
53enum AbstractValue {
54 Fresh,
55 Other,
56}
57
58type FunctionIdent<'a> = (&'a AccountAddress, &'a IdentStr, &'a IdentStr);
59const OBJECT_NEW: FunctionIdent = (
60 &IOTA_FRAMEWORK_ADDRESS,
61 OBJECT_MODULE_NAME,
62 ident_str!("new"),
63);
64const OBJECT_NEW_UID_FROM_HASH: FunctionIdent = (
65 &IOTA_FRAMEWORK_ADDRESS,
66 OBJECT_MODULE_NAME,
67 ident_str!("new_uid_from_hash"),
68);
69const TS_NEW_OBJECT: FunctionIdent = (
70 &IOTA_FRAMEWORK_ADDRESS,
71 ident_str!(TEST_SCENARIO_MODULE_NAME),
72 ident_str!("new_object"),
73);
74const IOTA_SYSTEM_CREATE: FunctionIdent = (
75 &IOTA_SYSTEM_ADDRESS,
76 IOTA_SYSTEM_MODULE_NAME,
77 ident_str!("create"),
78);
79const IOTA_CLOCK_CREATE: FunctionIdent = (
80 &IOTA_FRAMEWORK_ADDRESS,
81 CLOCK_MODULE_NAME,
82 ident_str!("create"),
83);
84const IOTA_AUTHENTICATOR_STATE_CREATE: FunctionIdent = (
85 &IOTA_FRAMEWORK_ADDRESS,
86 AUTHENTICATOR_STATE_MODULE_NAME,
87 ident_str!("create"),
88);
89const IOTA_RANDOMNESS_STATE_CREATE: FunctionIdent = (
90 &IOTA_FRAMEWORK_ADDRESS,
91 RANDOMNESS_MODULE_NAME,
92 ident_str!("create"),
93);
94const IOTA_DENY_LIST_CREATE: FunctionIdent = (
95 &IOTA_FRAMEWORK_ADDRESS,
96 DENY_LIST_MODULE,
97 DENY_LIST_CREATE_FUNC,
98);
99
100const IOTA_BRIDGE_CREATE: FunctionIdent = (
101 &GENESIS_BRIDGE_ADDRESS,
102 ident_str!("bridge"),
103 ident_str!("create"),
104);
105const FRESH_ID_FUNCTIONS: &[FunctionIdent] = &[OBJECT_NEW, OBJECT_NEW_UID_FROM_HASH, TS_NEW_OBJECT];
106const FUNCTIONS_TO_SKIP: &[FunctionIdent] = &[
107 IOTA_SYSTEM_CREATE,
108 IOTA_CLOCK_CREATE,
109 IOTA_AUTHENTICATOR_STATE_CREATE,
110 IOTA_RANDOMNESS_STATE_CREATE,
111 IOTA_DENY_LIST_CREATE,
112 IOTA_BRIDGE_CREATE,
113];
114
115impl AbstractValue {
116 pub fn join(&self, value: &AbstractValue) -> AbstractValue {
117 if self == value {
118 *value
119 } else {
120 AbstractValue::Other
121 }
122 }
123}
124
125pub fn verify_module(
126 module: &CompiledModule,
127 meter: &mut (impl Meter + ?Sized),
128) -> Result<(), ExecutionError> {
129 verify_id_leak(module, meter)
130}
131
132fn verify_id_leak(
133 module: &CompiledModule,
134 meter: &mut (impl Meter + ?Sized),
135) -> Result<(), ExecutionError> {
136 for (index, func_def) in module.function_defs.iter().enumerate() {
137 let code = match func_def.code.as_ref() {
138 Some(code) => code,
139 None => continue,
140 };
141 let handle = module.function_handle_at(func_def.function);
142 let func_view =
143 FunctionContext::new(module, FunctionDefinitionIndex(index as u16), code, handle);
144 let initial_state = AbstractState::new(&func_view);
145 let mut verifier = IDLeakAnalysis::new(module, &func_view);
146 let function_to_verify = verifier.cur_function();
147 if FUNCTIONS_TO_SKIP.contains(&function_to_verify) {
148 continue;
149 }
150 verifier
151 .analyze_function(initial_state, &func_view, meter)
152 .map_err(|err| {
153 if check_for_verifier_timeout(&err.major_status()) {
155 to_verification_timeout_error(err.to_string())
156 } else if let Some(message) = err.source().as_ref() {
157 let function_name =
158 module.identifier_at(module.function_handle_at(func_def.function).name);
159 let module_name = module.self_id();
160 verification_failure(format!(
161 "{message} Found in {module_name}::{function_name}"
162 ))
163 } else {
164 verification_failure(err.to_string())
165 }
166 })?;
167 }
168
169 Ok(())
170}
171
172#[derive(Clone, Debug, PartialEq, Eq)]
173pub(crate) struct AbstractState {
174 locals: BTreeMap<LocalIndex, AbstractValue>,
175}
176
177impl AbstractState {
178 pub fn new(function_context: &FunctionContext) -> Self {
180 let mut state = AbstractState {
181 locals: BTreeMap::new(),
182 };
183
184 for param_idx in 0..function_context.parameters().len() {
185 state
186 .locals
187 .insert(param_idx as LocalIndex, AbstractValue::Other);
188 }
189
190 state
191 }
192}
193
194impl AbstractDomain for AbstractState {
195 fn join(
197 &mut self,
198 state: &AbstractState,
199 meter: &mut (impl Meter + ?Sized),
200 ) -> Result<JoinResult, PartialVMError> {
201 meter.add(Scope::Function, JOIN_BASE_COST)?;
202 meter.add_items(Scope::Function, JOIN_PER_LOCAL_COST, state.locals.len())?;
203 let mut changed = false;
204 for (local, value) in &state.locals {
205 let old_value = *self.locals.get(local).unwrap_or(&AbstractValue::Other);
206 let new_value = value.join(&old_value);
207 changed |= new_value != old_value;
208 self.locals.insert(*local, new_value);
209 }
210 if changed {
211 Ok(JoinResult::Changed)
212 } else {
213 Ok(JoinResult::Unchanged)
214 }
215 }
216}
217
218struct IDLeakAnalysis<'a> {
219 binary_view: &'a CompiledModule,
220 function_context: &'a FunctionContext<'a>,
221 stack: AbstractStack<AbstractValue>,
222}
223
224impl<'a> IDLeakAnalysis<'a> {
225 fn new(binary_view: &'a CompiledModule, function_context: &'a FunctionContext<'a>) -> Self {
226 Self {
227 binary_view,
228 function_context,
229 stack: AbstractStack::new(),
230 }
231 }
232
233 fn stack_popn(&mut self, n: u64) -> Result<(), PartialVMError> {
234 let Some(n) = NonZeroU64::new(n) else {
235 return Ok(());
236 };
237 self.stack.pop_any_n(n).map_err(|e| {
238 PartialVMError::new(StatusCode::VERIFIER_INVARIANT_VIOLATION)
239 .with_message(format!("Unexpected stack error on pop_n: {e}"))
240 })
241 }
242
243 fn stack_push(&mut self, val: AbstractValue) -> Result<(), PartialVMError> {
244 self.stack.push(val).map_err(|e| {
245 PartialVMError::new(StatusCode::VERIFIER_INVARIANT_VIOLATION)
246 .with_message(format!("Unexpected stack error on push: {e}"))
247 })
248 }
249
250 fn stack_pushn(&mut self, n: u64, val: AbstractValue) -> Result<(), PartialVMError> {
251 self.stack.push_n(val, n).map_err(|e| {
252 PartialVMError::new(StatusCode::VERIFIER_INVARIANT_VIOLATION)
253 .with_message(format!("Unexpected stack error on push_n: {e}"))
254 })
255 }
256
257 fn resolve_function(&self, function_handle: &FunctionHandle) -> FunctionIdent<'a> {
258 let m = self.binary_view.module_handle_at(function_handle.module);
259 let address = self.binary_view.address_identifier_at(m.address);
260 let module = self.binary_view.identifier_at(m.name);
261 let function = self.binary_view.identifier_at(function_handle.name);
262 (address, module, function)
263 }
264
265 fn cur_function(&self) -> FunctionIdent<'a> {
266 let fdef = self
267 .binary_view
268 .function_def_at(self.function_context.index().unwrap());
269 let handle = self.binary_view.function_handle_at(fdef.function);
270 self.resolve_function(handle)
271 }
272}
273
274impl TransferFunctions for IDLeakAnalysis<'_> {
275 type Error = ExecutionError;
276 type State = AbstractState;
277
278 fn execute(
279 &mut self,
280 state: &mut Self::State,
281 bytecode: &Bytecode,
282 index: CodeOffset,
283 last_index: CodeOffset,
284 meter: &mut (impl Meter + ?Sized),
285 ) -> Result<(), PartialVMError> {
286 execute_inner(self, state, bytecode, index, meter)?;
287 if index == last_index && !self.stack.is_empty() {
291 let msg = "Invalid stack transitions. Non-zero stack size at the end of the block"
292 .to_string();
293 debug_assert!(false, "{msg}",);
294 return Err(
295 PartialVMError::new(StatusCode::VERIFIER_INVARIANT_VIOLATION).with_message(msg),
296 );
297 }
298 Ok(())
299 }
300}
301
302impl AbstractInterpreter for IDLeakAnalysis<'_> {}
303
304fn call(
305 verifier: &mut IDLeakAnalysis,
306 function_handle: &FunctionHandle,
307) -> Result<(), PartialVMError> {
308 let parameters = verifier
309 .binary_view
310 .signature_at(function_handle.parameters);
311 verifier.stack_popn(parameters.len() as u64)?;
312
313 let return_ = verifier.binary_view.signature_at(function_handle.return_);
314 let function = verifier.resolve_function(function_handle);
315 if FRESH_ID_FUNCTIONS.contains(&function) {
316 if return_.0.len() != 1 {
317 debug_assert!(false, "{function:?} should have a single return value");
318 return Err(PartialVMError::new(StatusCode::UNKNOWN_VERIFICATION_ERROR)
319 .with_message("Should have a single return value".to_string())
320 .with_sub_status(
321 VMMVerifierErrorSubStatusCode::MULTIPLE_RETURN_VALUES_NOT_ALLOWED as u64,
322 ));
323 }
324 verifier.stack_push(AbstractValue::Fresh)?;
325 } else {
326 verifier.stack_pushn(return_.0.len() as u64, AbstractValue::Other)?;
327 }
328 Ok(())
329}
330
331fn num_fields(struct_def: &StructDefinition) -> u64 {
332 match &struct_def.field_information {
333 StructFieldInformation::Native => 0,
334 StructFieldInformation::Declared(fields) => fields.len() as u64,
335 }
336}
337
338fn pack(
339 verifier: &mut IDLeakAnalysis,
340 struct_def: &StructDefinition,
341) -> Result<(), PartialVMError> {
342 let handle = verifier
346 .binary_view
347 .datatype_handle_at(struct_def.struct_handle);
348 let num_fields = num_fields(struct_def);
349 verifier.stack_popn(num_fields - 1)?;
350 let last_value = verifier.stack.pop().unwrap();
351 if handle.abilities.has_key() && last_value != AbstractValue::Fresh {
352 let (cur_package, cur_module, cur_function) = verifier.cur_function();
353 let msg = format!(
354 "Invalid object creation in {cur_package}::{cur_module}::{cur_function}. \
355 Object created without a newly created UID. \
356 The UID must come directly from iota::{}::{}. \
357 Or for tests, it can come from iota::{}::{}",
358 OBJECT_NEW.1, OBJECT_NEW.2, TS_NEW_OBJECT.1, TS_NEW_OBJECT.2,
359 );
360
361 return Err(PartialVMError::new(StatusCode::UNKNOWN_VERIFICATION_ERROR)
362 .with_message(msg)
363 .with_sub_status(VMMVerifierErrorSubStatusCode::INVALID_OBJECT_CREATION as u64));
364 }
365 verifier.stack_push(AbstractValue::Other)?;
366 Ok(())
367}
368
369fn unpack(
370 verifier: &mut IDLeakAnalysis,
371 struct_def: &StructDefinition,
372) -> Result<(), PartialVMError> {
373 verifier.stack.pop().unwrap();
374 verifier.stack_pushn(num_fields(struct_def), AbstractValue::Other)
375}
376
377fn execute_inner(
378 verifier: &mut IDLeakAnalysis,
379 state: &mut AbstractState,
380 bytecode: &Bytecode,
381 _: CodeOffset,
382 meter: &mut (impl Meter + ?Sized),
383) -> Result<(), PartialVMError> {
384 meter.add(Scope::Function, STEP_BASE_COST)?;
385 match bytecode {
387 Bytecode::Pop => {
388 verifier.stack.pop().unwrap();
389 }
390 Bytecode::CopyLoc(_local) => {
391 verifier.stack_push(AbstractValue::Other)?;
393 }
394 Bytecode::MoveLoc(local) => {
395 let value = state.locals.remove(local).unwrap();
396 verifier.stack_push(value)?;
397 }
398 Bytecode::StLoc(local) => {
399 let value = verifier.stack.pop().unwrap();
400 state.locals.insert(*local, value);
401 }
402
403 Bytecode::FreezeRef
405 | Bytecode::ReadRef
407 | Bytecode::CastU8
409 | Bytecode::CastU16
410 | Bytecode::CastU32
411 | Bytecode::CastU64
412 | Bytecode::CastU128
413 | Bytecode::CastU256
414 | Bytecode::Not
415 | Bytecode::VecLen(_)
416 | Bytecode::VecPopBack(_) => {
417 verifier.stack.pop().unwrap();
418 verifier.stack_push(AbstractValue::Other)?;
419 }
420
421 Bytecode::Branch(_)
423 | Bytecode::Nop => {}
424
425 Bytecode::Eq
427 | Bytecode::Neq
428 | Bytecode::Add
429 | Bytecode::Sub
430 | Bytecode::Mul
431 | Bytecode::Mod
432 | Bytecode::Div
433 | Bytecode::BitOr
434 | Bytecode::BitAnd
435 | Bytecode::Xor
436 | Bytecode::Shl
437 | Bytecode::Shr
438 | Bytecode::Or
439 | Bytecode::And
440 | Bytecode::Lt
441 | Bytecode::Gt
442 | Bytecode::Le
443 | Bytecode::Ge
444 | Bytecode::VecImmBorrow(_)
445 | Bytecode::VecMutBorrow(_) => {
446 verifier.stack.pop().unwrap();
447 verifier.stack.pop().unwrap();
448 verifier.stack_push(AbstractValue::Other)?;
449 }
450 Bytecode::WriteRef => {
451 verifier.stack.pop().unwrap();
452 verifier.stack.pop().unwrap();
453 }
454
455 Bytecode::MutBorrowLoc(_)
457 | Bytecode::ImmBorrowLoc(_) => verifier.stack_push(AbstractValue::Other)?,
458
459 | Bytecode::MutBorrowField(_)
460 | Bytecode::MutBorrowFieldGeneric(_)
461 | Bytecode::ImmBorrowField(_)
462 | Bytecode::ImmBorrowFieldGeneric(_) => {
463 verifier.stack.pop().unwrap();
464 verifier.stack_push(AbstractValue::Other)?;
465 }
466
467 Bytecode::MoveFromDeprecated(_)
470 | Bytecode::MoveFromGenericDeprecated(_)
471 | Bytecode::MoveToDeprecated(_)
472 | Bytecode::MoveToGenericDeprecated(_)
473 | Bytecode::ImmBorrowGlobalDeprecated(_)
474 | Bytecode::MutBorrowGlobalDeprecated(_)
475 | Bytecode::ImmBorrowGlobalGenericDeprecated(_)
476 | Bytecode::MutBorrowGlobalGenericDeprecated(_)
477 | Bytecode::ExistsDeprecated(_)
478 | Bytecode::ExistsGenericDeprecated(_) => {
479 panic!("Should have been checked by global_storage_access_verifier.");
480 }
481
482 Bytecode::Call(idx) => {
483 let function_handle = verifier.binary_view.function_handle_at(*idx);
484 call(verifier, function_handle)?;
485 }
486 Bytecode::CallGeneric(idx) => {
487 let func_inst = verifier.binary_view.function_instantiation_at(*idx);
488 let function_handle = verifier.binary_view.function_handle_at(func_inst.handle);
489 call(verifier, function_handle)?;
490 }
491
492 Bytecode::Ret => {
493 verifier.stack_popn(verifier.function_context.return_().len() as u64)?
494 }
495
496 Bytecode::BrTrue(_) | Bytecode::BrFalse(_) | Bytecode::Abort => {
497 verifier.stack.pop().unwrap();
498 }
499
500 Bytecode::LdTrue | Bytecode::LdFalse | Bytecode::LdU8(_) | Bytecode::LdU16(_)| Bytecode::LdU32(_) | Bytecode::LdU64(_) | Bytecode::LdU128(_)| Bytecode::LdU256(_) | Bytecode::LdConst(_) => {
502 verifier.stack_push(AbstractValue::Other)?;
503 }
504
505 Bytecode::Pack(idx) => {
506 let struct_def = verifier.binary_view.struct_def_at(*idx);
507 pack(verifier, struct_def)?;
508 }
509 Bytecode::PackGeneric(idx) => {
510 let struct_inst = verifier.binary_view.struct_instantiation_at(*idx);
511 let struct_def = verifier.binary_view.struct_def_at(struct_inst.def);
512 pack(verifier, struct_def)?;
513 }
514 Bytecode::Unpack(idx) => {
515 let struct_def = verifier.binary_view.struct_def_at(*idx);
516 unpack(verifier, struct_def)?;
517 }
518 Bytecode::UnpackGeneric(idx) => {
519 let struct_inst = verifier.binary_view.struct_instantiation_at(*idx);
520 let struct_def = verifier.binary_view.struct_def_at(struct_inst.def);
521 unpack(verifier, struct_def)?;
522 }
523
524 Bytecode::VecPack(_, num) => {
525 verifier.stack_popn(*num )?;
526 verifier.stack_push(AbstractValue::Other)?;
527 }
528
529 Bytecode::VecPushBack(_) => {
530 verifier.stack.pop().unwrap();
531 verifier.stack.pop().unwrap();
532 }
533
534 Bytecode::VecUnpack(_, num) => {
535 verifier.stack.pop().unwrap();
536 verifier.stack_pushn(*num, AbstractValue::Other)?;
537 }
538
539 Bytecode::VecSwap(_) => {
540 verifier.stack.pop().unwrap();
541 verifier.stack.pop().unwrap();
542 verifier.stack.pop().unwrap();
543 }
544 Bytecode::PackVariant(vidx) => {
545 let handle = verifier.binary_view.variant_handle_at(*vidx);
546 let variant = verifier.binary_view.variant_def_at(handle.enum_def, handle.variant);
547 let num_fields = variant.fields.len();
548 verifier.stack_popn(num_fields as u64)?;
549 verifier.stack_push(AbstractValue::Other)?;
550 }
551 Bytecode::PackVariantGeneric(vidx) => {
552 let handle = verifier.binary_view.variant_instantiation_handle_at(*vidx);
553 let enum_inst = verifier.binary_view.enum_instantiation_at(handle.enum_def);
554 let variant = verifier.binary_view.variant_def_at(enum_inst.def, handle.variant);
555 let num_fields = variant.fields.len();
556 verifier.stack_popn(num_fields as u64)?;
557 verifier.stack_push(AbstractValue::Other)?;
558 }
559 Bytecode::UnpackVariant(vidx)
560 | Bytecode::UnpackVariantImmRef(vidx)
561 | Bytecode::UnpackVariantMutRef(vidx) => {
562 let handle = verifier.binary_view.variant_handle_at(*vidx);
563 let variant = verifier.binary_view.variant_def_at(handle.enum_def, handle.variant);
564 let num_fields = variant.fields.len();
565 verifier.stack.pop().unwrap();
566 verifier.stack_pushn(num_fields as u64, AbstractValue::Other)?;
567 }
568 Bytecode::UnpackVariantGeneric(vidx)
569 | Bytecode::UnpackVariantGenericImmRef(vidx)
570 | Bytecode::UnpackVariantGenericMutRef(vidx) => {
571 let handle = verifier.binary_view.variant_instantiation_handle_at(*vidx);
572 let enum_inst = verifier.binary_view.enum_instantiation_at(handle.enum_def);
573 let variant = verifier.binary_view.variant_def_at(enum_inst.def, handle.variant);
574 let num_fields = variant.fields.len();
575 verifier.stack.pop().unwrap();
576 verifier.stack_pushn(num_fields as u64, AbstractValue::Other)?;
577 }
578 Bytecode::VariantSwitch(_) => {
579 verifier.stack.pop().unwrap();
580 }
581 };
582 Ok(())
583}