Summary: A single request to submit a post to /wallet/deploycontract with several megabytes of bytecode along with CPU intensive long parsing will consume CPU for about 10 minutes while still holding several megabytes of bytecode in heap. With enough requests (lets say 1K-10K depending upon available memory), its enough to use all the available threads to service incoming HTTP request, fill up the memory and render DDOS.
Getting a longValue from big decimal for large exponent is extremely slow. new BigDecimal("10000000e100000000").longValue(); snippet takes about 2-3 minutes to run in a modern macbook pro. /wallet/deploycontract has 6 fields that gets a long value from a parsed json object i.e. token_id, call_token_value, fee_limit, call_value, consume_user_resource_percent, origin_energy_limit. This means a single request can use up a thread for up to 12 minutes (assuming 2 minutes per parsing). While a thread is being locked for 12 minutes /deploycontract also puts the entire bytecode in memory which can fill up the memory and prematurely move objects from eden memory space to old memory space Once objects are moved to old memory space it will be very difficult to clean them up when when the pointers are released and hence the GC will get stuck trying to clean fore ever. Notice the gc log and screenshot where the memory stays up at 3G long after the attack was stopped.
Supporting Material/References: * jconsole screenshots representing memory, cpu and threads * gc log to show JVM going into infinite GCs and still unable to free up memory
Suggested fix * JSONObject.parse uses Feature.UseBigDecimal.getMask(); by default. Not using BigDecimal will fix the issue but may introduce issue in other places where BigDecimal is required. * Also, would be great if the entire bytecode wasnt put in memory the whole time.
Impact Using a single machine an attacker could send DDOS attack to all or 51% of the SR node and render Tron network unusable or make it unavailable.