-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
117 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# duplicate_mutable_accounts | ||
|
||
**What it does:** Checks to make sure there is a key check on identical Anchor accounts. | ||
The key check serves to make sure that two identical accounts do not have the same key, | ||
ie, they are unique. An Anchor account (`Account<'info, T>`) is identical to another if | ||
the generic parameter `T` is the same type for each account. | ||
|
||
**Why is this bad?** If a program contains two identical, mutable Anchor accounts, and | ||
performs some operation on those accounts, then a user could pass in the same account | ||
twice. Then any previous operations may be overwritten by the last operation, which may | ||
not be what the program wanted if it expected different accounts. | ||
|
||
**Known problems:** If a program is not using the anchor `#[account]` macro constraints, | ||
and is instead using checks in the function bodies, and the program uses boolean operator | ||
&& or || to link constraints in a single if statement, the lint will flag this as a false | ||
positive since the lint only catches statements with `==` or `!=`. | ||
|
||
Another issue is if a program uses an if statement such as `a.key() == b.key()` and then | ||
continues to modify the accounts, then this will not be caught. The reason is because the | ||
lint regards expressions with `==` as a secure check, since it assumes the program will | ||
then return an error (see the secure example). However, it does not explicitly check that | ||
an error is returned. | ||
|
||
In general, this lint will catch all vulnerabilities if the anchor macro constraints are | ||
used (see the recommended example). It is not as robust if alternative methods are utilized. | ||
Thus it is encouraged to use the anchor `#[account]` macro constraints. | ||
|
||
**Example:** | ||
|
||
```rust | ||
#[derive(Accounts)] | ||
pub struct Update<'info> { | ||
user_a: Account<'info, User>, | ||
user_b: Account<'info, User>, | ||
} | ||
``` | ||
|
||
Use instead: | ||
|
||
```rust | ||
#[derive(Accounts)] | ||
pub struct Update<'info> { | ||
#[account(constraint = user_a.key() != user_b.key())] | ||
user_a: Account<'info, User>, | ||
user_b: Account<'info, User>, | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 24 additions & 24 deletions
48
lints/duplicate-mutable-accounts/ui/insecure-2/src/lib.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,39 @@ | ||
error: user_a and user_b have identical account types but do not have a key check constraint | ||
--> $DIR/lib.rs:25:5 | ||
error: the expressions on line $DIR/lib.rs:15:27: 15:46 (#0) and $DIR/lib.rs:16:27: 16:46 (#0) have identical Account types, yet do not contain a proper key check. | ||
--> $DIR/lib.rs:15:27 | ||
| | ||
LL | user_a: Account<'info, User>, | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
LL | let user_a = &mut ctx.accounts.user_a; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= note: `-D duplicate-mutable-accounts` implied by `-D warnings` | ||
help: add an anchor key check constraint: #[account(constraint = user_a.key() != user_b.key())] | ||
--> $DIR/lib.rs:26:5 | ||
help: add a key check to make sure the accounts have different keys, e.g., x.key() != y.key() | ||
--> $DIR/lib.rs:16:27 | ||
| | ||
LL | user_b: Account<'info, User>, | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
LL | let user_b = &mut ctx.accounts.user_b; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: user_a and user_c have identical account types but do not have a key check constraint | ||
--> $DIR/lib.rs:25:5 | ||
error: the expressions on line $DIR/lib.rs:15:27: 15:46 (#0) and $DIR/lib.rs:17:27: 17:46 (#0) have identical Account types, yet do not contain a proper key check. | ||
--> $DIR/lib.rs:15:27 | ||
| | ||
LL | user_a: Account<'info, User>, | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
LL | let user_a = &mut ctx.accounts.user_a; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
help: add an anchor key check constraint: #[account(constraint = user_a.key() != user_c.key())] | ||
--> $DIR/lib.rs:27:5 | ||
help: add a key check to make sure the accounts have different keys, e.g., x.key() != y.key() | ||
--> $DIR/lib.rs:17:27 | ||
| | ||
LL | user_c: Account<'info, User>, | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
LL | let user_c = &mut ctx.accounts.user_c; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: user_b and user_c have identical account types but do not have a key check constraint | ||
--> $DIR/lib.rs:26:5 | ||
error: the expressions on line $DIR/lib.rs:16:27: 16:46 (#0) and $DIR/lib.rs:17:27: 17:46 (#0) have identical Account types, yet do not contain a proper key check. | ||
--> $DIR/lib.rs:16:27 | ||
| | ||
LL | user_b: Account<'info, User>, | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
LL | let user_b = &mut ctx.accounts.user_b; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
help: add an anchor key check constraint: #[account(constraint = user_b.key() != user_c.key())] | ||
--> $DIR/lib.rs:27:5 | ||
help: add a key check to make sure the accounts have different keys, e.g., x.key() != y.key() | ||
--> $DIR/lib.rs:17:27 | ||
| | ||
LL | user_c: Account<'info, User>, | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
LL | let user_c = &mut ctx.accounts.user_c; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: aborting due to 3 previous errors | ||
|
16 changes: 8 additions & 8 deletions
16
lints/duplicate-mutable-accounts/ui/insecure/src/lib.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,15 @@ | ||
error: user_a and user_b have identical account types but do not have a key check constraint | ||
--> $DIR/lib.rs:25:5 | ||
error: the expressions on line $DIR/lib.rs:14:27: 14:46 (#0) and $DIR/lib.rs:15:27: 15:46 (#0) have identical Account types, yet do not contain a proper key check. | ||
--> $DIR/lib.rs:14:27 | ||
| | ||
LL | user_a: Account<'info, User>, | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
LL | let user_a = &mut ctx.accounts.user_a; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= note: `-D duplicate-mutable-accounts` implied by `-D warnings` | ||
help: add an anchor key check constraint: #[account(constraint = user_a.key() != user_b.key())] | ||
--> $DIR/lib.rs:26:5 | ||
help: add a key check to make sure the accounts have different keys, e.g., x.key() != y.key() | ||
--> $DIR/lib.rs:15:27 | ||
| | ||
LL | user_b: Account<'info, User>, | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
LL | let user_b = &mut ctx.accounts.user_b; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: aborting due to previous error | ||
|