Skip to content

Commit 27bee57

Browse files
authored
move: leak verifier returns execution error (MystenLabs#7495)
1 parent a0978d6 commit 27bee57

9 files changed

+54
-48
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
processed 1 task
22

33
task 0 'publish'. lines 4-25:
4-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
5-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID leaked through function call."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
4+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
5+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID leaked through function call.") } }
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
processed 2 tasks
22

33
task 0 'publish'. lines 4-25:
4-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
5-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID is leaked into a struct."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
4+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
5+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID is leaked into a struct.") } }
66

77
task 1 'publish'. lines 27-48:
8-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
9-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID leaked through function call."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
8+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
9+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID leaked through function call.") } }
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
processed 1 task
22

33
task 0 'publish'. lines 4-34:
4-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
5-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID leaked through function call."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
4+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
5+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID leaked through function call.") } }
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
processed 1 task
22

33
task 0 'publish'. lines 4-19:
4-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
5-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID leaked through function return."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
4+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
5+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID leaked through function return.") } }
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
processed 1 task
22

33
task 0 'publish'. lines 4-19:
4-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
5-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID is leaked into a struct."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
4+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
5+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID is leaked into a struct.") } }
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
processed 2 tasks
22

33
task 0 'publish'. lines 4-36:
4-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
5-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID is leaked into a struct."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("test") }), indices: [], offsets: [] }) } }
4+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
5+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID is leaked into a struct.") } }
66

77
task 1 'publish'. lines 38-60:
8-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
9-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID is leaked into a struct."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
8+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
9+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID is leaked into a struct.") } }
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
processed 1 task
22

33
task 0 'publish'. lines 4-20:
4-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
5-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID is leaked into a vector"), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
4+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
5+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID is leaked into a vector.") } }
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
processed 1 task
22

33
task 0 'publish'. lines 4-28:
4-
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
5-
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: UNKNOWN_VERIFICATION_ERROR, sub_status: None, message: Some("Sui Move Bytecode Verification Error: ID is leaked into a struct."), exec_state: None, location: Module(ModuleId { address: _, name: Identifier("m") }), indices: [], offsets: [] }) } }
4+
Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information.
5+
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("ID is leaked into a struct.") } }

crates/sui-verifier/src/id_leak_verifier.rs

+34-28
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
//! 4. Passed to a function cal::;
1515
use move_binary_format::{
1616
binary_views::{BinaryIndexedView, FunctionView},
17-
errors::{Location, PartialVMError, PartialVMResult},
17+
errors::PartialVMError,
1818
file_format::{
1919
Bytecode, CodeOffset, CompiledModule, FunctionDefinitionIndex, FunctionHandle, LocalIndex,
2020
StructDefinition, StructFieldInformation,
@@ -23,9 +23,13 @@ use move_binary_format::{
2323
use move_bytecode_verifier::absint::{
2424
AbstractDomain, AbstractInterpreter, JoinResult, TransferFunctions,
2525
};
26-
use move_core_types::vm_status::StatusCode;
2726
use std::collections::BTreeMap;
28-
use sui_types::{error::ExecutionError, id::OBJECT_MODULE_NAME, SUI_FRAMEWORK_ADDRESS};
27+
use sui_types::{
28+
error::ExecutionError, id::OBJECT_MODULE_NAME, messages::ExecutionFailureStatus,
29+
SUI_FRAMEWORK_ADDRESS,
30+
};
31+
32+
use crate::verification_failure;
2933

3034
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3135
enum AbstractValue {
@@ -59,9 +63,7 @@ fn verify_id_leak(module: &CompiledModule) -> Result<(), ExecutionError> {
5963
FunctionView::function(module, FunctionDefinitionIndex(index as u16), code, handle);
6064
let initial_state = AbstractState::new(&func_view);
6165
let mut verifier = IDLeakAnalysis::new(&binary_view, &func_view);
62-
verifier
63-
.analyze_function(initial_state, &func_view)
64-
.map_err(|e| e.finish(Location::Module(module.self_id())))?;
66+
verifier.analyze_function(initial_state, &func_view)?;
6567
}
6668

6769
Ok(())
@@ -123,7 +125,7 @@ impl<'a> IDLeakAnalysis<'a> {
123125
}
124126

125127
impl<'a> TransferFunctions for IDLeakAnalysis<'a> {
126-
type Error = PartialVMError;
128+
type Error = ExecutionError;
127129
type State = AbstractState;
128130

129131
fn execute(
@@ -132,7 +134,7 @@ impl<'a> TransferFunctions for IDLeakAnalysis<'a> {
132134
bytecode: &Bytecode,
133135
index: CodeOffset,
134136
last_index: CodeOffset,
135-
) -> PartialVMResult<()> {
137+
) -> Result<(), ExecutionError> {
136138
execute_inner(self, state, bytecode, index)?;
137139
// invariant: the stack should be empty at the end of the block
138140
// If it is not, something is wrong with the implementation, so throw an invariant
@@ -142,8 +144,8 @@ impl<'a> TransferFunctions for IDLeakAnalysis<'a> {
142144
false,
143145
"Invalid stack transitions. Non-zero stack size at the end of the block",
144146
);
145-
return Err(PartialVMError::new(
146-
StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR,
147+
return Err(ExecutionError::from_kind(
148+
ExecutionFailureStatus::InvariantViolation,
147149
));
148150
}
149151
Ok(())
@@ -179,14 +181,19 @@ fn is_call_safe_to_leak(verifier: &IDLeakAnalysis, function_handle: &FunctionHan
179181
== "delete_child_object")
180182
}
181183

182-
fn call(verifier: &mut IDLeakAnalysis, function_handle: &FunctionHandle) -> PartialVMResult<()> {
184+
fn call(
185+
verifier: &mut IDLeakAnalysis,
186+
function_handle: &FunctionHandle,
187+
) -> Result<(), ExecutionError> {
183188
let guaranteed_safe = is_call_safe_to_leak(verifier, function_handle);
184189
let parameters = verifier
185190
.binary_view
186191
.signature_at(function_handle.parameters);
187192
for _ in 0..parameters.len() {
188193
if verifier.stack.pop().unwrap() == AbstractValue::ID && !guaranteed_safe {
189-
return Err(move_verification_error("ID leaked through function call."));
194+
return Err(verification_failure(
195+
"ID leaked through function call.".to_string(),
196+
));
190197
}
191198
}
192199

@@ -204,11 +211,16 @@ fn num_fields(struct_def: &StructDefinition) -> usize {
204211
}
205212
}
206213

207-
fn pack(verifier: &mut IDLeakAnalysis, struct_def: &StructDefinition) -> PartialVMResult<()> {
214+
fn pack(
215+
verifier: &mut IDLeakAnalysis,
216+
struct_def: &StructDefinition,
217+
) -> Result<(), ExecutionError> {
208218
for _ in 0..num_fields(struct_def) {
209219
let value = verifier.stack.pop().unwrap();
210220
if value == AbstractValue::ID {
211-
return Err(move_verification_error("ID is leaked into a struct."));
221+
return Err(verification_failure(
222+
"ID is leaked into a struct.".to_string(),
223+
));
212224
}
213225
}
214226
verifier.stack.push(AbstractValue::NonID);
@@ -239,7 +251,7 @@ fn execute_inner(
239251
state: &mut AbstractState,
240252
bytecode: &Bytecode,
241253
_: CodeOffset,
242-
) -> PartialVMResult<()> {
254+
) -> Result<(), ExecutionError> {
243255
// TODO: Better diagnostics with location
244256
match bytecode {
245257
Bytecode::Pop => {
@@ -309,7 +321,7 @@ fn execute_inner(
309321
// Top of stack is the reference, and the second element is the value.
310322
verifier.stack.pop().unwrap();
311323
if verifier.stack.pop().unwrap() == AbstractValue::ID {
312-
return Err(move_verification_error("ID is leaked to a reference."));
324+
return Err(verification_failure("ID is leaked to a reference.".to_string()));
313325
}
314326
}
315327

@@ -353,7 +365,7 @@ fn execute_inner(
353365
Bytecode::Ret => {
354366
for _ in 0..verifier.function_view.return_().len() {
355367
if verifier.stack.pop().unwrap() == AbstractValue::ID {
356-
return Err(move_verification_error("ID leaked through function return."));
368+
return Err(verification_failure("ID leaked through function return.".to_string()));
357369
}
358370
}
359371
}
@@ -389,15 +401,15 @@ fn execute_inner(
389401
Bytecode::VecPack(_, num) => {
390402
for _ in 0..*num {
391403
if verifier.stack.pop().unwrap() == AbstractValue::ID {
392-
return Err(move_verification_error("ID is leaked into a vector"));
404+
return Err(verification_failure("ID is leaked into a vector.".to_string()));
393405
}
394406
}
395407
verifier.stack.push(AbstractValue::NonID);
396408
}
397409

398410
Bytecode::VecPushBack(_) => {
399411
if verifier.stack.pop().unwrap() == AbstractValue::ID {
400-
return Err(move_verification_error("ID is leaked into a vector"));
412+
return Err(verification_failure("ID is leaked into a vector.".to_string()));
401413
}
402414
verifier.stack.pop().unwrap();
403415
}
@@ -419,7 +431,7 @@ fn execute_inner(
419431
Ok(())
420432
}
421433

422-
fn expect_ok<T>(res: Result<T, PartialVMError>) -> PartialVMResult<T> {
434+
fn expect_ok<T>(res: Result<T, PartialVMError>) -> Result<T, ExecutionError> {
423435
match res {
424436
Ok(x) => Ok(x),
425437
Err(partial_vm_error) => {
@@ -429,15 +441,9 @@ fn expect_ok<T>(res: Result<T, PartialVMError>) -> PartialVMResult<T> {
429441
Got error: {partial_vm_error:?}"
430442
);
431443
// This is an internal error, but we cannot accept the module as safe
432-
Err(PartialVMError::new(
433-
StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR,
444+
Err(ExecutionError::from_kind(
445+
ExecutionFailureStatus::InvariantViolation,
434446
))
435447
}
436448
}
437449
}
438-
439-
#[must_use]
440-
fn move_verification_error(msg: impl std::fmt::Display) -> PartialVMError {
441-
PartialVMError::new(StatusCode::UNKNOWN_VERIFICATION_ERROR)
442-
.with_message(format!("Sui Move Bytecode Verification Error: {}", msg))
443-
}

0 commit comments

Comments
 (0)