Skip to content

Comments

fix!: fix payment id type confusion#6901

Closed
hansieodendaal wants to merge 2 commits intotari-project:developmentfrom
hansieodendaal:ho_fix_payment_id
Closed

fix!: fix payment id type confusion#6901
hansieodendaal wants to merge 2 commits intotari-project:developmentfrom
hansieodendaal:ho_fix_payment_id

Conversation

@hansieodendaal
Copy link
Contributor

@hansieodendaal hansieodendaal commented Mar 31, 2025

Description

Fixed payment ID type confusion - adversaries can craft arbitrary PaymentId due to type confusion in deserialisation.

Fixes #6891

Motivation and Context

See #6891

How Has This Been Tested?

New unit test added
Expanded current unit tests

What process can a PR reviewer use to test or verify this change?

Breaking Changes

  • None
  • Requires data directory on base node to be deleted
  • Requires hard fork
  • Other - Please specify

BREAKING CHANGE: The new PaymentId serialization specification introduces a type byte as the first byte. Any payment id's that were been generated with prior versions will be deserialized as either open or empty.

Summary by CodeRabbit

  • New Features
    • Introduced a tagging mechanism for payment references to enhance transaction processing.
  • Refactor
    • Improved the serialization and parsing of payment data for greater accuracy.
  • Tests
    • Added test cases to verify the integrity of payment data handling during transactions.

Fixed payment id type confusion - adversaries can craft arbitrary PaymentId
due to type confusion in deserialisation.
@hansieodendaal hansieodendaal requested a review from a team as a code owner March 31, 2025 13:12
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 31, 2025

Walkthrough

The changes add an explicit type tag in the serialization and deserialization of PaymentId. A new enumeration PTag is introduced with a from_u8 method to convert a byte to a corresponding variant. Meanwhile, the PaymentId enum now includes a to_tag method. The methods get_size, to_bytes, and from_bytes are updated to incorporate a tag byte, and additional tests verify the parsing behavior.

Changes

File(s) Change Summary
base_layer/.../encrypted_data.rs Added new enum PTag with from_u8; implemented to_tag method for PaymentId; updated get_size, to_bytes, and from_bytes to use tag bytes; added tests.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant PaymentId
    participant PTag
    Client->>PaymentId: Serialize PaymentId
    PaymentId->>PTag: Call to_tag() to get type tag bytes
    PaymentId->>Client: Return tag prepended to serialized data
Loading
sequenceDiagram
    participant Client
    participant PaymentId
    participant PTag
    Client->>PaymentId: Deserialize PaymentId from bytes
    PaymentId->>PTag: Use from_u8() to parse type tag from first byte
    PaymentId->>Client: Process remaining bytes based on tag and return PaymentId
Loading

Assessment against linked issues

Objective Addressed Explanation
Prevent type confusion during PaymentId deserialization (#6891)

Poem

I'm a rabbit hopping with delight,
New tags in code making things bright,
PaymentId dons its tag with care,
Parsing bytes in a fresh new air,
Leaping through code with joy in sight! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b53e4f and 0b8c0cc.

📒 Files selected for processing (1)
  • base_layer/core/src/transactions/transaction_components/encrypted_data.rs (19 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: test (mainnet, stagenet)
  • GitHub Check: cargo check with stable
  • GitHub Check: test (nextnet, nextnet)
  • GitHub Check: test (testnet, esmeralda)
  • GitHub Check: ci
🔇 Additional comments (7)
base_layer/core/src/transactions/transaction_components/encrypted_data.rs (7)

192-199: Good addition of an explicit type tag enum.

Adding this explicit enumeration for payment ID types improves code clarity and introduces stronger type safety for serialization/deserialization. The numerical values (0-5) provide a simple and efficient encoding scheme.


201-212: Well-implemented type conversion.

The from_u8 implementation correctly maps numeric values to their corresponding enum variants, with a safe default to PTag::Empty for unrecognized values. This robustness helps handle potential issues with malformed input data.


218-227: Good implementation of tag serialization.

The to_tag method provides a clean way to serialize each enum variant to its corresponding tag byte. The empty vector for PaymentId::Empty is particularly well thought out as it avoids adding unnecessary bytes for empty IDs.


229-246: Correctly updated size calculations.

The size calculations have been properly adjusted to include the additional tag byte for each variant except Empty. This ensures correct memory allocation during serialization.


382-428: Good implementation of type-tagged serialization.

The to_bytes method now properly prepends the tag bytes to the serialized data for each variant. This ensures that type information is preserved during serialization, addressing the core issue mentioned in the PR.


431-544: Fixed type confusion vulnerability in deserialization.

The redesigned from_bytes method now properly checks the tag byte first before attempting to parse the payload. This structured approach prevents type confusion attacks by ensuring each byte array is interpreted according to its explicit type tag.


821-877: Excellent test case for the vulnerability fix.

This test case directly addresses the security vulnerability by attempting to create a PaymentId::Open that could be misinterpreted as another type. The test confirms that with the new tagging system, malicious payloads can no longer cause type confusion during deserialization.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
base_layer/core/src/transactions/transaction_components/encrypted_data.rs (1)

192-213: Return an error or safer fallback for unknown tag.

Currently, from_u8 defaults to TransactionInfo for unrecognized values, which may cause unintended deserialization outcomes. Consider defaulting to PTag::Empty or returning an error to avoid surprises and strengthen type safety.

Here is a possible minimal adjustment:

- _ => PTag::TransactionInfo,
+ _ => PTag::Empty,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1451f5 and 3b53e4f.

📒 Files selected for processing (1)
  • base_layer/core/src/transactions/transaction_components/encrypted_data.rs (19 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: test (mainnet, stagenet)
  • GitHub Check: test (nextnet, nextnet)
  • GitHub Check: cargo check with stable
  • GitHub Check: ci
  • GitHub Check: Cucumber tests / FFI
  • GitHub Check: Cucumber tests / Base Layer
🔇 Additional comments (22)
base_layer/core/src/transactions/transaction_components/encrypted_data.rs (22)

218-228: Consistent tagging logic.

to_tag appropriately distinguishes each variant by introducing a tag byte. Returning an empty vector for PaymentId::Empty aligns well with the logic in from_bytes, preventing unnecessary payload overhead.


232-234: Proper size accounting for U64 and U256.

Adding 1 byte for the tag plus the fixed size of each variant is correct and consistent with to_tag.


239-239: Accurate size for AddressAndData.

Including 1 byte for the tag and 1 byte for the tx_type ensures robust size calculation.


244-244: TransactionInfo size calculation.

Adding the tag byte plus SIZE_VALUE_AND_META_DATA (which includes tx_type) and user data length is consistent with the updated serialization format.


386-389: Appending tag and U64 value.

The logic to prepend the tag byte, followed by the little-endian u64 bytes, is clear and correct.


391-395: Appending tag and U256 value.

Constructing a 32-byte buffer, writing the U256 in little-endian, and then appending it after the tag is correctly implemented.


398-399: Inserting Open variant tag and tx_type.

It’s sensible to store the open variant tag byte, followed by tx_type.as_bytes(), then user data. Matches the stated serialization plan.


408-409: AddressAndData: prepend tag and address.

Including the sender_address bytes and then the tx_type is well-structured. This keeps the format predictable.


420-421: TransactionInfo: prepend tag and amount.

Serializing the tag first, then the 8-byte amount, facilitates consistent parsing on deserialization.


432-438: Graceful handling of empty bytes.

Interpreting empty slices as PTag::Empty and then processing the remaining bytes is a clean approach that ensures PaymentId::Empty is handled consistently.


439-440: Immediate return for an empty PaymentId.

This check properly short-circuits parsing and clarifies the logic flow.


443-443: Immediate return for U64 parsing.

Extracting 8 bytes into a u64 and returning is straightforward and avoids additional overhead.


445-449: Immediate return for U256 parsing.

Correctly brushing 32 bytes into a U256 in little-endian form. Straightforward and efficient.


449-470: Flexible address parsing for AddressAndData.

The dual- or single-address checks correctly match variable lengths, with graceful fallback upon parse failure.


471-493: Parsing TransactionInfo with structured offsets.

Reading amount, metadata, and addresses in order is well-structured. Good approach ensuring partial address parse does not break the entire flow.


534-535: Safe minimal catch-all.

Quietly ignoring other cases here is intentional, but ensure any truly malformed or unexpected data yields a safe fallback.


536-544: Fallback to Open variant.

Unrecognized data eventually falls back to PaymentId::Open, which is consistent with the design of enabling partial user data storage. Keep an eye on potential confusion if the data was intended for a recognized variant.


821-877: Comprehensive confusion test.

The test methodically checks for trick payloads that could be misparsed between Open and TransactionInfo. Excellent coverage against type confusion attacks.


896-901: Open variant with no data.

Straightforward addition to the test matrix, ensuring coverage for empty user data.


911-920: AddressAndData (dual) with no data.

Covers corner cases of minimal user data while ensuring the new tag logic still holds for addresses.


938-944: AddressAndData (single) with no data.

Confirms correct serialization-deserialization flow in a single-address scenario.


956-957: Test labeling updated.

Only a remark describing the new “TransactionInfo - single + amount, no data”. No additional review required.

@github-actions
Copy link

github-actions bot commented Mar 31, 2025

Test Results (CI)

    3 files    129 suites   42m 38s ⏱️
1 354 tests 1 354 ✅ 0 💤 0 ❌
4 060 runs  4 060 ✅ 0 💤 0 ❌

Results for commit 0b8c0cc.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

Test Results (Integration tests)

36 tests   36 ✅  16m 28s ⏱️
11 suites   0 💤
 2 files     0 ❌

Results for commit 0b8c0cc.

@SWvheerden
Copy link
Collaborator

replaced by: #6974

@SWvheerden SWvheerden closed this Apr 22, 2025
@hansieodendaal hansieodendaal deleted the ho_fix_payment_id branch May 7, 2025 09:23
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.

Adversary can craft arbitrary PaymentId due to type confusion in deserialization

2 participants