-
Notifications
You must be signed in to change notification settings - Fork 260
Description
Description
There is a specific blind signing freeze issue in the Ethereum app (firmware 2.5.1) when handling Aave's "Approve with signed message" flow for supplying assets like USDT. The freeze occurs during the post-checkmark dialog due to the app's parser struggling with the complex, nested calldata generated by EIP-2612 permit bundling (embedded signature data in a single supply transaction).
Your environment
- Device: Ledger Nano X (firmware 2.5.1)
- App: Ethereum (latest, reinstalled)
- Wallet: Rabby (v0.93.53+), MetaMask
- OS/Browser: macOS 15.0 (M4), Chrome 141/Brave
- Network: Arbitrum
Steps to reproduce
- Update to firmware 2.5.1 and latest ETH app (v2.3.0+).
- Enable blind signing in ETH app settings.
- Connect Ledger Nano X to Rabby/MetaMask via Chrome on macOS.
- In Aave: Supply 100 USDT > Select "Approve with signed message" > Proceed to sign.
- On device: Approve initial prompt (double-press both buttons) > Freezes on subsequent screen.
Expected behaviour
Approve the token spending and then supply the tokens (but the device freezes).
Actual behaviour
After double clicking the first dialog on the Ledger Nano X device, I the next confirmation screen the device freezes.
Workaround
Switch in Aave to Transaction mode in the Approve with Signed message option (click on the the gear icon)
Logs
N/A but I can provide eventually, just tell me what you need.
Proposed solution
To resolve the blind signing freeze during Aave's EIP-2612 permit-bundled transactions (e.g., "Approve with signed message" for USDT supply), we need to optimize the calldata handling in the signing flow. The issue stems from the Ethereum app's parser and hasher struggling with longer, nested payloads (~2-3x standard calldata length due to embedded permit signatures), leading to watchdog timeouts or buffer overflows during on-device processing.
This can be fixed by:
- Introducing chunked hashing for large calldata in the blind signing path to prevent long-running loops.
- Adding yield points (e.g., I/O status checks) in the UI rendering and parsing to avoid freezes on confirmation dialogs.
- Optionally, increasing buffer sizes for calldata if overflows are confirmed (via debug logs).
These changes are backward-compatible, minimally invasive, and can be tested with a mock Aave permit transaction.
Implementation Steps
-
Modify Calldata Hashing in APDU Parser (src/apdu_parser.c):
Update thehandleSignTransaction()or equivalent APDU handler to use incremental updates for Keccak hashing when blind signing is enabled. This breaks long payloads into chunks, yielding control periodically to prevent hangs.Before (potential bottleneck):
if (blind_sign_enabled) { cx_sha3_t sha3; cx_sha3_init(&sha3, 256); cx_sha3_update(&sha3, tx_data, tx_len); // Single call can freeze on large tx_len ux_blind_sign_prompt(); // UI after hash }
After:
if (blind_sign_enabled) { cx_sha3_t sha3; cx_sha3_init(&sha3, 256); const uint32_t chunk_size = 1024; // Tune based on SE limits for (uint32_t offset = 0; offset < tx_len; offset += chunk_size) { uint32_t this_chunk = MIN(chunk_size, tx_len - offset); cx_sha3_update(&sha3, tx_data + offset, this_chunk); io_seproxyhal_general_status(); // Yield to prevent timeout } ux_blind_sign_prompt(); // Safer post-chunked hash }
-
Enhance UI Rendering for Confirmation Dialogs (src/ui/screens.c or src/ui/blind_sign_ui.c):
In the post-prompt dialog renderer (e.g.,ui_display_blind_confirm()), add timeouts or split rendering steps for the "next dialog" (where the freeze occurs). This ensures the UI doesn't block on data review.Example Addition:
// In blind confirm UI loop for (uint32_t i = 0; i < num_steps; i++) { ux_step_render(i); // Render one step at a time if (io_seproxyhal_spi_prepare(0)) { // Check for user input or timeout break; } }
-
Update Transaction Parser for Better Validation (src/eth_tx_parser.c):
Add a pre-check for calldata length inparseTransactionData()to warn or chunk if exceeding a threshold (e.g., 4KB), falling back to clear signing if possible.Snippet:
if (calldata_len > MAX_SAFE_CALLDATA) { // Log warning or prompt user for blind override return ERR_TX_TOO_LONG; }
-
Buffer Adjustments (include/os_io_seproxyhal.h):
If logs show overflows, increaseG_io_seproxyhal_spi_bufferfrom default (e.g., 256 bytes) to 512 bytes for signing paths.
This should fully mitigate the freeze while improving robustness for future complex txs.
