Add rlp_decode fuzz test + some corpus generate code

This commit is contained in:
kdeme 2020-07-20 17:09:15 +02:00
parent 4e4836a0fe
commit f0638eb3f1
No known key found for this signature in database
GPG Key ID: 4E8DD21420AF43F5
8 changed files with 133 additions and 14 deletions

View File

@ -19,10 +19,10 @@ const
type type
PacketTag* = array[tagSize, byte] PacketTag* = array[tagSize, byte]
AuthResponse = object AuthResponse* = object
version: int version*: int
signature: array[64, byte] signature*: array[64, byte]
record: Option[enr.Record] record*: Option[enr.Record]
Codec* = object Codec* = object
localNode*: Node localNode*: Node

View File

@ -230,7 +230,7 @@ proc `xor`[N: static[int], T](a, b: array[N, T]): array[N, T] =
for i in 0 .. a.high: for i in 0 .. a.high:
result[i] = a[i] xor b[i] result[i] = a[i] xor b[i]
proc whoareyouMagic(toNode: NodeId): array[magicSize, byte] = proc whoareyouMagic*(toNode: NodeId): array[magicSize, byte] =
const prefix = "WHOAREYOU" const prefix = "WHOAREYOU"
var data: array[prefix.len + sizeof(toNode), byte] var data: array[prefix.len + sizeof(toNode), byte]
data[0 .. sizeof(toNode) - 1] = toNode.toByteArrayBE() data[0 .. sizeof(toNode) - 1] = toNode.toByteArrayBE()

View File

@ -8,7 +8,8 @@ var targetNode: protocol.Protocol
init: init:
let let
rng = newRng() rng = newRng()
privKey = PrivateKey.random(rng[]) privKey = PrivateKey.fromHex(
"5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[]
ip = some(ValidIpAddress.init("127.0.0.1")) ip = some(ValidIpAddress.init("127.0.0.1"))
port = Port(20301) port = Port(20301)
dbb = DiscoveryDB.init(newMemoryDB()) dbb = DiscoveryDB.init(newMemoryDB())

View File

@ -0,0 +1,32 @@
import
std/[os, strutils],
stew/shims/net,
eth/[rlp, keys], eth/p2p/discoveryv5/[encoding, enr, types],
../fuzzing_helpers
template sourceDir: string = currentSourcePath.rsplit(DirSep, 1)[0]
const inputsDir = sourceDir / "corpus" & DirSep
proc generate() =
let
rng = keys.newRng()
privKey = PrivateKey.random(rng[])
pubKey = PrivateKey.random(rng[]).toPublicKey()
var idNonce: IdNonce
brHmacDrbgGenerate(rng[], idNonce)
let
ephKeys = KeyPair.random(rng[])
signature = signIDNonce(privKey, idNonce, ephKeys.pubkey.toRaw)
record = enr.Record.init(1, privKey, none(ValidIpAddress), Port(9000),
Port(9000))[]
authResponse =
AuthResponse(version: 5, signature: signature.toRaw, record: some(record))
authResponseNoRecord =
AuthResponse(version: 5, signature: signature.toRaw, record: none(enr.Record))
rlp.encode(authResponse).toFile(inputsDir & "auth-response")
rlp.encode(authResponseNoRecord).toFile(inputsDir & "auth-response-no-enr")
discard existsOrCreateDir(inputsDir)
generate()

View File

@ -0,0 +1,51 @@
import
std/[os, strutils],
stew/shims/net,
eth/[keys, rlp, trie/db],
eth/p2p/discoveryv5/[protocol, discovery_db, enr, node, types, encoding],
../fuzzing_helpers
template sourceDir: string = currentSourcePath.rsplit(DirSep, 1)[0]
const inputsDir = sourceDir / "corpus" & DirSep
proc generate() =
let
rng = keys.newRng()
privKey = PrivateKey.random(rng[])
ip = some(ValidIpAddress.init("127.0.0.1"))
port = Port(20301)
dbb = DiscoveryDB.init(newMemoryDB())
d = newProtocol(privKey, dbb, ip, port, port, rng = rng)
# Same as the on in the fuzz test to have at least one working packet for
# the whoareyou-packet.
toPrivKey = PrivateKey.fromHex(
"5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[]
toRecord = enr.Record.init(1, toPrivKey,
some(ValidIpAddress.init("127.0.0.1")), Port(9000), Port(9000))[]
toNode = newNode(toRecord)[]
block: # random packet
# No handshake done obviously so a new packet will be a random packet.
let
reqId = RequestId.init(d.rng[])
message = encodeMessage(PingMessage(enrSeq: d.localNode.record.seqNum), reqId)
(data, _) = encodePacket(d.rng[], d.codec, toNode.id, toNode.address.get(),
message, challenge = nil)
data.toFile(inputsDir & "random-packet")
block: # whoareyou packet
var authTag: AuthTag
var idNonce: IdNonce
brHmacDrbgGenerate(d.rng[], authTag)
brHmacDrbgGenerate(d.rng[], idNonce)
let challenge = Whoareyou(authTag: authTag, idNonce: idNonce, recordSeq: 0)
var data = @(whoareyouMagic(toNode.id))
data.add(rlp.encode(challenge[]))
data.toFile(inputsDir & "whoareyou-packet")
discard existsOrCreateDir(inputsDir)
generate()

View File

@ -1,17 +1,12 @@
import import
streams, os, strutils, options, std/[os, strutils, options],
stew/shims/net, stew/shims/net,
eth/keys, eth/p2p/discoveryv5/enr eth/keys, eth/p2p/discoveryv5/enr,
../fuzzing_helpers
template sourceDir: string = currentSourcePath.rsplit(DirSep, 1)[0] template sourceDir: string = currentSourcePath.rsplit(DirSep, 1)[0]
const inputsDir = sourceDir / "corpus" const inputsDir = sourceDir / "corpus"
proc toFile(data: seq[byte], fn: string) =
var s = newFileStream(fn, fmWrite)
for x in data:
s.write(x)
s.close()
proc generate() = proc generate() =
let let
rng = newRng() rng = newRng()

View File

@ -0,0 +1,8 @@
import
std/streams
proc toFile*(data: seq[byte], fn: string) =
var s = newFileStream(fn, fmWrite)
for x in data:
s.write(x)
s.close()

View File

@ -0,0 +1,32 @@
import
testutils/fuzzing, chronicles,
eth/rlp
type
TestEnum = enum
one = 1
two = 2
TestObject* = object
test1: uint32
test2: string
template testDecode(payload: openarray, T: type) =
try:
discard rlp.decode(payload, T)
except RlpError as e:
debug "Decode failed", err = e.msg
test:
testDecode(payload, string)
testDecode(payload, uint)
testDecode(payload, uint8)
testDecode(payload, uint16)
testDecode(payload, uint32)
testDecode(payload, uint64)
testDecode(payload, int)
testDecode(payload, bool)
testDecode(payload, float64)
testDecode(payload, seq[byte])
testDecode(payload, (string, int32))
testDecode(payload, TestEnum)
testDecode(payload, TestObject)