RPC Server blindly believes whatever you specify in content-length header and allocates data and does a read() #4343

issue benburkhart1 opened this issue on June 15, 2014
  1. benburkhart1 commented at 11:26 PM on June 15, 2014: none

    The RPC server accepts what it's given in the Content-Length header as fact, and does very little checking before allocating and doing a read() command. It also does all of this before evaluating IP filters via rpcallowip and before evaluating authentication information. Meaning if someone can connect to your RPC server they can exhaust some memory and exhaust all of your connections with little maintenance or network capacity.

    This means you can do:

    for i in seq 125; do curl http://127.0.0.1:44555 -X POST -H "content-length: 30000000" -d "" & done;

    substituting 44555 with your RPC server's port and the loopback IP with the IP of your RPC server. This performs that way due to this code:

    This is where it reads the content-length header https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/rpcprotocol.cpp#L169-L170

    Here's where it gets that header data, and uses it to allocate a buffer and starts a read() call which will never finish due to that amount of data not being there.

    https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/rpcprotocol.cpp#L185-L195

    I understand this is not a huge issue as it's highly discouraged to allow any access to your RPC server's port, and it lacks basic functionality like timeouts to ensure clients do not exhaust its connections, but I thought of bringing this one up particularly because it trusts this value and allocates a buffer prior to authentication and evaluation of rpcallowip rules.

  2. laanwj added the label RPC on Jun 16, 2014
  3. laanwj referenced this in commit 7a086f8848 on Jun 20, 2014
  4. laanwj commented at 1:32 PM on June 20, 2014: member

    You are not correct that this is done before the rpcallowip check. The rpcallowip check is done immediately after the connection comes in in RPCAcceptHandler.

    Nevertheless, see #4373.

  5. jgarzik commented at 2:29 PM on June 20, 2014: contributor

    Related bug: we use C++'s getline(), which is of unbounded length.

  6. benburkhart1 commented at 2:40 PM on June 20, 2014: none

    I see that in RPCAcceptHandler, I believe my test method was flawed for that claim. My mistake.

  7. laanwj added the label Priority Low on Jun 20, 2014
  8. laanwj commented at 3:09 PM on June 20, 2014: member

    I don't think it's worth trying to work around this in the current state. Preventing connection exhaustion attacks in a remotely sane way would need a complete overhaul of the RPC server.

    The combination of boost::asio with getline() and stream.read() and friends is very strange to begin with. The HTTP(S) server should use async I/O all the way through, which would allow for setting timeouts for every connection phase. There are some HTTP server examples here: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/examples/cpp03_examples.html

  9. jgarzik commented at 3:11 PM on June 20, 2014: contributor

    @laanwj Agree 100% I even prototyped a multi-threaded async I/O JSON-RPC server based on boost::asio here: https://github.com/jgarzik/rpcsrv It is a fully working JSON-RPC server skeleton.

  10. laanwj commented at 3:13 PM on June 20, 2014: member

    @jgarzik Cool! Any specific reason why that was never integrated?

  11. jgarzik commented at 3:16 PM on June 20, 2014: contributor

    @laanwj Just time. Also, it's a lot of code for bitcoin, where a pure async I/O server might be more simple.

    boost::asio provides several HTTP server examples. I took their M-T server example, and adapted it. I can probably do the same for their async HTTP server example too.

  12. laanwj commented at 3:23 PM on June 20, 2014: member

    It's more code, sure, but the current rpcserver.cpp+rpcserver.h+rpcprotocol.cpp+rpcprotocol.h is also a lot of code, and less organized. It could be put in a subdir of src.

    And indeed a single-threaded asynchronous HTTP server would likely be enough for bitcoind's expected loads.

    We'd still need a thread pool for the actual RPC command handling, but that can be completely separate from the HTTP server thread.

  13. jgarzik commented at 4:37 PM on June 20, 2014: contributor

    @laanwj hmmm, true. My server does offer M-T execution as well as socket handling. Maybe it is worth merging that one. It's tested, working M-T JSON-RPC code after all.

  14. laanwj commented at 10:16 AM on June 21, 2014: member

    Yes, agreed.

  15. laanwj referenced this in commit 2ec5a3d212 on Jul 4, 2014
  16. laanwj closed this on Jul 7, 2014

  17. MathyV referenced this in commit 5e1ababfe0 on Nov 3, 2014
  18. reddink referenced this in commit b116351507 on May 27, 2020
  19. MarcoFalke locked this on Sep 8, 2021

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: 2026-04-13 15:15 UTC

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