fix(interface): validate Borsh string lengths in unpack() to prevent SBF heap abort#87
Open
bit2swaz wants to merge 1 commit into
Open
fix(interface): validate Borsh string lengths in unpack() to prevent SBF heap abort#87bit2swaz wants to merge 1 commit into
bit2swaz wants to merge 1 commit into
Conversation
…SBF heap abort Forged u32 length prefixes in Initialize/UpdateField/RemoveKey payloads could trigger an oversized allocation in try_from_slice that aborts on the 32 KiB SBF heap. Validate each string length against the remaining buffer before deserializing, returning InvalidInstructionData for malformed payloads. Closes solana-program/token-2022#1152 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
TokenMetadataInstruction::unpack()callstry_from_slice(rest)?directly on attacker-controlled instruction data. A BorshStringis a little-endianu32length prefix followed by that many bytes, so a forged prefix likeu32::MAXmakes Borsh try to allocate ~1 MiB before the?error path runs and discovers the buffer is too short. On the 32 KiB SBF heap that allocation aborts the program instead of returning a clean error.Only the variants that carry Borsh strings are affected:
Initialize(name, symbol, uri),UpdateField(thevaluestring, plus the nested string inField::Key, tag 3), andRemoveKey(thekeystring after theidempotentbool).UpdateAuthorityandEmithave no strings and are left alone.Fix
A new
check_borsh_stringhelper reads each string's declared length and checks it against the remaining buffer beforetry_from_sliceruns, returningInvalidInstructionDatawhen it doesn't fit. The three affected match arms walk a cursor through their fields and validate each string first. The length arithmetic is checked so it can't overflow.Tests
Three tests feed a forged
u32::MAXlength prefix throughunpack()forInitialize,UpdateField, andRemoveKeyand assertInvalidInstructionData. They run natively, no SBF build needed. They also work as real regression guards: before the fix Borsh returns a different (IO) error, so the assertion would fail.Context
This puts the validation in
spl-token-metadata-interface, where the data is deserialized, rather than in the token-2022 caller. It follows the discussion on solana-program/token-2022#1194 (now closed), where @joncinque suggested the fix should live here. References solana-program/token-2022#1152. The token-2022 side is then just a dependency bump once this releases.🤖 Generated with Claude Code