From ef306dd36e3aaf5b3c7d9900e58ed430d35815e8 Mon Sep 17 00:00:00 2001 From: EmelyanenkoK Date: Fri, 14 Jul 2023 15:25:07 +0300 Subject: [PATCH] Patch/fix ub (#724) * Fix input validation in storage-manager and bitstring * Fix potentially dangling pointer missing_library --------- Co-authored-by: SpyCheese --- crypto/common/bitstring.cpp | 8 +++--- crypto/smc-envelope/SmartContract.cpp | 10 +++---- crypto/smc-envelope/SmartContract.h | 2 +- crypto/vm/cells/CellString.cpp | 39 +++++++++++++++++++++++---- crypto/vm/cells/CellString.h | 2 +- crypto/vm/vm.cpp | 2 +- crypto/vm/vm.h | 5 ++-- emulator/emulator-extern.cpp | 12 ++++----- storage/TorrentHeader.hpp | 18 ++++++++++--- tonlib/tonlib/TonlibClient.cpp | 8 +++--- 10 files changed, 73 insertions(+), 33 deletions(-) diff --git a/crypto/common/bitstring.cpp b/crypto/common/bitstring.cpp index aabc6984..c10a4ff3 100644 --- a/crypto/common/bitstring.cpp +++ b/crypto/common/bitstring.cpp @@ -596,7 +596,7 @@ long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, con unsigned char* ptr = buff; const char* rptr = str; while (rptr < str_end) { - int c = *rptr++; + char c = *rptr++; if (c == ' ' || c == '\t') { continue; } @@ -627,14 +627,14 @@ long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, con if (cmpl && bits) { int t = (hex_digits_count & 1) ? (0x100 + *ptr) >> 4 : (0x100 + *--ptr); while (bits > 0) { + if (t == 1) { + t = 0x100 + *--ptr; + } --bits; if (t & 1) { break; } t >>= 1; - if (t == 1) { - t = 0x100 + *--ptr; - } } } return bits; diff --git a/crypto/smc-envelope/SmartContract.cpp b/crypto/smc-envelope/SmartContract.cpp index 7dbb65e7..64e26944 100644 --- a/crypto/smc-envelope/SmartContract.cpp +++ b/crypto/smc-envelope/SmartContract.cpp @@ -246,10 +246,10 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref actions; td::int32 code; td::int64 gas_used; - td::ConstBitPtr missing_library{0}; + td::optional missing_library; std::string vm_log; static int output_actions_count(td::Ref list); }; diff --git a/crypto/vm/cells/CellString.cpp b/crypto/vm/cells/CellString.cpp index b4738f88..474bc797 100644 --- a/crypto/vm/cells/CellString.cpp +++ b/crypto/vm/cells/CellString.cpp @@ -142,28 +142,57 @@ td::Ref CellText::do_store(td::BitSlice slice) { } template -void CellText::for_each(F &&f, CellSlice cs) { +td::Status CellText::for_each(F &&f, CellSlice cs) { + if (!cs.have(8)) { + return td::Status::Error("Cell underflow"); + } auto depth = cs.fetch_ulong(8); + if (depth > max_chain_length) { + return td::Status::Error("Too deep string"); + } for (td::uint32 i = 0; i < depth; i++) { - auto size = cs.fetch_ulong(8); - f(cs.fetch_bits(td::narrow_cast(size) * 8)); + if (!cs.have(8)) { + return td::Status::Error("Cell underflow"); + } + auto size = td::narrow_cast(cs.fetch_ulong(8)); + if (!cs.have(size * 8)) { + return td::Status::Error("Cell underflow"); + } + TRY_STATUS(f(cs.fetch_bits(size * 8))); if (i + 1 < depth) { + if (!cs.have_refs()) { + return td::Status::Error("Cell underflow"); + } cs = vm::load_cell_slice(cs.prefetch_ref()); } } + return td::Status::OK(); } td::Result CellText::load(CellSlice &cs) { unsigned int size = 0; - for_each([&](auto slice) { size += slice.size(); }, cs); + TRY_STATUS(for_each( + [&](auto slice) { + size += slice.size(); + if (size > max_bytes * 8) { + return td::Status::Error("String is too long"); + } + return td::Status::OK(); + }, + cs)); if (size % 8 != 0) { return td::Status::Error("Size is not divisible by 8"); } std::string res(size / 8, 0); td::BitPtr to(td::MutableSlice(res).ubegin()); - for_each([&](auto slice) { to.concat(slice); }, cs); + TRY_STATUS(for_each( + [&](auto slice) { + to.concat(slice); + return td::Status::OK(); + }, + cs)); CHECK(to.offs == (int)size); return res; } diff --git a/crypto/vm/cells/CellString.h b/crypto/vm/cells/CellString.h index 78b63f35..10bd89aa 100644 --- a/crypto/vm/cells/CellString.h +++ b/crypto/vm/cells/CellString.h @@ -52,7 +52,7 @@ class CellText { private: template - static void for_each(F &&f, CellSlice cs); + static td::Status for_each(F &&f, CellSlice cs); static td::Ref do_store(td::BitSlice slice); }; diff --git a/crypto/vm/vm.cpp b/crypto/vm/vm.cpp index 630f4991..4d3e67af 100644 --- a/crypto/vm/vm.cpp +++ b/crypto/vm/vm.cpp @@ -633,7 +633,7 @@ Ref VmState::load_library(td::ConstBitPtr hash) { return lib; } } - missing_library = hash; + missing_library = td::Bits256{hash}; return {}; } diff --git a/crypto/vm/vm.h b/crypto/vm/vm.h index 6fd1797c..e3fda318 100644 --- a/crypto/vm/vm.h +++ b/crypto/vm/vm.h @@ -25,6 +25,7 @@ #include "vm/log.h" #include "vm/continuation.h" #include "td/utils/HashSet.h" +#include "td/utils/optional.h" namespace vm { @@ -97,7 +98,7 @@ class VmState final : public VmStateInterface { td::HashSet loaded_cells; int stack_trace{0}, debug_off{0}; bool chksig_always_succeed{false}; - td::ConstBitPtr missing_library{0}; + td::optional missing_library; td::uint16 max_data_depth = 512; // Default value int global_version{0}; size_t chksgn_counter = 0; @@ -383,7 +384,7 @@ class VmState final : public VmStateInterface { Ref ref_to_cont(Ref cell) const { return td::make_ref(load_cell_slice_ref(std::move(cell)), get_cp()); } - td::ConstBitPtr get_missing_library() const { + td::optional get_missing_library() const { return missing_library; } void set_max_data_depth(td::uint16 depth) { diff --git a/emulator/emulator-extern.cpp b/emulator/emulator-extern.cpp index 885286d5..3a439831 100644 --- a/emulator/emulator-extern.cpp +++ b/emulator/emulator-extern.cpp @@ -522,10 +522,10 @@ const char *tvm_emulator_run_get_method(void *tvm_emulator, int method_id, const json_obj("gas_used", std::to_string(result.gas_used)); json_obj("vm_exit_code", result.code); json_obj("vm_log", result.vm_log); - if (result.missing_library.is_null()) { + if (!result.missing_library) { json_obj("missing_library", td::JsonNull()); } else { - json_obj("missing_library", td::Bits256(result.missing_library).to_hex()); + json_obj("missing_library", result.missing_library.value().to_hex()); } json_obj.leave(); @@ -548,10 +548,10 @@ const char *tvm_emulator_send_external_message(void *tvm_emulator, const char *m json_obj("vm_exit_code", result.code); json_obj("accepted", td::JsonBool(result.accepted)); json_obj("vm_log", result.vm_log); - if (result.missing_library.is_null()) { + if (!result.missing_library) { json_obj("missing_library", td::JsonNull()); } else { - json_obj("missing_library", td::Bits256(result.missing_library).to_hex()); + json_obj("missing_library", result.missing_library.value().to_hex()); } if (result.actions.is_null()) { json_obj("actions", td::JsonNull()); @@ -581,10 +581,10 @@ const char *tvm_emulator_send_internal_message(void *tvm_emulator, const char *m json_obj("vm_exit_code", result.code); json_obj("accepted", td::JsonBool(result.accepted)); json_obj("vm_log", result.vm_log); - if (result.missing_library.is_null()) { + if (!result.missing_library) { json_obj("missing_library", td::JsonNull()); } else { - json_obj("missing_library", td::Bits256(result.missing_library).to_hex()); + json_obj("missing_library", result.missing_library.value().to_hex()); } if (result.actions.is_null()) { json_obj("actions", td::JsonNull()); diff --git a/storage/TorrentHeader.hpp b/storage/TorrentHeader.hpp index d8f8f719..15b2d8b9 100644 --- a/storage/TorrentHeader.hpp +++ b/storage/TorrentHeader.hpp @@ -68,13 +68,23 @@ void TorrentHeader::parse(ParserT &parser) { parser.set_error("Unknown fec type"); return; } - name_index.resize(files_count); - for (auto &x : name_index) { + name_index.clear(); + for (size_t i = 0; i < files_count; ++i) { + td::uint64 x; parse(x, parser); + if (parser.get_error()) { + return; + } + name_index.push_back(x); } - data_index.resize(files_count); - for (auto &x : data_index) { + data_index.clear(); + for (size_t i = 0; i < files_count; ++i) { + td::uint64 x; parse(x, parser); + if (parser.get_error()) { + return; + } + data_index.push_back(x); } names = parser.template fetch_string_raw(tot_names_size); } diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index 816c6868..c571cf65 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -4552,12 +4552,12 @@ void TonlibClient::perform_smc_execution(td::Ref smc, ton::S } auto res_stack = R.move_as_ok(); - if (res.missing_library.not_null()) { - td::Bits256 hash = res.missing_library; + if (res.missing_library) { + td::Bits256 hash = res.missing_library.value(); LOG(DEBUG) << "Requesting missing library: " << hash.to_hex(); - std::vector req = {std::move(hash)}; + std::vector req = {hash}; client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(req)), - [self = this, res = std::move(res), res_stack = std::move(res_stack), hash = std::move(hash), + [self = this, res = std::move(res), res_stack = std::move(res_stack), hash, smc = std::move(smc), args = std::move(args), promise = std::move(promise)] (td::Result> r_libraries) mutable {