diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-03-18 18:55:41 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-03-18 18:55:41 +0100 |
commit | 23bf1eee74bed73cf98264c247ab44df8dadfcd9 (patch) | |
tree | 3d7fcba4b6fb8a84b79585b4fa6ccdf0fff6ade4 /src/mint/taler-mint-httpd_db.c | |
parent | 08958c73e8ba6ad30e98a30968077cdf55bc86e8 (diff) | |
download | exchange-23bf1eee74bed73cf98264c247ab44df8dadfcd9.tar.xz |
fix #3716: make sure amount-API offers proper checks against overflow and other issues
Diffstat (limited to 'src/mint/taler-mint-httpd_db.c')
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 143 |
1 files changed, 90 insertions, 53 deletions
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index df68b6570..05c2a48a7 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -35,26 +35,6 @@ /** - * Get an amount in the mint's currency that is zero. - * - * @return zero amount in the mint's currency - */ -static struct TALER_Amount -mint_amount_native_zero () -{ - struct TALER_Amount amount; - - memset (&amount, - 0, - sizeof (amount)); - memcpy (amount.currency, - MINT_CURRENCY, - strlen (MINT_CURRENCY) + 1); - return amount; -} - - -/** * Execute a deposit. The validity of the coin and signature * have already been checked. The database must now check that * the coin is not (double or over) spent, and execute the @@ -99,9 +79,12 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, mks = TALER_MINT_key_state_acquire (); dki = TALER_MINT_get_denom_key (mks, deposit->coin.denom_pub); - value = TALER_amount_ntoh (dki->issue.value); - fee_deposit = TALER_amount_ntoh (dki->issue.fee_deposit); - fee_refresh = TALER_amount_ntoh (dki->issue.fee_refresh); + TALER_amount_ntoh (&value, + &dki->issue.value); + TALER_amount_ntoh (&fee_deposit, + &dki->issue.fee_deposit); + TALER_amount_ntoh (&fee_refresh, + &dki->issue.fee_refresh); TALER_MINT_key_state_release (mks); if (GNUNET_OK != @@ -113,26 +96,49 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, tl = TALER_MINT_DB_get_coin_transactions (db_conn, &deposit->coin.coin_pub); spent = fee_deposit; /* fee for THIS transaction */ - /* FIXME: need to deal better with integer overflows - in the logic that follows! (change amount.c API! -- #3637) */ - spent = TALER_amount_add (spent, - deposit->amount); + if (GNUNET_OK != + TALER_amount_add (&spent, + &spent, + &deposit->amount)) + { + GNUNET_break (0); + TALER_MINT_DB_free_coin_transaction_list (tl); + return TALER_MINT_reply_internal_db_error (connection); + } for (pos = tl; NULL != pos; pos = pos->next) { switch (pos->type) { case TALER_MINT_DB_TT_DEPOSIT: - spent = TALER_amount_add (spent, - pos->details.deposit->amount); - spent = TALER_amount_add (spent, - fee_deposit); + if ( (GNUNET_OK != + TALER_amount_add (&spent, + &spent, + &pos->details.deposit->amount)) || + (GNUNET_OK != + TALER_amount_add (&spent, + &spent, + &fee_deposit)) ) + { + GNUNET_break (0); + TALER_MINT_DB_free_coin_transaction_list (tl); + return TALER_MINT_reply_internal_db_error (connection); + } break; case TALER_MINT_DB_TT_REFRESH_MELT: - spent = TALER_amount_add (spent, - pos->details.melt->amount); - spent = TALER_amount_add (spent, - fee_refresh); + if ( (GNUNET_OK != + TALER_amount_add (&spent, + &spent, + &pos->details.melt->amount)) || + (GNUNET_OK != + TALER_amount_add (&spent, + &spent, + &fee_refresh)) ) + { + GNUNET_break (0); + TALER_MINT_DB_free_coin_transaction_list (tl); + return TALER_MINT_reply_internal_db_error (connection); + } break; case TALER_MINT_DB_TT_LOCK: /* should check if lock is still active, @@ -146,11 +152,12 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, } } - if (0 < TALER_amount_cmp (spent, value)) + if (0 < TALER_amount_cmp (&spent, + &value)) { TALER_MINT_DB_rollback (db_conn); ret = TALER_MINT_reply_deposit_insufficient_funds (connection, - tl); + tl); TALER_MINT_DB_free_coin_transaction_list (tl); return ret; } @@ -251,6 +258,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, struct TALER_Amount withdraw_total; struct TALER_Amount balance; struct TALER_Amount value; + struct TALER_Amount fee_withdraw; struct GNUNET_HashCode h_blind; int res; @@ -318,8 +326,20 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, } /* calculate amount required including fees */ - amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value), - TALER_amount_ntoh (dki->issue.fee_withdraw)); + TALER_amount_ntoh (&value, + &dki->issue.value); + TALER_amount_ntoh (&fee_withdraw, + &dki->issue.fee_withdraw); + + if (GNUNET_OK != + TALER_amount_add (&amount_required, + &value, + &fee_withdraw)) + { + TALER_MINT_DB_rollback (db_conn); + TALER_MINT_key_state_release (key_state); + return TALER_MINT_reply_internal_db_error (connection); + } /* calculate balance of the reserve */ res = 0; @@ -331,29 +351,45 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, if (0 == (res & 1)) deposit_total = pos->details.bank->amount; else - deposit_total = TALER_amount_add (deposit_total, - pos->details.bank->amount); + if (GNUNET_OK != + TALER_amount_add (&deposit_total, + &deposit_total, + &pos->details.bank->amount)) + { + TALER_MINT_DB_rollback (db_conn); + TALER_MINT_key_state_release (key_state); + return TALER_MINT_reply_internal_db_error (connection); + } res |= 1; break; case TALER_MINT_DB_RO_WITHDRAW_COIN: tdki = TALER_MINT_get_denom_key (key_state, pos->details.withdraw->denom_pub); - value = TALER_amount_ntoh (tdki->issue.value); + TALER_amount_ntoh (&value, + &tdki->issue.value); if (0 == (res & 2)) withdraw_total = value; else - withdraw_total = TALER_amount_add (withdraw_total, - value); + if (GNUNET_OK != + TALER_amount_add (&withdraw_total, + &withdraw_total, + &value)) + { + TALER_MINT_DB_rollback (db_conn); + TALER_MINT_key_state_release (key_state); + return TALER_MINT_reply_internal_db_error (connection); + } res |= 2; break; } } - GNUNET_break (0 > TALER_amount_cmp (withdraw_total, - deposit_total)); - balance = TALER_amount_subtract (deposit_total, - withdraw_total); - if (0 < TALER_amount_cmp (amount_required, - balance)) + /* All reserve balances should be non-negative */ + GNUNET_break (GNUNET_SYSERR != + TALER_amount_subtract (&balance, + &deposit_total, + &withdraw_total)); + if (0 < TALER_amount_cmp (&amount_required, + &balance)) { TALER_MINT_key_state_release (key_state); TALER_MINT_DB_rollback (db_conn); @@ -450,7 +486,8 @@ refresh_accept_melts (struct MHD_Connection *connection, "denom not found")) ? GNUNET_NO : GNUNET_SYSERR; - coin_value = TALER_amount_ntoh (dki->value); + TALER_amount_ntoh (&coin_value, + &dki->value); tl = TALER_MINT_DB_get_coin_transactions (db_conn, &coin_public_info->coin_pub); /* FIXME: #3636: compute how much value is left with this coin and @@ -459,8 +496,8 @@ refresh_accept_melts (struct MHD_Connection *connection, /* Refuse to refresh when the coin does not have enough money left to * pay the refreshing fees of the coin. */ - if (TALER_amount_cmp (coin_residual, - coin_details->melt_amount) < 0) + if (TALER_amount_cmp (&coin_residual, + &coin_details->melt_amount) < 0) { res = (MHD_YES == TALER_MINT_reply_refresh_melt_insufficient_funds (connection, |