Skip to content

fuzz-tests: Add fuzz target for closing_complete #8216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Chand-ra
Copy link

@Chand-ra Chand-ra commented Apr 6, 2025

closing_signed and closing_complete are channel closing negotiation messages defined in BOLT #2.

While closing_signed has a wire fuzz test, closing_complete does not. Add a test to perform a round-trip encoding check (towire -> fromwire) similar to the other wire fuzzers.

Checklist

Before submitting the PR, ensure the following tasks are completed. If an item is not applicable to your PR, please mark it as checked:

  • The changelog has been updated in the relevant commit(s) according to the guidelines.
  • Tests have been added or modified to reflect the changes.
  • Documentation has been reviewed and updated as needed.
  • Related issues have been listed and linked, including any that this PR closes.

@vincenzopalazzo
Copy link
Collaborator

Probably the best person to review this code is @morehouse

@Chand-ra
Copy link
Author

Chand-ra commented Apr 9, 2025

Probably the best person to review this code is @morehouse

Yeah, I've had a conversation with him over mail. He said he'd get around to it soon.

Comment on lines 35 to 37
size_t upto_closer_scriptpubkey = (uintptr_t)&x->closer_scriptpubkey - (uintptr_t)x;
if (memcmp(x, y, upto_closer_scriptpubkey) != 0)
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned that some architectures may pad/align struct members to 8 bytes, which means there would be 4 bytes of uninitialized padding between locktime and fee_satoshis that could trigger false positives.

If we want to use the memcmp trick, we should probably move locktime to after fee_satoshis and then manually compare fields starting with locktime and thereafter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The memcmp dance takes as much lines as individually comparing struct closing_complete's members, so I've replaced the former with the latter in the latest push.

@morehouse
Copy link
Contributor

Also would be good to add a minimal input set as a seed corpus.

Copy link
Contributor

@morehouse morehouse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you use the run.py script to minimize the corpus?

Also, I think this should probably be a Changelog-None.

Comment on lines 35 to 37
assert(!memcmp(&x->channel_id, &y->channel_id, sizeof(struct channel_id)));
assert(x->locktime == y->locktime);
assert(!memcmp(&x->fee_satoshis, &y->fee_satoshis, sizeof(struct amount_sat)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: for better readability can we use assert(memcmp(...) == 0)? I've seen bugs arise because people thought !memcmp(...) meant the buffers differed.

Suggested change
assert(!memcmp(&x->channel_id, &y->channel_id, sizeof(struct channel_id)));
assert(x->locktime == y->locktime);
assert(!memcmp(&x->fee_satoshis, &y->fee_satoshis, sizeof(struct amount_sat)));
assert(memcmp(&x->channel_id, &y->channel_id, sizeof(struct channel_id)) == 0);
assert(x->locktime == y->locktime);
assert(memcmp(&x->fee_satoshis, &y->fee_satoshis, sizeof(struct amount_sat)) == 0);

Comment on lines 35 to 37
assert(!memcmp(&x->channel_id, &y->channel_id, sizeof(struct channel_id)));
assert(x->locktime == y->locktime);
assert(!memcmp(&x->fee_satoshis, &y->fee_satoshis, sizeof(struct amount_sat)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: common trick to avoid the memcmp breaking if the struct type changes in the future:

Suggested change
assert(!memcmp(&x->channel_id, &y->channel_id, sizeof(struct channel_id)));
assert(x->locktime == y->locktime);
assert(!memcmp(&x->fee_satoshis, &y->fee_satoshis, sizeof(struct amount_sat)));
assert(!memcmp(&x->channel_id, &y->channel_id, sizeof(x->channel_id)));
assert(x->locktime == y->locktime);
assert(!memcmp(&x->fee_satoshis, &y->fee_satoshis, sizeof(x->fee_satoshis)));

@Chand-ra
Copy link
Author

Chand-ra commented Apr 16, 2025

Did you use the run.py script to minimize the corpus?

I did. Doesn't seem to do a lot though. Am I using it right:

tests/fuzz/run.py tests/fuzz/corpora

Also, I think this should probably be a Changelog-None.

Right.

@morehouse
Copy link
Contributor

morehouse commented Apr 21, 2025

I did. Doesn't seem to do a lot though. Am I using it right:

tests/fuzz/run.py tests/fuzz/corpora

No, you should be making sure that tests/fuzz/corpora/fuzz-wire-closing_complete is empty and then use --merge_dir:

./tests/fuzz/run.py tests/fuzz/corpora --merge_dir your_closing_complete_corpus

See documentation here.

And please also make sure any other PRs you have open with new corpus inputs are properly minimized this way (e.g., #8183).

@Chand-ra
Copy link
Author

No, you should be making sure that tests/fuzz/corpora/fuzz-wire-closing_complete is empty and then use --merge_dir:

./tests/fuzz/run.py tests/fuzz/corpora --merge_dir your_closing_complete_corpus

See documentation here.

And please also make sure any other PRs you have open with new corpus inputs are properly minimized this way (e.g., #8183).

Done.

assert(tal_arr_eq(x->closee_scriptpubkey, y->closee_scriptpubkey));

assert(x->tlvs && y->tlvs);
return tal_arr_eq(x->tlvs->closer_and_closee_outputs, y->tlvs->closer_and_closee_outputs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we should also be comparing the other TLV fields:

closer_output_only
closee_output_only

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closer_and_closee_outputs field is actually an amalgamation of the closer_output and closee_output fields. Is there any merit to comparing both these fields separately as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure that's not true. They're all distinct signatures. https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#rationale-21

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay, I seem to have misinterpreted a comment in wire/peer_wiregen.c:

struct tlv_closing_tlvs {
    struct tlv_field *fields;

    /* The following explicit fields could just point into the
     * tlv_field entries above to save memory. */
    secp256k1_ecdsa_signature *closer_output_only;
    secp256k1_ecdsa_signature *closee_output_only;
    secp256k1_ecdsa_signature *closer_and_closee_outputs;
};

Chandra Pratap added 2 commits April 23, 2025 14:37
Changelog-None: 'closing_signed' and 'closing_complete'
are channel closing negotiation messages defined in BOLT ElementsProject#2.

While 'closing_signed' has a wire fuzz test, 'closing_complete'
does not. Add a test to perform a round-trip encoding check
(towire -> fromwire) similar to the other wire fuzzers.
Add a minimal input set as a seed corpus for the newly introduced
test. This leads to discovery of interesting code paths faster.
Copy link
Contributor

@morehouse morehouse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 2a2e9cd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants