Skip to content

LegacyECChain CBOR decode accepts lengths above ChainMaxLen #1081

Description

@zeusec

I think LegacyECChain.UnmarshalCBOR is using the default cbor-gen slice cap, but ECChain has a much smaller valid max length. I am not claiming this bypasses pubsub size limits, zstd limits, or consensus validation. It just looks like the CBOR decoder accepts and allocates a chain length that ECChain.Validate() already treats as invalid.

The generated decoder in gpbft/cbor_gen.go rejects only arrays above 8192:

if extra > 8192 {
    return fmt.Errorf("(*t): array too large (%d)", extra)
}

It then allocates make([]TipSet, extra).

But in gpbft/chain.go, ChainMaxLen is 128, and ECChain.Validate() rejects longer chains with chain too long.

I checked this locally with a small test:

  • create a LegacyECChain with ChainMaxLen + 1 tipsets
  • marshal it
  • decode it into ECChain
  • call Validate()

Current behavior is that decode succeeds, the decoded chain has length 129, and only then does Validate() reject it.

This matters because decode happens before validation in the paths I checked, including GPBFT pubsub (host.go) and chainexchange pubsub (chainexchange/pubsub.go). Finality certificate decode also goes through ECChain.UnmarshalCBOR before later certificate/chain validation.

Since gpbft/cbor_gen.go is generated from gen/main.go, I am not sure what patch shape you would prefer. But I would expect LegacyECChain decode to reject extra > ChainMaxLen before allocating.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions