Skip to main content

sui_verifier_latest/
tx_context_restrictions_verifier.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Enforces a signature-level rule on system packages at publish time:
5//!
6//! > If a function has an `&mut TxContext` parameter and any `&mut _` in its
7//! > return list, its parameter list must also contain at least one `&mut U`
8//! > for some `U != TxContext`.
9//!
10//! Gated on `VerifierConfig::framework_tx_context_mut_restrictions`, populated from
11//! `ProtocolConfig::framework_tx_context_mut_restrictions()`. Activates at protocol
12//! version 131.
13//!
14//! The rule applies only to system packages: it is a checksum on our own
15//! implementations, ensuring no framework function can hand back a mutable
16//! reference rooted in the auto-injected `TxContext`. It cannot be enforced
17//! generally because user packages can always express the same shape through
18//! generic instantiation; for user code, PTB argument arity and auto-injection
19//! checks are the actual safety mechanism. User-published modules are exempt
20//! (their addresses are freshly generated, never system addresses).
21//!
22//! Within a system package, functions that do not take `&mut TxContext` are
23//! out of scope: they cannot use `TxContext` as a mutable root because they
24//! never hold one. The rule covers natives too (framework natives are
25//! declared as `native fun` in Move source and appear here as function defs
26//! with `None` code). No safelist: any function violating the rule must be
27//! reworked, not grandfathered.
28
29use move_binary_format::{
30    CompiledModule,
31    file_format::{FunctionDefinition, SignatureToken},
32};
33use move_vm_config::verifier::VerifierConfig;
34use sui_types::{
35    base_types::{TxContext, TxContextKind},
36    error::ExecutionError,
37    is_system_package,
38};
39
40use crate::verification_failure;
41
42pub fn verify_module(
43    module: &CompiledModule,
44    verifier_config: &VerifierConfig,
45) -> Result<(), ExecutionError> {
46    if !verifier_config.framework_tx_context_mut_restrictions {
47        return Ok(());
48    }
49    if !is_system_package(*module.self_id().address()) {
50        return Ok(());
51    }
52    for func_def in &module.function_defs {
53        verify_function(module, func_def).map_err(|error| {
54            let name = module.identifier_at(module.function_handle_at(func_def.function).name);
55            verification_failure(format!("{}::{}. {}", module.self_id(), name, error))
56        })?;
57    }
58    Ok(())
59}
60
61fn verify_function(module: &CompiledModule, fdef: &FunctionDefinition) -> Result<(), &'static str> {
62    let fhandle = module.function_handle_at(fdef.function);
63    let returns = &module.signature_at(fhandle.return_).0;
64    let safe_returns = returns
65        .iter()
66        .all(|t| !matches!(t, SignatureToken::MutableReference(_)));
67    if safe_returns {
68        return Ok(());
69    }
70    let params = &module.signature_at(fhandle.parameters).0;
71    let (tx_context_muts, other_muts): (Vec<_>, Vec<_>) = params
72        .iter()
73        .filter(|t| matches!(t, SignatureToken::MutableReference(_)))
74        .partition(|t| TxContext::kind(module, t) == TxContextKind::Mutable);
75    if !tx_context_muts.is_empty() && other_muts.is_empty() {
76        return Err(
77            "Function takes `&mut TxContext` and returns a mutable reference, \
78             but has no non-`TxContext` `&mut U` parameter. `TxContext` cannot \
79             serve as the mutable root for a returned reference; add a mutable \
80             reference parameter of another type or return by value.",
81        );
82    }
83    Ok(())
84}