From 43a56777d0137991fa419a3eff3b3f4638dcd36e Mon Sep 17 00:00:00 2001 From: Julian Yap Date: Thu, 1 Jun 2017 22:10:16 -1000 Subject: [PATCH] Backport security fix from Geth 1.6.5 core/vm: Use a bitmap instead of a map for jumpdest analysis --- core/vm/analysis.go | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 66e77be818..f2e6530af1 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -22,41 +22,39 @@ import ( "github.com/ubiq/go-ubiq/common" ) -var bigMaxUint64 = new(big.Int).SetUint64(^uint64(0)) - // destinations stores one map per contract (keyed by hash of code). // The maps contain an entry for each location of a JUMPDEST // instruction. -type destinations map[common.Hash]map[uint64]struct{} +type destinations map[common.Hash][]byte // has checks whether code has a JUMPDEST at dest. func (d destinations) has(codehash common.Hash, code []byte, dest *big.Int) bool { - // PC cannot go beyond len(code) and certainly can't be bigger than 64bits. + // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. // Don't bother checking for JUMPDEST in that case. - if dest.Cmp(bigMaxUint64) > 0 { + udest := dest.Uint64() + if dest.BitLen() >= 63 || udest >= uint64(len(code)) { return false } + m, analysed := d[codehash] if !analysed { m = jumpdests(code) d[codehash] = m } - _, ok := m[dest.Uint64()] - return ok + return (m[udest/8] & (1 << (udest % 8))) != 0 } // jumpdests creates a map that contains an entry for each // PC location that is a JUMPDEST instruction. -func jumpdests(code []byte) map[uint64]struct{} { - m := make(map[uint64]struct{}) +func jumpdests(code []byte) []byte { + m := make([]byte, len(code)/8+1) for pc := uint64(0); pc < uint64(len(code)); pc++ { - var op OpCode = OpCode(code[pc]) - switch op { - case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: + op := OpCode(code[pc]) + if op == JUMPDEST { + m[pc/8] |= 1 << (pc % 8) + } else if op >= PUSH1 && op <= PUSH32 { a := uint64(op) - uint64(PUSH1) + 1 pc += a - case JUMPDEST: - m[pc] = struct{}{} } } return m