check accessing an element past the end of a container

This commit is contained in:
moneromooo-monero 2017-12-12 11:08:11 +00:00
parent 2305bf260d
commit b49ddc766d
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
8 changed files with 46 additions and 12 deletions

View file

@ -259,7 +259,7 @@ namespace cryptonote
ar.tag("rctsig_prunable"); ar.tag("rctsig_prunable");
ar.begin_object(); ar.begin_object();
r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(), r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(),
vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(vin[0]).key_offsets.size() - 1 : 0); vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(vin[0]).key_offsets.size() - 1 : 0);
if (!r || !ar.stream().good()) return false; if (!r || !ar.stream().good()) return false;
ar.end_object(); ar.end_object();
} }

View file

@ -2338,7 +2338,7 @@ void Blockchain::on_new_tx_from_block(const cryptonote::transaction &tx)
TIME_MEASURE_FINISH(a); TIME_MEASURE_FINISH(a);
if(m_show_time_stats) if(m_show_time_stats)
{ {
size_t ring_size = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0; size_t ring_size = !tx.vin.empty() && tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a); MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a);
} }
} }
@ -2373,7 +2373,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_heigh
TIME_MEASURE_FINISH(a); TIME_MEASURE_FINISH(a);
if(m_show_time_stats) if(m_show_time_stats)
{ {
size_t ring_size = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0; size_t ring_size = !tx.vin.empty() && tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx)); MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx));
} }
if (!res) if (!res)
@ -2466,6 +2466,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
// mixRing - full and simple store it in opposite ways // mixRing - full and simple store it in opposite ways
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof) if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
{ {
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys[0].size()); rv.mixRing.resize(pubkeys[0].size());
for (size_t m = 0; m < pubkeys[0].size(); ++m) for (size_t m = 0; m < pubkeys[0].size(); ++m)
rv.mixRing[m].clear(); rv.mixRing[m].clear();
@ -2480,6 +2481,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
} }
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeSimpleBulletproof) else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeSimpleBulletproof)
{ {
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys.size()); rv.mixRing.resize(pubkeys.size());
for (size_t n = 0; n < pubkeys.size(); ++n) for (size_t n = 0; n < pubkeys.size(); ++n)
{ {
@ -2811,7 +2813,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
} }
for (size_t n = 0; n < tx.vin.size(); ++n) for (size_t n = 0; n < tx.vin.size(); ++n)
{ {
if (memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32)) if (rv.p.MGs[n].II.empty() || memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32))
{ {
MERROR_VER("Failed to check ringct signatures: mismatched key image"); MERROR_VER("Failed to check ringct signatures: mismatched key image");
return false; return false;
@ -2864,7 +2866,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
MERROR_VER("Failed to check ringct signatures: Bad MGs size"); MERROR_VER("Failed to check ringct signatures: Bad MGs size");
return false; return false;
} }
if (rv.p.MGs[0].II.size() != tx.vin.size()) if (rv.p.MGs.empty() || rv.p.MGs[0].II.size() != tx.vin.size())
{ {
MERROR_VER("Failed to check ringct signatures: mismatched II/vin sizes"); MERROR_VER("Failed to check ringct signatures: mismatched II/vin sizes");
return false; return false;

View file

@ -190,6 +190,12 @@ namespace cryptonote
//--------------------------------------------------------------- //---------------------------------------------------------------
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout) bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
{ {
if (sources.empty())
{
LOG_ERROR("Empty sources");
return false;
}
std::vector<rct::key> amount_keys; std::vector<rct::key> amount_keys;
tx.set_null(); tx.set_null();
amount_keys.clear(); amount_keys.clear();

View file

@ -76,6 +76,7 @@ namespace rct {
//Generates a vector of secret key //Generates a vector of secret key
//Mainly used in testing //Mainly used in testing
keyV skvGen(size_t rows ) { keyV skvGen(size_t rows ) {
CHECK_AND_ASSERT_THROW_MES(rows > 0, "0 keys requested");
keyV rv(rows); keyV rv(rows);
size_t i = 0; size_t i = 0;
crypto::rand(rows * sizeof(key), (uint8_t*)&rv[0]); crypto::rand(rows * sizeof(key), (uint8_t*)&rv[0]);
@ -351,6 +352,7 @@ namespace rct {
//This takes the outputs and commitments //This takes the outputs and commitments
//and hashes them into a 32 byte sized key //and hashes them into a 32 byte sized key
key cn_fast_hash(const ctkeyV &PC) { key cn_fast_hash(const ctkeyV &PC) {
if (PC.empty()) return rct::hash2rct(crypto::cn_fast_hash("", 0));
key rv; key rv;
cn_fast_hash(rv, &PC[0], 64*PC.size()); cn_fast_hash(rv, &PC[0], 64*PC.size());
return rv; return rv;
@ -367,6 +369,7 @@ namespace rct {
//put them in the key vector and it concatenates them //put them in the key vector and it concatenates them
//and then hashes them //and then hashes them
key cn_fast_hash(const keyV &keys) { key cn_fast_hash(const keyV &keys) {
if (keys.empty()) return rct::hash2rct(crypto::cn_fast_hash("", 0));
key rv; key rv;
cn_fast_hash(rv, &keys[0], keys.size() * sizeof(keys[0])); cn_fast_hash(rv, &keys[0], keys.size() * sizeof(keys[0]));
//dp(rv); //dp(rv);

View file

@ -293,6 +293,10 @@ std::vector<std::string> UnsignedTransactionImpl::recipientAddress() const
// TODO: return integrated address if short payment ID exists // TODO: return integrated address if short payment ID exists
std::vector<string> result; std::vector<string> result;
for (const auto &utx: m_unsigned_tx_set.txes) { for (const auto &utx: m_unsigned_tx_set.txes) {
if (utx.dests.empty()) {
MERROR("empty destinations, skipped");
continue;
}
result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->testnet(), utx.dests[0].is_subaddress, utx.dests[0].addr)); result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->testnet(), utx.dests[0].is_subaddress, utx.dests[0].addr));
} }
return result; return result;

View file

@ -540,6 +540,11 @@ crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx)
{ {
if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
{ {
if (ptx.dests.empty())
{
MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt");
return crypto::null_hash8;
}
decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key); decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key);
} }
} }
@ -4050,6 +4055,11 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const
crypto::hash8 payment_id8 = null_hash8; crypto::hash8 payment_id8 = null_hash8;
if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
{ {
if (ptx.dests.empty())
{
MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt");
return crypto::null_hash;
}
if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key)) if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key))
{ {
memcpy(payment_id.data, payment_id8.data, 8); memcpy(payment_id.data, payment_id8.data, 8);
@ -4274,6 +4284,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
for (size_t n = 0; n < exported_txs.txes.size(); ++n) for (size_t n = 0; n < exported_txs.txes.size(); ++n)
{ {
tools::wallet2::tx_construction_data &sd = exported_txs.txes[n]; tools::wallet2::tx_construction_data &sd = exported_txs.txes[n];
THROW_WALLET_EXCEPTION_IF(sd.sources.empty(), error::wallet_internal_error, "Empty sources");
LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size()); LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
signed_txes.ptx.push_back(pending_tx()); signed_txes.ptx.push_back(pending_tx());
tools::wallet2::pending_tx &ptx = signed_txes.ptx.back(); tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
@ -6637,7 +6648,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Made a " << ((txBlob.size() + 1023) / 1024) << " kB tx, with " << print_money(available_for_fee) << " available for fee (" << LOG_PRINT_L2("Made a " << ((txBlob.size() + 1023) / 1024) << " kB tx, with " << print_money(available_for_fee) << " available for fee (" <<
print_money(needed_fee) << " needed)"); print_money(needed_fee) << " needed)");
if (needed_fee > available_for_fee && dsts[0].amount > 0) if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0)
{ {
// we don't have enough for the fee, but we've only partially paid the current address, // we don't have enough for the fee, but we've only partially paid the current address,
// so we can take the fee from the paid amount, since we'll have to make another tx anyway // so we can take the fee from the paid amount, since we'll have to make another tx anyway
@ -8912,6 +8923,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
throw std::runtime_error(oss.str()); throw std::runtime_error(oss.str());
} }
cryptonote::block blk_min, blk_mid, blk_max; cryptonote::block blk_min, blk_mid, blk_max;
if (res.blocks.size() < 3) throw std::runtime_error("Not enough blocks returned from daemon");
if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_min)); if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_min));
if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_mid)); if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_mid));
if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_max)); if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_max));

View file

@ -486,7 +486,7 @@ namespace tools
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er) bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er)
{ {
crypto::hash8 integrated_payment_id = crypto::null_hash8; crypto::hash8 integrated_payment_id = crypto::null_hash8;
std::string extra_nonce; std::string extra_nonce;
@ -541,6 +541,13 @@ namespace tools
} }
} }
if (at_least_one_destination && dsts.empty())
{
er.code = WALLET_RPC_ERROR_CODE_ZERO_DESTINATION;
er.message = "No destinations for this transfer";
return false;
}
if (!payment_id.empty()) if (!payment_id.empty())
{ {
@ -592,7 +599,7 @@ namespace tools
} }
// validate the transfer requested and populate dsts & extra // validate the transfer requested and populate dsts & extra
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er)) if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er))
{ {
return false; return false;
} }
@ -690,7 +697,7 @@ namespace tools
} }
// validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types. // validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types.
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er)) if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er))
{ {
return false; return false;
} }
@ -887,7 +894,7 @@ namespace tools
destination.push_back(wallet_rpc::transfer_destination()); destination.push_back(wallet_rpc::transfer_destination());
destination.back().amount = 0; destination.back().amount = 0;
destination.back().address = req.address; destination.back().address = req.address;
if (!validate_transfer(destination, req.payment_id, dsts, extra, er)) if (!validate_transfer(destination, req.payment_id, dsts, extra, true, er))
{ {
return false; return false;
} }
@ -986,7 +993,7 @@ namespace tools
destination.push_back(wallet_rpc::transfer_destination()); destination.push_back(wallet_rpc::transfer_destination());
destination.back().amount = 0; destination.back().amount = 0;
destination.back().address = req.address; destination.back().address = req.address;
if (!validate_transfer(destination, req.payment_id, dsts, extra, er)) if (!validate_transfer(destination, req.payment_id, dsts, extra, true, er))
{ {
return false; return false;
} }

View file

@ -137,7 +137,7 @@ namespace tools
bool on_create_account(const wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::response& res, epee::json_rpc::error& er); bool on_create_account(const wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::response& res, epee::json_rpc::error& er);
bool on_label_account(const wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::response& res, epee::json_rpc::error& er); bool on_label_account(const wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::response& res, epee::json_rpc::error& er);
bool on_getheight(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res, epee::json_rpc::error& er); bool on_getheight(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res, epee::json_rpc::error& er);
bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er); bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er);
bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er); bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er);
bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er); bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er);
bool on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er); bool on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er);