You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Our team at FuzzingLabs discovered a new non-compliance in the implementation of the CALLDATACOPY opcode, the resizing of memory does not take into account the entire size specified in the operation. Instead, the memory is only resized for the first 32 bytes of data, regardless of whether the size parameter exceeds this length. This leads to incorrect memory management and an invalid MSIZE value.
When size = 34, for example, the memory is resized only to accommodate 32 bytes ([0; 32]). This means that any subsequent memory accesses outside this range will not reflect the expected size, and MSIZE will return 32 instead of 64.
The CALLDATACOPY opcode should resize memory to account for the full size specified in the stack input. If size = 34, the memory should be resized to at least 64 bytes to ensure alignment with the EVM specification. This should be calculated like this :
#[test]fntest_non_compliance_calldatacopy_memory_resize(){letmut vm = new_vm_with_bytecode(Bytes::copy_from_slice(&[0x60,34,0x5f,0x5f,55,89])).unwrap();letmut current_call_frame = vm.call_frames.pop().unwrap();
vm.execute(&mut current_call_frame);assert_eq!(current_call_frame.stack.stack[0],U256::from(64));}
Backtrace
thread 'test_non_compliance_calldatacopy_memory_resize' panicked at crates/vm/levm/tests/edge_case_tests.rs:18:5:
assertion `left == right` failed
left:32
right:64
stack backtrace:0: rust_begin_unwind
at /rustc/8adb4b30f40e6fbd21dc1ba26c3301c7eeb6de3c/library/std/src/panicking.rs:665:51:core::panicking::panic_fmt
at /rustc/8adb4b30f40e6fbd21dc1ba26c3301c7eeb6de3c/library/core/src/panicking.rs:76:142:core::panicking::assert_failed_inner
3: core::panicking::assert_failed
at /home/mhoste/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:373:54:edge_case_tests::test_non_compliance_calldatacopy_memory_resize
at ./tests/edge_case_tests.rs:18:55:edge_case_tests::test_non_compliance_calldatacopy_memory_resize::{{closure}}
at ./tests/edge_case_tests.rs:11:526:core::ops::function::FnOnce::call_once
at /home/mhoste/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:57:core::ops::function::FnOnce::call_once
at /rustc/8adb4b30f40e6fbd21dc1ba26c3301c7eeb6de3c/library/core/src/ops/function.rs:250:5
note:Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
failures:
test_non_compliance_calldatacopy_memory_resize
test result:FAILED.0 passed;1 failed;0 ignored;0 measured;17 filtered out; finished in0.10s
The text was updated successfully, but these errors were encountered:
Our team at FuzzingLabs discovered a new non-compliance in the implementation of the CALLDATACOPY opcode, the resizing of memory does not take into account the entire
size
specified in the operation. Instead, the memory is only resized for the first 32 bytes of data, regardless of whether thesize
parameter exceeds this length. This leads to incorrect memory management and an invalidMSIZE
value.Root cause
Here is the portion of code responsible for this non-compliance:
When
size = 34
, for example, the memory is resized only to accommodate 32 bytes ([0; 32]
). This means that any subsequent memory accesses outside this range will not reflect the expected size, andMSIZE
will return 32 instead of 64.The
CALLDATACOPY
opcode should resize memory to account for the fullsize
specified in the stack input. Ifsize = 34
, the memory should be resized to at least 64 bytes to ensure alignment with the EVM specification. This should be calculated like this :Example
When
size = 34
:!size + 1 = 0xFFFFFFFF...FFFD + 1 = 0xFFFFFFFF...FFFE
(Two's complement).(0xFFFFFFFF...FFFE & 31) = 30
(Padding required to reach the next multiple of 32).aligned_size = 30 + 34 = 64
(Final aligned size).Explanation: The original size of 34 is not a multiple of 32, so the nearest multiple is 64. This padding ensures the memory is correctly aligned.
When
size = 32
:!size + 1 = 0xFFFFFFFF...FFE0 + 1 = 0xFFFFFFFF...FFE1
.(0xFFFFFFFF...FFE1 & 31) = 0
(No padding required).aligned_size = 0 + 32 = 32
.Explanation: Since the original size is already a multiple of 32, no additional padding is needed.
Step to reproduce
Payload
Add to test :
Backtrace
The text was updated successfully, but these errors were encountered: