Skip to content

Commit

Permalink
[verifier] check type instantiations behind a reference or inside vec…
Browse files Browse the repository at this point in the history
…tor generics (move-language#758)

The verifier current doesn't check ability constraints on types that are behind a reference, or inside a vector (i.e., the `T` in `&T`, `&mut T`, or `vector<T>`). This sounds alarming, but is fortunately not possible to take advantage of because doing so always creates a bad struct instantiation that will be flagged b the ability checker.

Fix the bug in version 7--left it in version 6 and below because it is (to the best of our understanding) harmless and the fix is a breaking change in the verifier--it will reject some function declarations that were previously accepted.
  • Loading branch information
sblackshear authored Dec 19, 2022
1 parent 781c844 commit 78a9e2b
Show file tree
Hide file tree
Showing 12 changed files with 440 additions and 14 deletions.
44 changes: 30 additions & 14 deletions language/move-bytecode-verifier/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,24 +317,40 @@ impl<'a> SignatureChecker<'a> {

fn check_type_instantiation(
&self,
ty: &SignatureToken,
s: &SignatureToken,
type_parameters: &[AbilitySet],
) -> PartialVMResult<()> {
match ty {
SignatureToken::StructInstantiation(idx, type_arguments) => {
// Check that the instantiation satisfies the `idx` struct's constraints
// Cannot be checked completely if we do not know the constraints of type parameters
// i.e. it cannot be checked unless we are inside some module member. The only case
// where that happens is when checking the signature pool itself
let sh = self.resolver.struct_handle_at(*idx);
self.check_generic_instance(
type_arguments,
sh.type_param_constraints(),
type_parameters,
)
for ty in s.preorder_traversal() {
match ty {
SignatureToken::StructInstantiation(idx, type_arguments) => {
// Check that the instantiation satisfies the `idx` struct's constraints
// Cannot be checked completely if we do not know the constraints of type parameters
// i.e. it cannot be checked unless we are inside some module member. The only case
// where that happens is when checking the signature pool itself
let sh = self.resolver.struct_handle_at(*idx);
self.check_generic_instance(
type_arguments,
sh.type_param_constraints(),
type_parameters,
)?
}
SignatureToken::Reference(_)
| SignatureToken::MutableReference(_)
| SignatureToken::Vector(_)
| SignatureToken::TypeParameter(_)
| SignatureToken::Struct(_)
| SignatureToken::Bool
| SignatureToken::U8
| SignatureToken::U16
| SignatureToken::U32
| SignatureToken::U64
| SignatureToken::U128
| SignatureToken::U256
| SignatureToken::Address
| SignatureToken::Signer => (),
}
_ => Ok(()),
}
Ok(())
}

// Checks if the given types are well defined and satisfy the constraints in the given context.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
processed 4 tasks

task 0 'publish'. lines 1-4:
Error: Unable to publish module '00000000000000000000000000000042::M1'. Got VMError: {
major_status: INVALID_SIGNATURE_TOKEN,
sub_status: None,
location: 0x42::M1,
indices: [(FieldDefinition, 0), (StructDefinition, 0)],
offsets: [],
}

task 1 'publish'. lines 6-9:
Error: Unable to publish module '00000000000000000000000000000042::M2'. Got VMError: {
major_status: INVALID_SIGNATURE_TOKEN,
sub_status: None,
location: 0x42::M2,
indices: [(FieldDefinition, 0), (StructDefinition, 0)],
offsets: [],
}

task 2 'publish'. lines 11-14:
Error: Unable to publish module '00000000000000000000000000000042::M3'. Got VMError: {
major_status: INVALID_SIGNATURE_TOKEN,
sub_status: None,
location: 0x42::M3,
indices: [(FieldDefinition, 0), (StructDefinition, 0)],
offsets: [],
}

task 3 'publish'. lines 16-19:
Error: Unable to publish module '00000000000000000000000000000042::M4'. Got VMError: {
major_status: INVALID_SIGNATURE_TOKEN,
sub_status: None,
location: 0x42::M4,
indices: [(FieldDefinition, 0), (StructDefinition, 0)],
offsets: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//# publish
module 0x42.M1 {
struct S { x: &u64 }
}

//# publish
module 0x42.M2 {
struct S { x: &mut u64 }
}

//# publish
module 0x42.M3 {
struct S<T> { t: &T }
}

//# publish
module 0x42.M4 {
struct S<T> { t: &mut T }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
processed 4 tasks

task 0 'publish'. lines 1-10:
Error: Unable to publish module '00000000000000000000000000000042::M1'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M1,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}

task 1 'publish'. lines 12-21:
Error: Unable to publish module '00000000000000000000000000000042::M2'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M2,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}

task 2 'publish'. lines 23-32:
Error: Unable to publish module '00000000000000000000000000000042::M3'. Got VMError: {
major_status: NUMBER_OF_TYPE_ARGUMENTS_MISMATCH,
sub_status: None,
location: undefined,
indices: [],
offsets: [],
}

task 3 'publish'. lines 34-44:
Error: Unable to publish module '00000000000000000000000000000042::M4'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M4,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//# publish
module 0x42.M1 {
struct S<T: copy> { t: T }

// should get flagged w/ constraint not satisfied--T does not have copy
public bad_sig<T>(s: &Self.S<T>) {
label b0:
return;
}
}

//# publish
module 0x42.M2 {
struct S<T: copy> { t: T }

// should get flagged w/ constraint not satisfied--T does not have copy
public bad_sig<T>(s: &mut Self.S<T>) {
label b0:
return;
}
}

//# publish
module 0x42.M3 {
struct S<T: copy> { t: T }

// should get flagged--missing type argument
public bad_sig<T>(s: &Self.S) {
label b0:
return;
}
}

//# publish
module 0x42.M4 {
struct Box<T> { t: T }
struct S<T: copy> { t: T }

// should be rejected
public bad_sig<T>(v: Self.Box<Self.S<T>>): Self.Box<Self.S<T>> {
label b0:
return move(v);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
processed 5 tasks

task 0 'publish'. lines 1-11:
Error: Unable to publish module '00000000000000000000000000000042::M1'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M1,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}

task 1 'publish'. lines 13-23:
Error: Unable to publish module '00000000000000000000000000000042::M2'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M2,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}

task 2 'publish'. lines 25-36:
Error: Unable to publish module '00000000000000000000000000000042::M3'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M3,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}

task 3 'publish'. lines 38-54:
Error: Unable to publish module '00000000000000000000000000000042::M4'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M4,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}

task 4 'publish'. lines 56-72:
Error: Unable to publish module '00000000000000000000000000000042::M5'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M5,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//# publish
module 0x42.M1 {
struct S<T: copy> { t: T }

// note: T does not have copy
// if this worked, it would be very bad because `T` can be (e.g.) a Coin
public copy_inner<T>(s: &Self.S<T>): T { // should get flagged w/ constraint not satisfied
label b0:
return *&move(s).S<T>::t;
}
}

//# publish
module 0x42.M2 {
struct S<T: copy> has copy { t: T }

// note: T does not have copy
// if this worked, it would be very bad because `T` can be (e.g.) a Coin
public copy_direct<T>(s: &Self.S<T>): Self.S<T> { // should get flagged w/ constraint not satisfied
label b0:
return *move(s);
}
}

//# publish
module 0x42.M3 {
struct S<T: store> has store { t: T }

// note: T does not have store
// if this worked, it would be very bad because `T` can be (e.g.) a hot potato
public store_inner<T>(s: &mut Self.S<T>, t: T) { // should get flagged w/ constraint not satisfied
label b0:
*&mut move(s).S<T>::t = move(t);
return;
}
}

//# publish
module 0x42.M4 {
struct S<T: copy> { t: T }

public bad_sig<T>(s: &Self.S<T>) { // should get flagged w/ constraint not satisfied
label b0:
return;
}

public call(): Self.S<u64> {
let x: Self.S<u64>;
label b0:
x = S<u64> { t: 10 };
Self.bad_sig(&x);
return move(x);
}
}

//# publish
module 0x42.M5 {
struct S<T: copy> { t: T }

public bad_sig<T>(s: &Self.S<T>) { // should get flagged w/ constraint not satisfied
label b0:
return;
}

public call(s: signer): Self.S<signer> {
let x: Self.S<signer>;
label b0:
x = S<u64> { t: move(s) };
Self.bad_sig(&x);
return move(x);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
processed 3 tasks

task 0 'publish'. lines 1-10:
Error: Unable to publish module '00000000000000000000000000000042::M1'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M1,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}

task 1 'publish'. lines 12-21:
Error: Unable to publish module '00000000000000000000000000000042::M2'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M2,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}

task 2 'publish'. lines 23-32:
Error: Unable to publish module '00000000000000000000000000000042::M3'. Got VMError: {
major_status: CONSTRAINT_NOT_SATISFIED,
sub_status: None,
location: 0x42::M3,
indices: [(Signature, 0), (FunctionHandle, 0)],
offsets: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//# publish
module 0x42.M1 {
struct S<T: copy> { t: T }

// should get flagged w/ constraint not satisfied--T does not have copy
public bad_sig<T>(v: vector<Self.S<T>>): vector<Self.S<T>> {
label b0:
return move(v);
}
}

//# publish
module 0x42.M2 {
struct S<T: copy> { t: T }

// should get flagged w/ constraint not satisfied--T does not have copy
public bad_sig<T>(v: &vector<Self.S<T>>) {
label b0:
return;
}
}

//# publish
module 0x42.M3 {
struct S<T: copy> { t: T }

// should get flagged w/ constraint not satisfied--T does not have copy
public bad_sig<T>(v: &mut vector<Self.S<T>>) {
label b0:
return;
}
}
Loading

0 comments on commit 78a9e2b

Please sign in to comment.