8000 psbt: overflow checks when computing Taproot BIP32 derivation min size by ffranr · Pull Request #2374 · btcsuite/btcd · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

psbt: overflow checks when computing Taproot BIP32 derivation min size #2374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

ffranr
Copy link
Contributor
@ffranr ffranr commented May 18, 2025

Closes #2372

Thank you to @brunoerg for opening the issue.


Protect against overflows when parsing malformed Taproot BIP32 derivation fields. This ensures that deserialization fails safely if the declared number of leaf hashes would otherwise cause an integer overflow.

@ffranr
Copy link
Contributor Author
ffranr commented May 18, 2025

An alternative safeguard would be to explicitly cap numHashes at some chosen maximum. However, I couldn't find a BIP-defined upper bound for the number of leaf hashes.

Given that, I think it's more appropriate to rely on the natural limit imposed by uint64 overflow rather than introduce an arbitrary cap. This keeps the implementation simple and avoids enforcing assumptions not defined by the spec.

// 1 (leaf hash count) + (N × 32) + 4 (fingerprint) + 1 (empty path count)
//
// First, we calculate the total number of bytes for the leaf hashes.
totalHashesBytes, mulCarry := bits.Mul64(numHashes, 32)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: when will the mulCarry or the addCarry be non-zero? Why is this method preferred than, say, just calculating 32 * numHashes + 6?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since numHashes is uint64, numHashes * 32 fits in 64 bits unless numHashes > 2^64 / 32. mulCarry will be non-zero only in that overflow case. Using bits.Mul64 is safer and explicit about overflow handling.

Copy link
Collaborator
@guggero guggero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix. Though I think this can be simplified quite a bit.

@ffranr ffranr force-pushed the 2372-fix-bip32-derivation-overflow-bug branch 3 times, most recently from b4ef41a to 16450e3 Compare May 22, 2025 12:24
@coveralls
Copy link
coveralls commented May 22, 2025

Pull Request Test Coverage Report for Build 15211625047

Details

  • 32 of 38 (84.21%) changed or added relevant lines in 1 file are covered.
  • 3 unchanged lines in 3 files lost coverage.
  • Overall coverage increased (+0.03%) to 56.757%

Changes Missing Coverage Covered Lines Changed/Added Lines %
btcutil/psbt/taproot.go 32 38 84.21%
Files with Coverage Reduction New Missed Lines %
btcec/v2/schnorr/signature.go 1 81.68%
btcutil/gcs/gcs.go 1 80.95%
mempool/mempool.go 1 66.56%
Totals Coverage Status
Change from base Build 14871723979: 0.03%
Covered Lines: 31169
Relevant Lines: 54917

💛 - Coveralls

Protect against overflows when parsing malformed Taproot BIP32
derivation fields. This ensures that deserialization fails safely if the
declared number of leaf hashes would otherwise cause an integer
overflow.
@ffranr ffranr force-pushed the 2372-fix-bip32-derivation-overflow-bug branch from 16450e3 to 16c2b92 Compare May 22, 2025 12:34
@ffranr ffranr requested review from guggero and yyforyongyu May 22, 2025 12:43
Copy link
Collaborator
@guggero guggero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🎉

}

// Ensure that value is at least the minimum size.
if uint64(len(value)) < minByteSize {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I guess this check prevents us from OOMing if the encoded length is larger from the number of bytes we actually have available.

Copy link
Contributor Author
@ffranr ffranr May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your attention/review. I think you reviewed before I managed to push my latest change. I've added:

	// This function allocates additional memory while parsing the serialized
	// data. To prevent potential out-of-memory (OOM) issues, we must validate
	// the length of the value slice before proceeding.
	if len(value) > MaxPsbtValueLength {
		return nil, ErrInvalidPsbtFormat
	}

let me know if that works for you

Cap the `value` slice to `MaxPsbtValueLength` to prevent potential
out-of-memory conditions during parsing. This ensures that total
allocation remains bounded and consistent with other PSBT fields.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[bug]: panic on ReadTaprootBip32Derivation
4 participants
0