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