-
Notifications
You must be signed in to change notification settings - Fork 37.7k
fuzz: wallet, add target for Crypter
#28074
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
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. |
In addition to this and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 6c98f4c
non blocker, just an idea: Perhaps we could have encrypt/decrypt stuff outside of LIMITED_WHILE
and then we could have a call just to fill them. I suppose this way we would have more chance of decrypting a previous encrypted thing. Just an example:
diff --git a/src/wallet/test/fuzz/crypter.cpp b/src/wallet/test/fuzz/crypter.cpp
index 7ba43821b..03ad97a35 100644
--- a/src/wallet/test/fuzz/crypter.cpp
+++ b/src/wallet/test/fuzz/crypter.cpp
@@ -24,6 +24,9 @@ FUZZ_TARGET_INIT(crypter, initialize_crypter)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CCrypter crypt;
+ std::vector<unsigned char> cipher_text_ed;
+ CKeyingMaterial plain_text_ed;
+
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
{
@@ -49,14 +52,16 @@ FUZZ_TARGET_INIT(crypter, initialize_crypter)
},
[&] {
const std::vector<unsigned char> random_vector = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- const CKeyingMaterial plain_text(random_vector.begin(), random_vector.end());
- std::vector<unsigned char> cipher_text;
- crypt.Encrypt(plain_text, cipher_text);
+ plain_text_ed = CKeyingMaterial(random_vector.begin(), random_vector.end());
},
[&] {
- CKeyingMaterial plain_text;
- const std::vector<unsigned char> cipher_text = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- crypt.Decrypt(cipher_text, plain_text);
+ std::vector<unsigned char> cipher_text_ed = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ },
+ [&] {
+ crypt.Encrypt(plain_text_ed, cipher_text_ed);
+ },
+ [&] {
+ crypt.Decrypt(cipher_text_ed, plain_text_ed);
},
[&] {
0e2c657
to
f4ba405
Compare
Thanks, @MarcoFalke and @brunoerg for the reviews.
|
f4ba405
to
e010fdd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reACK e010fdd
e010fdd
to
7570e22
Compare
Forced pushed updating changes in PR 28065. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reACK 7570e22
src/wallet/test/fuzz/crypter.cpp
Outdated
plain_text_ed = CKeyingMaterial(random_vector.begin(), random_vector.end()); | ||
}, | ||
[&] { | ||
std::vector<unsigned char> cipher_text_ed = ConsumeRandomLengthByteVector(fuzzed_data_provider); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a no-op assignment due to the symbol shadow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much for noticing this. I don't know how I missed this.
7570e22
to
fe1a271
Compare
Forced pushed fixing the Shadow variable issue. |
src/wallet/test/fuzz/crypter.cpp
Outdated
const std::string random_string = fuzzed_data_provider.ConsumeRandomLengthString(); | ||
SecureString secure_string(random_string.begin(), random_string.end()); | ||
|
||
const unsigned int nDerivationMethod = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<unsigned int>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit, see https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#coding-style-c
const unsigned int nDerivationMethod = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<unsigned int>(); | |
const unsigned int derivation_method = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<unsigned int>(); |
src/wallet/test/fuzz/crypter.cpp
Outdated
crypt.SetKeyFromPassphrase(/*strKeyData=*/secure_string, | ||
/*chSalt=*/ConsumeRandomLengthByteVector(fuzzed_data_provider), | ||
/*nRounds=*/fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 25000), | ||
/*nDerivationMethod=*/ nDerivationMethod); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit:
/*nDerivationMethod=*/ nDerivationMethod); | |
/*nDerivationMethod=*/nDerivationMethod); |
src/wallet/test/fuzz/crypter.cpp
Outdated
g_setup = testing_setup.get(); | ||
} | ||
|
||
FUZZ_TARGET(crypter, .init = initialize_crypter) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand why the CI isn't failing here. You're using the new macro from #28065 but you haven't rebased past that PR, so this shouldn't work.
These are the errors that i get locally:
wallet/test/fuzz/crypter.cpp:22:22: error: too many arguments provided to function-like macro invocation
FUZZ_TARGET(crypter, .init = initialize_crypter)
^
./test/fuzz/fuzz.h:31:9: note: macro 'FUZZ_TARGET' defined here
#define FUZZ_TARGET(name) \
^
wallet/test/fuzz/crypter.cpp:22:1: error: a type specifier is required for all declarations
FUZZ_TARGET(crypter, .init = initialize_crypter)
^
wallet/test/fuzz/crypter.cpp:24:5: error: 'FuzzedDataProvider' does not refer to a value
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
^
./test/fuzz/FuzzedDataProvider.h:31:7: note: declared here
class FuzzedDataProvider {
^
wallet/test/fuzz/crypter.cpp:89:2: error: expected ';' after top level declarator
}
^
;
4 errors generated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI does a "rebase" before each run. Generally this detects more issues (silent merge conflicts), and I think this is the first case that CI missed a compile failure of this kind. (Generally it is assumed that developers at a minimum try to compile their changes locally, so it would be odd to have a dedicated CI check for that, but maybe there should be?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we are moving to persistent workers, we can even compile all commits in a pull request. Maybe as a separate task on a runner where it doesn't matter when the CI run takes a day or two?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we are moving to persistent workers, we can even compile all commits in a pull request.
Sounds good but would that really take one or two days? With caching this should only take marginally longer, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure how much CPU we want to spend on this. It should only ever find an issue once every couple of months. And there could be quite a backlog easily. For example, 3 devs could each force push a 15 commit pull that touches serialize.h
at the same time. So the cache would be useless and the CI would have to do 45 builds from scratch. (Assuming each takes half an hour, that'd be a day of backlog)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, should be trivial to implement by removing the if: github.event.pull_request.commits != 1
and git checkout HEAD~
from #28497 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is out of the blue, but the reason I struggle to compile after each change is that I'm currently using a Windows 10 OS. And I can't run Wallet Fuzz tests on my machine for some unknown reason. I've attempted Fuzz tests outside of Wallet code, and they run fine. I've also experimented with other Windows machines, and this issue seems to persists across all of them.
So, I've been using an Ubuntu VM for code testing. I've gone through Makefile.test.include, and everything appears to be in order. I'm uncertain about the reason of this problem here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems fine to report an issue about this, with exact steps to reproduce.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm on it. Will try to reproduce it once again and create an issue then.
fe1a271
to
04a2a36
Compare
Thank you for pointing this up, @dergoegge. Actually, I thought it was just a one-line change and became overly relaxed about it. But I'm sorry, and from now on I'll compile before pushing every time. I'm also going to address your style nits in the next push. |
04a2a36
to
066402c
Compare
|
a8ec1f1
to
6697ada
Compare
|
6697ada
to
d7290d6
Compare
… be used fa9be2f lint: [doc] Clarify Windows line endings (CR LF) not to be used (MarcoFalke) Pull request description: It has been this case since the linter was introduced years ago. Given a misunderstanding (#28074 (comment)), clarify the docs. ACKs for top commit: brunoerg: ACK fa9be2f Tree-SHA512: be714db9df533e0962ed84102ffdb72717902949b930d58cf5a79cba36297f6b2b1f75e65a2c1f46bcb8e2f4ad5d025f3d15210f468a5ec9631a580b74f923ea
Fixed the |
A soft ping. Can we move forward with this PR if this looks good? |
utACK d7290d6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK d7290d6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My fuzzer is crashing when I run this. I'm going to look more into it tomorrow.
Please indicate the traceback, and the sanitizers you used, also the fuzz input file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used ASan and UBSan. I think it might just be a mac specifc issue, I'm fuzzing on a mac with m3 chip.
Here's the error:
INFO: seed corpus: files: 111934 min: 1b max: 5242880b total: 2040057759b rss: 216Mb
#8192 pulse cov: 938 ft: 2162 corp: 81/730b exec/s: 4096 rss: 318Mb
#16384 pulse cov: 1049 ft: 2510 corp: 127/2096b exec/s: 5461 rss: 416Mb
#32768 pulse cov: 1571 ft: 4427 corp: 219/9334b exec/s: 4681 rss: 565Mb
#65536 pulse cov: 1774 ft: 7969 corp: 371/56Kb exec/s: 4681 rss: 565Mb
libc++abi: terminating due to uncaught exception of type std::bad_alloc: std::bad_alloc
==15322== ERROR: libFuzzer: deadly signal
#0 0x10824cee4 in __sanitizer_print_stack_trace+0x28 (libclang_rt.asan_osx_dynamic.dylib:arm64+0x5cee4)
#1 0x105025088 in fuzzer::PrintStackTrace() FuzzerUtil.cpp:210
#2 0x10500ae70 in fuzzer::Fuzzer::CrashCallback() FuzzerLoop.cpp:231
#3 0x1944b3580 in _sigtramp+0x34 (libsystem_platform.dylib:arm64+0x4580)
#4 0xf96f000194482c1c (<unknown module>)
#5 0xda0700019438fa1c (<unknown module>)
#6 0x2560000194439d2c (<unknown module>)
#7 0x5f79800194429fc8 (<unknown module>)
#8 0x23020001940c81dc (<unknown module>)
#9 0x31568001944390f0 (<unknown module>)
#10 0x756e00019443c344 (<unknown module>)
#11 0x462e00019443c288 (<unknown module>)
#12 0x4867000102c4910c (<unknown module>)
#13 0x102c4b74c in std::__1::vector<unsigned char, secure_allocator<unsigned char>>::__vallocate[abi:ne180100](unsigned long) vector:741
#14 0x102c45a44 in wallet::(anonymous namespace)::crypter_fuzz_target(Span<unsigned char const>) crypter.cpp:34
#15 0x103361680 in LLVMFuzzerTestOneInput fuzz.cpp:179
#16 0x10500c298 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:614
#17 0x10500bb9c in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) FuzzerLoop.cpp:516
#18 0x10500d9b8 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__1::vector<fuzzer::SizedFile, std::__1::allocator<fuzzer::SizedFile>>&) FuzzerLoop.cpp:829
#19 0x10500da74 in fuzzer::Fuzzer::Loop(std::__1::vector<fuzzer::SizedFile, std::__1::allocator<fuzzer::SizedFile>>&) FuzzerLoop.cpp:867
#20 0x104ffe380 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:914
#21 0x105025970 in main FuzzerMain.cpp:20
#22 0x1940fa0dc (<unknown module>)
#23 0x810fffffffffffc (<unknown module>)
And here is the super long crash input
https://gist.github.com/marcofleon/f2f50cc2e5eb3c2f5efabc511e4fb6ef
If I add limits (1024 for example) to ConsumeRandomLengthByteVector
and ConsumeRandomLengthString
the harness works. But that could be defeating the purpose of fuzzing.
I couldn't reproduce on MacOS 14.3 with that input file.
Changing the harness can invalidate the input. Also, |
If I don't start with a seed corpus (inputs from scratch) then it seems to run fine. I let it go for a while and no crashes happen. It's only when I run something like this: Then it continuously fails to merge and that bad alloc error keeps coming up over and over. I tried this same command on other harnesses that contain @brunoerg, if you don't mind could you try a couple of these other crash inputs too? |
This uses more memory than |
ACK d7290d6 I get that any coverage of these functions is better than no coverage, but it seems less useful to me when we aren't checking the output. There may not be a crash, but each function could be doing something unexpected, and we should be checking to make sure that they aren't. I'm going to merge this for now though just so there is coverage, but a followup which verifies the behavior would be welcomed. |
(void)crypt.Encrypt(plain_text_ed, cipher_text_ed); | ||
}, | ||
[&] { | ||
(void)crypt.Decrypt(cipher_text_ed, plain_text_ed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR adds fuzz coverage for
wallet/crypter
.Motivation: Issue 27272
I ran this for a long time with Sanitizers on and had no crashes; the average
exec/sec
also looks good to me. However, I would really appreciate it if some of the reviewers could try it on their machines too, and give their feedback.