Gocoin incorrectly parsing OP_0NOTEQUAL
Gocoin is a full Bitcoin solution written entirely from scratch in Go language with zero dependencies, according to their website. Since it is a full node implementation, we thought it would be good to have it on bitcoinfuzz, especially for the target that evaluates Bitcoin scripts.
Abhiramjampani worked on it and opened a PR recently. It is missing addressing some key concerns, brought by Erick, which is why the PR has not been merged yet. However, as part of the review, we left this target running for some time, and it quickly crashed with the following script, which gocoin returned success and Bitcoin Core false:
-1 OP_HASH256 OP_0NOTEQUAL
I first checked that the target was properly implemented and then jumped to understand where the bug was happening. Conceptually, I understand that this is script is not valid, because the hash generated by the opcode OP_HASH256 does not fit in the 4 bytes required by the arithmetic opcodes (OP_0NOTEQUAL, in this case). The gocoin’s code - at that moment - to parse this opcode was:
d := stack.pop()
if checkMinVals && len(d) > 1 {
if DBG_ERR {
fmt.Println("Not minimal bool value", hex.EncodeToString(d))
}
return false
}
As can be seen, it was using pop to get the element instead of using popInt, which makes it not fail for values longer than 4 bytes. The fix was addressed here by Piotr and can be seen in the following diff:
- d := stack.pop()
- if checkMinVals && len(d) > 1 {
- if DBG_ERR {
- fmt.Println("Not minimal bool value", hex.EncodeToString(d))
- }
- return false
- }
- stack.pushBool(bts2bool(d))
+ stack.pushBool(stack.popInt(checkMinVals) != 0)
Thanks Piotr Narewski for responding to my report and fixing the bug so quickly. Also, he told me to go ahead and disclosure it.