Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] ExecuteCallbackWithCtx leaves dangling goroutines when context is canceled #5989

Open
1 task done
jak0ne opened this issue Jan 15, 2025 · 0 comments
Open
1 task done
Labels
Type: Bug Inconsistencies or issues which will cause an issue or problem for users or implementors.

Comments

@jak0ne
Copy link

jak0ne commented Jan 15, 2025

Is there an existing issue for this?

  • I have searched the existing issues.

Current Behavior

The ExecuteCallbackWithCtx function in the sdk does not seem to clean up properly when the context is canceled and leaves running goroutines behind. These goroutines will cause a panic (nil pointer dereference) if the engine is closed right after, which should be safe to do as nothing should be running at that point.

I investigated a little bit to see if I could find the source of these dangling goroutines, still not sure if this is the cause but I saw that both host spray and template spray strategies are not deferring the workpool Wait call, so it does not get called when the context is canceled and the function returns:

For host sprays:

func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*templates.Template, target *contextargs.MetaInput, results *atomic.Bool) {
// all templates are executed on single target
// wp is workpool that contains different waitgroups for
// headless and non-headless templates
// global waitgroup should not be used here
wp := e.GetWorkPool()
for _, tpl := range alltemplates {
select {
case <-ctx.Done():
return
default:
}

For template sprays:

func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*templates.Template, target provider.InputProvider) *atomic.Bool {
results := &atomic.Bool{}
// wp is workpool that contains different waitgroups for
// headless and non-headless templates
wp := e.GetWorkPool()
for _, template := range templatesList {
select {
case <-ctx.Done():
return results
default:
}

Both of these functions call Wait at the end, but if the context is canceled, the functions will return early and not wait for workers to finish. Maybe the Wait() call should be deferred as below?

wp := e.GetWorkPool()
defer wp.Wait()

I believe it could be either this or some inner goroutine leak that does not take the context into consideration.

I can dig deeper and try to come up with a fix if you think the issue is valid.

Expected Behavior

ExecuteCallbackWithCtx should not return until all goroutines have finished. If the context is canceled, context cancellation should be propagated to all running goroutines and properly handled.

Steps To Reproduce

The following code should help reproducing the issue:

package main

import (
	"context"
	"fmt"
	"time"

	nuclei "github.com/projectdiscovery/nuclei/v3/lib"
	"github.com/projectdiscovery/nuclei/v3/pkg/output"
)

func main() {
	nucleiEngine, err := nuclei.NewNucleiEngineCtx(context.Background())
	if err != nil {
		panic("Could not initialize nuclei engine")
	}

	nucleiEngine.LoadTargets([]string{"https://example.com"}, false)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	err = nucleiEngine.ExecuteCallbackWithCtx(ctx, func(event *output.ResultEvent) {
		fmt.Printf(
			"[%s] %s -> %s\n",
			event.Info.SeverityHolder.Severity,
			event.Info.Name,
			event.Host,
		)
	})
	if err != nil {
		panic("Failed to run scan")
	}

	// At this point nothing should be running

	if ctx.Err() == nil {
		// Scan finished before context timeout, adjust timeout duration and retry
		return
	}

	// Engine should be safe to close, but dangling goroutines will generate a nil pointer dereference panic
	nucleiEngine.Close()
	time.Sleep(time.Minute) // Wait for panic, adjust duration if needed
}

Relevant log output

[INF] Templates clustered: 1257 (Reduced 1203 Requests)
[INF] Using Interactsh Server: oast.me
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7f26bc]

goroutine 11667 [running]:
github.com/projectdiscovery/fastdialer/fastdialer.(*Dialer).GetDialedIP(0x4002251d68?, {0x4002251d68?, 0x2d580e0?})
        /home/jak0/.local/share/go/pkg/mod/github.com/projectdiscovery/[email protected]/fastdialer/dialer.go:317 +0x1c
github.com/projectdiscovery/nuclei/v3/pkg/protocols/http.(*Request).executeRequest(0x4005ad6400, 0x40064b0510, 0x4005e9e3c0, 0x40064b0660, 0x0, 0x40075d58c0?, 0x1)
        /home/jak0/.local/share/go/pkg/mod/github.com/projectdiscovery/nuclei/[email protected]/pkg/protocols/http/request.go:848 +0x2da8
github.com/projectdiscovery/nuclei/v3/pkg/protocols/http.(*Request).ExecuteWithResults.func1({0x400752cbd0, 0x25}, 0x40064b06f0, 0x40064b0330)
        /home/jak0/.local/share/go/pkg/mod/github.com/projectdiscovery/nuclei/[email protected]/pkg/protocols/http/request.go:518 +0x4bc
github.com/projectdiscovery/nuclei/v3/pkg/protocols/http.(*Request).ExecuteWithResults(0x4005ad6400, 0x40064b0510, 0x40064b0330, 0x40064b0660, 0x40064b0690)
        /home/jak0/.local/share/go/pkg/mod/github.com/projectdiscovery/nuclei/[email protected]/pkg/protocols/http/request.go:590 +0x2c0
github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic.(*Generic).ExecuteWithResults(0x40061ef410, 0x4006b67680)
        /home/jak0/.local/share/go/pkg/mod/github.com/projectdiscovery/nuclei/[email protected]/pkg/tmplexec/generic/exec.go:61 +0x280
github.com/projectdiscovery/nuclei/v3/pkg/tmplexec.(*TemplateExecuter).Execute(0x4005f7c540, 0x4006b67680)
        /home/jak0/.local/share/go/pkg/mod/github.com/projectdiscovery/nuclei/[email protected]/pkg/tmplexec/exec.go:212 +0x354
github.com/projectdiscovery/nuclei/v3/pkg/core.(*Engine).executeTemplateWithTargets.func2.1(0x4d2b9e0?, 0x40?, 0x4000ec0140)
        /home/jak0/.local/share/go/pkg/mod/github.com/projectdiscovery/nuclei/[email protected]/pkg/core/executors.go:139 +0x1b0
created by github.com/projectdiscovery/nuclei/v3/pkg/core.(*Engine).executeTemplateWithTargets.func2 in goroutine 11666
        /home/jak0/.local/share/go/pkg/mod/github.com/projectdiscovery/nuclei/[email protected]/pkg/core/executors.go:115 +0x484
exit status 2

Environment

- OS: Arch Linux
- Nuclei: v3.3.8
- Go: 1.22.8

Anything else?

No response

@jak0ne jak0ne added the Type: Bug Inconsistencies or issues which will cause an issue or problem for users or implementors. label Jan 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Inconsistencies or issues which will cause an issue or problem for users or implementors.
Projects
None yet
Development

No branches or pull requests

1 participant