Fix outliers whose auth_events are in a different room are correctly rejected
(#2791)
Fixes `outliers whose auth_events are in a different room are correctly rejected`, by validating that auth events are all from the same room and not using rejected events for event auth.
This commit is contained in:
parent
f3be4b3185
commit
088ad1dd21
2
go.mod
2
go.mod
|
@ -22,7 +22,7 @@ require (
|
||||||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20221011115330-49fa704b9a64
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20221014061925-a132619fa241
|
||||||
github.com/matrix-org/pinecone v0.0.0-20220929155234-2ce51dd4a42c
|
github.com/matrix-org/pinecone v0.0.0-20220929155234-2ce51dd4a42c
|
||||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
||||||
github.com/mattn/go-sqlite3 v1.14.15
|
github.com/mattn/go-sqlite3 v1.14.15
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -384,8 +384,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20221011115330-49fa704b9a64 h1:QJmfAPC3P0ZHJzYD/QtbNc5EztKlK1ipRWP5SO/m4jw=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20221014061925-a132619fa241 h1:e5o68MWeU7wjTvvNKmVo655oCYesoNRoPeBb1Xfz54g=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20221011115330-49fa704b9a64/go.mod h1:Mtifyr8q8htcBeugvlDnkBcNUy5LO8OzUoplAf1+mb4=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20221014061925-a132619fa241/go.mod h1:Mtifyr8q8htcBeugvlDnkBcNUy5LO8OzUoplAf1+mb4=
|
||||||
github.com/matrix-org/pinecone v0.0.0-20220929155234-2ce51dd4a42c h1:iCHLYwwlPsf4TYFrvhKdhQoAM2lXzcmDZYqwBNWcnVk=
|
github.com/matrix-org/pinecone v0.0.0-20220929155234-2ce51dd4a42c h1:iCHLYwwlPsf4TYFrvhKdhQoAM2lXzcmDZYqwBNWcnVk=
|
||||||
github.com/matrix-org/pinecone v0.0.0-20220929155234-2ce51dd4a42c/go.mod h1:K0N1ixHQxXoCyqolDqVxPM3ArrDtcMs8yegOx2Lfv9k=
|
github.com/matrix-org/pinecone v0.0.0-20220929155234-2ce51dd4a42c/go.mod h1:K0N1ixHQxXoCyqolDqVxPM3ArrDtcMs8yegOx2Lfv9k=
|
||||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4 h1:eCEHXWDv9Rm335MSuB49mFUK44bwZPFSDde3ORE3syk=
|
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4 h1:eCEHXWDv9Rm335MSuB49mFUK44bwZPFSDde3ORE3syk=
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/roomserver/state"
|
"github.com/matrix-org/dendrite/roomserver/state"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage"
|
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckForSoftFail returns true if the event should be soft-failed
|
// CheckForSoftFail returns true if the event should be soft-failed
|
||||||
|
@ -129,6 +130,12 @@ type authEvents struct {
|
||||||
stateKeyNIDMap map[string]types.EventStateKeyNID
|
stateKeyNIDMap map[string]types.EventStateKeyNID
|
||||||
state stateEntryMap
|
state stateEntryMap
|
||||||
events EventMap
|
events EventMap
|
||||||
|
valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid verifies that all auth events are from the same room.
|
||||||
|
func (ae *authEvents) Valid() bool {
|
||||||
|
return ae.valid
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create implements gomatrixserverlib.AuthEventProvider
|
// Create implements gomatrixserverlib.AuthEventProvider
|
||||||
|
@ -197,6 +204,7 @@ func loadAuthEvents(
|
||||||
needed gomatrixserverlib.StateNeeded,
|
needed gomatrixserverlib.StateNeeded,
|
||||||
state []types.StateEntry,
|
state []types.StateEntry,
|
||||||
) (result authEvents, err error) {
|
) (result authEvents, err error) {
|
||||||
|
result.valid = true
|
||||||
// Look up the numeric IDs for the state keys needed for auth.
|
// Look up the numeric IDs for the state keys needed for auth.
|
||||||
var neededStateKeys []string
|
var neededStateKeys []string
|
||||||
neededStateKeys = append(neededStateKeys, needed.Member...)
|
neededStateKeys = append(neededStateKeys, needed.Member...)
|
||||||
|
@ -218,6 +226,16 @@ func loadAuthEvents(
|
||||||
if result.events, err = db.Events(ctx, eventNIDs); err != nil {
|
if result.events, err = db.Events(ctx, eventNIDs); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
roomID := ""
|
||||||
|
for _, ev := range result.events {
|
||||||
|
if roomID == "" {
|
||||||
|
roomID = ev.RoomID()
|
||||||
|
}
|
||||||
|
if ev.RoomID() != roomID {
|
||||||
|
result.valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,16 @@ package input
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
"github.com/opentracing/opentracing-go"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
fedapi "github.com/matrix-org/dendrite/federationapi/api"
|
fedapi "github.com/matrix-org/dendrite/federationapi/api"
|
||||||
"github.com/matrix-org/dendrite/internal"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||||
|
@ -31,11 +38,6 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
|
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
|
||||||
"github.com/matrix-org/dendrite/roomserver/state"
|
"github.com/matrix-org/dendrite/roomserver/state"
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
|
||||||
"github.com/matrix-org/util"
|
|
||||||
"github.com/opentracing/opentracing-go"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Does this value make sense?
|
// TODO: Does this value make sense?
|
||||||
|
@ -196,7 +198,7 @@ func (r *Inputer) processRoomEvent(
|
||||||
isRejected := false
|
isRejected := false
|
||||||
authEvents := gomatrixserverlib.NewAuthEvents(nil)
|
authEvents := gomatrixserverlib.NewAuthEvents(nil)
|
||||||
knownEvents := map[string]*types.Event{}
|
knownEvents := map[string]*types.Event{}
|
||||||
if err = r.fetchAuthEvents(ctx, logger, headered, &authEvents, knownEvents, serverRes.ServerNames); err != nil {
|
if err = r.fetchAuthEvents(ctx, logger, roomInfo, headered, &authEvents, knownEvents, serverRes.ServerNames); err != nil {
|
||||||
return fmt.Errorf("r.fetchAuthEvents: %w", err)
|
return fmt.Errorf("r.fetchAuthEvents: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +338,7 @@ func (r *Inputer) processRoomEvent(
|
||||||
// doesn't have any associated state to store and we don't need to
|
// doesn't have any associated state to store and we don't need to
|
||||||
// notify anyone about it.
|
// notify anyone about it.
|
||||||
if input.Kind == api.KindOutlier {
|
if input.Kind == api.KindOutlier {
|
||||||
logger.Debug("Stored outlier")
|
logger.WithField("rejected", isRejected).Debug("Stored outlier")
|
||||||
hooks.Run(hooks.KindNewEventPersisted, headered)
|
hooks.Run(hooks.KindNewEventPersisted, headered)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -536,6 +538,7 @@ func (r *Inputer) processStateBefore(
|
||||||
func (r *Inputer) fetchAuthEvents(
|
func (r *Inputer) fetchAuthEvents(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *logrus.Entry,
|
logger *logrus.Entry,
|
||||||
|
roomInfo *types.RoomInfo,
|
||||||
event *gomatrixserverlib.HeaderedEvent,
|
event *gomatrixserverlib.HeaderedEvent,
|
||||||
auth *gomatrixserverlib.AuthEvents,
|
auth *gomatrixserverlib.AuthEvents,
|
||||||
known map[string]*types.Event,
|
known map[string]*types.Event,
|
||||||
|
@ -557,9 +560,19 @@ func (r *Inputer) fetchAuthEvents(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ev := authEvents[0]
|
ev := authEvents[0]
|
||||||
|
|
||||||
|
isRejected := false
|
||||||
|
if roomInfo != nil {
|
||||||
|
isRejected, err = r.DB.IsEventRejected(ctx, roomInfo.RoomNID, ev.EventID())
|
||||||
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return fmt.Errorf("r.DB.IsEventRejected failed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
known[authEventID] = &ev // don't take the pointer of the iterated event
|
known[authEventID] = &ev // don't take the pointer of the iterated event
|
||||||
if err = auth.AddEvent(ev.Event); err != nil {
|
if !isRejected {
|
||||||
return fmt.Errorf("auth.AddEvent: %w", err)
|
if err = auth.AddEvent(ev.Event); err != nil {
|
||||||
|
return fmt.Errorf("auth.AddEvent: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
63
roomserver/internal/input/input_events_test.go
Normal file
63
roomserver/internal/input/input_events_test.go
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package input
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_EventAuth(t *testing.T) {
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
|
||||||
|
// create two rooms, so we can craft "illegal" auth events
|
||||||
|
room1 := test.NewRoom(t, alice)
|
||||||
|
room2 := test.NewRoom(t, alice, test.RoomPreset(test.PresetPublicChat))
|
||||||
|
|
||||||
|
authEventIDs := make([]string, 0, 4)
|
||||||
|
authEvents := []*gomatrixserverlib.Event{}
|
||||||
|
|
||||||
|
// Add the legal auth events from room2
|
||||||
|
for _, x := range room2.Events() {
|
||||||
|
if x.Type() == gomatrixserverlib.MRoomCreate {
|
||||||
|
authEventIDs = append(authEventIDs, x.EventID())
|
||||||
|
authEvents = append(authEvents, x.Event)
|
||||||
|
}
|
||||||
|
if x.Type() == gomatrixserverlib.MRoomPowerLevels {
|
||||||
|
authEventIDs = append(authEventIDs, x.EventID())
|
||||||
|
authEvents = append(authEvents, x.Event)
|
||||||
|
}
|
||||||
|
if x.Type() == gomatrixserverlib.MRoomJoinRules {
|
||||||
|
authEventIDs = append(authEventIDs, x.EventID())
|
||||||
|
authEvents = append(authEvents, x.Event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the illegal auth event from room1 (rooms are different)
|
||||||
|
for _, x := range room1.Events() {
|
||||||
|
if x.Type() == gomatrixserverlib.MRoomMember {
|
||||||
|
authEventIDs = append(authEventIDs, x.EventID())
|
||||||
|
authEvents = append(authEvents, x.Event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Craft the illegal join event, with auth events from different rooms
|
||||||
|
ev := room2.CreateEvent(t, bob, "m.room.member", map[string]interface{}{
|
||||||
|
"membership": "join",
|
||||||
|
}, test.WithStateKey(bob.ID), test.WithAuthIDs(authEventIDs))
|
||||||
|
|
||||||
|
// Add the auth events to the allower
|
||||||
|
allower := gomatrixserverlib.NewAuthEvents(nil)
|
||||||
|
for _, a := range authEvents {
|
||||||
|
if err := allower.AddEvent(a); err != nil {
|
||||||
|
t.Fatalf("allower.AddEvent failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally check that the event is NOT allowed
|
||||||
|
if err := gomatrixserverlib.Allowed(ev.Event, &allower); err == nil {
|
||||||
|
t.Fatalf("event should not be allowed, but it was")
|
||||||
|
}
|
||||||
|
}
|
|
@ -744,3 +744,4 @@ User in remote room doesn't appear in user directory after server left room
|
||||||
User in shared private room does appear in user directory until leave
|
User in shared private room does appear in user directory until leave
|
||||||
Existing members see new member's presence
|
Existing members see new member's presence
|
||||||
Inbound federation can return missing events for joined visibility
|
Inbound federation can return missing events for joined visibility
|
||||||
|
outliers whose auth_events are in a different room are correctly rejected
|
|
@ -30,6 +30,7 @@ type eventMods struct {
|
||||||
unsigned interface{}
|
unsigned interface{}
|
||||||
keyID gomatrixserverlib.KeyID
|
keyID gomatrixserverlib.KeyID
|
||||||
privKey ed25519.PrivateKey
|
privKey ed25519.PrivateKey
|
||||||
|
authEvents []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type eventModifier func(e *eventMods)
|
type eventModifier func(e *eventMods)
|
||||||
|
@ -52,6 +53,12 @@ func WithUnsigned(unsigned interface{}) eventModifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithAuthIDs(evs []string) eventModifier {
|
||||||
|
return func(e *eventMods) {
|
||||||
|
e.authEvents = evs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WithKeyID(keyID gomatrixserverlib.KeyID) eventModifier {
|
func WithKeyID(keyID gomatrixserverlib.KeyID) eventModifier {
|
||||||
return func(e *eventMods) {
|
return func(e *eventMods) {
|
||||||
e.keyID = keyID
|
e.keyID = keyID
|
||||||
|
|
|
@ -21,8 +21,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Preset int
|
type Preset int
|
||||||
|
@ -174,11 +175,17 @@ func (r *Room) CreateEvent(t *testing.T, creator *User, eventType string, conten
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("CreateEvent[%s]: failed to StateNeededForEventBuilder: %s", eventType, err)
|
t.Fatalf("CreateEvent[%s]: failed to StateNeededForEventBuilder: %s", eventType, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
refs, err := eventsNeeded.AuthEventReferences(&r.authEvents)
|
refs, err := eventsNeeded.AuthEventReferences(&r.authEvents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("CreateEvent[%s]: failed to AuthEventReferences: %s", eventType, err)
|
t.Fatalf("CreateEvent[%s]: failed to AuthEventReferences: %s", eventType, err)
|
||||||
}
|
}
|
||||||
builder.AuthEvents = refs
|
builder.AuthEvents = refs
|
||||||
|
|
||||||
|
if len(mod.authEvents) > 0 {
|
||||||
|
builder.AuthEvents = mod.authEvents
|
||||||
|
}
|
||||||
|
|
||||||
ev, err := builder.Build(
|
ev, err := builder.Build(
|
||||||
mod.originServerTS, mod.origin, mod.keyID,
|
mod.originServerTS, mod.origin, mod.keyID,
|
||||||
mod.privKey, r.Version,
|
mod.privKey, r.Version,
|
||||||
|
|
Loading…
Reference in a new issue