mirror of
https://github.com/codex-storage/constantine.git
synced 2025-01-28 19:46:19 +00:00
fix fuzz 18: modexp - handling of infinitely right-padded inputs leading to buffer overflow or stack overflow (#264)
This commit is contained in:
parent
4e0ca43af1
commit
c85ffb069a
@ -120,7 +120,7 @@ func eth_evm_ecadd*(r: var openArray[byte], inputs: openarray[byte]): CttEVMStat
|
||||
|
||||
# Auto-pad with zero
|
||||
var padded: array[128, byte]
|
||||
padded.rawCopy(0, inputs, 0, min(inputs.len, 128))
|
||||
padded.rawCopy(0, inputs, 0, min(inputs.len, padded.len))
|
||||
|
||||
var P{.noInit.}, Q{.noInit.}, R{.noInit.}: ECP_ShortW_Jac[Fp[BN254_Snarks], G1]
|
||||
|
||||
@ -173,8 +173,8 @@ func eth_evm_ecmul*(r: var openArray[byte], inputs: openarray[byte]): CttEVMStat
|
||||
return cttEVM_InvalidOutputSize
|
||||
|
||||
# Auto-pad with zero
|
||||
var padded: array[128, byte]
|
||||
padded.rawCopy(0, inputs, 0, min(inputs.len, 128))
|
||||
var padded: array[96, byte]
|
||||
padded.rawCopy(0, inputs, 0, min(inputs.len, padded.len))
|
||||
|
||||
var P{.noInit.}: ECP_ShortW_Jac[Fp[BN254_Snarks], G1]
|
||||
|
||||
@ -401,10 +401,15 @@ func eth_evm_modexp*(r: var openArray[byte], inputs: openArray[byte]): CttEVMSta
|
||||
|
||||
# Input parse sizes
|
||||
# -----------------
|
||||
|
||||
# Auto-pad with zero
|
||||
var paddedLengths: array[96, byte]
|
||||
paddedLengths.rawCopy(0, inputs, 0, min(inputs.len, paddedLengths.len))
|
||||
|
||||
let
|
||||
bL = BigInt[256].unmarshal(inputs.toOpenArray(0, 31), bigEndian)
|
||||
eL = BigInt[256].unmarshal(inputs.toOpenArray(32, 63), bigEndian)
|
||||
mL = BigInt[256].unmarshal(inputs.toOpenArray(64, 95), bigEndian)
|
||||
bL = BigInt[256].unmarshal(paddedLengths.toOpenArray(0, 31), bigEndian)
|
||||
eL = BigInt[256].unmarshal(paddedLengths.toOpenArray(32, 63), bigEndian)
|
||||
mL = BigInt[256].unmarshal(paddedLengths.toOpenArray(64, 95), bigEndian)
|
||||
|
||||
maxSize = BigInt[256].fromUint(high(uint)) # A CPU can only address up to high(uint)
|
||||
|
||||
@ -433,13 +438,20 @@ func eth_evm_modexp*(r: var openArray[byte], inputs: openArray[byte]): CttEVMSta
|
||||
|
||||
# Special cases
|
||||
# ----------------------
|
||||
if paddedLengths.len + baseByteLen + exponentByteLen >= inputs.len:
|
||||
# Modulus value is in the infinitely right padded zeros input, hence is zero.
|
||||
r.setZero()
|
||||
return cttEVM_Success
|
||||
|
||||
if modulusByteLen == 0:
|
||||
r.setZero()
|
||||
return cttEVM_Success
|
||||
|
||||
if exponentByteLen == 0:
|
||||
r.setZero()
|
||||
r[r.len-1] = byte 1 # 0^0 = 1 and x^0 = 1
|
||||
return cttEVM_Success
|
||||
|
||||
if baseByteLen == 0:
|
||||
r.setZero()
|
||||
return cttEVM_Success
|
||||
@ -448,25 +460,42 @@ func eth_evm_modexp*(r: var openArray[byte], inputs: openArray[byte]): CttEVMSta
|
||||
# ---------------------
|
||||
|
||||
# Inclusive stops
|
||||
let baseStart = 96
|
||||
# Due to special-case checks and early returns,
|
||||
# only the modulus can require right-padding with zeros here
|
||||
# inputs[expStop] cannot buffer overflow
|
||||
let baseStart = paddedLengths.len
|
||||
let baseStop = baseStart+baseByteLen-1
|
||||
let expStart = baseStop+1
|
||||
let expStop = expStart+exponentByteLen-1
|
||||
let modStart = expStop+1
|
||||
let modStop = modStart+modulusByteLen-1
|
||||
|
||||
# We assume that gas checks prevent numbers too big for stack allocation.
|
||||
var baseBuf = allocStackArray(SecretWord, baseWordLen)
|
||||
var modulusBuf = allocStackArray(SecretWord, modulusWordLen)
|
||||
var outputBuf = allocStackArray(SecretWord, modulusWordLen)
|
||||
|
||||
template base(): untyped = baseBuf.toOpenArray(0, baseWordLen-1)
|
||||
template exponent(): untyped = inputs.toOpenArray(expStart, expStop)
|
||||
template modulus(): untyped = modulusBuf.toOpenArray(0, modulusWordLen-1)
|
||||
template output(): untyped = outputBuf.toOpenArray(0, modulusWordLen-1)
|
||||
|
||||
# Base deserialization
|
||||
base.toOpenArray(0, baseWordLen-1).unmarshal(inputs.toOpenArray(baseStart, baseStop), WordBitWidth, bigEndian)
|
||||
modulus.toOpenArray(0, modulusWordLen-1).unmarshal(inputs.toOpenArray(modStart, modStop), WordBitWidth, bigEndian)
|
||||
template exponent(): untyped =
|
||||
inputs.toOpenArray(expStart, expStop)
|
||||
|
||||
# Modulus deserialization
|
||||
let realLen = paddedLengths.len + baseByteLen + exponentByteLen + modulusByteLen
|
||||
let overflowLen = realLen - inputs.len
|
||||
if overflowLen > 0:
|
||||
let physLen = inputs.len-modStart # Length of data physically present (i.e. excluding padded zeros)
|
||||
var paddedModBuf = allocStackArray(byte, modulusByteLen)
|
||||
template paddedMod(): untyped = paddedModBuf.toOpenArray(0, modulusByteLen-1)
|
||||
|
||||
paddedMod.rawCopy(0, inputs, modStart, physLen)
|
||||
zeroMem(paddedMod[physLen].addr, overflowLen)
|
||||
modulus.unmarshal(paddedMod, WordBitWidth, bigEndian)
|
||||
else:
|
||||
modulus.unmarshal(inputs.toOpenArray(modStart, modStop), WordBitWidth, bigEndian)
|
||||
|
||||
# Computation
|
||||
# ---------------------
|
||||
|
@ -75,4 +75,40 @@ suite "EVM ModExp precompile (EIP-198)":
|
||||
|
||||
var r = newSeq[byte](56)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
|
||||
test "Audit #18 - Handling of inputs infinitely right-padded with zeros (read past buffers or stack overflow for temporaries)":
|
||||
let input = [
|
||||
# Base length
|
||||
uint8 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
|
||||
# Exponent length
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xa8, 0xfd,
|
||||
# Modulus length
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
|
||||
0xc1, 0x00, 0x00, 0x00, 0x51, 0x00, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x00, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0xbc, 0x9b, 0xa0, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x00, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00, 0x00,
|
||||
0xa0]
|
||||
var r = newSeq[byte](1)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
Loading…
x
Reference in New Issue
Block a user