Skip to content

Commit 8d39aed

Browse files
committed
core/evm, contracts: avoid copying memory for input in calls + make ecrecover not modify input buffer
1 parent d5b79e7 commit 8d39aed

File tree

3 files changed

+74
-6
lines changed

3 files changed

+74
-6
lines changed

core/vm/contracts.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,13 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) {
106106
if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) {
107107
return nil, nil
108108
}
109+
// We must make sure not to modify the 'input', so placing the 'v' along with
110+
// the signature needs to be done on a new allocation
111+
sig := make([]byte, 65)
112+
copy(sig, input[64:128])
113+
sig[64] = v
109114
// v needs to be at the end for libsecp256k1
110-
pubKey, err := crypto.Ecrecover(input[:32], append(input[64:128], v))
115+
pubKey, err := crypto.Ecrecover(input[:32], sig)
111116
// make sure the public key is a valid one
112117
if err != nil {
113118
return nil, nil

core/vm/contracts_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package vm
1818

1919
import (
20+
"bytes"
2021
"fmt"
2122
"math/big"
2223
"reflect"
@@ -409,6 +410,11 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
409410
} else if common.Bytes2Hex(res) != test.expected {
410411
t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))
411412
}
413+
// Verify that the precompile did not touch the input buffer
414+
exp := common.Hex2Bytes(test.input)
415+
if !bytes.Equal(in, exp) {
416+
t.Errorf("Precompiled %v modified input data", addr)
417+
}
412418
})
413419
}
414420

@@ -423,6 +429,11 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing
423429
if !reflect.DeepEqual(err, test.expectedError) {
424430
t.Errorf("Expected error [%v], got [%v]", test.expectedError, err)
425431
}
432+
// Verify that the precompile did not touch the input buffer
433+
exp := common.Hex2Bytes(test.input)
434+
if !bytes.Equal(in, exp) {
435+
t.Errorf("Precompiled %v modified input data", addr)
436+
}
426437
})
427438
}
428439

@@ -574,3 +585,55 @@ func TestPrecompileBlake2FMalformedInput(t *testing.T) {
574585
testPrecompiledFailure("09", test, t)
575586
}
576587
}
588+
589+
// EcRecover test vectors
590+
var ecRecoverTests = []precompiledTest{
591+
{
592+
input: "a8b53bdf3306a35a7103ab5504a0c9b492295564b6202b1942a84ef300107281" +
593+
"000000000000000000000000000000000000000000000000000000000000001b" +
594+
"3078356531653033663533636531386237373263636230303933666637316633" +
595+
"6635336635633735623734646362333161383561613862383839326234653862" +
596+
"1122334455667788991011121314151617181920212223242526272829303132",
597+
expected: "",
598+
name: "CallEcrecoverUnrecoverableKey",
599+
},
600+
{
601+
input: "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" +
602+
"000000000000000000000000000000000000000000000000000000000000001c" +
603+
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f" +
604+
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
605+
expected: "000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
606+
name: "ValidKey",
607+
},
608+
{
609+
input: "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" +
610+
"100000000000000000000000000000000000000000000000000000000000001c" +
611+
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f" +
612+
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
613+
expected: "",
614+
name: "InvalidHighV-bits-1",
615+
},
616+
{
617+
input: "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" +
618+
"000000000000000000000000000000000000001000000000000000000000001c" +
619+
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f" +
620+
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
621+
expected: "",
622+
name: "InvalidHighV-bits-2",
623+
},
624+
{
625+
input: "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" +
626+
"000000000000000000000000000000000000001000000000000000000000011c" +
627+
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f" +
628+
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
629+
expected: "",
630+
name: "InvalidHighV-bits-3",
631+
},
632+
}
633+
634+
func TestPrecompiledEcrecover(t *testing.T) {
635+
for _, test := range ecRecoverTests {
636+
testPrecompiled("01", test, t)
637+
}
638+
639+
}

core/vm/instructions.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
384384

385385
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
386386
offset, size := stack.pop(), stack.pop()
387-
data := memory.Get(offset.Int64(), size.Int64())
387+
data := memory.GetPtr(offset.Int64(), size.Int64())
388388

389389
if interpreter.hasher == nil {
390390
interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
@@ -757,7 +757,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
757757
toAddr := common.BigToAddress(addr)
758758
value = math.U256(value)
759759
// Get the arguments from the memory.
760-
args := memory.Get(inOffset.Int64(), inSize.Int64())
760+
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
761761

762762
if value.Sign() != 0 {
763763
gas += params.CallStipend
@@ -786,7 +786,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem
786786
toAddr := common.BigToAddress(addr)
787787
value = math.U256(value)
788788
// Get arguments from the memory.
789-
args := memory.Get(inOffset.Int64(), inSize.Int64())
789+
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
790790

791791
if value.Sign() != 0 {
792792
gas += params.CallStipend
@@ -814,7 +814,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
814814
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
815815
toAddr := common.BigToAddress(addr)
816816
// Get arguments from the memory.
817-
args := memory.Get(inOffset.Int64(), inSize.Int64())
817+
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
818818

819819
ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas)
820820
if err != nil {
@@ -839,7 +839,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m
839839
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
840840
toAddr := common.BigToAddress(addr)
841841
// Get arguments from the memory.
842-
args := memory.Get(inOffset.Int64(), inSize.Int64())
842+
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
843843

844844
ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas)
845845
if err != nil {

0 commit comments

Comments
 (0)