Skip to content

Commit

Permalink
Bugfix: Fixed crash with timeout handling on API handler (#3187)
Browse files Browse the repository at this point in the history
Race condition could result in logging messages being sent after the
connection is already closed.
  • Loading branch information
scudette committed Dec 23, 2023
1 parent 5dfbb65 commit e557b9a
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 7 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
name: Windows Test
on: [pull_request]

jobs:
build:
name: Windows Test
Expand All @@ -16,7 +17,7 @@ jobs:

- name: Configure test environment
shell: cmd
if: success()
if: always()
run: |
echo %PATH%
echo %GOPATH%
Expand All @@ -36,7 +37,7 @@ jobs:
regedit /S artifacts/testdata/windows/init.reg
- name: Build
if: success()
if: always()
env:
CC: x86_64-w64-mingw32-gcc
shell: bash
Expand Down Expand Up @@ -65,7 +66,7 @@ jobs:
- name: Test
shell: bash
if: success()
if: always()
env:
# Disable CGO for building tests - it takes too long and it is
# not needed (mainly disables Yara building again).
Expand Down
18 changes: 16 additions & 2 deletions api/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"io"
"log"
"runtime/debug"
"sync"
"time"

"github.com/Velocidex/ordereddict"
Expand All @@ -36,6 +37,7 @@ import (
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
"www.velocidex.com/golang/velociraptor/logging"
"www.velocidex.com/golang/velociraptor/services"
"www.velocidex.com/golang/velociraptor/utils"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
"www.velocidex.com/golang/velociraptor/vql/acl_managers"
"www.velocidex.com/golang/vfilter"
Expand Down Expand Up @@ -99,6 +101,10 @@ func streamQuery(
// Now execute the query.
scope := manager.BuildScope(builder)

// Keep the connection open until the logs are sent.
wg := sync.WaitGroup{}
defer wg.Wait()

subctx, cancel := context.WithCancel(ctx)
defer cancel()

Expand All @@ -108,13 +114,19 @@ func streamQuery(
timed_ctx, timed_cancel := context.WithTimeout(subctx,
time.Second*time.Duration(arg.Timeout))

wg.Add(1)
go func() {
defer wg.Done()

select {
case <-ctx.Done():
// Cancelling the parent will not return a log.
case <-subctx.Done():
timed_cancel()

// Log the timeout
case <-timed_ctx.Done():
scope.Log("collect: <red>Timeout Error:</> Collection timed out after %v",
time.Now().Sub(start))
utils.GetTime().Now().Sub(start))
// Cancel the main context.
cancel()
timed_cancel()
Expand All @@ -126,7 +138,9 @@ func streamQuery(
scope.SetThrottler(
actions.NewThrottler(subctx, scope, 0, float64(arg.CpuLimit), 0))

wg.Add(1)
go func() {
defer wg.Done()
defer close(response_channel)
defer scope.Close()

Expand Down
2 changes: 1 addition & 1 deletion file_store/directory/listener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (self *TestSuite) TestListenerPreserveTypes() {
Set("B", uint64(9223372036854775808))
listener.Send(event_source)

vtesting.WaitUntil(time.Second, self.T(), func() bool {
vtesting.WaitUntil(time.Second*5, self.T(), func() bool {
// Make sure we wrote to the buffer file.
size, _ := listener.Debug().GetInt64("Size")
return size > directory.FirstRecordOffset
Expand Down
8 changes: 7 additions & 1 deletion services/interrogation/interrogation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package interrogation_test

import (
"context"
"fmt"
"testing"
"time"

Expand All @@ -15,6 +16,7 @@ import (
flows_proto "www.velocidex.com/golang/velociraptor/flows/proto"
"www.velocidex.com/golang/velociraptor/paths"
"www.velocidex.com/golang/velociraptor/services"
"www.velocidex.com/golang/velociraptor/utils"
"www.velocidex.com/golang/velociraptor/vtesting"

_ "www.velocidex.com/golang/velociraptor/result_sets/timed"
Expand All @@ -37,7 +39,7 @@ type: INTERNAL
`,
})

self.client_id = "C.12312"
self.client_id = fmt.Sprintf("C.1%d", utils.GetId())
self.flow_id = "F.1232"

self.TestSuite.SetupTest()
Expand Down Expand Up @@ -180,6 +182,10 @@ func (self *ServicesTestSuite) TestEnrollService() {
}
}

if len(children) > 1 {
test_utils.GetMemoryDataStore(self.T(), self.ConfigObj).Debug(self.ConfigObj)
}

assert.Equal(self.T(), len(children), 1)
assert.Equal(self.T(), children[0].Base(),
client_info.LastInterrogateFlowId)
Expand Down

0 comments on commit e557b9a

Please sign in to comment.