From 2519f934aafc30e7fa12f68a674c3a4b7fcf02a1 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Mon, 18 Nov 2019 20:02:55 +0100 Subject: [PATCH] tlv: Add validity check codegen for the tlv namespaces Since the parser itself just parses and doesn't include validation anymore we need to put that functionality somewhere. The validation consists of enforcing that the types are in monotonically increasing order without duplicates and that for the even types we know how to handle it. --- tools/gen/header_template | 12 ++++++++++++ tools/gen/impl_template | 35 +++++++++++++++++++++++++++++++++++ wallet/test/run-wallet.c | 3 +++ 3 files changed, 50 insertions(+) diff --git a/tools/gen/header_template b/tools/gen/header_template index 56dbd3c18..2cd7ad50c 100644 --- a/tools/gen/header_template +++ b/tools/gen/header_template @@ -68,6 +68,18 @@ struct ${tlv.struct_name()} { struct ${tlv.struct_name()} *${tlv.struct_name()}_new(const tal_t *ctx); bool fromwire_${tlv.name}(const u8 **cursor, size_t *max, struct ${tlv.struct_name()} *record); +/** + * Check that the TLV stream is valid. + * + * Enforces the followin validity rules: + * - Types must be in monotonic non-repeating order + * - We must understand all even types + * + * Returns the index of the field that was invalid, or -1 if the stream is + * valid. + */ +int ${tlv.name}_is_valid(const struct ${tlv.struct_name()} *record); + % if tlv.name in options.expose_tlv_type: #define TLVS_${tlv.name.upper()}_ARRAY_SIZE ${len(tlv.messages)} extern const struct tlv_record_type tlvs_${tlv.name}[]; diff --git a/tools/gen/impl_template b/tools/gen/impl_template index d559ea782..296328ce0 100644 --- a/tools/gen/impl_template +++ b/tools/gen/impl_template @@ -304,6 +304,41 @@ fail: fromwire_fail(cursor, max); return false; } + +int ${tlv.name}_is_valid(const struct ${tlv.struct_name()} *record) +{ + size_t numfields = tal_count(record->fields); + bool first = true; + u64 prev_type = 0; + for (int i=0; ifields[i]; + if (f->numtype % 2 == 0 && f->meta == NULL) { + /* BOLT #1: + * - otherwise, if `type` is unknown: + * - if `type` is even: + * - MUST fail to parse the `tlv_stream`. + * - otherwise, if `type` is odd: + * - MUST discard the next `length` bytes. + */ + SUPERVERBOSE("Unknown even type in TLV"); + return i; + } else if (!first && f->numtype <= prev_type) { + /* BOLT #1: + * - if decoded `type`s are not monotonically-increasing: + * - MUST fail to parse the `tlv_stream`. + */ + if (f->numtype == prev_type) + SUPERVERBOSE("duplicate tlv type"); + else + SUPERVERBOSE("invalid ordering"); + return i; + } + first = false; + prev_type = f->numtype; + } + return -1; +} + % endfor ## END TLV's % for msg in messages: ## START Wire Messages diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index c3e0ae6ab..6854b38e2 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -554,6 +554,9 @@ void subd_req_(const tal_t *ctx UNNEEDED, /* Generated stub for subd_send_msg */ void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED) { fprintf(stderr, "subd_send_msg called!\n"); abort(); } +/* Generated stub for tlv_payload_is_valid */ +int tlv_payload_is_valid(const struct tlv_tlv_payload *record UNNEEDED) +{ fprintf(stderr, "tlv_payload_is_valid called!\n"); abort(); } /* Generated stub for topology_add_sync_waiter_ */ void topology_add_sync_waiter_(const tal_t *ctx UNNEEDED, struct chain_topology *topo UNNEEDED,