From a7da1153cd2c05ccc2ae5f0ec3c2bcb10af9d2f6 Mon Sep 17 00:00:00 2001 From: "roman.khlopkov" <roman.khlopkov@demlabs.net> Date: Thu, 22 Aug 2024 18:12:50 +0300 Subject: [PATCH] [*] Verificators security checks added --- dap-sdk | 2 +- modules/common/dap_chain_datum_tx_receipt.c | 58 ++++++++++++------- .../include/dap_chain_datum_tx_receipt.h | 3 +- modules/net/srv/dap_chain_net_srv.c | 31 ++++++---- .../stake/dap_chain_net_srv_stake_lock.c | 22 +++---- .../dap_chain_net_srv_stake_pos_delegate.c | 27 +-------- 6 files changed, 74 insertions(+), 69 deletions(-) diff --git a/dap-sdk b/dap-sdk index e97dc15096..76bb290ca9 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit e97dc15096ffa39761dc8f6c68f9ce8fe53bc49d +Subproject commit 76bb290ca9d93e5adac3a56a32d42bc94ad354c5 diff --git a/modules/common/dap_chain_datum_tx_receipt.c b/modules/common/dap_chain_datum_tx_receipt.c index 51a4dda42b..27b0bdda72 100644 --- a/modules/common/dap_chain_datum_tx_receipt.c +++ b/modules/common/dap_chain_datum_tx_receipt.c @@ -98,23 +98,21 @@ dap_chain_datum_tx_receipt_t *dap_chain_datum_tx_receipt_sign_add(dap_chain_datu */ dap_sign_t *dap_chain_datum_tx_receipt_sign_get(dap_chain_datum_tx_receipt_t *a_receipt, size_t a_receipt_size, uint16_t a_sign_position) { - dap_return_val_if_fail(a_receipt && a_receipt_size == a_receipt->size && - a_receipt_size > a_receipt->exts_size && - a_receipt_size >= sizeof(dap_chain_datum_tx_receipt_t) + a_receipt->exts_size, - NULL); - uint64_t l_offset = a_receipt->exts_size; - uint16_t l_sign_position; + if (dap_chain_datum_tx_receipt_check_size(a_receipt, a_receipt_size)) { + log_it(L_WARNING, "Receipt size check error"); + return NULL; + } + size_t l_offset = a_receipt->exts_size; + size_t l_total_signs_size = a_receipt->size - sizeof(dap_chain_datum_tx_receipt_t) - a_receipt->exts_size; + if (!l_total_signs_size) + return NULL; dap_sign_t *l_sign = NULL; - for (l_sign_position = a_sign_position + 1; l_sign_position; l_sign_position--) { - l_sign = (dap_sign_t *)(a_receipt->exts_n_signs + l_offset); - // not enough signs in receipt - if (sizeof(dap_chain_datum_tx_receipt_t) + l_offset + sizeof(dap_sign_t) > a_receipt_size) - return NULL; + for (uint16_t l_sign_position = a_sign_position + 1; l_sign_position; l_sign_position--) { + dap_sign_t *l_sign = (dap_sign_t *)(a_receipt->exts_n_signs + l_offset); uint64_t l_sign_size = dap_sign_get_size(l_sign); - // incorrect sign size - if (!l_sign_size || l_offset + l_sign_size < l_offset) - return NULL; l_offset += l_sign_size; + if (l_offset > l_total_signs_size) + return NULL; } return l_sign; } @@ -147,17 +145,37 @@ uint256_t dap_chain_datum_tx_receipt_value_get(dap_chain_datum_tx_receipt_t *a * @param a_receipt_size * @return */ -uint16_t dap_chain_datum_tx_receipt_signs_count(dap_chain_datum_tx_receipt_t * a_receipt, size_t a_receipt_size) +uint16_t dap_chain_datum_tx_receipt_signs_count(dap_chain_datum_tx_receipt_t *a_receipt) { uint16_t l_ret = 0; - if(!a_receipt) - return 0; + dap_return_val_if_fail(a_receipt, 0); dap_sign_t *l_sign; - for (l_sign = (dap_sign_t *)a_receipt->exts_n_signs; a_receipt_size > (size_t) ( (byte_t *) l_sign - (byte_t *) a_receipt ) ; + for (l_sign = (dap_sign_t *)a_receipt->exts_n_signs; a_receipt->size > (size_t) ( (byte_t *) l_sign - (byte_t *) a_receipt ) ; l_sign =(dap_sign_t *) (((byte_t*) l_sign)+ dap_sign_get_size( l_sign )) ){ l_ret++; } - if(a_receipt_size != (size_t) ((byte_t *) l_sign - (byte_t *) a_receipt) ) - log_it(L_ERROR, "Receipt 0x%zu (size=%zu) is corrupted", (size_t)a_receipt, a_receipt_size); return l_ret; } + +int dap_chain_datum_tx_receipt_check_size(dap_chain_datum_tx_receipt_t *a_receipt, size_t a_control_size) +{ + dap_return_val_if_fail(a_receipt && a_control_size == a_receipt->size && + a_control_size >= sizeof(dap_chain_datum_tx_receipt_t) + a_receipt->exts_size, + -1); // Main controls incosistentency + if (a_control_size == sizeof(dap_chain_datum_tx_receipt_t) + a_receipt->exts_size) + return 0; // No signs at receipt, it's OK + if (a_control_size < sizeof(dap_chain_datum_tx_receipt_t) + a_receipt->exts_size + sizeof(dap_sign_t)) + return -2; + dap_sign_t *l_sign = (dap_sign_t *)(a_receipt->exts_n_signs + a_receipt->exts_size); + for (uint16_t l_sign_position = 2; l_sign_position; l_sign_position--) { + size_t l_sign_offset = (byte_t *)l_sign - (byte_t *)a_receipt; + if (a_control_size < l_sign_offset + sizeof(dap_sign_t)) + return -2; // Left space is too samll to contain a sign + uint64_t l_sign_size = dap_sign_get_size(l_sign); + if (l_sign_size + l_sign_offset <= l_sign_offset || l_sign_size + l_sign_offset > a_control_size) + return -3; + l_sign = (dap_sign_t *)((byte_t *)l_sign + l_sign_size); + } + size_t l_sign_offset = (byte_t *)l_sign - (byte_t *)a_receipt; + return l_sign_offset == a_control_size ? 0 : -4; // Receipt is lagrer that two signs need +} diff --git a/modules/common/include/dap_chain_datum_tx_receipt.h b/modules/common/include/dap_chain_datum_tx_receipt.h index cbbb246d2a..e5f1e92d7f 100644 --- a/modules/common/include/dap_chain_datum_tx_receipt.h +++ b/modules/common/include/dap_chain_datum_tx_receipt.h @@ -67,7 +67,8 @@ uint32_t dap_chain_datum_tx_receipt_utype_get(dap_chain_datum_tx_receipt_t *a uint64_t dap_chain_datum_tx_receipt_srv_uid_get(dap_chain_datum_tx_receipt_t *a_receipt); uint64_t dap_chain_datum_tx_receipt_units_get(dap_chain_datum_tx_receipt_t *a_receipt); uint256_t dap_chain_datum_tx_receipt_value_get(dap_chain_datum_tx_receipt_t *a_receipt); -uint16_t dap_chain_datum_tx_receipt_signs_count(dap_chain_datum_tx_receipt_t *a_receipt, size_t a_receipt_size); +uint16_t dap_chain_datum_tx_receipt_signs_count(dap_chain_datum_tx_receipt_t *a_receipt); +int dap_chain_datum_tx_receipt_check_size(dap_chain_datum_tx_receipt_t *a_receipt, size_t a_control_size); #ifdef __cplusplus } diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c index 5b8954710d..88ca4c3c6e 100644 --- a/modules/net/srv/dap_chain_net_srv.c +++ b/modules/net/srv/dap_chain_net_srv.c @@ -702,15 +702,16 @@ static int s_pay_verificator_callback(dap_ledger_t * a_ledger, dap_chain_tx_out_ { if (a_owner) return 0; + size_t l_receipt_size = 0; dap_chain_datum_tx_receipt_t *l_receipt = (dap_chain_datum_tx_receipt_t *) - dap_chain_datum_tx_item_get(a_tx_in, NULL, NULL, TX_ITEM_TYPE_RECEIPT, NULL); + dap_chain_datum_tx_item_get(a_tx_in, NULL, NULL, TX_ITEM_TYPE_RECEIPT, &l_receipt_size); if (!l_receipt){ log_it(L_ERROR, "Can't find receipt."); return -1; } // Check provider sign - dap_sign_t *l_sign = dap_chain_datum_tx_receipt_sign_get(l_receipt, l_receipt->size, 0); + dap_sign_t *l_sign = dap_chain_datum_tx_receipt_sign_get(l_receipt, l_receipt_size, 0); if (!l_sign){ log_it(L_ERROR, "Can't get provider sign from receipt."); @@ -754,7 +755,7 @@ static int s_pay_verificator_callback(dap_ledger_t * a_ledger, dap_chain_tx_out_ } // Check client sign - l_sign = dap_chain_datum_tx_receipt_sign_get(l_receipt, l_receipt->size, 1); + l_sign = dap_chain_datum_tx_receipt_sign_get(l_receipt, l_receipt_size, 1); if (!l_sign){ log_it(L_ERROR, "Can't get client signature from receipt."); return -8; @@ -776,11 +777,11 @@ static int s_pay_verificator_callback(dap_ledger_t * a_ledger, dap_chain_tx_out_ dap_chain_tx_out_cond_t *l_prev_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_prev, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, NULL); uint256_t l_unit_price = {}; - if (l_receipt->receipt_info.units != 0){ - DIV_256(l_receipt->receipt_info.value_datoshi, GET_256_FROM_64(l_receipt->receipt_info.units), &l_unit_price); - } else { + if (!l_receipt->receipt_info.units) { + log_it(L_ERROR, "Receipt units can't be a zero"); return -11; } + DIV_256(l_receipt->receipt_info.value_datoshi, GET_256_FROM_64(l_receipt->receipt_info.units), &l_unit_price); if( !IS_ZERO_256(l_prev_out_cond->subtype.srv_pay.unit_price_max_datoshi) && compare256(l_unit_price, l_prev_out_cond->subtype.srv_pay.unit_price_max_datoshi) > 0){ @@ -801,14 +802,19 @@ static int s_pay_verificator_callback(dap_ledger_t * a_ledger, dap_chain_tx_out_ case TX_ITEM_TYPE_OUT: { // 256 dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*)l_item; l_out_addr = l_tx_out->addr; - if (dap_chain_addr_compare(&l_out_addr, &l_network_fee_addr)){ - SUM_256_256(l_value, l_tx_out->header.value, &l_value); + if (dap_chain_addr_compare(&l_out_addr, &l_network_fee_addr) && + SUM_256_256(l_value, l_tx_out->header.value, &l_value)) { + log_it(L_WARNING, "Integer overflow while sum of outs calculation"); + return -14; } } break; case TX_ITEM_TYPE_OUT_COND: { dap_chain_tx_out_cond_t *l_tx_out = (dap_chain_tx_out_cond_t*)l_item; - if (l_tx_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE){ - SUM_256_256(l_value, l_tx_out->header.value, &l_value); + if (l_tx_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) { + if (SUM_256_256(l_value, l_tx_out->header.value, &l_value)) { + log_it(L_WARNING, "Integer overflow while sum of outs calculation"); + return -14; + } } else if (l_tx_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY){ l_cond_out_value = l_tx_out->header.value; } @@ -817,7 +823,10 @@ static int s_pay_verificator_callback(dap_ledger_t * a_ledger, dap_chain_tx_out_ break; } } - SUBTRACT_256_256(l_prev_out_cond->header.value, l_value, &l_value); + if (SUBTRACT_256_256(l_prev_out_cond->header.value, l_value, &l_value)) { + log_it(L_WARNING, "Integer overflow while payback calculation"); + return -14; + } return compare256(l_value, l_cond_out_value) ? log_it(L_ERROR, "Value in tx out is invalid!"), -13 : 0; } diff --git a/modules/service/stake/dap_chain_net_srv_stake_lock.c b/modules/service/stake/dap_chain_net_srv_stake_lock.c index ab4ec0d346..ab4876cdce 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_lock.c +++ b/modules/service/stake/dap_chain_net_srv_stake_lock.c @@ -1027,12 +1027,14 @@ static int s_stake_lock_callback_verificator(dap_ledger_t *a_ledger, dap_chain_t MULT_256_COIN(a_cond->header.value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) return -6; - - l_receipt = (dap_chain_datum_tx_receipt_t *)dap_chain_datum_tx_item_get(a_tx_in, NULL, NULL, TX_ITEM_TYPE_RECEIPT, NULL); + size_t l_receipt_size = 0; + l_receipt = (dap_chain_datum_tx_receipt_t *)dap_chain_datum_tx_item_get(a_tx_in, NULL, NULL, TX_ITEM_TYPE_RECEIPT, &l_receipt_size); if (l_receipt) { + if (dap_chain_datum_tx_receipt_check_size(l_receipt, l_receipt_size)) + return -13; if (!dap_chain_net_srv_uid_compare_scalar(l_receipt->receipt_info.srv_uid, DAP_CHAIN_NET_SRV_STAKE_LOCK_ID)) return -7; - if (!l_receipt->exts_size) + if (l_receipt->exts_size != sizeof(dap_hash_fast_t)) return -8; l_burning_tx_hash = *(dap_hash_fast_t*)l_receipt->exts_n_signs; if (dap_hash_fast_is_blank(&l_burning_tx_hash)) @@ -1076,19 +1078,17 @@ static int s_stake_lock_callback_verificator(dap_ledger_t *a_ledger, dap_chain_t } if (s_debug_more) { - char *str1 = dap_chain_balance_print(a_cond->header.value); - char *str2 = dap_chain_balance_print(l_value_delegated); - char *str3 = dap_chain_balance_print(l_blank_out_value); - log_it(L_INFO, "hold/take_value: %s", str1); - log_it(L_INFO, "delegated_value: %s", str2); - log_it(L_INFO, "burning_value: %s", str3); + char *str1 = dap_chain_balance_to_coins(a_cond->header.value); + char *str2 = dap_chain_balance_to_coins(l_value_delegated); + char *str3 = dap_chain_balance_to_coins(l_blank_out_value); + log_it(L_INFO, "hold/take_value: %s, delegated_value: %s, burning_value: %s", str1, str2, str3); DAP_DEL_MULTY(str1, str2, str3); } if (!EQUAL_256(l_blank_out_value, l_value_delegated)) { // !!! A terrible legacy crutch, TODO !!! - SUM_256_256(l_value_delegated, GET_256_FROM_64(10), &l_value_delegated); - if (!EQUAL_256(l_blank_out_value, l_value_delegated)) { + if (SUM_256_256(l_value_delegated, GET_256_FROM_64(10), &l_value_delegated) || + !EQUAL_256(l_blank_out_value, l_value_delegated)) { log_it(L_ERROR, "Burning and delegated value mismatch"); return -12; } diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c index 1c3c413192..9a2aa0f161 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c +++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c @@ -241,36 +241,13 @@ static int s_stake_verificator_callback(dap_ledger_t *a_ledger, dap_chain_tx_out log_it(L_ERROR, "Conditional in item not found in checking tx"); return -6; } + // ATTENTION: It's correct only with single IN_COND TX item dap_hash_fast_t *l_prev_hash = &l_tx_in_cond->header.tx_prev_hash; if (dap_hash_fast_is_blank(l_prev_hash)) { log_it(L_ERROR, "Blank hash of prev tx in tx_in_cond"); return -7; } - dap_chain_datum_tx_t *l_prev_tx = dap_ledger_tx_find_by_hash(a_ledger, l_prev_hash); - if (!l_prev_tx) { - log_it(L_ERROR, "Previous tx not found for now but is found in ledger before"); - return -8; - } - bool l_owner = false; - dap_chain_tx_in_cond_t *l_tx_prev_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(l_prev_tx, NULL, NULL, TX_ITEM_TYPE_IN_COND, NULL); - if (!l_tx_prev_in_cond) - l_owner = a_owner; - else { - dap_hash_fast_t *l_owner_tx_hash = &l_tx_prev_in_cond->header.tx_prev_hash; - dap_chain_datum_tx_t *l_owner_tx = dap_ledger_tx_find_by_hash(a_ledger, l_owner_tx_hash); - dap_sign_t *l_owner_sign = dap_chain_datum_tx_get_sign(l_owner_tx, 0); - if (!l_owner_sign) { - log_it(L_ERROR, "Can't get owner sign"); - return -9; - } - dap_sign_t *l_taker_sign = dap_chain_datum_tx_get_sign(a_tx_in, 0); - if (!l_taker_sign) { - log_it(L_ERROR, "Can't get taker sign"); - return -10; - } - l_owner = dap_sign_compare_pkeys(l_taker_sign, l_owner_sign); - } - if (!l_owner) { + if (!a_owner) { log_it(L_WARNING, "Trying to spend conditional tx not by owner"); return -11; } -- GitLab