-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
contrib: change default value of epee::serialization to fix limitation #9433
base: master
Are you sure you want to change the base?
contrib: change default value of epee::serialization to fix limitation #9433
Conversation
bcc2265
to
7d1911a
Compare
Co-authored-by: Boog900 <[email protected]>
7d1911a
to
13c5aa5
Compare
And code for the benchmark is available here [1]. Incase anyone wants to take a look at it. |
What is the RAM usage? We added these limits to avoid DoS packets using too much RAM. |
@selsta RAM usage was negligible. On my |
Just to add some more details on how these limits were chosen, the string limit was chosen to allow us to roughly reach the 100mb packet size limit with average size txs. Then the object limit was chosen to allow us to store the same amount of pruned txs in an However looking at the pruned monero/src/cryptonote_protocol/cryptonote_protocol_defs.h Lines 121 to 128 in 0db9e74
A 130k string limit may be too high, in which case it might be best to accept that when syncing pruned blocks we are not able to pack as many txs as when syncing full blocks. If we were to accept this we could decrease the object limit to 32k and field limit to 64k. |
The reported time units in the benchmark don't make sense: For example, in the final tiny_4_string_test, the benchmark reports 13461399ms for "Time" (which I assume means wall clock time) and 3396ms for CPU. Does pausing and resuming the timer break wall clock timing, or are the units here wrong, or something else? |
I am pausing and resuming the timer when I am creating the objects. Only measuring the You can build the |
Setting aside my prior comment, assuming the CPU time values are accurate, the required time in many of these scenarios seems too high: In the faster of the two runs (the experimental setup lacks details, such as thread count, affinity, etc, to determine why there's such a huge gap between them), the maximum time is ~23s. The test doesn't split serialization and deserialization, but if one assumes an even split for each operation, that's ~11s spent just to deserialize the message, i.e. ~10% of the expected time between blocks. Aside from implying a lot of net splits, if an attacker can jam up a CPU for 11s at will, that's a big problem. |
What I mean is the numbers plainly make no sense: Wall time (13461399ms) shouldn't exceed CPU time (3396ms) by a factor of ~4000 for a CPU-bound operation. |
A few points about this:
Hope this helps. |
The latest numbers look much more reasonable, thanks. I agree with the overall methodology. The high watermark (~17.8 s) is still a bit concerning, but not bad enough that I consider it within the scope of this PR (ultimately, it should be lowered a lot by other work to improve serialization). |
@selsta asked a while back here:
Not sure whether this has already be mentioned and explained clearly enough, but the limits that this PR wants to rise were introduced as a reaction to an attack on the Monero network. As far as I understand daemons were crashed using specially crafted packets that, while themselves reasonably small, blew up to an enormous size in RAM when deserialized. You can read a bit about the attack here on Reddit. The PR that introduced these limits at the start of 2021 is [#7286]. It seems that knowledge exactly how that attack worked is lost, unfortunately. Which, like @selsta probably as well, I find mildly worrying: Under these circumstances, how can we be reasonably sure we do not re-enable such an attack by larger limits? We are probably safe, I would say. But on the other hand I don't think like an attacker ... |
The details are not lost. #7999 and #8867 both contain tests that simulate the attack. The primary mechanism for the attack was serializing 0-length strings or 0-length objects inside of an array. Each element was ~1 byte on the wire compared to ~128 bytes in the DOM. The ratio of 1/128 meant that you could have unpacked size ~12.5 GiB. IIRC, the first attempt to stop it failed because it enforced limits per array instead of global. |
I also forgot fields. The unpacked size is at least 160 bytes (not including |
Thanks for the interesting details, @vtnerd ! They make sense, and basically make my worries go away. |
Based on different benchmarks and measurements we realized that
65536
would be the idea number for this limitation.Co-authored-by: Boog900 <[email protected]>