From ef28e54d65443a61207a4ad7b7419ecf03ebd02c Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Mon, 21 Aug 2023 14:42:54 -0500 Subject: [PATCH] fuzz: target for accept_channel Fuzz the decoding and encoding of accept_channel. We create a wire.h header to share code with future targets. --- tests/fuzz/Makefile | 1 + tests/fuzz/fuzz-wire-accept_channel.c | 77 +++++++++++++++++++++++++++ tests/fuzz/wire.h | 51 ++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 tests/fuzz/fuzz-wire-accept_channel.c create mode 100644 tests/fuzz/wire.h diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile index e5bf67604..1fa493e1a 100644 --- a/tests/fuzz/Makefile +++ b/tests/fuzz/Makefile @@ -5,6 +5,7 @@ LIBFUZZ_OBJS := $(LIBFUZZ_SRC:.c=.o) tests/fuzz/fuzz-connectd-handshake-act*.o: tests/fuzz/connectd_handshake.h tests/fuzz/fuzz-ripemd160: LDLIBS += -lcrypto tests/fuzz/fuzz-sha256: LDLIBS += -lcrypto +tests/fuzz/fuzz-wire-*.o: tests/fuzz/wire.h FUZZ_TARGETS_SRC := $(wildcard tests/fuzz/fuzz-*.c) FUZZ_TARGETS_OBJS := $(FUZZ_TARGETS_SRC:.c=.o) diff --git a/tests/fuzz/fuzz-wire-accept_channel.c b/tests/fuzz/fuzz-wire-accept_channel.c new file mode 100644 index 000000000..474dcb5f6 --- /dev/null +++ b/tests/fuzz/fuzz-wire-accept_channel.c @@ -0,0 +1,77 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include + +struct accept_channel { + struct channel_id temporary_channel_id; + struct amount_sat dust_limit_satoshis; + struct amount_msat max_htlc_value_in_flight_msat; + struct amount_sat channel_reserve_satoshis; + struct amount_msat htlc_minimum_msat; + u32 minimum_depth; + u16 to_self_delay; + u16 max_accepted_htlcs; + struct pubkey funding_pubkey; + struct pubkey revocation_basepoint; + struct pubkey payment_basepoint; + struct pubkey delayed_payment_basepoint; + struct pubkey htlc_basepoint; + struct pubkey first_per_commitment_point; + struct tlv_accept_channel_tlvs *tlvs; +}; + +static void *encode(const tal_t *ctx, const struct accept_channel *s) +{ + return towire_accept_channel( + ctx, &s->temporary_channel_id, s->dust_limit_satoshis, + s->max_htlc_value_in_flight_msat, s->channel_reserve_satoshis, + s->htlc_minimum_msat, s->minimum_depth, s->to_self_delay, + s->max_accepted_htlcs, &s->funding_pubkey, &s->revocation_basepoint, + &s->payment_basepoint, &s->delayed_payment_basepoint, + &s->htlc_basepoint, &s->first_per_commitment_point, s->tlvs); +} + +static struct accept_channel *decode(const tal_t *ctx, const void *p) +{ + struct accept_channel *s = tal(ctx, struct accept_channel); + + if (fromwire_accept_channel( + s, p, &s->temporary_channel_id, &s->dust_limit_satoshis, + &s->max_htlc_value_in_flight_msat, &s->channel_reserve_satoshis, + &s->htlc_minimum_msat, &s->minimum_depth, &s->to_self_delay, + &s->max_accepted_htlcs, &s->funding_pubkey, + &s->revocation_basepoint, &s->payment_basepoint, + &s->delayed_payment_basepoint, &s->htlc_basepoint, + &s->first_per_commitment_point, &s->tlvs)) + return s; + return tal_free(s); +} + +static bool equal(const struct accept_channel *x, + const struct accept_channel *y) +{ + size_t upto_tlvs = (uintptr_t)&x->tlvs - (uintptr_t)x; + if (memcmp(x, y, upto_tlvs) != 0) + return false; + + assert(x->tlvs && y->tlvs); + + if (!memeq(x->tlvs->upfront_shutdown_script, + tal_bytelen(x->tlvs->upfront_shutdown_script), + y->tlvs->upfront_shutdown_script, + tal_bytelen(y->tlvs->upfront_shutdown_script))) + return false; + + return memeq(x->tlvs->channel_type, tal_bytelen(x->tlvs->channel_type), + y->tlvs->channel_type, tal_bytelen(y->tlvs->channel_type)); +} + +void run(const u8 *data, size_t size) +{ + test_decode_encode(data, size, WIRE_ACCEPT_CHANNEL, + struct accept_channel); +} diff --git a/tests/fuzz/wire.h b/tests/fuzz/wire.h new file mode 100644 index 000000000..28a523064 --- /dev/null +++ b/tests/fuzz/wire.h @@ -0,0 +1,51 @@ +/* Helper functions used by all the fuzz-wire-* targets. Each target needs to + * implement encode(), decode(), and equal() for its message type. It can then + * use the test_decode_encode() macro to run the fuzz test. + */ +#ifndef LIGHTNING_TESTS_FUZZ_WIRE_H +#define LIGHTNING_TESTS_FUZZ_WIRE_H + +#include "config.h" +#include +#include + +#include +#include + +static u8 *prefix_arr(const u8 *data, size_t size, u16 prefix) +{ + u8 *p = tal_arr(NULL, u8, 0); + towire_u16(&p, prefix); + towire(&p, data, size); + return p; +} + +/* The init function used by all fuzz-wire-* targets. */ +void init(int *argc, char ***argv) { common_setup("fuzzer"); } + +/* Test that decoding arbitrary data does not crash. Then, if the data was + * successfully decoded, test that encoding and decoding the message does not + * alter it. */ +#define test_decode_encode(data, size, prefix, msgtype) \ + do { \ + const u8 *buf = prefix_arr(data, size, prefix); \ + msgtype *decoded1, *decoded2; \ + void *encoded; \ + do { \ + decoded1 = decode(buf, buf); \ + if (!decoded1) \ + break; \ + \ + encoded = encode(buf, decoded1); \ + assert(encoded && "failed to re-encode message"); \ + \ + decoded2 = decode(buf, encoded); \ + assert(decoded2 && "failed to re-decode message"); \ + \ + assert(equal(decoded1, decoded2)); \ + } while (0); \ + \ + tal_free(buf); \ + } while (0) + +#endif /* LIGHTNING_TESTS_FUZZ_WIRE_H */