Skip to content

Commit 22143b7

Browse files
committed
Avoid double free in simplicity pointer when copying PrecomputedTransactionData
1 parent 22413ab commit 22143b7

File tree

4 files changed

+24
-10
lines changed

4 files changed

+24
-10
lines changed

src/script/interpreter.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -2669,7 +2669,7 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
26692669
simplicityRawTx.version = txTo.nVersion;
26702670
simplicityRawTx.lockTime = txTo.nLockTime;
26712671

2672-
m_simplicity_tx_data = simplicity_elements_mallocTransaction(&simplicityRawTx);
2672+
m_simplicity_tx_data_ptr = std::make_unique<SimplicityTxData>(&simplicityRawTx);
26732673

26742674
m_bip341_taproot_ready = true;
26752675
}
@@ -3119,9 +3119,10 @@ bool GenericTransactionSignatureChecker<T>::CheckSimplicity(const valtype& progr
31193119
simplicity_err error;
31203120
tapEnv* simplicityTapEnv = simplicity_elements_mallocTapEnv(&simplicityRawTap);
31213121

3122-
assert(txdata->m_simplicity_tx_data);
3122+
assert(txdata->m_simplicity_tx_data_ptr);
3123+
assert(txdata->m_simplicity_tx_data_ptr->m_simplicity_tx_data);
31233124
assert(simplicityTapEnv);
3124-
if (!simplicity_elements_execSimplicity(&error, 0, txdata->m_simplicity_tx_data, nIn, simplicityTapEnv, txdata->m_hash_genesis_block.data(), budget, 0, program.data(), program.size(), witness.data(), witness.size())) {
3125+
if (!simplicity_elements_execSimplicity(&error, 0, txdata->m_simplicity_tx_data_ptr->m_simplicity_tx_data, nIn, simplicityTapEnv, txdata->m_hash_genesis_block.data(), budget, 0, program.data(), program.size(), witness.data(), witness.size())) {
31253126
assert(!"simplicity_elements_execSimplicity internal error");
31263127
}
31273128
simplicity_elements_freeTapEnv(simplicityTapEnv);

src/script/interpreter.h

+15-4
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,23 @@ enum : uint32_t {
169169

170170
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
171171

172+
struct SimplicityTxData {
173+
transaction* m_simplicity_tx_data = nullptr;
174+
// No default assignment operator or copy constructor
175+
SimplicityTxData& operator=(const SimplicityTxData&) = delete;
176+
SimplicityTxData(const SimplicityTxData&) = delete;
177+
SimplicityTxData(rawTransaction* tx) {
178+
m_simplicity_tx_data = simplicity_elements_mallocTransaction(tx);
179+
};
180+
~SimplicityTxData() {
181+
simplicity_elements_freeTransaction(m_simplicity_tx_data);
182+
m_simplicity_tx_data = nullptr;
183+
};
184+
};
172185
struct PrecomputedTransactionData
173186
{
174-
transaction* m_simplicity_tx_data = nullptr;
187+
// Make sure that only one copy of the simplicity tx is kept around if the struct is moved
188+
std::unique_ptr<SimplicityTxData> m_simplicity_tx_data_ptr;
175189
// BIP341 precomputed data.
176190
// These are single-SHA256, see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-15.
177191
uint256 m_prevouts_single_hash;
@@ -221,9 +235,6 @@ struct PrecomputedTransactionData
221235

222236
template <class T>
223237
explicit PrecomputedTransactionData(const T& tx);
224-
~PrecomputedTransactionData() {
225-
simplicity_elements_freeTransaction(m_simplicity_tx_data);
226-
}
227238
};
228239

229240
enum class SigVersion

src/test/fuzz/simplicity.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,14 @@ FUZZ_TARGET_INIT(simplicity, initialize_simplicity)
204204
PrecomputedTransactionData txdata{GENESIS_HASH};
205205
std::vector<CTxOut> spent_outs_copy{spent_outs};
206206
txdata.Init(mtx, std::move(spent_outs_copy));
207-
assert(txdata.m_simplicity_tx_data != NULL);
207+
assert(txdata.m_simplicity_tx_data_ptr);
208+
assert(txdata.m_simplicity_tx_data_ptr->m_simplicity_tx_data);
208209

209210
// 4. Main test
210211
unsigned char imr_out[32];
211212
unsigned char *imr = mtx.vin[0].prevout.hash.data()[2] & 2 ? imr_out : NULL;
212213

213-
const transaction* tx = txdata.m_simplicity_tx_data;
214+
const transaction* tx = txdata.m_simplicity_tx_data_ptr->m_simplicity_tx_data;
214215
tapEnv* taproot = simplicity_elements_mallocTapEnv(&simplicityRawTap);
215216
simplicity_elements_execSimplicity(&error, imr, tx, nIn, taproot, GENESIS_HASH.data(), budget, amr, prog_bytes.data(), prog_bytes.size(), wit_bytes.data(), wit_bytes.size());
216217

src/test/fuzz/simplicity_tx.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ FUZZ_TARGET_INIT(simplicity_tx, initialize_simplicity_tx)
217217
// that we will allocate Simplicity data. The check for whether to do this is very
218218
// lax: is this a 34-byte scriptPubKey that starts with OP_1 and does it have a
219219
// nonempty witness.
220-
assert(txdata.m_simplicity_tx_data != NULL);
220+
assert(txdata.m_simplicity_tx_data_ptr);
221+
assert(txdata.m_simplicity_tx_data_ptr->m_simplicity_tx_data);
221222
}
222223

223224
const CTransaction tx{mtx};

0 commit comments

Comments
 (0)