compact blocks in IBD resets m_stalling_since #31962

issue Crypt-iQ openend this issue on February 28, 2025
  1. Crypt-iQ commented at 1:53 am on February 28, 2025: contributor

    During IBD it is possible that a malicious peer sends unsolicited compact-block messages to reset its m_stalling_since state. This requires two or more malicious peer connections and can happen with the following steps:

    • Malicious peer A sends a headers message that contains height h+1. The node requests block h+1 from peer A.
    • Malicious peer B sends a headers message that contains heights {h+1, h+2, ..., h+1024}. The node requests MAX_BLOCKS_IN_TRANSIT_PER_PEER blocks from B. Peer B does not need to reply with any of these blocks.
    • Honest peer C sends a headers message that contains heights {h+1, h+2, ..., h+1024}. The node will request blocks continuing from where it last requested from peer B.
    • Peer A sends a compact-block for h+2 with non-empty but bogus shorttxids.
      • The target node will attempt to process the compact-block since it is within two blocks of h. The CanDirectFetch logic is also skipped here as the block is already in-flight with peer B.
      • Since the shorttxids field is bogus, execution hits this branch and calls RemoveBlockRequest. This will reset m_stalling_since even though peer A hasn’t actually provided a block.
      • This can be repeated by peer A to reset m_stalling_since before the timeout triggers. The peer should eventually be disconnected (unless it gives the block) after the larger block download timeout of ~10minutes+ depending on the number of downloading peers which could be numerous in IBD.

    I think this scenario is a bit contrived since it requires two (or more?) malicious peers whom are requested subsequent blocks, but it illustrates that:

    • resetting m_stalling_since in this case is a bug
    • compact-blocks can be received unsolicited even in IBD. The block must be currently in-flight and must be one of the two blocks above the target node’s tip.

    Here is a branch that demonstrates this with a functional test: https://github.com/Crypt-iQ/bitcoin/tree/ibd_cmpct

  2. maflcko added the label P2P on Feb 28, 2025
  3. mzumsande commented at 8:47 pm on March 3, 2025: contributor

    I don’t think this would work with blocks below the minchainwork threshold, we should abort here - so large parts of IBD shouldn’t be affected. We will still be in IBD for a while after reaching that threshold though, depending on how up-to-date the bitcoind release is.

    Also, the node schedules the blocks it downloads during IBD not as an answer to received headers messages, but on its own initiative in SendMessages. So it shouldn’t be possible to trigger this by sending header messages, but the two attacking peers could be be randomly selected next to each other.

    Guessing that this could be connected to #27626 (fyi @instagibbs) because before we shouldn’t have processed a CMPCTBLOCK for a block that was already in flight?!

    As for a fix, I wonder Is there a reason to have https://github.com/bitcoin/bitcoin/blob/3c1f72a36700271c7c1293383549c3be29f28edb/src/net_processing.cpp#L4386-L4389 dependent on already_in_flight - could we unconditionally skip out here if CanDirectFetch() returns false? At least removing the condition doesn’t break any existing tests.

  4. Crypt-iQ commented at 9:46 pm on March 3, 2025: contributor

    Ah, I did not consider the minchainwork.

    So it shouldn’t be possible to trigger this by sending header messages, but the two attacking peers could be be randomly selected next to each other.

    I could have made that more clear in the description that the attacker needed two peers to be selected in sequence for the SendMessages call. That’s what I meant by “subsequent” but I think it was unclear.

    dependent on already_in_flight - could we unconditionally skip out here if CanDirectFetch() returns false? At least removing the condition doesn’t break any existing tests.

    That was what I was thinking, I can’t see a current use for the !already_in_flight check.

  5. instagibbs commented at 9:57 pm on March 3, 2025: member

    That code block appears to be in since the dawn of compact blocks: https://github.com/bitcoin/bitcoin/commit/d25cd3ec4e8#diff-34d21af3c614ea3cee120df276c9c4ae95053830d7f1d3deaf009a4625409ad2R5312

    I might be missing something of course.

    At least removing the condition doesn’t break any existing tests.

    Not very comforting :)


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-03-29 18:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me