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