Skip to content

Commit

Permalink
Fix stack overflow panic in reverse entry check when inbox ends with …
Browse files Browse the repository at this point in the history
…wildcard
  • Loading branch information
neilalexander committed Feb 13, 2023
1 parent 7afddb3 commit ba0b1f8
Showing 1 changed file with 22 additions and 6 deletions.
28 changes: 22 additions & 6 deletions server/accounts.go
Expand Up @@ -1701,7 +1701,7 @@ func (a *Account) addReverseRespMapEntry(acc *Account, reply, from string) {
// checkForReverseEntries is for when we are trying to match reverse entries to a wildcard.
// This will be called from checkForReverseEntry when the reply arg is a wildcard subject.
// This will usually be called in a go routine since we need to walk all the entries.
func (a *Account) checkForReverseEntries(reply string, checkInterest bool) {
func (a *Account) checkForReverseEntries(reply string, checkInterest, recursed bool) {
a.mu.RLock()
if len(a.imports.rrMap) == 0 {
a.mu.RUnlock()
Expand All @@ -1710,7 +1710,7 @@ func (a *Account) checkForReverseEntries(reply string, checkInterest bool) {

if subjectIsLiteral(reply) {
a.mu.RUnlock()
a.checkForReverseEntry(reply, nil, checkInterest)
a._checkForReverseEntry(reply, nil, checkInterest, recursed)
return
}

Expand All @@ -1723,28 +1723,44 @@ func (a *Account) checkForReverseEntries(reply string, checkInterest bool) {
}
a.mu.RUnlock()

for _, reply := range rs {
a.checkForReverseEntry(reply, nil, checkInterest)
for _, r := range rs {
a._checkForReverseEntry(r, nil, checkInterest, recursed)
}
}

// This checks for any response map entries. If you specify an si we will only match and
// clean up for that one, otherwise we remove them all.
func (a *Account) checkForReverseEntry(reply string, si *serviceImport, checkInterest bool) {
a._checkForReverseEntry(reply, si, checkInterest, false)
}

// Callers should use checkForReverseEntry instead. This function exists to help prevent
// infinite recursion.
func (a *Account) _checkForReverseEntry(reply string, si *serviceImport, checkInterest, recursed bool) {
a.mu.RLock()
if len(a.imports.rrMap) == 0 {
a.mu.RUnlock()
return
}

if subjectHasWildcard(reply) {
if recursed {
// If we have reached this condition then it is because the reverse entries also
// contain wildcards (that shouldn't happen but a client *could* provide an inbox
// prefix that is illegal because it ends in a wildcard character), at which point
// we will end up with infinite recursion between this func and checkForReverseEntries.
// To avoid a stack overflow panic, we'll give up instead.
a.mu.RUnlock()
return
}

doInline := len(a.imports.rrMap) <= 64
a.mu.RUnlock()

if doInline {
a.checkForReverseEntries(reply, checkInterest)
a.checkForReverseEntries(reply, checkInterest, true)
} else {
go a.checkForReverseEntries(reply, checkInterest)
go a.checkForReverseEntries(reply, checkInterest, true)
}
return
}
Expand Down

0 comments on commit ba0b1f8

Please sign in to comment.