Verify jumpsub destination validation (#1022)

Improved JUMP and JUMPSUB destination check. Avoid having to browse the code if the destination == code size

Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
pull/1043/head
Karim T 5 years ago committed by GitHub
parent 3ad217730c
commit d4208892c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/Code.java
  2. 133
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/JumpOperationTest.java
  3. 33
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/JumpSubOperationTest.java

@ -87,7 +87,7 @@ public class Code {
if (!destination.fitsInt()) return false;
final int jumpDestination = destination.intValue();
if (jumpDestination > getSize()) return false;
if (jumpDestination >= getSize()) return false;
if (validJumpDestinations == null) {
// Calculate valid jump destinations
@ -116,7 +116,7 @@ public class Code {
final EVM evm, final MessageFrame frame, final UInt256 destination) {
if (!destination.fitsInt()) return false;
final int jumpDestination = destination.intValue();
if (jumpDestination > getSize()) return false;
if (jumpDestination >= getSize()) return false;
if (validJumpSubDestinations == null) {
// Calculate valid jump destinations

@ -0,0 +1,133 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.core.WorldUpdater;
import org.hyperledger.besu.ethereum.mainnet.IstanbulGasCalculator;
import org.hyperledger.besu.ethereum.vm.Code;
import org.hyperledger.besu.ethereum.vm.EVM;
import org.hyperledger.besu.ethereum.vm.ExceptionalHaltReason;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.OperationRegistry;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.Before;
import org.junit.Test;
public class JumpOperationTest {
private static final IstanbulGasCalculator gasCalculator = new IstanbulGasCalculator();
private static final int CURRENT_PC = 1;
private Blockchain blockchain;
private Address address;
private WorldUpdater worldStateUpdater;
private EVM evm;
private MessageFrameTestFixture createMessageFrameBuilder(final Gas initialGas) {
final BlockHeader blockHeader = new BlockHeaderTestFixture().buildHeader();
return new MessageFrameTestFixture()
.address(address)
.worldState(worldStateUpdater)
.blockHeader(blockHeader)
.blockchain(blockchain)
.initialGas(initialGas);
}
@Before
public void init() {
blockchain = mock(Blockchain.class);
address = Address.fromHexString("0x18675309");
WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive();
worldStateUpdater = worldStateArchive.getMutable().updater();
worldStateUpdater.getOrCreate(address).getMutable().setBalance(Wei.of(1));
worldStateUpdater.commit();
final OperationRegistry registry = new OperationRegistry();
registry.put(new JumpOperation(gasCalculator), 0);
registry.put(new JumpDestOperation(gasCalculator), 0);
evm = new EVM(registry, gasCalculator);
}
@Test
public void shouldJumpWhenLocationIsJumpDest() {
final JumpOperation operation = new JumpOperation(gasCalculator);
final MessageFrame frame =
createMessageFrameBuilder(Gas.of(1))
.pushStackItem(Bytes32.fromHexString("0x03"))
.code(new Code(Bytes.fromHexString("0x6003565b00")))
.build();
frame.setPC(CURRENT_PC);
assertThat(operation.exceptionalHaltCondition(frame, null, evm)).isNotPresent();
operation.execute(frame);
}
@Test
public void shouldJumpWhenLocationIsJumpDestAndAtEndOfCode() {
final JumpOperation operation = new JumpOperation(gasCalculator);
final MessageFrame frame =
createMessageFrameBuilder(Gas.of(1))
.pushStackItem(Bytes32.fromHexString("0x03"))
.code(new Code(Bytes.fromHexString("0x6003565b")))
.build();
frame.setPC(CURRENT_PC);
assertThat(operation.exceptionalHaltCondition(frame, null, evm)).isNotPresent();
operation.execute(frame);
}
@Test
public void shouldHaltWithInvalidJumDestinationWhenLocationIsOutsideOfCodeRange() {
final JumpOperation operation = new JumpOperation(gasCalculator);
final MessageFrame frameDestinationGreaterThanCodeSize =
createMessageFrameBuilder(Gas.of(1))
.pushStackItem(Bytes32.fromHexString("0xFFFFFFFF"))
.code(new Code(Bytes.fromHexString("0x6801000000000000000c565b00")))
.build();
frameDestinationGreaterThanCodeSize.setPC(CURRENT_PC);
assertThat(operation.exceptionalHaltCondition(frameDestinationGreaterThanCodeSize, null, null))
.contains(ExceptionalHaltReason.INVALID_JUMP_DESTINATION);
final MessageFrame frameDestinationEqualsToCodeSize =
createMessageFrameBuilder(Gas.of(1))
.pushStackItem(Bytes32.fromHexString("0x04"))
.code(new Code(Bytes.fromHexString("0x60045600")))
.returnStack(new ReturnStack())
.build();
frameDestinationEqualsToCodeSize.setPC(CURRENT_PC);
assertThat(operation.exceptionalHaltCondition(frameDestinationEqualsToCodeSize, null, null))
.contains(ExceptionalHaltReason.INVALID_JUMP_DESTINATION);
}
}

@ -124,17 +124,44 @@ public class JumpSubOperationTest {
}
@Test
public void shouldHaltWithInvalidJumDestinationWhenLocationIsOutsideOfCodeRange() {
public void shouldJumpWhenLocationIsBeginSubAndAtEndOfCode() {
final JumpSubOperation operation = new JumpSubOperation(gasCalculator);
final MessageFrame frame =
createMessageFrameBuilder(Gas.of(1))
.pushStackItem(Bytes32.fromHexString("0x04"))
.code(new Code(Bytes.fromHexString("0x60045e005c")))
.returnStack(new ReturnStack())
.build();
frame.setPC(CURRENT_PC);
assertThat(operation.exceptionalHaltCondition(frame, null, evm)).isNotPresent();
operation.execute(frame);
assertThat(frame.popReturnStackItem()).isEqualTo(CURRENT_PC + 1);
}
@Test
public void shouldHaltWithInvalidJumDestinationWhenLocationIsOutsideOfCodeRange() {
final JumpSubOperation operation = new JumpSubOperation(gasCalculator);
final MessageFrame frameDestinationGreaterThanCodeSize =
createMessageFrameBuilder(Gas.of(1))
.pushStackItem(Bytes32.fromHexString("0xFFFFFFFF"))
.code(new Code(Bytes.fromHexString("0x6801000000000000000c5e005c60115e5d5c5d")))
.returnStack(new ReturnStack())
.build();
frame.setPC(CURRENT_PC);
frameDestinationGreaterThanCodeSize.setPC(CURRENT_PC);
assertThat(operation.exceptionalHaltCondition(frame, null, null))
assertThat(operation.exceptionalHaltCondition(frameDestinationGreaterThanCodeSize, null, null))
.contains(ExceptionalHaltReason.INVALID_JUMP_DESTINATION);
final MessageFrame frameDestinationEqualsToCodeSize =
createMessageFrameBuilder(Gas.of(1))
.pushStackItem(Bytes32.fromHexString("0x05"))
.code(new Code(Bytes.fromHexString("0x60045e005c")))
.returnStack(new ReturnStack())
.build();
frameDestinationEqualsToCodeSize.setPC(CURRENT_PC);
assertThat(operation.exceptionalHaltCondition(frameDestinationEqualsToCodeSize, null, null))
.contains(ExceptionalHaltReason.INVALID_JUMP_DESTINATION);
}

Loading…
Cancel
Save