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

Attacker validator can issue steak at AnteHandler #2772

Closed
2 of 4 tasks
kauchy opened this issue Nov 12, 2018 · 19 comments · Fixed by #2781
Closed
2 of 4 tasks

Attacker validator can issue steak at AnteHandler #2772

kauchy opened this issue Nov 12, 2018 · 19 comments · Fixed by #2781
Assignees

Comments

@kauchy
Copy link

kauchy commented Nov 12, 2018

Summary of Bug

In AnteHandler, FeeCollectionKeeper adds collected fees before saving signerAccs[0].
Attacker validator can send txs with fee and signerAccs[0] holding a false pubkey, ignoring the sig check error in CheckTx. Such txs will pass to DeliverTx, the FeeCollectionKeeper will collect fees, but these fees won't be charged from attacker's account due to sig check failure.

At gaia-9001 block 31998, we use this bug issue 150000 steaks.

@rigelrozanski


For Admin Use

  • Not duplicate issue
  • Appropriate labels applied
  • Appropriate contributors tagged
  • Contributor assigned/self-assigned
@kauchy kauchy changed the title AnteHandler addCollectedFees before singerAccs[0] save Attacker validator can issue atom at AnteHandler Nov 12, 2018
@kauchy kauchy changed the title Attacker validator can issue atom at AnteHandler Attacker validator can issue steak at AnteHandler Nov 12, 2018
@alexanderbez
Copy link
Contributor

You mean sending in invalid signature and checkTx ignores validating signatures?

@kauchy
Copy link
Author

kauchy commented Nov 12, 2018

yes @alexanderbez

@blackpainter
Copy link

it remains in unconfirmed txs in mempool and once the attacker propose, it get broadcasted @alexanderbez

@alexanderbez
Copy link
Contributor

Indeed! Good catch @kauchy!

@kauchy
Copy link
Author

kauchy commented Nov 12, 2018

gaia-9001 can not delegate now,because unbond pool is nearly negative😱

@cwgoes
Copy link
Contributor

cwgoes commented Nov 12, 2018

Excellent catch. Thanks @kauchy.

This is the most directly profitable exploit, but I think the underlying problem is more general - a proposer can cause partial state changes to be written from the ante handler even when the ante handler fails. Maybe we need to revert state changes when running the ante handler in DeliverTx (or equivalently, operate on a cached context). Alternatively, we could require that all state writes occur after checks in the ante handler, but that seems riskier and possibly less efficient in the non-Byzantine case.

@gamarin2
Copy link
Contributor

gaia-9001 can not delegate now,because unbond pool is nearly negative😱

I confirm, we can't delegate anymore. Seems to affect all validators?

@alexanderbez alexanderbez self-assigned this Nov 12, 2018
@cwgoes
Copy link
Contributor

cwgoes commented Nov 12, 2018

I confirm, we can't delegate anymore. Seems to affect all validators?

This sounds like a separate bug. What's the error?

@gamarin2
Copy link
Contributor

gamarin2 commented Nov 12, 2018

This sounds like a separate bug. What's the error?

Same as what aurel posted:

ERROR: {"codespace":1,"code":1,"abci_code":65537,"message":"recovered: sanity check: loose tokens negative, pool: {-3898400000000 1254736300000000}
stack:
goroutine 94329 [running]:
runtime/debug.Stack(0xc440345878, 0xdcab00, 0xc42ad55fc0)
	/usr/local/go/src/runtime/debug/stack.go:24 +0xa7
github.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).runTx.func1(0xc440347b68, 0xc4403478f0, 0xc440347940)
	/root/.go/src/github.com/cosmos/cosmos-sdk/baseapp/baseapp.go:612 +0xc8
panic(0xdcab00, 0xc42ad55fc0)
	/usr/local/go/src/runtime/panic.go:505 +0x229
github.com/cosmos/cosmos-sdk/x/stake/types.Pool.looseTokensToBonded(0xc431311000, 0xc431311060, 0xc431311120, 0x1158f20, 0xc430c2de40)
	/root/.go/src/github.com/cosmos/cosmos-sdk/x/stake/types/pool.go:56 +0x2cc
github.com/cosmos/cosmos-sdk/x/stake/types.Validator.AddTokensFromDel(0xc423b5cc40, 0x14, 0x14, 0x1158f20, 0xc430c2de40, 0x200, 0xc42bd3c980, 0xc42bd3c9e0, 0xc428397cf0, 0x10, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/x/stake/types/validator.go:392 +0x208
github.com/cosmos/cosmos-sdk/x/stake/keeper.Keeper.AddValidatorTokensAndShares(0x114f8e0, 0xc420216f90, 0x114f920, 0xc420216fa0, 0xc420253110, 0x115d6c0, 0xc4201e5d80, 0x115eda0, 0xc420906360, 0xc420253110, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/x/stake/keeper/validator.go:132 +0x211
github.com/cosmos/cosmos-sdk/x/stake/keeper.Keeper.Delegate(0x114f8e0, 0xc420216f90, 0x114f920, 0xc420216fa0, 0xc420253110, 0x115d6c0, 0xc4201e5d80, 0x115eda0, 0xc420906360, 0xc420253110, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/x/stake/keeper/delegation.go:399 +0x560
github.com/cosmos/cosmos-sdk/x/stake.handleMsgDelegate(0x1157a60, 0xc42b313b60, 0xc43491efc0, 0x10, 0xc423b5cb60, 0x14, 0x14, 0xc423b5cc40, 0x14, 0x14, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/x/stake/handler.go:193 +0x400
github.com/cosmos/cosmos-sdk/x/stake.NewHandler.func1(0x1157a60, 0xc42b313b60, 0xc43491efc0, 0x10, 0x115a920, 0xc42dd74b90, 0x0, 0x0, 0x0, 0x0, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/x/stake/handler.go:22 +0x3b7
github.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).runMsgs(0xc420ae05a0, 0x1157a60, 0xc42b313b60, 0xc43491efc0, 0x10, 0xc42ad55340, 0x1, 0x1, 0xc43491ef02, 0x0, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/baseapp/baseapp.go:541 +0xbd6
github.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).runTx(0xc420ae05a0, 0x2, 0xc42b8f0820, 0xc2, 0xc2, 0x114dea0, 0xc4364a2ae0, 0x0, 0x0, 0x0, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/baseapp/baseapp.go:655 +0x3b9
github.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).DeliverTx(0xc420ae05a0, 0xc42b8f0820, 0xc2, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/baseapp/baseapp.go:476 +0x267
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/abci/client.(*localClient).DeliverTxAsync(0xc420b145a0, 0xc42b8f0820, 0xc2, 0xc2, 0x0)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/abci/client/local_client.go:76 +0x88
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/proxy.(*appConnConsensus).DeliverTxAsync(0xc420216b80, 0xc42b8f0820, 0xc2, 0xc2, 0xc42b3120f0)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/proxy/app_conn.go:73 +0x51
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/state.execBlockOnProxyApp(0x11586e0, 0xc422071860, 0x115d360, 0xc420216b80, 0xc4233f01e0, 0xc42e9b3470, 0x1161e40, 0xc4201e2520, 0x3207, 0xc42f217740, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/state/execution.go:248 +0x616
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/state.(*BlockExecutor).ApplyBlock(0xc42208a310, 0x7, 0x0, 0xc42207cd10, 0x6, 0xc42207cd20, 0x9, 0x7e0e, 0x3207, 0xc42f217740, ...)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/state/execution.go:96 +0x1a5
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).finalizeCommit(0xc42206e700, 0x7e0f)\

n	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1327 +0xad9
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).tryFinalizeCommit(0xc42206e700, 0x7e0f)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1258 +0x462
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).enterCommit.func1(0xc42206e700, 0x0, 0x7e0f)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1204 +0x98
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).enterCommit(0xc42206e700, 0x7e0f, 0x0)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1235 +0x72c
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote(0xc42206e700, 0xc432c94780, 0xc4202996b0, 0x28, 0x42b5a9, 0x10cced8, 0x9)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1659 +0xc1e
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote(0xc42206e700, 0xc432c94780, 0xc4202996b0, 0x28, 0xb107c7, 0xc4239b40b0, 0xc440232b40)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1506 +0x59
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg(0xc42206e700, 0x114c580, 0xc43da93670, 0xc4202996b0, 0x28)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:660 +0x6af
github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine(0xc42206e700, 0x0)
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:617 +0x6a2
created by github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).OnStart
	/root/.go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:311 +0x140
"}

@pete001
Copy link

pete001 commented Nov 12, 2018

Same our end too:

ERROR: {"codespace":1,"code":1,"abci_code":65537,"message":"recovered: sanity check: loose tokens negative, pool: {-3998400000000 1254836300000000}\nstack:\ngoroutine 755 [running]:\nruntime/debug.Stack(0xc426dc9878, 0xdcaa40, 0xc4266681d0)\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0xa7\ngithub.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).runTx.func1(0xc426dcbb68, 0xc426dcb8f0, 0xc426dcb940)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/baseapp/baseapp.go:612 +0xc8\npanic(0xdcaa40, 0xc4266681d0)\n\t/usr/local/go/src/runtime/panic.go:505 +0x229\ngithub.com/cosmos/cosmos-sdk/x/stake/types.Pool.looseTokensToBonded(0xc427965700, 0xc427965760, 0xc427965840, 0x1158e60, 0xc421683e00)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/x/stake/types/pool.go:56 +0x2cc\ngithub.com/cosmos/cosmos-sdk/x/stake/types.Validator.AddTokensFromDel(0xc422c47c40, 0x14, 0x14, 0x1158e60, 0xc421683e00, 0x200, 0xc425c7a280, 0xc425c7a2e0, 0xc425c34080, 0xb, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/x/stake/types/validator.go:392 +0x208\ngithub.com/cosmos/cosmos-sdk/x/stake/keeper.Keeper.AddValidatorTokensAndShares(0x114f820, 0xc4201db140, 0x114f860, 0xc4201db150, 0xc4200de850, 0x115d600, 0xc4201e2ee0, 0x115ece0, 0xc4201b3320, 0xc4200de850, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/x/stake/keeper/validator.go:132 +0x211\ngithub.com/cosmos/cosmos-sdk/x/stake/keeper.Keeper.Delegate(0x114f820, 0xc4201db140, 0x114f860, 0xc4201db150, 0xc4200de850, 0x115d600, 0xc4201e2ee0, 0x115ece0, 0xc4201b3320, 0xc4200de850, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/x/stake/keeper/delegation.go:399 +0x560\ngithub.com/cosmos/cosmos-sdk/x/stake.handleMsgDelegate(0x11579a0, 0xc422f6d650, 0xc42492e080, 0x10, 0xc422c47c20, 0x14, 0x14, 0xc422c47c40, 0x14, 0x14, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/x/stake/handler.go:193 +0x400\ngithub.com/cosmos/cosmos-sdk/x/stake.NewHandler.func1(0x11579a0, 0xc422f6d650, 0xc42492e080, 0x10, 0x115a860, 0xc4259ce690, 0x0, 0x0, 0x0, 0x0, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/x/stake/handler.go:22 +0x3b7\ngithub.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).runMsgs(0xc420218960, 0x11579a0, 0xc422f6d650, 0xc42492e080, 0x10, 0xc424ad5580, 0x1, 0x1, 0xc42492e002, 0x0, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/baseapp/baseapp.go:541 +0xbd6\ngithub.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).runTx(0xc420218960, 0x2, 0xc423a11e10, 0xc2, 0xc2, 0x114dde0, 0xc424e88360, 0x0, 0x0, 0x0, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/baseapp/baseapp.go:655 +0x3b9\ngithub.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).DeliverTx(0xc420218960, 0xc423a11e10, 0xc2, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/baseapp/baseapp.go:476 +0x267\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/abci/client.(*localClient).DeliverTxAsync(0xc420088d80, 0xc423a11e10, 0xc2, 0xc2, 0x0)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/abci/client/local_client.go:76 +0x88\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/proxy.(*appConnConsensus).DeliverTxAsync(0xc420222b00, 0xc423a11e10, 0xc2, 0xc2, 0x7)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/proxy/app_conn.go:73 +0x51\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/state.execBlockOnProxyApp(0x1158620, 0xc420881fa0, 0x115d2a0, 0xc420222b00, 0xc4211da1e0, 0xc42141f8c0, 0x1161d80, 0xc42000e490, 0x32e4, 0xc424984140, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/state/execution.go:248 +0x616\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/state.(*BlockExecutor).ApplyBlock(0xc42010fd50, 0x7, 0x0, 0xc420c087b6, 0x6, 0xc420c087d0, 0x9, 0x7ea9, 0x32e4, 0xc424984140, ...)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/state/execution.go:96 +0x1a5\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).finalizeCommit(0xc4200bf880, 0x7eaa)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1327 +0xad9\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).tryFinalizeCommit(0xc4200bf880, 0x7eaa)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1258 +0x462\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).enterCommit.func1(0xc4200bf880, 0x0, 0x7eaa)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1204 +0x98\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).enterCommit(0xc4200bf880, 0x7eaa, 0x0)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1235 +0x72c\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote(0xc4200bf880, 0xc4241e7c20, 0xc424eba840, 0x28, 0x42b4d9, 0x10cce18, 0x109)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1659 +0xc1e\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote(0xc4200bf880, 0xc4241e7c20, 0xc424eba840, 0x28, 0xb106f7, 0xc421a02000, 0xc4214585a0)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:1506 +0x59\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg(0xc4200bf880, 0x114c4c0, 0xc4230e6898, 0xc424eba840, 0x28)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:660 +0x6af\ngithub.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine(0xc4200bf880, 0x0)\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:617 +0x6a2\ncreated by github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).OnStart\n\t/root/go/src/github.com/cosmos/cosmos-sdk/vendor/github.com/tendermint/tendermint/consensus/state.go:311 +0x140\n"}

@LeeBlues
Copy link

LeeBlues commented Nov 12, 2018

Thanks @kauchy!! good job sir!

@kauchy
Copy link
Author

kauchy commented Nov 12, 2018

the issue steak do not add by lossen pool,but can delegate,this made lossen nearly 0,so no one can delegate now @cwgoes

@cwgoes
Copy link
Contributor

cwgoes commented Nov 12, 2018

@gamarin2 OK - that's presumably happening since tokens were minted without being deducted but the pool tracking total supply wasn't updated (since the tokens never should have been minted).

@iammelea
Copy link

awesome, thanks for discovering and sharing.

@jaybxyz
Copy link

jaybxyz commented Nov 12, 2018

thanks for sharing before GoS begins!

@wansYoon
Copy link

Thanks for sharing. @kauchy

And we want to give you 300Atom after mainnet launching.

kauchy3

Great work !

@bneiluj
Copy link

bneiluj commented Nov 12, 2018

Amazing! Right before GoS 👏

@awrelll
Copy link

awrelll commented Nov 12, 2018

Thanks for sharing. @kauchy

And we want to give you 300Atom after mainnet launching.

kauchy3

Great work !

Also add 200 Atoms from me !

@kauchy
Copy link
Author

kauchy commented May 22, 2019

@wansYoon @awrelll
If your reward is still effective.Please send the Atoms to cosmos1hcj3ze7ju4rll52qrc9260nl2rqv9jwqtzw7l0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.