diff options
author | Till <2353100+S7evinK@users.noreply.github.com> | 2023-07-07 20:37:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-07 20:37:23 +0200 |
commit | eb9e90379d9f19b1b4192248cbf4931874324857 (patch) | |
tree | 4178b1b03ee3a33a70d5b6630e580d029ddf8bec /roomserver | |
parent | e93bdd56fd2c155eaf577e337e565f2054408fd4 (diff) |
Add event size checks similar to Synapse (#3140)
Companion to https://github.com/matrix-org/gomatrixserverlib/pull/400
This tries to mimic the logic found in Synapse, as dropping events can
break rooms (and we may end up in endless loops..)
Diffstat (limited to 'roomserver')
-rw-r--r-- | roomserver/internal/input/input_events.go | 15 | ||||
-rw-r--r-- | roomserver/internal/input/input_missing.go | 71 |
2 files changed, 74 insertions, 12 deletions
diff --git a/roomserver/internal/input/input_events.go b/roomserver/internal/input/input_events.go index db3c9550..93f6cc01 100644 --- a/roomserver/internal/input/input_events.go +++ b/roomserver/internal/input/input_events.go @@ -250,6 +250,21 @@ func (r *Inputer) processRoomEvent( // really do anything with the event other than reject it at this point. isRejected = true rejectionErr = fmt.Errorf("missingState.processEventWithMissingState: %w", err) + switch e := err.(type) { + case gomatrixserverlib.EventValidationError: + if e.Persistable && stateSnapshot != nil { + // We retrieved some state and we ended up having to call /state_ids for + // the new event in question (probably because closing the gap by using + // /get_missing_events didn't do what we hoped) so we'll instead overwrite + // the state snapshot with the newly resolved state. + missingPrev = false + input.HasState = true + input.StateEventIDs = make([]string, 0, len(stateSnapshot.StateEvents)) + for _, se := range stateSnapshot.StateEvents { + input.StateEventIDs = append(input.StateEventIDs, se.EventID()) + } + } + } } else if stateSnapshot != nil { // We retrieved some state and we ended up having to call /state_ids for // the new event in question (probably because closing the gap by using diff --git a/roomserver/internal/input/input_missing.go b/roomserver/internal/input/input_missing.go index 7ee84e4c..5b4c0727 100644 --- a/roomserver/internal/input/input_missing.go +++ b/roomserver/internal/input/input_missing.go @@ -259,12 +259,20 @@ func (t *missingStateReq) lookupResolvedStateBeforeEvent(ctx context.Context, e // Therefore, we cannot just query /state_ids with this event to get the state before. Instead, we need to query // the state AFTER all the prev_events for this event, then apply state resolution to that to get the state before the event. var states []*respState + var validationError error for _, prevEventID := range e.PrevEventIDs() { // Look up what the state is after the backward extremity. This will either // come from the roomserver, if we know all the required events, or it will // come from a remote server via /state_ids if not. prevState, trustworthy, err := t.lookupStateAfterEvent(ctx, roomVersion, e.RoomID(), prevEventID) - if err != nil { + switch err2 := err.(type) { + case gomatrixserverlib.EventValidationError: + if !err2.Persistable { + return nil, err2 + } + validationError = err2 + case nil: + default: return nil, fmt.Errorf("t.lookupStateAfterEvent: %w", err) } // Append the state onto the collected state. We'll run this through the @@ -311,12 +319,19 @@ func (t *missingStateReq) lookupResolvedStateBeforeEvent(ctx context.Context, e t.roomsMu.Lock(e.RoomID()) resolvedState, err = t.resolveStatesAndCheck(ctx, roomVersion, respStates, e) t.roomsMu.Unlock(e.RoomID()) - if err != nil { + switch err2 := err.(type) { + case gomatrixserverlib.EventValidationError: + if !err2.Persistable { + return nil, err2 + } + validationError = err2 + case nil: + default: return nil, fmt.Errorf("t.resolveStatesAndCheck: %w", err) } } - return resolvedState, nil + return resolvedState, validationError } // lookupStateAfterEvent returns the room state after `eventID`, which is the state before eventID with the state of `eventID` (if it's a state event) @@ -339,8 +354,15 @@ func (t *missingStateReq) lookupStateAfterEvent(ctx context.Context, roomVersion } // fetch the event we're missing and add it to the pile + var validationError error h, err := t.lookupEvent(ctx, roomVersion, roomID, eventID, false) - switch err.(type) { + switch e := err.(type) { + case gomatrixserverlib.EventValidationError: + if !e.Persistable { + logrus.WithContext(ctx).WithError(err).Errorf("Failed to look up event %s", eventID) + return nil, false, e + } + validationError = e case verifySigError: return respState, false, nil case nil: @@ -365,7 +387,7 @@ func (t *missingStateReq) lookupStateAfterEvent(ctx context.Context, roomVersion } } - return respState, false, nil + return respState, false, validationError } func (t *missingStateReq) cacheAndReturn(ev gomatrixserverlib.PDU) gomatrixserverlib.PDU { @@ -481,6 +503,7 @@ func (t *missingStateReq) resolveStatesAndCheck(ctx context.Context, roomVersion return nil, err } // apply the current event + var validationError error retryAllowedState: if err = checkAllowedByState(backwardsExtremity, resolvedStateEvents, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { return t.inputer.Queryer.QueryUserIDForSender(ctx, roomID, senderID) @@ -488,7 +511,12 @@ retryAllowedState: switch missing := err.(type) { case gomatrixserverlib.MissingAuthEventError: h, err2 := t.lookupEvent(ctx, roomVersion, backwardsExtremity.RoomID(), missing.AuthEventID, true) - switch err2.(type) { + switch e := err2.(type) { + case gomatrixserverlib.EventValidationError: + if !e.Persistable { + return nil, e + } + validationError = e case verifySigError: return &parsedRespState{ AuthEvents: authEventList, @@ -509,7 +537,7 @@ retryAllowedState: return &parsedRespState{ AuthEvents: authEventList, StateEvents: resolvedStateEvents, - }, nil + }, validationError } // get missing events for `e`. If `isGapFilled`=true then `newEvents` contains all the events to inject, @@ -779,7 +807,11 @@ func (t *missingStateReq) lookupMissingStateViaStateIDs(ctx context.Context, roo // Define what we'll do in order to fetch the missing event ID. fetch := func(missingEventID string) { h, herr := t.lookupEvent(ctx, roomVersion, roomID, missingEventID, false) - switch herr.(type) { + switch e := herr.(type) { + case gomatrixserverlib.EventValidationError: + if !e.Persistable { + return + } case verifySigError: return case nil: @@ -869,6 +901,8 @@ func (t *missingStateReq) lookupEvent(ctx context.Context, roomVersion gomatrixs } var event gomatrixserverlib.PDU found := false + var validationError error +serverLoop: for _, serverName := range t.servers { reqctx, cancel := context.WithTimeout(ctx, time.Second*30) defer cancel() @@ -886,12 +920,25 @@ func (t *missingStateReq) lookupEvent(ctx context.Context, roomVersion gomatrixs continue } event, err = verImpl.NewEventFromUntrustedJSON(txn.PDUs[0]) - if err != nil { + switch e := err.(type) { + case gomatrixserverlib.EventValidationError: + // If the event is persistable, e.g. failed validation for exceeding + // byte sizes, we can "accept" the event. + if e.Persistable { + validationError = e + found = true + break serverLoop + } + // If we can't persist the event, we probably can't do so with results + // from other servers, so also break the loop. + break serverLoop + case nil: + found = true + break serverLoop + default: t.log.WithError(err).WithField("missing_event_id", missingEventID).Warnf("Failed to parse event JSON of event returned from /event") continue } - found = true - break } if !found { t.log.WithField("missing_event_id", missingEventID).Warnf("Failed to get missing /event for event ID from %d server(s)", len(t.servers)) @@ -903,7 +950,7 @@ func (t *missingStateReq) lookupEvent(ctx context.Context, roomVersion gomatrixs t.log.WithError(err).Warnf("Couldn't validate signature of event %q from /event", event.EventID()) return nil, verifySigError{event.EventID(), err} } - return t.cacheAndReturn(event), nil + return t.cacheAndReturn(event), validationError } func checkAllowedByState(e gomatrixserverlib.PDU, stateEvents []gomatrixserverlib.PDU, userIDForSender spec.UserIDForSender) error { |