mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +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:
parent
9b34217bf0
commit
ef306dd36e
10 changed files with 73 additions and 33 deletions
|
@ -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;
|
||||
|
|
|
@ -246,10 +246,10 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
|||
LOG(DEBUG) << "VM accepted: " << res.accepted;
|
||||
LOG(DEBUG) << "VM success: " << res.success;
|
||||
}
|
||||
td::ConstBitPtr mlib = vm.get_missing_library();
|
||||
if (!mlib.is_null()) {
|
||||
LOG(DEBUG) << "Missing library: " << mlib.to_hex(256);
|
||||
res.missing_library = mlib;
|
||||
auto mlib = vm.get_missing_library();
|
||||
if (mlib) {
|
||||
LOG(DEBUG) << "Missing library: " << mlib.value().to_hex();
|
||||
res.missing_library = mlib.value();
|
||||
}
|
||||
if (res.success) {
|
||||
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"
|
||||
<< 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"
|
||||
<< res.gas_used << "\n";
|
||||
return res;
|
||||
|
|
|
@ -49,7 +49,7 @@ class SmartContract : public td::CntObject {
|
|||
td::Ref<vm::Cell> actions;
|
||||
td::int32 code;
|
||||
td::int64 gas_used;
|
||||
td::ConstBitPtr missing_library{0};
|
||||
td::optional<td::Bits256> missing_library;
|
||||
std::string vm_log;
|
||||
static int output_actions_count(td::Ref<vm::Cell> list);
|
||||
};
|
||||
|
|
|
@ -142,28 +142,57 @@ td::Ref<vm::Cell> CellText::do_store(td::BitSlice slice) {
|
|||
}
|
||||
|
||||
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);
|
||||
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<int>(size) * 8));
|
||||
if (!cs.have(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 (!cs.have_refs()) {
|
||||
return td::Status::Error("Cell underflow");
|
||||
}
|
||||
cs = vm::load_cell_slice(cs.prefetch_ref());
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<td::string> 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;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class CellText {
|
|||
|
||||
private:
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
@ -633,7 +633,7 @@ Ref<Cell> VmState::load_library(td::ConstBitPtr hash) {
|
|||
return lib;
|
||||
}
|
||||
}
|
||||
missing_library = hash;
|
||||
missing_library = td::Bits256{hash};
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CellHash> loaded_cells;
|
||||
int stack_trace{0}, debug_off{0};
|
||||
bool chksig_always_succeed{false};
|
||||
td::ConstBitPtr missing_library{0};
|
||||
td::optional<td::Bits256> 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<OrdCont> ref_to_cont(Ref<Cell> cell) const {
|
||||
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;
|
||||
}
|
||||
void set_max_data_depth(td::uint16 depth) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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<std::string>(tot_names_size);
|
||||
}
|
||||
|
|
|
@ -4552,12 +4552,12 @@ void TonlibClient::perform_smc_execution(td::Ref<ton::SmartContract> 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<td::Bits256> req = {std::move(hash)};
|
||||
std::vector<td::Bits256> 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<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue