mirror of
https://github.com/codex-storage/constantine.git
synced 2025-02-11 10:16:30 +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
|
# Auto-pad with zero
|
||||||
var padded: array[128, byte]
|
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]
|
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
|
return cttEVM_InvalidOutputSize
|
||||||
|
|
||||||
# Auto-pad with zero
|
# Auto-pad with zero
|
||||||
var padded: array[128, byte]
|
var padded: array[96, byte]
|
||||||
padded.rawCopy(0, inputs, 0, min(inputs.len, 128))
|
padded.rawCopy(0, inputs, 0, min(inputs.len, padded.len))
|
||||||
|
|
||||||
var P{.noInit.}: ECP_ShortW_Jac[Fp[BN254_Snarks], G1]
|
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
|
# Input parse sizes
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|
||||||
|
# Auto-pad with zero
|
||||||
|
var paddedLengths: array[96, byte]
|
||||||
|
paddedLengths.rawCopy(0, inputs, 0, min(inputs.len, paddedLengths.len))
|
||||||
|
|
||||||
let
|
let
|
||||||
bL = BigInt[256].unmarshal(inputs.toOpenArray(0, 31), bigEndian)
|
bL = BigInt[256].unmarshal(paddedLengths.toOpenArray(0, 31), bigEndian)
|
||||||
eL = BigInt[256].unmarshal(inputs.toOpenArray(32, 63), bigEndian)
|
eL = BigInt[256].unmarshal(paddedLengths.toOpenArray(32, 63), bigEndian)
|
||||||
mL = BigInt[256].unmarshal(inputs.toOpenArray(64, 95), 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)
|
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
|
# 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:
|
if modulusByteLen == 0:
|
||||||
r.setZero()
|
r.setZero()
|
||||||
return cttEVM_Success
|
return cttEVM_Success
|
||||||
|
|
||||||
if exponentByteLen == 0:
|
if exponentByteLen == 0:
|
||||||
r.setZero()
|
r.setZero()
|
||||||
r[r.len-1] = byte 1 # 0^0 = 1 and x^0 = 1
|
r[r.len-1] = byte 1 # 0^0 = 1 and x^0 = 1
|
||||||
return cttEVM_Success
|
return cttEVM_Success
|
||||||
|
|
||||||
if baseByteLen == 0:
|
if baseByteLen == 0:
|
||||||
r.setZero()
|
r.setZero()
|
||||||
return cttEVM_Success
|
return cttEVM_Success
|
||||||
@ -448,25 +460,42 @@ func eth_evm_modexp*(r: var openArray[byte], inputs: openArray[byte]): CttEVMSta
|
|||||||
# ---------------------
|
# ---------------------
|
||||||
|
|
||||||
# Inclusive stops
|
# 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 baseStop = baseStart+baseByteLen-1
|
||||||
let expStart = baseStop+1
|
let expStart = baseStop+1
|
||||||
let expStop = expStart+exponentByteLen-1
|
let expStop = expStart+exponentByteLen-1
|
||||||
let modStart = expStop+1
|
let modStart = expStop+1
|
||||||
let modStop = modStart+modulusByteLen-1
|
let modStop = modStart+modulusByteLen-1
|
||||||
|
|
||||||
|
# We assume that gas checks prevent numbers too big for stack allocation.
|
||||||
var baseBuf = allocStackArray(SecretWord, baseWordLen)
|
var baseBuf = allocStackArray(SecretWord, baseWordLen)
|
||||||
var modulusBuf = allocStackArray(SecretWord, modulusWordLen)
|
var modulusBuf = allocStackArray(SecretWord, modulusWordLen)
|
||||||
var outputBuf = allocStackArray(SecretWord, modulusWordLen)
|
var outputBuf = allocStackArray(SecretWord, modulusWordLen)
|
||||||
|
|
||||||
template base(): untyped = baseBuf.toOpenArray(0, baseWordLen-1)
|
template base(): untyped = baseBuf.toOpenArray(0, baseWordLen-1)
|
||||||
|
template exponent(): untyped = inputs.toOpenArray(expStart, expStop)
|
||||||
template modulus(): untyped = modulusBuf.toOpenArray(0, modulusWordLen-1)
|
template modulus(): untyped = modulusBuf.toOpenArray(0, modulusWordLen-1)
|
||||||
template output(): untyped = outputBuf.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)
|
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 =
|
# Modulus deserialization
|
||||||
inputs.toOpenArray(expStart, expStop)
|
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
|
# Computation
|
||||||
# ---------------------
|
# ---------------------
|
||||||
|
@ -76,3 +76,39 @@ suite "EVM ModExp precompile (EIP-198)":
|
|||||||
var r = newSeq[byte](56)
|
var r = newSeq[byte](56)
|
||||||
let status = r.eth_evm_modexp(input)
|
let status = r.eth_evm_modexp(input)
|
||||||
doAssert status == cttEVM_Success
|
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