Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: lyhistory on January 10, 2019, 08:03:44 AM



Title: why separate execution of unlocking and locking scripts
Post by: lyhistory on January 10, 2019, 08:03:44 AM
quote:
"In the original bitcoin client, the unlocking and locking scripts were concatenated and executed in sequence. For security reasons, this was changed in 2010, because of a vulnerability that allowed a malformed unlocking script to push data onto the stack and corrupt the locking script. In the current implementation, the scripts are executed separately with the stack transferred between the two executions, as described next."

--<Mastering bitcoin, second edition>, https://github.com/bitcoinbook/bitcoinbook/blob/second_edition_print3_rc2/ch06.asciidoc#tx_script

could anyone kindly give an example or more info about what happened in 2010, try to understand this vulnerability when concatenate and execute unlocking and locking scripts, thanks


Title: Re: why separate execution of unlocking and locking scripts
Post by: darosior on January 10, 2019, 08:57:43 AM
could anyone kindly give an example or more info about what happened in 2010, try to understand this vulnerability when concatenate and execute unlocking and locking scripts, thanks
Hi,

Here (https://en.bitcoin.it/wiki/Common_Vulnerabilities_and_Exposures) you can see a list of all Bitcoin CVEs, including the one you are talking about (https://en.bitcoin.it/wiki/Common_Vulnerabilities_and_Exposures#CVE-2010-5141).

To understand what happened in CVE-2010-5141 you need to understand Script execution and OP_PUSHDATA. When validating a script, bitcoin-core used to use a stack and fusion script_sig with script_pubkey onto it, which led to a stack being :
Code:
<OP_CODEs from scriptsig><OP_CODEs from scriptpubkey>
You could simply use an OP_PUSHDATA in script_sig, which would push the scriptpubkey onto the stack without executing it.
The scriptpubkey not executed resulting in conditions under which you can spend the output that are not set. Thus you could spend any output using OP_PUSHDATA. Now, the code executes script_sig on a stack, copy it (to stackCopy (https://github.com/bitcoin/bitcoin/blob/5da08e0ac51682376767d823e76d2a92c61a5d97/src/script/interpreter.cpp#L1486)), then executes script_pubkey on stack (the first one).
Here (https://github.com/bitcoin/bitcoin/blob/5da08e0ac51682376767d823e76d2a92c61a5d97/src/script/interpreter.cpp#L1472) is the link to the function evaluating the script.


Title: Re: why separate execution of unlocking and locking scripts
Post by: achow101 on January 10, 2019, 05:04:12 PM
To understand what happened in CVE-2010-5141 you need to understand Script execution and OP_PUSHDATA.
While what you described is likely possible, the issue with CVE-2010-5141 was actually with OP_RETURN. What OP_RETURN used to do is it would skip to the end of the script so whatever was on the stack was interpreted for the final script result. So what you could do was create a scriptSig that was just
Code:
OP_TRUE OP_RETURN
which would push true to the stack and skip the rest of the script (which included the scriptPubKey at this time). The interpreter would see that at the end of script execution a true was left on the stack so it would say that the script passed. Obviously this is bad because the nothing in the scriptPubKey was evaluated so none of the spending conditions were actually met.

In fixing this bug, Satoshi disabled many other opcodes, changed OP_RETURN to always cause script execution to fail, and separated the execution of the scriptSig and the scriptPubKey so that the scriptPubKey is always executed.


Title: Re: why separate execution of unlocking and locking scripts
Post by: lyhistory on January 11, 2019, 03:00:43 AM
thanks @darosior @achow101 for your quick reply, that's very helpful  :)