mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
add sto APIs
This commit is contained in:
@@ -2993,207 +2993,6 @@ DEFINE_HOOK_FUNCTION(
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
|
||||
// these are only used by get_stobject_length below
|
||||
enum parse_error : int32_t {
|
||||
pe_unexpected_end = -1,
|
||||
pe_unknown_type_early = -2, // detected early
|
||||
pe_unknown_type_late = -3, // end of function
|
||||
pe_excessive_nesting = -4,
|
||||
pe_excessive_size = -5
|
||||
};
|
||||
|
||||
// RH NOTE this is a light-weight stobject parsing function for drilling into a
|
||||
// provided serialzied object however it could probably be replaced by an
|
||||
// existing class or routine or set of routines in XRPLD Returns object length
|
||||
// including header bytes (and footer bytes in the event of array or object)
|
||||
// negative indicates error
|
||||
inline int32_t
|
||||
get_stobject_length(
|
||||
unsigned char* start, // in - begin iterator
|
||||
unsigned char* maxptr, // in - end iterator
|
||||
int& type, // out - populated by serialized type code
|
||||
int& field, // out - populated by serialized field code
|
||||
int& payload_start, // out - the start of actual payload data for this type
|
||||
int& payload_length, // out - the length of actual payload data for this
|
||||
// type
|
||||
int recursion_depth = 0) // used internally
|
||||
{
|
||||
if (recursion_depth > 10)
|
||||
return pe_excessive_nesting;
|
||||
|
||||
unsigned char* end = maxptr;
|
||||
unsigned char* upto = start;
|
||||
int high = *upto >> 4;
|
||||
int low = *upto & 0xF;
|
||||
|
||||
upto++;
|
||||
if (upto >= end)
|
||||
return pe_unexpected_end;
|
||||
if (high > 0 && low > 0)
|
||||
{
|
||||
// common type common field
|
||||
type = high;
|
||||
field = low;
|
||||
}
|
||||
else if (high > 0)
|
||||
{
|
||||
// common type, uncommon field
|
||||
type = high;
|
||||
field = *upto++;
|
||||
}
|
||||
else if (low > 0)
|
||||
{
|
||||
// common field, uncommon type
|
||||
field = low;
|
||||
type = *upto++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// uncommon type and field
|
||||
type = *upto++;
|
||||
if (upto >= end)
|
||||
return pe_unexpected_end;
|
||||
field = *upto++;
|
||||
}
|
||||
|
||||
DBG_PRINTF(
|
||||
"%d get_st_object found field %d type %d\n",
|
||||
recursion_depth,
|
||||
field,
|
||||
type);
|
||||
|
||||
if (upto >= end)
|
||||
return pe_unexpected_end;
|
||||
|
||||
// RH TODO: link this to rippled's internal STObject constants
|
||||
// E.g.:
|
||||
/*
|
||||
int field_code = (safe_cast<int>(type) << 16) | field;
|
||||
auto const& fieldObj = ripple::SField::getField;
|
||||
*/
|
||||
|
||||
if (type < 1 || type > 19 || (type >= 9 && type <= 13))
|
||||
return pe_unknown_type_early;
|
||||
|
||||
bool is_vl = (type == 8 /*ACCID*/ || type == 7 || type == 18 || type == 19);
|
||||
|
||||
int length = -1;
|
||||
if (is_vl)
|
||||
{
|
||||
length = *upto++;
|
||||
if (upto >= end)
|
||||
return pe_unexpected_end;
|
||||
|
||||
if (length < 193)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if (length > 192 && length < 241)
|
||||
{
|
||||
length -= 193;
|
||||
length *= 256;
|
||||
length += *upto++ + 193;
|
||||
if (upto > end)
|
||||
return pe_unexpected_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
int b2 = *upto++;
|
||||
if (upto >= end)
|
||||
return pe_unexpected_end;
|
||||
length -= 241;
|
||||
length *= 65536;
|
||||
length += 12481 + (b2 * 256) + *upto++;
|
||||
if (upto >= end)
|
||||
return pe_unexpected_end;
|
||||
}
|
||||
}
|
||||
else if ((type >= 1 && type <= 5) || type == 16 || type == 17)
|
||||
{
|
||||
length =
|
||||
(type == 1
|
||||
? 2
|
||||
: (type == 2
|
||||
? 4
|
||||
: (type == 3
|
||||
? 8
|
||||
: (type == 4
|
||||
? 16
|
||||
: (type == 5
|
||||
? 32
|
||||
: (type == 16
|
||||
? 1
|
||||
: (type == 17 ? 20
|
||||
: -1)))))));
|
||||
}
|
||||
else if (type == 6) /* AMOUNT */
|
||||
{
|
||||
length = (*upto >> 6 == 1) ? 8 : 48;
|
||||
if (upto >= end)
|
||||
return pe_unexpected_end;
|
||||
}
|
||||
|
||||
if (length > -1)
|
||||
{
|
||||
payload_start = upto - start;
|
||||
payload_length = length;
|
||||
DBG_PRINTF(
|
||||
"%d get_stobject_length field: %d Type: %d VL: %s Len: %d "
|
||||
"Payload_Start: %d Payload_Len: %d\n",
|
||||
recursion_depth,
|
||||
field,
|
||||
type,
|
||||
(is_vl ? "yes" : "no"),
|
||||
length,
|
||||
payload_start,
|
||||
payload_length);
|
||||
return length + (upto - start);
|
||||
}
|
||||
|
||||
if (type == 15 || type == 14) /* Object / Array */
|
||||
{
|
||||
payload_start = upto - start;
|
||||
|
||||
for (int i = 0; i < 1024; ++i)
|
||||
{
|
||||
int subfield = -1, subtype = -1, payload_start_ = -1,
|
||||
payload_length_ = -1;
|
||||
int32_t sublength = get_stobject_length(
|
||||
upto,
|
||||
end,
|
||||
subtype,
|
||||
subfield,
|
||||
payload_start_,
|
||||
payload_length_,
|
||||
recursion_depth + 1);
|
||||
DBG_PRINTF(
|
||||
"%d get_stobject_length i %d %d-%d, upto %d sublength %d\n",
|
||||
recursion_depth,
|
||||
i,
|
||||
subtype,
|
||||
subfield,
|
||||
upto - start,
|
||||
sublength);
|
||||
if (sublength < 0)
|
||||
return pe_unexpected_end;
|
||||
upto += sublength;
|
||||
if (upto >= end)
|
||||
return pe_unexpected_end;
|
||||
|
||||
if ((*upto == 0xE1U && type == 0xEU) ||
|
||||
(*upto == 0xF1U && type == 0xFU))
|
||||
{
|
||||
payload_length = upto - start - payload_start;
|
||||
upto++;
|
||||
return (upto - start);
|
||||
}
|
||||
}
|
||||
return pe_excessive_size;
|
||||
}
|
||||
|
||||
return pe_unknown_type_late;
|
||||
}
|
||||
|
||||
// Given an serialized object in memory locate and return the offset and length
|
||||
// of the payload of a subfield of that object. Arrays are returned fully
|
||||
// formed. If successful returns offset and length joined as int64_t. Use
|
||||
@@ -3211,58 +3010,13 @@ DEFINE_HOOK_FUNCTION(
|
||||
if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
|
||||
return OUT_OF_BOUNDS;
|
||||
|
||||
if (read_len < 2)
|
||||
return TOO_SMALL;
|
||||
|
||||
unsigned char* start = (unsigned char*)(memory + read_ptr);
|
||||
unsigned char* upto = start;
|
||||
unsigned char* end = start + read_len;
|
||||
|
||||
DBG_PRINTF(
|
||||
"sto_subfield called, looking for field %u type %u\n",
|
||||
field_id & 0xFFFF,
|
||||
(field_id >> 16));
|
||||
for (int j = -5; j < 5; ++j)
|
||||
DBG_PRINTF((j == 0 ? " >%02X< " : " %02X "), *(start + j));
|
||||
DBG_PRINTF("\n");
|
||||
|
||||
// if ((*upto & 0xF0) == 0xE0)
|
||||
// upto++;
|
||||
|
||||
for (int i = 0; i < 1024 && upto < end; ++i)
|
||||
{
|
||||
int type = -1, field = -1, payload_start = -1, payload_length = -1;
|
||||
int32_t length = get_stobject_length(
|
||||
upto, end, type, field, payload_start, payload_length, 0);
|
||||
if (length < 0)
|
||||
return PARSE_ERROR;
|
||||
if ((type << 16) + field == field_id)
|
||||
{
|
||||
DBG_PRINTF(
|
||||
"sto_subfield returned for field %u type %u\n",
|
||||
field_id & 0xFFFF,
|
||||
(field_id >> 16));
|
||||
for (int j = -5; j < 5; ++j)
|
||||
DBG_PRINTF((j == 0 ? " [%02X] " : " %02X "), *(upto + j));
|
||||
DBG_PRINTF("\n");
|
||||
|
||||
if (type == 0xF) // we return arrays fully formed
|
||||
return (((int64_t)(upto - start))
|
||||
<< 32) /* start of the object */
|
||||
+ (uint32_t)(length);
|
||||
|
||||
// return pointers to all other objects as payloads
|
||||
return (((int64_t)(upto - start + payload_start))
|
||||
<< 32U) /* start of the object */
|
||||
+ (uint32_t)(payload_length);
|
||||
}
|
||||
upto += length;
|
||||
}
|
||||
|
||||
if (upto != end)
|
||||
return PARSE_ERROR;
|
||||
|
||||
return DOESNT_EXIST;
|
||||
hook::HookAPI api(hookCtx);
|
||||
Bytes data{memory + read_ptr, memory + read_ptr + read_len};
|
||||
auto const result = api.sto_subfield(data, field_id);
|
||||
if (!result)
|
||||
return result.error();
|
||||
auto const& pair = result.value();
|
||||
return (uint64_t(pair.first) << 32U) + (uint32_t)pair.second;
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -3281,56 +3035,13 @@ DEFINE_HOOK_FUNCTION(
|
||||
if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
|
||||
return OUT_OF_BOUNDS;
|
||||
|
||||
if (read_len < 2)
|
||||
return TOO_SMALL;
|
||||
|
||||
unsigned char* start = (unsigned char*)(memory + read_ptr);
|
||||
unsigned char* upto = start;
|
||||
unsigned char* end = start + read_len;
|
||||
|
||||
// unwrap the array if it is wrapped,
|
||||
// by removing a byte from the start and end
|
||||
if ((*upto & 0xF0U) == 0xF0U)
|
||||
{
|
||||
upto++;
|
||||
end--;
|
||||
}
|
||||
|
||||
if (upto >= end)
|
||||
return PARSE_ERROR;
|
||||
|
||||
/*
|
||||
DBG_PRINTF("sto_subarray called, looking for index %u\n", index_id);
|
||||
for (int j = -5; j < 5; ++j)
|
||||
printf(( j == 0 ? " >%02X< " : " %02X "), *(start + j));
|
||||
DBG_PRINTF("\n");
|
||||
*/
|
||||
for (int i = 0; i < 1024 && upto < end; ++i)
|
||||
{
|
||||
int type = -1, field = -1, payload_start = -1, payload_length = -1;
|
||||
int32_t length = get_stobject_length(
|
||||
upto, end, type, field, payload_start, payload_length, 0);
|
||||
if (length < 0)
|
||||
return PARSE_ERROR;
|
||||
|
||||
if (i == index_id)
|
||||
{
|
||||
DBG_PRINTF("sto_subarray returned for index %u\n", index_id);
|
||||
for (int j = -5; j < 5; ++j)
|
||||
DBG_PRINTF(
|
||||
(j == 0 ? " [%02X] " : " %02X "), *(upto + j + length));
|
||||
DBG_PRINTF("\n");
|
||||
|
||||
return (((int64_t)(upto - start)) << 32U) /* start of the object */
|
||||
+ (int64_t)(length);
|
||||
}
|
||||
upto += length;
|
||||
}
|
||||
|
||||
if (upto != end)
|
||||
return PARSE_ERROR;
|
||||
|
||||
return DOESNT_EXIST;
|
||||
hook::HookAPI api(hookCtx);
|
||||
Bytes data{memory + read_ptr, memory + read_ptr + read_len};
|
||||
auto const result = api.sto_subarray(data, index_id);
|
||||
if (!result)
|
||||
return result.error();
|
||||
auto const& pair = result.value();
|
||||
return (uint64_t(pair.first) << 32U) + (uint32_t)pair.second;
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -3526,92 +3237,26 @@ DEFINE_HOOK_FUNCTION(
|
||||
return MEM_OVERLAP;
|
||||
}
|
||||
|
||||
// we must inject the field at the canonical location....
|
||||
// so find that location
|
||||
unsigned char* start = (unsigned char*)(memory + sread_ptr);
|
||||
unsigned char* upto = start;
|
||||
unsigned char* end = start + sread_len;
|
||||
unsigned char* inject_start = end;
|
||||
unsigned char* inject_end = end;
|
||||
hook::HookAPI api(hookCtx);
|
||||
Bytes source{memory + sread_ptr, memory + sread_ptr + sread_len};
|
||||
std::optional<Bytes> field;
|
||||
if (fread_len > 0 && fread_ptr > 0)
|
||||
field = Bytes{memory + fread_ptr, memory + fread_ptr + fread_len};
|
||||
auto const result = api.sto_emplace(source, field, field_id);
|
||||
if (!result)
|
||||
return result.error();
|
||||
auto const& bytes = result.value();
|
||||
|
||||
DBG_PRINTF(
|
||||
"sto_emplace called, looking for field %u type %u\n",
|
||||
field_id & 0xFFFF,
|
||||
(field_id >> 16));
|
||||
for (int j = -5; j < 5; ++j)
|
||||
DBG_PRINTF((j == 0 ? " >%02X< " : " %02X "), *(start + j));
|
||||
DBG_PRINTF("\n");
|
||||
if (bytes.size() > write_len)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
for (int i = 0; i < 1024 && upto < end; ++i)
|
||||
{
|
||||
int type = -1, field = -1, payload_start = -1, payload_length = -1;
|
||||
int32_t length = get_stobject_length(
|
||||
upto, end, type, field, payload_start, payload_length, 0);
|
||||
if (length < 0)
|
||||
return PARSE_ERROR;
|
||||
if ((type << 16) + field == field_id)
|
||||
{
|
||||
inject_start = upto;
|
||||
inject_end = upto + length;
|
||||
break;
|
||||
}
|
||||
else if ((type << 16) + field > field_id)
|
||||
{
|
||||
inject_start = upto;
|
||||
inject_end = upto;
|
||||
break;
|
||||
}
|
||||
upto += length;
|
||||
}
|
||||
|
||||
// if the scan loop ends past the end of the source object
|
||||
// then the source object is invalid/corrupt, so we must
|
||||
// return an error
|
||||
if (upto > end)
|
||||
return PARSE_ERROR;
|
||||
|
||||
// upto is injection point
|
||||
int64_t bytes_written = 0;
|
||||
|
||||
// part 1
|
||||
if (inject_start - start > 0)
|
||||
{
|
||||
WRITE_WASM_MEMORY(
|
||||
bytes_written,
|
||||
write_ptr,
|
||||
write_len,
|
||||
start,
|
||||
(inject_start - start),
|
||||
memory,
|
||||
memory_length);
|
||||
}
|
||||
|
||||
if (fread_len > 0)
|
||||
{
|
||||
// write the field (or don't if it's a delete operation)
|
||||
WRITE_WASM_MEMORY(
|
||||
bytes_written,
|
||||
(write_ptr + bytes_written),
|
||||
(write_len - bytes_written),
|
||||
memory + fread_ptr,
|
||||
fread_len,
|
||||
memory,
|
||||
memory_length);
|
||||
}
|
||||
|
||||
// part 2
|
||||
if (end - inject_end > 0)
|
||||
{
|
||||
WRITE_WASM_MEMORY(
|
||||
bytes_written,
|
||||
(write_ptr + bytes_written),
|
||||
(write_len - bytes_written),
|
||||
inject_end,
|
||||
(end - inject_end),
|
||||
memory,
|
||||
memory_length);
|
||||
}
|
||||
return bytes_written;
|
||||
WRITE_WASM_MEMORY_AND_RETURN(
|
||||
write_ptr,
|
||||
write_len,
|
||||
bytes.data(),
|
||||
bytes.size(),
|
||||
memory,
|
||||
memory_length);
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -3660,24 +3305,12 @@ DEFINE_HOOK_FUNCTION(
|
||||
if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
|
||||
return OUT_OF_BOUNDS;
|
||||
|
||||
if (read_len < 2)
|
||||
return TOO_SMALL;
|
||||
|
||||
unsigned char* start = (unsigned char*)(memory + read_ptr);
|
||||
unsigned char* upto = start;
|
||||
unsigned char* end = start + read_len;
|
||||
|
||||
for (int i = 0; i < 1024 && upto < end; ++i)
|
||||
{
|
||||
int type = -1, field = -1, payload_start = -1, payload_length = -1;
|
||||
int32_t length = get_stobject_length(
|
||||
upto, end, type, field, payload_start, payload_length, 0);
|
||||
if (length < 0)
|
||||
return 0;
|
||||
upto += length;
|
||||
}
|
||||
|
||||
return upto == end ? 1 : 0;
|
||||
Bytes data{read_ptr + memory, read_ptr + read_len + memory};
|
||||
hook::HookAPI api(hookCtx);
|
||||
auto const result = api.sto_validate(data);
|
||||
if (!result)
|
||||
return result.error();
|
||||
return result.value() ? 1 : 0;
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user