Submitted by xuwinnie
Attempting to read a word that spans across the pointer bound start+offset should return zero bytes for the addresses. When offset >= length, the result should be completely zeros, so we can skip the read. However, in current implementation, this case is not handled properly so that attacker can forge arbitrary read result.
Lets see what happens when skip_if_legitimate_fat_ptr.
We skip memory access if offset >= length.
bytes_out_of_bound will be masked zero and bytes_to_cleanup_out_of_bounds will also be zero.
This case is not treated specially and will not panic, so finally we will push it to dst0. (We should push zeros!)
Above are the main steps to get dst0_value. At first we read two consecutive words from memory. Then we choose the selected word inside them. Finally, we mask it by uma_cleanup_bitspread. The problem is we neither actually read from memory nor mask the value.
We do not read from memory, which means the memory sponge will not be enforced.
We dont mask neither, since bytes_to_cleanup_out_of_bounds is zero.
This two facts mean that we (attacker) can put whatever value into dst0_value. The principle that if memory state is not enforced, the memory value should not be used is not followed here.
When skip_if_legitimate_fat_ptr, bytes_to_cleanup_out_of_bounds should be set to 32.
Context
miladpiri (zkSync) confirmed
Alex the Entreprenerd (judge) commented:
