Fix CodeBytes: invalidPositions out of bound crash (#2523)

This commit is contained in:
andri lim 2024-07-25 19:23:53 +07:00 committed by GitHub
parent 3a7f025fd9
commit 0cc730dd05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 86 additions and 38 deletions

View File

@ -64,7 +64,7 @@ func isValidOpcode*(c: CodeBytesRef, position: int): bool =
var opcode = Op(c.bytes[i]) var opcode = Op(c.bytes[i])
if opcode >= Op.Push1 and opcode <= Op.Push32: if opcode >= Op.Push1 and opcode <= Op.Push32:
var leftBound = (i + 1) var leftBound = (i + 1)
var rightBound = leftBound + (opcode.int - 95) var rightBound = min(leftBound + (opcode.int - 95), c.bytes.len)
for z in leftBound ..< rightBound: for z in leftBound ..< rightBound:
let (bpos, bbit) = bitpos(z) let (bpos, bbit) = bitpos(z)
c.invalidPositions[bpos] = c.invalidPositions[bpos] or bbit c.invalidPositions[bpos] = c.invalidPositions[bpos] or bbit

View File

@ -6,7 +6,11 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms. # at your option. This file may not be copied, modified, or distributed except according to those terms.
import import
std/[sequtils, strutils], chronicles, eth/common, ./interpreter/op_codes, ./code_bytes chronicles,
eth/common,
stew/byteutils,
./interpreter/op_codes,
./code_bytes
export code_bytes export code_bytes
@ -80,24 +84,23 @@ func isValidOpcode*(c: CodeStream, position: int): bool =
func bytes*(c: CodeStream): lent seq[byte] = func bytes*(c: CodeStream): lent seq[byte] =
c.code.bytes() c.code.bytes()
func atEnd*(c: CodeStream): bool =
c.pc >= c.code.bytes.len
proc decompile*(original: CodeStream): seq[(int, Op, string)] = proc decompile*(original: CodeStream): seq[(int, Op, string)] =
# behave as https://etherscan.io/opcode-tool # behave as https://etherscan.io/opcode-tool
var c = CodeStream.init(original.bytes) var c = CodeStream.init(original.bytes)
while true: while not c.atEnd:
var op = c.next var op = c.next
if op >= Push1 and op <= Push32: if op >= Push1 and op <= Push32:
result.add( result.add(
( (
c.pc - 1, c.pc - 1,
op, op,
"0x" & c.read(op.int - 95).mapIt($(it.BiggestInt.toHex(2))).join(""), "0x" & c.read(op.int - 95).toHex,
) )
) )
elif op != Op.Stop: elif op != Op.Stop:
result.add((c.pc - 1, op, "")) result.add((c.pc - 1, op, ""))
else: else:
result.add((-1, Op.Stop, "")) result.add((-1, Op.Stop, ""))
break
func atEnd*(c: CodeStream): bool =
c.pc >= c.code.bytes.len

View File

@ -953,5 +953,14 @@ proc opMemoryMain*() =
success: false success: false
fork: Cancun fork: Cancun
assembler:
title: "Code bytes: invalidPositions out of bound crash issue #2522"
code:
Push1 "0x01" # 0: ok to jump
Push1 "0x06" # 2: jump to pc 6
JumpI # 4
"0x695b00" # 5: PUSH10 First byte is jumpDestOp but operand is too short
success: false
when isMainModule: when isMainModule:
opMemoryMain() opMemoryMain()

View File

@ -67,9 +67,8 @@ proc toBytes(x: string): seq[byte] =
method getAncestorHash(vmState: TestVMState; blockNumber: BlockNumber): Hash256 = method getAncestorHash(vmState: TestVMState; blockNumber: BlockNumber): Hash256 =
keccakHash(toBytes($blockNumber)) keccakHash(toBytes($blockNumber))
proc verifyResult(ctx: var StateContext, vmState: BaseVMState) = proc verifyResult(ctx: var StateContext, vmState: BaseVMState, obtainedHash: Hash256) =
ctx.error = "" ctx.error = ""
let obtainedHash = vmState.readOnlyStateDB.rootHash
if obtainedHash != ctx.expectedHash: if obtainedHash != ctx.expectedHash:
ctx.error = "post state root mismatch: got $1, want $2" % ctx.error = "post state root mismatch: got $1, want $2" %
[($obtainedHash).toLowerAscii, $ctx.expectedHash] [($obtainedHash).toLowerAscii, $ctx.expectedHash]
@ -99,31 +98,9 @@ proc writeResultToStdout(stateRes: seq[StateResult]) =
stdout.write(n.pretty) stdout.write(n.pretty)
stdout.write("\n") stdout.write("\n")
when false: proc writeRootHashToStderr(stateRoot: Hash256) =
proc dumpAccounts(db: LedgerRef): Table[EthAddress, DumpAccount] =
for accAddr in db.addresses():
let acc = DumpAccount(
balance : db.getBalance(accAddr),
nonce : db.getNonce(accAddr),
root : db.getStorageRoot(accAddr),
codeHash: db.getCodeHash(accAddr),
code : db.getCode(accAddr),
key : keccakHash(accAddr)
)
for k, v in db.storage(accAddr):
acc.storage[k] = v
result[accAddr] = acc
proc dumpState(vmState: BaseVMState): StateDump =
StateDump(
root: vmState.readOnlyStateDB.rootHash,
accounts: dumpAccounts(vmState.stateDB)
)
proc writeRootHashToStderr(vmState: BaseVMState) =
let stateRoot = %{ let stateRoot = %{
"stateRoot": %(vmState.readOnlyStateDB.rootHash) "stateRoot": %(stateRoot)
} }
stderr.writeLine($stateRoot) stderr.writeLine($stateRoot)
@ -159,18 +136,19 @@ proc runExecution(ctx: var StateContext, conf: StateConf, pre: JsonNode): StateR
db.persist(clearEmptyAccount = false) # settle accounts storage db.persist(clearEmptyAccount = false) # settle accounts storage
defer: defer:
ctx.verifyResult(vmState) let stateRoot = vmState.readOnlyStateDB.rootHash
ctx.verifyResult(vmState, stateRoot)
result = StateResult( result = StateResult(
name : ctx.name, name : ctx.name,
pass : ctx.error.len == 0, pass : ctx.error.len == 0,
root : vmState.readOnlyStateDB.rootHash, root : stateRoot,
fork : ctx.forkStr, fork : ctx.forkStr,
error: ctx.error error: ctx.error
) )
if conf.dumpEnabled: if conf.dumpEnabled:
result.state = dumpState(vmState.stateDB) result.state = dumpState(vmState.stateDB)
if conf.jsonEnabled: if conf.jsonEnabled:
writeRootHashToStderr(vmState) writeRootHashToStderr(stateRoot)
try: try:
let rc = vmState.processTransaction( let rc = vmState.processTransaction(

View File

@ -0,0 +1,58 @@
{
"01400578-mixed-11": {
"env": {
"currentCoinbase": "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty": "0x200000",
"currentRandom": "0x0000000000000000000000000000000000000000000000000000000000200000",
"currentGasLimit": "0x26e1f476fe1e22",
"currentNumber": "0x1",
"currentTimestamp": "0x3e8",
"previousHash": "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d",
"currentBaseFee": "0x10"
},
"pre": {
"0x00000000000000000000000000000000000000f1": {
"code": "0x605e607f6084600c60f760da603f4257527a7f995050406839323e027077853c6a3330146282387532923e0993618743475b10018e09179e66407c48198ef5349e8e898183740080781d5b308a1189473617771660588c96639c4610643d17741b117734429e81198f5307737981fda26448436303577d312020015a0a9e035a75865576869d895774736dfd656e518e895643346b4392325697483f39637c699d93868b32035562419459550b5a416b647510455134fe47823a085369737f6d6e88387e8d055686771478fd3877351868a082656199857940605411351a09050b123b37517c9e74504376848814727c04483f361b6a61396c7a7f010b72338e358b5b348b8542118d148d7266f21578a033475a523e717f8d31a3fda01257a1898d6f82401b583b514883368c5b62845044107c5a6e637f09868a818564203f14086e6085168832906d0896793c113e973d3348020594718385533082029a8b65026e4858391a901a557c5783081aa358f339147c85029a3240f30b77029d91f13e6f179c31784704606f07524486159452060656ff4515500a7d8a8d3f98768a3e68053b91628d1d38036907587d585b9c32601c6d3b40076efd39168b931c151b6e73041b930a7640764568794030070881548b86101000ff30567884045504468a1d6e2016098e2008141877831c3b3d7556815983917a061242186c98739a087d01603ffe03689d805b064492a11212039b40146d67200902fd44088f94867a916a008079a4366e31601890f3153f6c0a611d023177783e19f53f408509885064a159046388863e82173a599c095b9864449456305030518ea341691ba37f7442f1038ef206578a3d860b67959d18879e8d8418596e70899b016c817310ff42307c3006788c3f32546f6e63364320593e3c356814677492117d653b61933c8b45a06677105b0a541c99115856983774037c801553a0806f423b508f1c3368716809557c3676105143617e6207606f07897b634833203c17609f7467823042763f1431005267705417836c8f951b458b3d50806b806d141530830611a372511575636260613082ff185180597a8054f346811201733b771d898f07745734816bfd1b41411d0964575b110405204472075b6d5b7955a11084f0a460849e3b371c81695b9a3e30607866f19b097d5954651a595257446010840402578643351a15778c84f35231090b9544f035155242593d7e04a3327462417c9d7271849f64643843156d04f5811c620987350b50596c7f947b38778f3d431482856f97809d068d46658d31468b887e350a7a7815966984437432343a6a6803080645f272581690013e7d1132734167761807711dfa8d9d563c388b8246684174f487404170369d44387e47925b886f3c380b131d10fe1af06e4873123634a2007d93656b",
"storage": {},
"balance": "0x0",
"nonce": "0x0"
},
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"code": "0x",
"storage": {},
"balance": "0xffffffffff",
"nonce": "0x0"
}
},
"transaction": {
"gasPrice": "0x10",
"nonce": "0x0",
"to": "0x00000000000000000000000000000000000000f1",
"data": [
"0xa789e12ba04bb2"
],
"gasLimit": [
"0x5299"
],
"value": [
"0x"
],
"sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
},
"out": "0x",
"post": {
"Merge": [
{
"hash": "0xb2cde3c1decab7a146fe0442ed7a8f16e1b044dab737d1196b107c769f86e034",
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"indexes": {
"data": 0,
"gas": 0,
"value": 0
}
}
]
}
}
}