diff --git a/nfuzz/libnfuzz.h b/nfuzz/libnfuzz.h index aaf5d5876..7a8a67b87 100644 --- a/nfuzz/libnfuzz.h +++ b/nfuzz/libnfuzz.h @@ -12,9 +12,13 @@ extern "C" { void NimMain(); /** Supported fuzzing tests */ +bool nfuzz_attestation(uint8_t* input_ptr, size_t input_size, + uint8_t* output_ptr, size_t* output_size); +bool nfuzz_attester_slashing(uint8_t* input_ptr, size_t input_size, + uint8_t* output_ptr, size_t* output_size); bool nfuzz_block(uint8_t* input_ptr, size_t input_size, uint8_t* output_ptr, size_t* output_size); -bool nfuzz_attestation(uint8_t* input_ptr, size_t input_size, +bool nfuzz_block_header(uint8_t* input_ptr, size_t input_size, uint8_t* output_ptr, size_t* output_size); bool nfuzz_shuffle(uint8_t* seed_ptr, uint64_t* output_ptr, size_t output_size); diff --git a/nfuzz/libnfuzz.nim b/nfuzz/libnfuzz.nim index 56d61a023..58b460a10 100644 --- a/nfuzz/libnfuzz.nim +++ b/nfuzz/libnfuzz.nim @@ -1,7 +1,7 @@ import endians, stew/ptrops, stew/ranges/ptr_arith, ../beacon_chain/[ssz, state_transition], - ../beacon_chain/spec/[datatypes, helpers, digest, validator, beaconstate], + ../beacon_chain/spec/[datatypes, helpers, digest, validator, beaconstate, state_transition_block], # Required for deserialisation of ValidatorSig in Attestation due to # https://github.com/nim-lang/Nim/issues/11225 ../beacon_chain/spec/crypto @@ -10,6 +10,10 @@ type BlockInput = object state: BeaconState beaconBlock: BeaconBlock + BlockHeaderInput = BlockInput + AttesterSlashingInput = object + state: BeaconState + attesterSlashing: AttesterSlashing AttestationInput = object state: BeaconState attestation: Attestation @@ -43,33 +47,6 @@ proc copyState(state: BeaconState, output: ptr byte, copyMem(output, unsafeAddr resultState[0], output_size[]) result = true -proc nfuzz_block(input: openArray[byte], output: ptr byte, - output_size: ptr uint): bool {.exportc, raises:[FuzzCrashError, Defect].} = - var data: BlockInput - - try: - data = SSZ.decode(input, BlockInput) - except MalformedSszError, SszSizeMismatchError: - let e = getCurrentException() - raise newException(FuzzCrashError, "SSZ deserialisation failed, likely bug in preprocessing.", e) - - try: - result = state_transition(data.state, data.beaconBlock, flags = {}) - except IOError as e: - # TODO why an IOError? - raise newException(FuzzCrashError, "Unexpected IOError in state transition", e) - except Exception as e: - # TODO why an Exception? - # Lots of vendor code looks like it might raise straight exceptions - raise newException(FuzzCrashError, "Unexpected IOError in state transition", e) - except ValueError: - # TODO is a ValueError indicative of correct or incorrect processing code? - # If correct (but given invalid input), we should return false - # If incorrect, we should allow it to crash - result = false - - if result: - result = copyState(data.state, output, output_size) proc nfuzz_attestation(input: openArray[byte], output: ptr byte, output_size: ptr uint): bool {.exportc, raises:[FuzzCrashError, Defect].} = @@ -95,6 +72,87 @@ proc nfuzz_attestation(input: openArray[byte], output: ptr byte, if result: result = copyState(data.state, output, output_size) + +proc nfuzz_attester_slashing(input: openArray[byte], output: ptr byte, + output_size: ptr uint): bool {.exportc, raises:[FuzzCrashError, Defect].} = + var + data: AttesterSlashingInput + cache = get_empty_per_epoch_cache() + + try: + data = SSZ.decode(input, AttesterSlashingInput) + except MalformedSszError, SszSizeMismatchError: + let e = getCurrentException() + raise newException(FuzzCrashError, "SSZ deserialisation failed, likely bug in preprocessing.", e) + + try: + result = process_attester_slashing(data.state, data.attesterSlashing, cache) + except ValueError: + # TODO is a ValueError indicative of correct or incorrect processing code? + # If correct (but given invalid input), we should return false + # If incorrect, we should allow it to crash + result = false + + if result: + result = copyState(data.state, output, output_size) + + +proc nfuzz_block(input: openArray[byte], output: ptr byte, + output_size: ptr uint): bool {.exportc, raises:[FuzzCrashError, Defect].} = + var data: BlockInput + + try: + data = SSZ.decode(input, BlockInput) + except MalformedSszError, SszSizeMismatchError: + let e = getCurrentException() + raise newException(FuzzCrashError, "SSZ deserialisation failed, likely bug in preprocessing.", e) + + try: + result = state_transition(data.state, data.beaconBlock, flags = {}) + except IOError as e: + # TODO why an IOError? + raise newException(FuzzCrashError, "Unexpected IOError in state transition", e) + except Exception as e: + # TODO why an Exception? + # Lots of vendor code looks like it might raise a bare exception type + raise newException(FuzzCrashError, "Unexpected IOError in state transition", e) + except ValueError: + # TODO is a ValueError indicative of correct or incorrect processing code? + # If correct (but given invalid input), we should return false + # If incorrect, we should allow it to crash + result = false + + if result: + result = copyState(data.state, output, output_size) + + +proc nfuzz_block_header(input: openArray[byte], output: ptr byte, + output_size: ptr uint): bool {.exportc, raises:[FuzzCrashError, Defect].} = + var + data: BlockHeaderInput + cache = get_empty_per_epoch_cache() + + try: + data = SSZ.decode(input, BlockHeaderInput) + except MalformedSszError, SszSizeMismatchError: + let e = getCurrentException() + raise newException(FuzzCrashError, "SSZ deserialisation failed, likely bug in preprocessing.", e) + + try: + result = process_block_header(data.state, data.beaconBlock, flags = {}, cache) + except IOError as e: + # TODO why an IOError? - is this expected/should we return false? + raise newException(FuzzCrashError, "Unexpected IOError in block header processing", e) + except ValueError: + # TODO is a ValueError indicative of correct or incorrect processing code? + # If correct (but given invalid input), we should return false + # If incorrect, we should allow it to crash + result = false + + if result: + result = copyState(data.state, output, output_size) + + # Note: Could also accept raw input pointer and access list_size + seed here. # However, list_size needs to be known also outside this proc to allocate output. # TODO: rework to copy immediatly in an uint8 openArray, considering we have to