lang: Fix unexpected account substitution in InterfaceAccount
#4139
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
InterfaceAccountallows account substitution between unexpected types.PoC
Passing
AnotherAccountto an account typed asInterfaceAccount<ExpectedAccount>:Details
The PR titled "feat(account): Check Owner on Reload" #3837 changed
InterfaceAccount::try_fromfrom:anchor/lang/src/accounts/account.rs
Lines 303 to 313 in 2da4120
to:
anchor/lang/src/accounts/interface_account.rs
Lines 243 to 252 in 3a799e2
The author assumes
InterfaceAccountis only intended to work with programs that "do not have Anchor discriminators". However, similar toAccount, theInterfaceAccountimplementation does not actually make any assumptions about discriminators. As its name suggests, it's for accounts that share the same interface between different programs; or in other words, it's the same as theAccounttype, but instead of checking only a single owner via theOwnertrait, it allows multiple owners via theOwnerstrait.Similar to the
Accounttype,InterfaceAccount's documentation even has a section called UsingInterfaceAccountwith non-anchor programs that starts with:anchor/lang/src/accounts/interface_account.rs
Line 85 in 3a799e2
which in itself should be enough to suggest that
InterfaceAccountcan also be used with Anchor program accounts, or generally, accounts that have discriminators.The same erroneous understanding also resulted in changing the
reloadmethod ofAccountInterfacefrom:anchor/lang/src/accounts/interface_account.rs
Line 188 in 2da4120
which used
Account::reloadwith checked account deserialization (AccountDeserialize::try_deserialize):anchor/lang/src/accounts/account.rs
Line 271 in 2da4120
to an implementation that uses unchecked account deserialization (
AccountDeserialize::try_deserialize_unchecked):anchor/lang/src/accounts/interface_account.rs
Line 206 in 3a799e2
The misconception might have arisen from the fact that
InterfaceAccountwas initially added (in #2386) in order to make handling SPL Token and SPL Token 2022 accounts easier. However, its implementation is fully generic, just like theAccounttype. In fact, in its implementation PR, the first commit is titled 'Add "interface" and "interface account" concept', and it does not even touchanchor-spl.The reason why
anchor-spltypes such astoken::Mintandtoken_interface::Mintonly implementtry_deserialize_uncheckedis becausetry_deserializedefaults totry_deserialize_unchecked(in this case they are all checked in reality):anchor/lang/src/lib.rs
Lines 361 to 370 in 3a799e2
This means changing
try_deserializetotry_deserialize_uncheckedhere in the best case has no benefits (same impl), and in the worst case allows bypassing account checks.Summary of changes (WIP)
InterfaceAccount, including unexpected account substitutionInterfaceAccount::try_from(revert to how it was before)