Skip to content

mixing: validate SR matrix dimensions before indexing - #3817

Open
methakon wants to merge 2 commits into
decred:masterfrom
methakon:fix/3788-sr-matrix-dimensions
Open

methakon wants to merge 2 commits into
decred:masterfrom
methakon:fix/3788-sr-matrix-dimensions

Conversation

@methakon

Copy link
Copy Markdown

Problem

The SR blame path indexes the peer's submitted matrix as p.sr.DCMix[j][k], where j is bounded
by the peer's MessageCount and k by the width of the mix being compared against it.

MessageCount and len(SlotReserveMsgs) are both checked when the run is set up
(blame.go:274), but the matrix the peer actually published is trusted to have those dimensions.
So a peer that publishes too few rows, or a row narrower than the mix, is read out of bounds here.

The DC-net path immediately below already gets this right: it checks
uint32(len(p.dc.DCNet)) != mcount and blames the peer, and it compares via the length-safe
Vec.Equals. The SR path does neither.

Change

Two length checks in the SR loop, each blaming the peer and moving on, which is how every other
dimension mismatch in this file is handled:

  • len(p.sr.DCMix) != len(p.srMsg) before the loop, since p.srMsg is sized to the already
    validated MessageCount
  • len(p.sr.DCMix[j]) != len(srMix) inside it, before the comparison

The second check also converts an out-of-bounds panic into a message naming the problem, so a
short row is reported as misbehaviour rather than crashing the node.

Test

srdimensions_test.go covers both directions for the row count and the row width, plus the exact
match and empty cases. It also pins the invariant the width check relies on: SRMix returns
exactly len(SRMixPads(...)) entries, which is what makes a narrower committed row an
out-of-bounds read.

ok  github.com/decred/dcrd/mixing/mixclient

Verification

Run from the mixing module, which is separate from the root module:

Command Result
go test ./... -count=1 (in mixing/) ok — mixing, mixclient, mixpool all pass
go test ./mixclient/ -run TestSR -count=1 ok, 2 tests pass
go vet ./mixclient/ clean
gofmt -l on both files clean

TestSRDisruption in the same package skips, as it requires the csppsolver binary which is not
on this machine; that is pre-existing and unrelated.

Note on scope

The panic this guards is reachable by a peer that completes a MixPartners handshake, so it is
behind the same access control as the rest of the misbehaviour handling in this file, which blames
rather than errors. I have not added a CVE or opened a disclosure, since the report is public;
flagging it here in case a maintainer wants it handled differently.

Fixes #3788

The parameter is optional and typed *bool, so a client may send an explicit
JSON null for it. The declared jsonrpcdefault is only applied when the field is
absent, which leaves the pointer nil, and the handler dereferenced it as its
first effective statement. The handler runs on a goroutine with no recover, so
the result is a process crash rather than a failed request, and the limited
tier of RPC credential is enough to trigger it.

Nil-guard the dereference the same way the other optional pointer parameters
in this command set are guarded at their dereference sites. Absent and explicit
false then behave identically, which is what the declared default already
implies: a request that does not opt in to high fees declines them. No signature
or wire change, so clients are unaffected.

The existing table test missed this because every case constructs the command
with a non-nil pointer, as one naturally does. The nil state is only reachable
through a parsed request. The new case is first in the table so the panic is the
first thing exercised, and it fails on the unfixed handler with a SIGSEGV at
this line before the guard is added.

Fixes decred#3813
The SR blame path indexes the submitted matrix as DCMix[j][k], with j bounded
by the peer's MessageCount and k by the width of the mix being compared. The
sizes of MessageCount and SlotReserveMsgs are checked when the run is set up,
but the matrix the peer published is trusted to have those dimensions.

The DC-net path immediately below already validates its own dimensions and
uses the length-safe Vec.Equals. The SR path does neither, so a peer that
publishes fewer rows, or a row shorter than the mix, is read out of bounds
here rather than blamed.

Add the two length checks the loop depends on, blaming the peer in each case
the way every other dimension mismatch in this file is handled. Placing the
width check before the comparison loop means a short row is reported with a
message naming the problem instead of panicking on the index.

Tests cover both directions, plus the exact-match case, and pin the invariant
that the mix width is the pads width.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mixclient: Validate SR matrix dimensions before access

1 participant