Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insufficient htlc_extend_operation validation #1696

Closed
2 of 17 tasks
abitmore opened this issue Apr 4, 2019 · 10 comments
Closed
2 of 17 tasks

Insufficient htlc_extend_operation validation #1696

abitmore opened this issue Apr 4, 2019 · 10 comments
Assignees
Labels
3d Bug Classification indicating the existing implementation does not match the intention of the design 4c High Priority Priority indicating significant impact to system/user -OR- workaround is prohibitivly expensive 6 Protocol Impact flag identifying the blockchain logic, consensus, validation, etc. hardfork

Comments

@abitmore
Copy link
Member

abitmore commented Apr 4, 2019

Bug Description

  1. Everyone can extend a HTLC, which means funds inside can be locked forever (although need to pay per-day fee).

    void_result htlc_extend_evaluator::do_evaluate(const htlc_extend_operation& o)
    {
    htlc_obj = &db().get<htlc_object>(o.htlc_id);
    return void_result();
    }

  2. Theoretically the sender can overflow a HTLC and got refunded (although may need to pay a large per-day fee).

    void_result htlc_extend_evaluator::do_apply(const htlc_extend_operation& o)
    {
    db().modify(*htlc_obj, [&o](htlc_object& db_obj) {
    db_obj.conditions.time_lock.expiration += o.seconds_to_add;
    });
    return void_result();
    }

Impacts
Describe which portion(s) of BitShares Core may be impacted by this bug. Please tick at least one box.

  • API (the application programming interface)
  • Build (the build process or something prior to compiled code)
  • CLI (the command line wallet)
  • Deployment (the deployment process after building such as Docker, Travis, etc.)
  • DEX (the Decentralized EXchange, market engine, etc.)
  • P2P (the peer-to-peer network for transaction/block propagation)
  • Performance (system or user efficiency, etc.)
  • Protocol (the blockchain logic, consensus, validation, etc.)
  • Security (the security of system or user data, etc.)
  • UX (the User Experience)
  • Other (please add below)

CORE TEAM TASK LIST

  • Evaluate / Prioritize Bug Report
  • Refine User Stories / Requirements
  • Define Test Cases
  • Design / Develop Solution
  • Perform QA/Testing
  • Update Documentation
@abitmore abitmore added hardfork 3d Bug Classification indicating the existing implementation does not match the intention of the design 4c High Priority Priority indicating significant impact to system/user -OR- workaround is prohibitivly expensive 6 Protocol Impact flag identifying the blockchain logic, consensus, validation, etc. labels Apr 4, 2019
@xeroc
Copy link
Member

xeroc commented Apr 4, 2019

Related, the fee_payer for that operation:

*/
account_id_type fee_payer()const { return update_issuer; }

with no check if the update_issuer has to do with the HLTC, at all.

The question is whether this is a bug or a feature.

@pmconrad
Copy link
Contributor

pmconrad commented Apr 4, 2019

This is clearly a bug. BSIP-44 specifies checks on both update_issuer and time:

transaction_obj htlc_extend(id, issuer, timeout_threshold, broadcast)
Validate: 'issuer' = get_htlc(id).from
Validate: timeout_threshold < now() + GRAPHENE_HTLC_MAXIMUM_DURRATION

How the hell did we miss that?

@abitmore
Copy link
Member Author

abitmore commented Apr 4, 2019

By the way, the fee_payer in htlc_redeem_operation is not validated as well, however the funds will be sent to the to account of the HTLC object, so it's not a big deal.

void_result htlc_redeem_evaluator::do_evaluate(const htlc_redeem_operation& o)
{
htlc_obj = &db().get<htlc_object>(o.htlc_id);
FC_ASSERT(o.preimage.size() == htlc_obj->conditions.hash_lock.preimage_size, "Preimage size mismatch.");
const htlc_redeem_visitor vtor( o.preimage );
FC_ASSERT( htlc_obj->conditions.hash_lock.preimage_hash.visit( vtor ), "Provided preimage does not generate correct hash.");
return void_result();
}
void_result htlc_redeem_evaluator::do_apply(const htlc_redeem_operation& o)
{
db().adjust_balance(htlc_obj->transfer.to, asset(htlc_obj->transfer.amount, htlc_obj->transfer.asset_id) );
// notify related parties
htlc_redeemed_operation virt_op( htlc_obj->id, htlc_obj->transfer.from, htlc_obj->transfer.to,
asset(htlc_obj->transfer.amount, htlc_obj->transfer.asset_id ) );
db().push_applied_operation( virt_op );
db().remove(*htlc_obj);
return void_result();
}

An issue related to this is:

void operator()( const htlc_redeem_operation& op )
{
_impacted.insert( op.fee_payer() );
}
void operator()( const htlc_redeemed_operation& op )
{
_impacted.insert( op.from );
}

which means the real to account won't be notified when the redemption is done by a 3rd party.

@jmjatlanta jmjatlanta self-assigned this Apr 4, 2019
@jmjatlanta
Copy link
Contributor

As for htlc_redeem: I cannot think of a scenario where it would be advantageous to allow someone else to execute an HTLC. I think we should validate that the redeemer is the "from".

If someone can think of a scenario, then we can conditionally add "to" to the _impacted collection.

I do not feel this redeem issue is urgent. I await the opinions of others.

@abitmore
Copy link
Member Author

abitmore commented Apr 4, 2019

@jmjatlanta in the scenario: A initialized a HTLC to transfer to B, C redeemed, get_account_history of A contains a create and a redeemed, history of B contains only a create, history of C contains only a redeem. It would be a bit strange that B doesn't have a history entry while the balance increased.

Actually, if we can prevent another account from redeeming the HTLC, this issue would be gone. That said, we should validate that the redeemer is the "to".

@jmjatlanta
Copy link
Contributor

Actually, if we can prevent another account from redeeming the HTLC, this issue would be gone. That said, we should validate that the redeemer is the "to".

Done as part of #1699. Please take a look.

@pmconrad
Copy link
Contributor

pmconrad commented Apr 5, 2019

https://github.com/bitshares/bsips/blob/master/bsip-0044.md#redeem specifies that

// NOTE: any account may attempt to redeem

IMO the correct fix is to include htlc_redeemed_operation also in the history of to.

@jmjatlanta
Copy link
Contributor

IMO the correct fix is to include htlc_redeemed_operation also in the history of to.

I guess we should follow the spec. #1699 updated.

@abitmore
Copy link
Member Author

abitmore commented Apr 5, 2019

I agree that it's good to follow the spec. However, it means the history object numbering of new code is different than 3.0.0, thus we need to force everyone to upgrade to avoid potential data mismatching issues (which would be messy). So IMHO under the current situation it's easier and more practicable to apply a more strict rule (can be witness-only) even if to is added to impacted of htlc_redeemed_operation until next consensus release.

This was referenced Apr 8, 2019
@abitmore abitmore added this to the 3.0.1 - hotfix milestone Apr 8, 2019
@abitmore
Copy link
Member Author

Fixed by #1699.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3d Bug Classification indicating the existing implementation does not match the intention of the design 4c High Priority Priority indicating significant impact to system/user -OR- workaround is prohibitivly expensive 6 Protocol Impact flag identifying the blockchain logic, consensus, validation, etc. hardfork
Projects
None yet
Development

No branches or pull requests

4 participants