Skip to content

Commit

Permalink
feat: api: sanity check the "to" address of outgoing messages
Browse files Browse the repository at this point in the history
If the "to" address of an outgoing message is a _delegated_ address,
verify that it maps to a valid Ethereum address. This isn't a consensus
critical change, but it'll help prevent client-side address conversion
libraries from directing messages into oblivion (e.g., by
mis-translating `0xff0000....` addresses into `f410f...` addresses
instead of `f0...` addresses.
  • Loading branch information
Stebalien committed Jun 21, 2024
1 parent 286fada commit d2285e0
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions node/impl/full/mpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/messagesigner"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/node/modules/dtypes"
)

Expand Down Expand Up @@ -131,14 +132,24 @@ func (a *MpoolAPI) MpoolClear(ctx context.Context, local bool) error {
}

func (m *MpoolModule) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) {
if err := m.messageSanityCheck(&smsg.Message); err != nil {

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Check (gen-check)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-eth_legacy_transactions)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-eth_legacy_transactions)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_terminate)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_terminate)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-eth_block_hash)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-eth_block_hash)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-wdpost_dispute)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-wdpost_dispute)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-eth_filter)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-eth_filter)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-splitstore)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-splitstore)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-supply)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-supply)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-paych_cli)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-paych_cli)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-wdpost_config)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-wdpost_config)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-eth_hash_lookup)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-eth_hash_lookup)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-direct_data_onboard)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-direct_data_onboard)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-paych_api)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-paych_api)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-fevm)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-fevm)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-deadlines)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-deadlines)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-migration)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-migration)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-api)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-api)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-direct_data_onboard_verified)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-direct_data_onboard_verified)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-wdpost_worker_config)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-wdpost_worker_config)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Build

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-manual_onboarding)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-manual_onboarding)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-gateway)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-gateway)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-wdpost_no_miner_storage)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-wdpost_no_miner_storage)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_unseal)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_unseal)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-harmonydb)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-harmonydb)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_import_full)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_import_full)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_import_simple)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_import_simple)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_pledge)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sector_pledge)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sealing_resources)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (itest-sealing_resources)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (unit-cli)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (unit-rest)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)

Check failure on line 135 in node/impl/full/mpool.go

View workflow job for this annotation

GitHub Actions / Test (unit-rest)

m.messageSanityCheck undefined (type *MpoolModule has no field or method messageSanityCheck)
return cid.Undef, xerrors.Errorf("message %s from %s with nonce %d failed sanity check: %w", smsg.Cid(), smsg.Message.From, smsg.Message.Nonce, err)
}
return m.Mpool.Push(ctx, smsg, true)
}

func (a *MpoolAPI) MpoolPushUntrusted(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) {
if err := sanityCheckOutgoingMessage(&smsg.Message); err != nil {
return cid.Undef, xerrors.Errorf("message %s from %s with nonce %d failed sanity check: %w", smsg.Cid(), smsg.Message.From, smsg.Message.Nonce, err)
}
return a.Mpool.PushUntrusted(ctx, smsg)
}

func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
if err := sanityCheckOutgoingMessage(msg); err != nil {
return nil, xerrors.Errorf("message from %s failed sanity check: %w", msg.From, err)
}

cp := *msg
msg = &cp
inMsg := *msg
Expand Down Expand Up @@ -223,6 +234,11 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe
}

func (a *MpoolAPI) MpoolBatchPush(ctx context.Context, smsgs []*types.SignedMessage) ([]cid.Cid, error) {
for _, msg := range smsgs {
if err := sanityCheckOutgoingMessage(&msg.Message); err != nil {
return nil, xerrors.Errorf("message %s from %s with nonce %d failed sanity check: %w", msg.Cid(), msg.Message.From, msg.Message.Nonce, err)
}
}
var messageCids []cid.Cid
for _, smsg := range smsgs {
smsgCid, err := a.Mpool.Push(ctx, smsg, true)
Expand All @@ -235,6 +251,11 @@ func (a *MpoolAPI) MpoolBatchPush(ctx context.Context, smsgs []*types.SignedMess
}

func (a *MpoolAPI) MpoolBatchPushUntrusted(ctx context.Context, smsgs []*types.SignedMessage) ([]cid.Cid, error) {
for _, msg := range smsgs {
if err := sanityCheckOutgoingMessage(&msg.Message); err != nil {
return nil, xerrors.Errorf("message %s from %s with nonce %d failed sanity check: %w", msg.Cid(), msg.Message.From, msg.Message.Nonce, err)
}
}
var messageCids []cid.Cid
for _, smsg := range smsgs {
smsgCid, err := a.Mpool.PushUntrusted(ctx, smsg)
Expand All @@ -247,6 +268,11 @@ func (a *MpoolAPI) MpoolBatchPushUntrusted(ctx context.Context, smsgs []*types.S
}

func (a *MpoolAPI) MpoolBatchPushMessage(ctx context.Context, msgs []*types.Message, spec *api.MessageSendSpec) ([]*types.SignedMessage, error) {
for i, msg := range msgs {
if err := sanityCheckOutgoingMessage(msg); err != nil {
return nil, xerrors.Errorf("message #%d from %s with failed sanity check: %w", i, msg.From, err)
}
}
var smsgs []*types.SignedMessage
for _, msg := range msgs {
smsg, err := a.MpoolPushMessage(ctx, msg, spec)
Expand Down Expand Up @@ -277,3 +303,19 @@ func (a *MpoolAPI) MpoolGetNonce(ctx context.Context, addr address.Address) (uin
func (a *MpoolAPI) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate, error) {
return a.Mpool.Updates(ctx)
}

func sanityCheckOutgoingMessage(msg *types.Message) error {
// Check that the message's TO address is a _valid_ Eth address if it's a delegated address.
//
// It's legal (from a consensus perspective) to send funds to any 0xf410f address as long as
// the payload is at most 54 bytes, but the vast majority of this address space is
// essentially a black-hole. Unfortunately, the conversion from 0x addresses to Filecoin
// native addresses has a few pitfalls (especially with respect to masked ID addresses), so
// we've added this check to the API to avoid accidentally (and avoidably) sending messages
// to these black-hole addresses.
if msg.To.Protocol() == address.Delegated && !ethtypes.IsEthAddress(msg.To) {
return xerrors.Errorf("message recipient %s is a delegated address but not a valid Eth Address", msg.To)
}

return nil
}

0 comments on commit d2285e0

Please sign in to comment.