diff --git a/tools/gen/header_template b/tools/gen/header_template index 56dbd3c1846a..2cd7ad50c55a 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 d559ea782bff..296328ce0f4e 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 c3e0ae6abfef..6854b38e2b80 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,