1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

Patch/fix ub (#724)

* Fix input validation in storage-manager and bitstring

* Fix potentially dangling pointer missing_library

---------

Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
EmelyanenkoK 2023-07-14 15:25:07 +03:00 committed by GitHub
parent 9b34217bf0
commit ef306dd36e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 73 additions and 33 deletions

View file

@ -596,7 +596,7 @@ long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, con
unsigned char* ptr = buff; unsigned char* ptr = buff;
const char* rptr = str; const char* rptr = str;
while (rptr < str_end) { while (rptr < str_end) {
int c = *rptr++; char c = *rptr++;
if (c == ' ' || c == '\t') { if (c == ' ' || c == '\t') {
continue; continue;
} }
@ -627,14 +627,14 @@ long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, con
if (cmpl && bits) { if (cmpl && bits) {
int t = (hex_digits_count & 1) ? (0x100 + *ptr) >> 4 : (0x100 + *--ptr); int t = (hex_digits_count & 1) ? (0x100 + *ptr) >> 4 : (0x100 + *--ptr);
while (bits > 0) { while (bits > 0) {
if (t == 1) {
t = 0x100 + *--ptr;
}
--bits; --bits;
if (t & 1) { if (t & 1) {
break; break;
} }
t >>= 1; t >>= 1;
if (t == 1) {
t = 0x100 + *--ptr;
}
} }
} }
return bits; return bits;

View file

@ -246,10 +246,10 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
LOG(DEBUG) << "VM accepted: " << res.accepted; LOG(DEBUG) << "VM accepted: " << res.accepted;
LOG(DEBUG) << "VM success: " << res.success; LOG(DEBUG) << "VM success: " << res.success;
} }
td::ConstBitPtr mlib = vm.get_missing_library(); auto mlib = vm.get_missing_library();
if (!mlib.is_null()) { if (mlib) {
LOG(DEBUG) << "Missing library: " << mlib.to_hex(256); LOG(DEBUG) << "Missing library: " << mlib.value().to_hex();
res.missing_library = mlib; res.missing_library = mlib.value();
} }
if (res.success) { if (res.success) {
res.new_state.data = vm.get_c4(); res.new_state.data = vm.get_c4();
@ -257,7 +257,7 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
LOG(DEBUG) << "output actions:\n" LOG(DEBUG) << "output actions:\n"
<< block::gen::OutList{res.output_actions_count(res.actions)}.as_string_ref(res.actions); << block::gen::OutList{res.output_actions_count(res.actions)}.as_string_ref(res.actions);
} }
LOG_IF(ERROR, gas_credit != 0 && (res.accepted && !res.success) && mlib.is_null()) LOG_IF(ERROR, gas_credit != 0 && (res.accepted && !res.success) && !mlib)
<< "Accepted but failed with code " << res.code << "\n" << "Accepted but failed with code " << res.code << "\n"
<< res.gas_used << "\n"; << res.gas_used << "\n";
return res; return res;

View file

@ -49,7 +49,7 @@ class SmartContract : public td::CntObject {
td::Ref<vm::Cell> actions; td::Ref<vm::Cell> actions;
td::int32 code; td::int32 code;
td::int64 gas_used; td::int64 gas_used;
td::ConstBitPtr missing_library{0}; td::optional<td::Bits256> missing_library;
std::string vm_log; std::string vm_log;
static int output_actions_count(td::Ref<vm::Cell> list); static int output_actions_count(td::Ref<vm::Cell> list);
}; };

View file

@ -142,28 +142,57 @@ td::Ref<vm::Cell> CellText::do_store(td::BitSlice slice) {
} }
template <class F> template <class F>
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); 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++) { for (td::uint32 i = 0; i < depth; i++) {
auto size = cs.fetch_ulong(8); if (!cs.have(8)) {
f(cs.fetch_bits(td::narrow_cast<int>(size) * 8)); return td::Status::Error("Cell underflow");
}
auto size = td::narrow_cast<int>(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 (i + 1 < depth) {
if (!cs.have_refs()) {
return td::Status::Error("Cell underflow");
}
cs = vm::load_cell_slice(cs.prefetch_ref()); cs = vm::load_cell_slice(cs.prefetch_ref());
} }
} }
return td::Status::OK();
} }
td::Result<td::string> CellText::load(CellSlice &cs) { td::Result<td::string> CellText::load(CellSlice &cs) {
unsigned int size = 0; 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) { if (size % 8 != 0) {
return td::Status::Error("Size is not divisible by 8"); return td::Status::Error("Size is not divisible by 8");
} }
std::string res(size / 8, 0); std::string res(size / 8, 0);
td::BitPtr to(td::MutableSlice(res).ubegin()); 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); CHECK(to.offs == (int)size);
return res; return res;
} }

View file

@ -52,7 +52,7 @@ class CellText {
private: private:
template <class F> template <class F>
static void for_each(F &&f, CellSlice cs); static td::Status for_each(F &&f, CellSlice cs);
static td::Ref<vm::Cell> do_store(td::BitSlice slice); static td::Ref<vm::Cell> do_store(td::BitSlice slice);
}; };

View file

@ -633,7 +633,7 @@ Ref<Cell> VmState::load_library(td::ConstBitPtr hash) {
return lib; return lib;
} }
} }
missing_library = hash; missing_library = td::Bits256{hash};
return {}; return {};
} }

View file

@ -25,6 +25,7 @@
#include "vm/log.h" #include "vm/log.h"
#include "vm/continuation.h" #include "vm/continuation.h"
#include "td/utils/HashSet.h" #include "td/utils/HashSet.h"
#include "td/utils/optional.h"
namespace vm { namespace vm {
@ -97,7 +98,7 @@ class VmState final : public VmStateInterface {
td::HashSet<CellHash> loaded_cells; td::HashSet<CellHash> loaded_cells;
int stack_trace{0}, debug_off{0}; int stack_trace{0}, debug_off{0};
bool chksig_always_succeed{false}; bool chksig_always_succeed{false};
td::ConstBitPtr missing_library{0}; td::optional<td::Bits256> missing_library;
td::uint16 max_data_depth = 512; // Default value td::uint16 max_data_depth = 512; // Default value
int global_version{0}; int global_version{0};
size_t chksgn_counter = 0; size_t chksgn_counter = 0;
@ -383,7 +384,7 @@ class VmState final : public VmStateInterface {
Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const { Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const {
return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp()); return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp());
} }
td::ConstBitPtr get_missing_library() const { td::optional<td::Bits256> get_missing_library() const {
return missing_library; return missing_library;
} }
void set_max_data_depth(td::uint16 depth) { void set_max_data_depth(td::uint16 depth) {

View file

@ -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("gas_used", std::to_string(result.gas_used));
json_obj("vm_exit_code", result.code); json_obj("vm_exit_code", result.code);
json_obj("vm_log", result.vm_log); json_obj("vm_log", result.vm_log);
if (result.missing_library.is_null()) { if (!result.missing_library) {
json_obj("missing_library", td::JsonNull()); json_obj("missing_library", td::JsonNull());
} else { } 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(); 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("vm_exit_code", result.code);
json_obj("accepted", td::JsonBool(result.accepted)); json_obj("accepted", td::JsonBool(result.accepted));
json_obj("vm_log", result.vm_log); json_obj("vm_log", result.vm_log);
if (result.missing_library.is_null()) { if (!result.missing_library) {
json_obj("missing_library", td::JsonNull()); json_obj("missing_library", td::JsonNull());
} else { } 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()) { if (result.actions.is_null()) {
json_obj("actions", td::JsonNull()); 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("vm_exit_code", result.code);
json_obj("accepted", td::JsonBool(result.accepted)); json_obj("accepted", td::JsonBool(result.accepted));
json_obj("vm_log", result.vm_log); json_obj("vm_log", result.vm_log);
if (result.missing_library.is_null()) { if (!result.missing_library) {
json_obj("missing_library", td::JsonNull()); json_obj("missing_library", td::JsonNull());
} else { } 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()) { if (result.actions.is_null()) {
json_obj("actions", td::JsonNull()); json_obj("actions", td::JsonNull());

View file

@ -68,13 +68,23 @@ void TorrentHeader::parse(ParserT &parser) {
parser.set_error("Unknown fec type"); parser.set_error("Unknown fec type");
return; return;
} }
name_index.resize(files_count); name_index.clear();
for (auto &x : name_index) { for (size_t i = 0; i < files_count; ++i) {
td::uint64 x;
parse(x, parser); parse(x, parser);
if (parser.get_error()) {
return;
}
name_index.push_back(x);
} }
data_index.resize(files_count); data_index.clear();
for (auto &x : data_index) { for (size_t i = 0; i < files_count; ++i) {
td::uint64 x;
parse(x, parser); parse(x, parser);
if (parser.get_error()) {
return;
}
data_index.push_back(x);
} }
names = parser.template fetch_string_raw<std::string>(tot_names_size); names = parser.template fetch_string_raw<std::string>(tot_names_size);
} }

View file

@ -4552,12 +4552,12 @@ void TonlibClient::perform_smc_execution(td::Ref<ton::SmartContract> smc, ton::S
} }
auto res_stack = R.move_as_ok(); auto res_stack = R.move_as_ok();
if (res.missing_library.not_null()) { if (res.missing_library) {
td::Bits256 hash = res.missing_library; td::Bits256 hash = res.missing_library.value();
LOG(DEBUG) << "Requesting missing library: " << hash.to_hex(); LOG(DEBUG) << "Requesting missing library: " << hash.to_hex();
std::vector<td::Bits256> req = {std::move(hash)}; std::vector<td::Bits256> req = {hash};
client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(req)), 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)] smc = std::move(smc), args = std::move(args), promise = std::move(promise)]
(td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable (td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
{ {