-
Notifications
You must be signed in to change notification settings - Fork 37.7k
rpc/wallet: initialize nFeeRequired to avoid using garbage value on failure #18274
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
Concept ACK Good catch! FWIW I still think it would be a good idea to consider moving towards a "initialize-to-zero-or-sane-value-by-default" policy. Realistically and empirically it seems like that is the only way we'll permanently avoid the steady stream of uninitialised reads we're seeing in the project. From the C++ Core Guidlines (edited by Herb Sutter & Bjarne Stroustrup):
J F Bastien of Clang/LLVM fame from the "Automatic variable initialization" LLVM patch thread:
Kees (“Case”) Cook of the Kernel Self-Protection Project (KSPP): Kostya Serebryany - the father of AddressSanitizer, libFuzzer, OSS-Fuzz and Clang Control Flow Integrity - on the topic of auto-initialization in Clang/LLVM:
I know about the "but if you initialize then Valgrind won't find the issue" argument. I love Valgrind and MSan - I use them daily, but we're facing a trade-off here: I think the security benefits of avoiding uninitialized reads by initializing outweighs the discoverability benefits of not initializing. |
I agree with this, would it be worth the time to start refactoring code to initialize to zero/sane? |
Concept ACK. Don't forget to remove the original from line 2664. Can you also initialize Maybe instead of initializing inside
Pure refactor PRs usually don't work well. There is already a code guideline to do this in new places, and in code that's being touched by a PR: https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#c-data-structures |
Can a type of change that is known to have prevented literally countless security bugs in other projects (had the type of change been in place) really be called a "pure refactoring"? :) Perhaps mitigation is a better term. |
NACK. I have a hard time following the discussion here and why people seem to agree that this is a good change. My rationale for the NACK:
So NACK on hiding the bug and not actually fixing it. If it is too hard to fix the bug without major code changes, we are lucky that C++ offers us many ways to safely return values from functions that may fail:
|
I am pretty sure we have had this exact discussion about uninitialized reads the 7th time. I wonder if it helps to write up a policy about that. |
If we do this for all builds, we might as well remove valgrind et al (as I mentioned above). I think it could make sense to enable it for release builds, but I see no way where it could make sense to enable this for developer builds. |
If we decide to do initialization everywhere, it should be done with the |
Tend to agree with Marco and think that a policy of initializing variables to 0 or -1 in cases where these values would still be bugs could be counterproductive and reduce our ability to find these bugs with fuzzing and static analysis. A different rule to either declare every variable with a valid initial value or to declare it as |
ACK b585873 |
b585873
to
e918006
Compare
Pushed removal of duplicate |
@MarcoFalke I see what you're saying, but I'm not sure how trivial/hard it would be to actually track down the cases where the current "error message override" behavior is triggered. Also, I don't think
is correct, because |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, 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. |
Are you sure there is no reasonable way to fix this at the call site instead? I think that would be much preferred. I'm a bit hesitant to ACK the code as currently written. Generally, given Context for reviewers - this is the call site: // Create and send the transaction
CAmount nFeeRequired;
std::string strError;
std::vector<CRecipient> vecSend;
int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
CTransactionRef tx;
if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
} AFAICT that is the only place in our code base where an uninitialized
|
@practicalswift Yeah, either way works, to be honest, but since we are currently using the result in one place, there's no guarantee we won't use it in another in the future. That's my only reasoning, really. |
+1 on fixing at the call site. A refactor could come next IMO. |
e918006
to
a652ba6
Compare
I have changed the code & description of the PR to fix in |
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 a652ba6.
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 a652ba6
ACK a652ba6 -- patch looks correct |
utACK a652ba6
That sounds reasonable, and this fix is in line with that. |
- rpc/wallet: initialize nFeeRequired to avoid using garbage value on failure bitcoin#18274 - httpserver: use own HTTP status codes bitcoin#18168 - tests: Add fuzzing harnesses for various Base{32,58,64} and hex related functions bitcoin#17229 - util: Don't allow Base32/64-decoding or ParseMoney(…) on strings with embedded NUL characters. Add tests. bitcoin#17753 - util: Fail to parse empty string in ParseMoney bitcoin#18225 - util: Fail to parse whitespace-only strings in ParseMoney(...) (instead of parsing as zero) bitcoin#18270 - Replace the LogPrint function with a macro bitcoin#17218 - Fix wallet unload race condition bitcoin#18338 - qt: Fix Window -> Minimize menu item bitcoin#18549 - windows: Enable heap terminate-on-corruption bitcoin#17916
Summary: I do not think that we have the same issue as Core, but it is still nice to see an explicit initialization to 0 in the code. This is a backport of Core [[bitcoin/bitcoin#18274 | PR18274]] Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, majcosta Reviewed By: #bitcoin_abc, majcosta Differential Revision: https://reviews.bitcoinabc.org/D8805
Initialize the
nFeeRequired
variable to avoid using an uninitialized value for errors happening before it is set to 0.Note: this originally fixed
nFeeRet
inwallet.cpp
.