Skip to content

Commit

Permalink
fix(ocv2): offset parsing verification
Browse files Browse the repository at this point in the history
  • Loading branch information
loicttn committed Dec 12, 2024
1 parent 0f9bb64 commit 889b5ad
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 8 deletions.
9 changes: 8 additions & 1 deletion src/kiln_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,20 @@ typedef struct {
} v2_request_exit_t;

typedef struct {
uint16_t cask_ids_offset;
// -- utils
uint16_t cask_ids_offset;

uint16_t current_item_count;
} v2_claim_t;

typedef struct {
// -- utils
uint16_t ticket_ids_offset;
uint16_t cask_ids_offset;
uint8_t checksum_preview[CX_KECCAK_256_SIZE];
uint8_t checksum_value[CX_KECCAK_256_SIZE];
uint32_t cached_offset;

uint16_t parent_item_count;
uint16_t current_item_count;
} v2_multiclaim_t;
Expand Down
183 changes: 178 additions & 5 deletions src/provide_parameter/ocv2.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,27 @@ void handle_v2_multiclaim(ethPluginProvideParameter_t *msg, context_t *context)
v2_multiclaim_t *params = &context->param_data.v2_multiclaim;

switch (context->next_param) {
case V2_MULTICLAIM_EXIT_QUEUES_OFFSET:
case V2_MULTICLAIM_EXIT_QUEUES_OFFSET: {
uint16_t offset;
U2BE_from_parameter(msg->parameter, &offset);
if (offset != PARAMETER_LENGTH * 3) {
PRINTF("Malformed calldata, unexpected exitqueues parameter offset %d != %d\n",
offset,
PARAMETER_LENGTH);
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}
context->next_param = V2_MULTICLAIM_TICKET_IDS_OFFSET;
break;
}
case V2_MULTICLAIM_TICKET_IDS_OFFSET:
U2BE_from_parameter(msg->parameter, &params->ticket_ids_offset);
params->ticket_ids_offset += SELECTOR_SIZE;
context->next_param = V2_MULTICLAIM_CASK_IDS_OFFSET;
break;
case V2_MULTICLAIM_CASK_IDS_OFFSET:
U2BE_from_parameter(msg->parameter, &params->cask_ids_offset);
params->cask_ids_offset += SELECTOR_SIZE;
context->next_param = V2_MULTICLAIM_EXIT_QUEUES_LENGTH;
break;
case V2_MULTICLAIM_EXIT_QUEUES_LENGTH:
Expand Down Expand Up @@ -209,50 +223,209 @@ void handle_v2_multiclaim(ethPluginProvideParameter_t *msg, context_t *context)
break;
}
case V2_MULTICLAIM_TICKETIDS_LENGTH:
if (msg->parameterOffset != params->ticket_ids_offset) {
PRINTF("Malformed calldata, unexpected ticketids[X][] parameter offset %d != %d\n",
msg->parameterOffset,
params->ticket_ids_offset);
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

memset(params->checksum_preview, 0, sizeof(params->checksum_preview));
memset(params->checksum_value, 0, sizeof(params->checksum_value));
params->cached_offset = 0;

U2BE_from_parameter(msg->parameter, &params->parent_item_count);
params->current_item_count = params->parent_item_count;

context->next_param = V2_MULTICLAIM_TICKETIDS__OFFSET_ITEMS;
break;
case V2_MULTICLAIM_TICKETIDS__OFFSET_ITEMS:
// ********************************************************************
// TICKETIDS[][]
// ********************************************************************
case V2_MULTICLAIM_TICKETIDS__OFFSET_ITEMS: {
uint16_t offset;
U2BE_from_parameter(msg->parameter, &offset);
// We have limited size on the context and can't store all the offset values
// of the ticketids subarrays. So we compute their checksum and expect to
// be able to recompute it using the offset of the parsed structures later.
// _preview will be equal to _value at the end of the parsing if everything is fine
checksum_offset_params_t h_params;
memset(&h_params, 0, sizeof(h_params));
memcpy(&h_params.prev_checksum,
&(params->checksum_preview),
sizeof(h_params.prev_checksum));

// if we are on the first element of the array, we save the offset, which all
// received offset values will be based on for checksum computation
if (params->cached_offset == 0) {
params->cached_offset = msg->parameterOffset;
}

// we hash the previous checksum with the offset of the beginning of the structure.
h_params.new_offset = offset + params->cached_offset;
PRINTF("V2_MULTICLAIM_TICKETIDS__OFFSET_ITEMS_PREVIEW: %d\n", h_params.new_offset);

if (cx_keccak_256_hash((void *) &h_params,
sizeof(h_params),
params->checksum_preview) != CX_OK) {
PRINTF("unable to compute keccak hash\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

params->current_item_count -= 1;
if (params->current_item_count == 0) {
context->next_param = V2_MULTICLAIM_TICKETIDS__ITEM_LENGTH;
}
break;
case V2_MULTICLAIM_TICKETIDS__ITEM_LENGTH:
}
// ********************************************************************
// TICKETIDS[][]
// . ^
// ********************************************************************
case V2_MULTICLAIM_TICKETIDS__ITEM_LENGTH: {
// here we compute the offset of the ticketIds subarray checksum
checksum_offset_params_t h_params;
memset(&h_params, 0, sizeof(h_params));
memcpy(&h_params.prev_checksum,
&(params->checksum_value),
sizeof(h_params.prev_checksum));

// we hash the previous checksum with the offset of the beginning of the structure.
h_params.new_offset = msg->parameterOffset;
PRINTF("V2_MULTICLAIM_TICKETIDS__OFFSET_ITEMS_VALUE: %d\n", h_params.new_offset);

if (cx_keccak_256_hash((void *) &h_params, sizeof(h_params), params->checksum_value) !=
CX_OK) {
PRINTF("unable to compute keccak hash\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

U2BE_from_parameter(msg->parameter, &params->current_item_count);
context->next_param = V2_MULTICLAIM_TICKETIDS__ITEM__ITEMS;
break;
}
case V2_MULTICLAIM_TICKETIDS__ITEM__ITEMS:
params->current_item_count -= 1;
if (params->current_item_count == 0) {
params->parent_item_count -= 1;
if (params->parent_item_count == 0) {
// we check the checksums
if (memcmp(params->checksum_preview,
params->checksum_value,
sizeof(params->checksum_preview)) != 0) {
PRINTF("Tokenids[][] checksums do not match\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

context->next_param = V2_MULTICLAIM_CASKIDS_LENGTH;

} else {
context->next_param = V2_MULTICLAIM_TICKETIDS__ITEM_LENGTH;
}
}
break;
// ********************************************************************
// CASKIDS[][]
// ********************************************************************
case V2_MULTICLAIM_CASKIDS_LENGTH:
if (msg->parameterOffset != params->cask_ids_offset) {
PRINTF("Malformed calldata, unexpected caskids parameter offset %d != %d\n",
msg->parameterOffset,
params->cask_ids_offset);
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

memset(params->checksum_preview, 0, sizeof(params->checksum_preview));
memset(params->checksum_value, 0, sizeof(params->checksum_value));
params->cached_offset = 0;

U2BE_from_parameter(msg->parameter, &params->parent_item_count);
params->current_item_count = params->parent_item_count;
context->next_param = V2_MULTICLAIM_CASKIDS__OFFSET_ITEMS;
break;
case V2_MULTICLAIM_CASKIDS__OFFSET_ITEMS:
case V2_MULTICLAIM_CASKIDS__OFFSET_ITEMS: {
uint16_t offset;
U2BE_from_parameter(msg->parameter, &offset);
// We have limited size on the context and can't store all the offset values
// of the caskids subarrays. So we compute their checksum and expect to
// be able to recompute it using the offset of the parsed structures later.
// _preview will be equal to _value at the end of the parsing if everything is fine
checksum_offset_params_t h_params;
memset(&h_params, 0, sizeof(h_params));
memcpy(&h_params.prev_checksum,
&(params->checksum_preview),
sizeof(h_params.prev_checksum));

// if we are on the first element of the array, we save the offset, which all
// received offset values will be based on for checksum computation
if (params->cached_offset == 0) {
params->cached_offset = msg->parameterOffset;
}

// we hash the previous checksum with the offset of the beginning of the structure.
h_params.new_offset = offset + params->cached_offset;
PRINTF("V2_MULTICLAIM_CASKIDS__OFFSET_ITEMS_PREVIEW: %d\n", h_params.new_offset);

if (cx_keccak_256_hash((void *) &h_params,
sizeof(h_params),
params->checksum_preview) != CX_OK) {
PRINTF("unable to compute keccak hash\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

params->current_item_count -= 1;
if (params->current_item_count == 0) {
context->next_param = V2_MULTICLAIM_CASKIDS__ITEM_LENGTH;
}
break;
case V2_MULTICLAIM_CASKIDS__ITEM_LENGTH:
}
// ********************************************************************
// CASKIDS[][]
// . ^
// ********************************************************************
case V2_MULTICLAIM_CASKIDS__ITEM_LENGTH: {
// here we compute the offset of the caskIds subarray checksum
checksum_offset_params_t h_params;

memset(&h_params, 0, sizeof(h_params));
memcpy(&h_params.prev_checksum,
&(params->checksum_value),
sizeof(h_params.prev_checksum));

// we hash the previous checksum with the offset of the beginning of the structure.
h_params.new_offset = msg->parameterOffset;
PRINTF("V2_MULTICLAIM_CASKIDS__OFFSET_ITEMS_VALUE: %d\n", h_params.new_offset);

if (cx_keccak_256_hash((void *) &h_params, sizeof(h_params), params->checksum_value) !=
CX_OK) {
PRINTF("unable to compute keccak hash\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

U2BE_from_parameter(msg->parameter, &params->current_item_count);
context->next_param = V2_MULTICLAIM_CASKIDS__ITEM__ITEMS;
break;
}
case V2_MULTICLAIM_CASKIDS__ITEM__ITEMS:
params->current_item_count -= 1;
if (params->current_item_count == 0) {
if (params->parent_item_count == 0) {
// we check the checksums
if (memcmp(params->checksum_preview,
params->checksum_value,
sizeof(params->checksum_preview)) != 0) {
PRINTF("Caskids[][] checksums do not match\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

context->next_param = V2_MULTICLAIM_UNEXPECTED_PARAMETER;
} else {
context->next_param = V2_MULTICLAIM_CASKIDS__ITEM_LENGTH;
Expand Down
5 changes: 3 additions & 2 deletions tests/src/multiClaim.v2.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ nano_models.forEach(function (model) {
'0x86358F7B33b599c484e0335B8Ee4f7f7f92d8b60',
],
[
[42, 47],
[150, 2],
[42, 47, 3],
[150, 2, 3],
[150, 2, 3],
],
[
[0, 1],
Expand Down

0 comments on commit 889b5ad

Please sign in to comment.