Skip to content

Conversation

@maflcko
Copy link
Member

@maflcko maflcko commented Apr 4, 2020

No description provided.

@DrahtBot
Copy link
Contributor

DrahtBot commented Apr 4, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@practicalswift
Copy link
Contributor

Concept ACK

Very nice fuzzing harness! Keep them coming! :)

@practicalswift
Copy link
Contributor

Tested ACK fa6a008

Thanks for adding a very nice harness!

@maflcko
Copy link
Member Author

maflcko commented Apr 6, 2020

Thanks for testing. Did you find the CVE after re-introducing it?

@practicalswift
Copy link
Contributor

@MarcoFalke

Yes :)

Live demo:

$ mkdir -p process_messages/
$ src/test/fuzz/process_messages process_messages/
…
bloom.cpp:45:69: runtime error: division by zero
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior bloom.cpp:45:69 in
AddressSanitizer:DEADLYSIGNAL
=================================================================
==17357==ERROR: AddressSanitizer: FPE on unknown address 0x55b551298dca (pc 0x55b551298dca bp 0x7ffd02f6f890 sp 0x7ffd02f6f860 T0)
    #0 0x55b551298dca in CBloomFilter::Hash(unsigned int, std::vector<unsigned char, std::allocator<unsigned char> > const&) const src/bloom.cpp:45:69
    #1 0x55b551298b69 in CBloomFilter::insert(std::vector<unsigned char, std::allocator<unsigned char> > const&) src/bloom.cpp:54:31
    #2 0x55b550a820c6 in ProcessMessage(CNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, CDataStream&, long, CChainParams const&, CTxMemPool&, CConnman*, BanMan*, std::atomic<bool> const&) src/net_processing.cpp:3183:45
    #3 0x55b550abd122 in PeerLogicValidation::ProcessMessages(CNode*, std::atomic<bool>&) src/net_processing.cpp:3359:16
    #4 0x55b550ac0f25 in non-virtual thunk to PeerLogicValidation::ProcessMessages(CNode*, std::atomic<bool>&) src/net_processing.cpp
    #5 0x55b550907f01 in ConnmanTestMsg::ProcessMessagesOnce(CNode&) src/./test/util/net.h:26:56
    #6 0x55b550904ecf in test_one_input(std::vector<unsigned char, std::allocator<unsigned char> > const&) src/test/fuzz/process_messages.cpp:69:21
…
$ xxd -p < ./crash-55a890a083dbb4291c5dbc367a58651d02854d86
697665726163ffff006e5757a860a80d5d5c6966696c7465726164640061
fc010000000064645757575757a8a8b661a85ca866696c7465726c6f6164
00bb000500000000d08cff00000000613000ad000000005c6966696c7465
72616464031561b800fc40636d7063ffffffffffffff325c6966696c7465
726164640061fc00a8e0a87800000000000000ffff4100ff67cb59570d41
4141fffedf4141415ca8a5a85a006ea5a8a865a867e5cb79570d5c57572f
a8a5ffff00ff020d5ca8a8a8a8a8696e76a8a86464
$ strings ./crash-55a890a083dbb4291c5dbc367a58651d02854d86
iverac
]\ifilteradd
ddWWWWW
filterload
\ifilteradd
@cmpc
2\ifilteradd
AAA\
\WW/

@maflcko
Copy link
Member Author

maflcko commented Apr 8, 2020

Going to go ahead and merge this. If someone has feedback or questions, you are welcome to leave them here.

@maflcko maflcko merged commit 3410fe6 into bitcoin:master Apr 8, 2020
@maflcko maflcko deleted the 2004-fuzzMsgs branch April 8, 2020 16:16
Copy link
Contributor

@robot-visions robot-visions left a comment

Choose a reason for hiding this comment

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

ACK fa6a008.

This looks extremely useful, thanks for adding! I was also able to reproduce the CVE:

bloom.cpp:45:69: runtime error: division by zero
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior bloom.cpp:45:69 in 
AddressSanitizer:DEADLYSIGNAL
=================================================================
==56684==ERROR: AddressSanitizer: FPE on unknown address 0x00010a4a031e (pc 0x00010a4a031e bp 0x7ffee63a2d60 sp 0x7ffee63a2d30 T0)
    #0 0x10a4a031e in CBloomFilter::Hash(unsigned int, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&) const bloom.cpp:45
    #1 0x10a49ffeb in CBloomFilter::insert(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&) bloom.cpp:52
    #2 0x109c1d4f8 in ProcessMessage(CNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CDataStream&, long long, CChainParams const&, CTxMemPool&, CConnman*, BanMan*, std::__1::atomic<bool> const&) net_processing.cpp:3183
    #3 0x109c5d928 in PeerLogicValidation::ProcessMessages(CNode*, std::__1::atomic<bool>&) net_processing.cpp:3359
    #4 0x10985b7a9 in test_one_input(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&) process_messages.cpp:70

}

while (fuzzed_data_provider.ConsumeBool()) {
const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()};
Copy link
Contributor

Choose a reason for hiding this comment

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

Could the fuzzer check "interesting" cases more quickly by choosing a random but valid command, instead of generating a random string of length COMMAND_SIZE?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question. I think there is a trade-off here between giving the fuzz engine as much freedom to explore as possible at a potentially slight cost of performance (citation needed, giving more freedom could also increase efficiency).

Your suggestion would involve enumerating all netmessage types in an array and then having the fuzz engine pick one from it. This is possible, but as soon as you add a new message type, the developed seeds (inputs) render invalid and need to be adjusted. Readjusting the seeds should not be an issue for the fuzz engine, but it has to be done.

Apart from the above slight inconvenience of having to readjust the seeds on every added (or removed) message type, there is also an issue that the enumeration could accidentally miss one message type. On top, Bitcoin Core ignores unknown message types, and I'd say we want to test this code path as well. (Have at least one unknown message type generated by the fuzzer). This can also be fixed by adding an unknown message type to the fixed array the fuzz engine can pick from. E.g. "foobarfoo".

Moreover, we might also want to test for slight modifications of the same message type and see if they affect behavior in any way. For example b"filteradd\x01add" vs b"filteradd\x02". Those two should never be treated as a valid command and obviously shouldn't crash Bitcoin Core. There should be unit and maybe other fuzz tests in place to check this, but I think allowing the fuzz engine in this test more freedom can't hurt.

Finally, while I don't know the internals of fuzz engines, I believe they are really smart and quick about figuring out "interesting" strings that appear in the source code. If I had to guess what the performance penalty was of allowing any message type as opposed to limiting it to a fixed set of types, I'd presume it is an unnoticeable difference, maybe slight slow down or possibly a slight speed up even. A benchmark might help here.

I tried a few other presumed performance improvements while writing the test and surprisingly I found that writing the least code, simplest code, while allowing the fuzz engine the most freedom was also the fastest way to find the CVE.

Copy link
Contributor

@robot-visions robot-visions Apr 12, 2020

Choose a reason for hiding this comment

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

Thanks for the really thorough explanation! That tradeoff / your decision makes sense to me, especially since I didn't know that fuzz engines might do better than "just generate random strings".

Copy link
Contributor

@mzumsande mzumsande Apr 15, 2020

Choose a reason for hiding this comment

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

I agree as well that the merged version makes sense, but just out of interest I ran both versions (PR and a version which samples an array with all NetMsgTypes currently defined in protocol.cpp ) in parallel with libfuzzer and it was the altered version which found the reintroduced CVE first after 2.3M iterations / 2 hours, while the PR version hadn't found it after 10M tries.
I found it interesting that while the cov metric was similar between the runs, the ft metric of the fuzzer was consistently higher for the array version throughout the run.

Although this was just sample size 1, so finding the CVE might have just been a lucky mutation in the fuzzer algorithm...

Copy link
Member Author

Choose a reason for hiding this comment

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

How many workers did you run in parallel?

Copy link
Contributor

Choose a reason for hiding this comment

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

Just 1 for each version.

Copy link
Member Author

Choose a reason for hiding this comment

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

This sounds like a promising speed-up. I wouldn't object either having this one replaced or a new fuzz target with the array version.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll do some more runs tomorrow, maybe I was just lucky. I don't have a good feeling for the variance of runtimes yet.

Copy link
Member Author

Choose a reason for hiding this comment

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

I saw it vary by a factor or 5 or 10 in my tests last week, so it could very well be just noise

sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Apr 13, 2020
fa6a008 fuzz: Add process_messages harness (MarcoFalke)

Pull request description:

ACKs for top commit:
  practicalswift:
    Tested ACK fa6a008

Tree-SHA512: 2d8788308c7f45c97ca003378f58a9d51f51265958557a65e5e505b1666b4cb928f0d010622870175090a0ad25e2d10b41f26f4eef14b6ff334a024baa250f8c
@narula
Copy link
Contributor

narula commented Apr 22, 2020

As a data point, I was able to reproduce the CVE. It took about ~5-6 hours running 16 jobs.

bloom.cpp:45:69: runtime error: division by zero
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior bloom.cpp:45:69 in 
AddressSanitizer:DEADLYSIGNAL
=================================================================
==40871==ERROR: AddressSanitizer: FPE on unknown address 0x55931bfc0b75 (pc 0x55931bfc0b75 bp 0x7ffc03d58840 sp 0x7ffc03d58810 T0)
    #0 0x55931bfc0b74  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x2526b74)
    #1 0x55931bfbb90b  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x252190b)
    #2 0x55931b823465  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1d89465)
    #3 0x55931b8528f1  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1db88f1)
    #4 0x55931b855d15  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1dbbd15)
    #5 0x55931b687ea4  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1bedea4)
    #6 0x55931b684453  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1bea453)
    #7 0x55931c85a94f  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x2dc094f)
    #8 0x55931b562ce7  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1ac8ce7)
    #9 0x55931b56d554  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1ad3554)
    #10 0x55931b56ebbf  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1ad4bbf)
    #11 0x55931b55df7c  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1ac3f7c)
    #12 0x55931b5427d2  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1aa87d2)
    #13 0x7f81d6280b96  (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #14 0x55931b550e99  (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x1ab6e99)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: FPE (/home/neha/src/bitcoin/src/test/fuzz/process_messages+0x2526b74) 
==40871==ABORTING
MS: 2 ChangeByte-CrossOver-; base unit: 369297d2ec45713fa6113836603e63a500a2403c
artifact_prefix='./'; Test unit written to ./crash-b8f6aae14715726dbd88ef4a5b383e1b50c0fa46

jasonbcox pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Nov 13, 2020
Summary:
Backport of core [[bitcoin/bitcoin#18521 | PR18521]].
Depends on D8374.

Test Plan:
  ninja bitcoin-fuzzers
  ./src/test/fuzz/process_messages <path_to_corpus>

Reviewers: #bitcoin_abc, PiRK

Reviewed By: #bitcoin_abc, PiRK

Differential Revision: https://reviews.bitcoinabc.org/D8376
deadalnix pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Dec 9, 2020
Summary:
This reverts commit rABC22c85ce64493710b114ad598a594f9a9b25422c5.

This is a backport of core [[bitcoin/bitcoin#18521 | PR18521]]. It is similar to D8376 rebased
on top of D8525 which fixes the tsan race.

Depends on D8634 for the test plan.

Test Plan:
  ninja bitcoin-fuzzers
  ./src/test/fuzz/process_messages <path_to_corpus>

  ninja all check-all

With TSAN:
  ninja check-bitcoin-radix_tests check-bitcoin-coinselector_tests
This will likely trigger the TSAN issue on D8376 but not on this diff.

Reviewers: #bitcoin_abc, deadalnix

Reviewed By: #bitcoin_abc, deadalnix

Differential Revision: https://reviews.bitcoinabc.org/D8635
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());

ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get();
Copy link
Member

Choose a reason for hiding this comment

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

I'm pretty sure this is UB. You can't cast to a subclass of the actually created object, even if it adds no fields or member functions.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good find, further discussion in #24373

(Obviously I was testing the review process to see how long it would take to find out)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants