mirror of https://github.com/status-im/nim-eth.git
Allow for fuzzing with libFuzzer
This commit is contained in:
parent
0f020d5df8
commit
70a892fff7
|
@ -1,55 +1,25 @@
|
||||||
import
|
import
|
||||||
streams, posix, sequtils, strutils, chronicles, chronos, stew/byteutils,
|
chronicles, eth/p2p/[discovery, enode], eth/[keys, rlp],
|
||||||
eth/p2p/[discovery, kademlia, enode], eth/[keys, rlp],
|
../../p2p/p2p_test_helper, ../fuzz_helpers
|
||||||
../../p2p/p2p_test_helper
|
|
||||||
|
|
||||||
template fuzz(body) =
|
|
||||||
# For code we want to fuzz.
|
|
||||||
try:
|
|
||||||
body
|
|
||||||
except:
|
|
||||||
let e = getCurrentException()
|
|
||||||
debug "Fuzzer input created exception", exception=e.name, trace=e.repr
|
|
||||||
discard kill(getpid(), SIGSEGV)
|
|
||||||
|
|
||||||
template noFuzz(body) =
|
|
||||||
# For code not in the scope of the test.
|
|
||||||
# Lets not have false negatives due to possible issues in this code.
|
|
||||||
try:
|
|
||||||
body
|
|
||||||
except:
|
|
||||||
let e = getCurrentException()
|
|
||||||
debug "Exception out of scope of the fuzzing target",
|
|
||||||
exception=e.name, trace=e.repr
|
|
||||||
return
|
|
||||||
|
|
||||||
const DefaultListeningPort = 30303
|
const DefaultListeningPort = 30303
|
||||||
|
var targetNode: DiscoveryProtocol
|
||||||
|
|
||||||
proc fuzzTest() =
|
proc init() =
|
||||||
|
# Set up a discovery node, this is the node we target when fuzzing
|
||||||
var
|
var
|
||||||
msg: seq[byte]
|
|
||||||
address: Address
|
|
||||||
targetNode: DiscoveryProtocol
|
|
||||||
|
|
||||||
noFuzz:
|
|
||||||
# Set up a discovery node, this is the node we target with fuzzing
|
|
||||||
let
|
|
||||||
targetNodeKey = initPrivateKey("a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")
|
targetNodeKey = initPrivateKey("a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")
|
||||||
targetNodeAddr = localAddress(DefaultListeningPort)
|
targetNodeAddr = localAddress(DefaultListeningPort)
|
||||||
targetNode = newDiscoveryProtocol(targetNodeKey, targetNodeAddr, @[])
|
targetNode = newDiscoveryProtocol(targetNodeKey, targetNodeAddr, @[])
|
||||||
# Create the transport as else replies on the messages send will fail.
|
# Create the transport as else replies on the messages send will fail.
|
||||||
targetNode.open()
|
targetNode.open()
|
||||||
|
|
||||||
# Read input from stdin (fastest for AFL)
|
proc test(payload: seq[byte]) =
|
||||||
let s = newFileStream(stdin)
|
var
|
||||||
# We use binary files as with hex we can get lots of "not hex" failures
|
msg: seq[byte]
|
||||||
var input = s.readAll()
|
address: Address
|
||||||
s.close()
|
|
||||||
# Remove newline if it is there
|
|
||||||
input.removeSuffix
|
|
||||||
# TODO: is there a better/faster way?
|
|
||||||
let payload = input.mapIt(it.byte)
|
|
||||||
|
|
||||||
|
fuzz:
|
||||||
# Sending raw payload is possible but won't find us much. We need a hash and
|
# Sending raw payload is possible but won't find us much. We need a hash and
|
||||||
# a signature, and without it there is a big chance it will always result in
|
# a signature, and without it there is a big chance it will always result in
|
||||||
# "Wrong msg mac from" error.
|
# "Wrong msg mac from" error.
|
||||||
|
@ -64,5 +34,31 @@ proc fuzzTest() =
|
||||||
except RlpError, DiscProtocolError:
|
except RlpError, DiscProtocolError:
|
||||||
debug "Receive failed", err = getCurrentExceptionMsg()
|
debug "Receive failed", err = getCurrentExceptionMsg()
|
||||||
|
|
||||||
fuzz:
|
proc NimMain() {.importc: "NimMain".}
|
||||||
fuzzTest()
|
|
||||||
|
proc fuzzerInit(): cint {.exportc: "LLVMFuzzerInitialize".} =
|
||||||
|
NimMain()
|
||||||
|
|
||||||
|
init()
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
template `+`*[T](p: ptr T, off: int): ptr T =
|
||||||
|
cast[ptr type(p[])](cast[ByteAddress](p) +% off * sizeof(p[]))
|
||||||
|
|
||||||
|
proc fuzzerCall(data: ptr byte, len: csize): cint {.exportc: "LLVMFuzzerTestOneInput".} =
|
||||||
|
if len > 0:
|
||||||
|
var input: seq[byte]
|
||||||
|
|
||||||
|
# TODO: something better to get this data in the seq?
|
||||||
|
newSeq(input, len)
|
||||||
|
for i in 0..<len:
|
||||||
|
input[i] = (data + i)[]
|
||||||
|
|
||||||
|
test(input)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
when defined(afl):
|
||||||
|
init()
|
||||||
|
test(readStdin())
|
|
@ -7,8 +7,7 @@ if not dirExists("generated-input"):
|
||||||
if not fileExists("fuzz"):
|
if not fileExists("fuzz"):
|
||||||
# Requires afl-gcc to be installed
|
# Requires afl-gcc to be installed
|
||||||
# TODO: add + test option for clang
|
# TODO: add + test option for clang
|
||||||
exec "nim c --cc=gcc --gcc.exe=afl-gcc --gcc.linkerexe=afl-gcc fuzz"
|
exec "nim c -d:afl -d:noSignalHandler --cc=gcc --gcc.exe=afl-gcc --gcc.linkerexe=afl-gcc fuzz"
|
||||||
|
|
||||||
if dirExists("output"):
|
if dirExists("output"):
|
||||||
exec "afl-fuzz -i - -o output -M fuzzer01 -- ./fuzz"
|
exec "afl-fuzz -i - -o output -M fuzzer01 -- ./fuzz"
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import streams, posix, sequtils, strutils, chronicles
|
||||||
|
|
||||||
|
template fuzz*(body) =
|
||||||
|
# For code we want to fuzz, SIGSEGV is needed on unwanted exceptions.
|
||||||
|
# However, this is only needed when fuzzing with afl.
|
||||||
|
when defined(afl):
|
||||||
|
try:
|
||||||
|
body
|
||||||
|
except Exception as e:
|
||||||
|
error "Fuzzer input created exception", exception=e.name, trace=e.repr, msg=e.msg
|
||||||
|
discard kill(getpid(), SIGSEGV)
|
||||||
|
else:
|
||||||
|
body
|
||||||
|
|
||||||
|
proc readStdin*(): seq[byte] =
|
||||||
|
# Read input from stdin (fastest for AFL)
|
||||||
|
let s = newFileStream(stdin)
|
||||||
|
if s.isNil:
|
||||||
|
error "Error opening stdin"
|
||||||
|
discard kill(getpid(), SIGSEGV)
|
||||||
|
# We use binary files as with hex we can get lots of "not hex" failures
|
||||||
|
var input = s.readAll()
|
||||||
|
s.close()
|
||||||
|
# Remove newline if it is there
|
||||||
|
input.removeSuffix
|
||||||
|
# TODO: is there a better/faster way?
|
||||||
|
result = input.mapIt(it.byte)
|
Loading…
Reference in New Issue