mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 17:56:56 +00:00
Feat 6231 deadlock (#6469)
* fixing recursive deadlock * using atomics * fixing init
This commit is contained in:
parent
0ea42e5f66
commit
39e9286371
@ -3,7 +3,7 @@ package authx
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/projectdiscovery/gologger"
|
"github.com/projectdiscovery/gologger"
|
||||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
|
||||||
@ -30,8 +30,8 @@ type Dynamic struct {
|
|||||||
Input string `json:"input" yaml:"input"` // (optional) target for the dynamic secret
|
Input string `json:"input" yaml:"input"` // (optional) target for the dynamic secret
|
||||||
Extracted map[string]interface{} `json:"-" yaml:"-"` // extracted values from the dynamic secret
|
Extracted map[string]interface{} `json:"-" yaml:"-"` // extracted values from the dynamic secret
|
||||||
fetchCallback LazyFetchSecret `json:"-" yaml:"-"`
|
fetchCallback LazyFetchSecret `json:"-" yaml:"-"`
|
||||||
m *sync.Mutex `json:"-" yaml:"-"` // mutex for lazy fetch
|
fetched *atomic.Bool `json:"-" yaml:"-"` // atomic flag to check if the secret has been fetched
|
||||||
fetched bool `json:"-" yaml:"-"` // flag to check if the secret has been fetched
|
fetching *atomic.Bool `json:"-" yaml:"-"` // atomic flag to prevent recursive fetch calls
|
||||||
error error `json:"-" yaml:"-"` // error if any
|
error error `json:"-" yaml:"-"` // error if any
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,8 @@ func (d *Dynamic) UnmarshalJSON(data []byte) error {
|
|||||||
|
|
||||||
// Validate validates the dynamic secret
|
// Validate validates the dynamic secret
|
||||||
func (d *Dynamic) Validate() error {
|
func (d *Dynamic) Validate() error {
|
||||||
d.m = &sync.Mutex{}
|
d.fetched = &atomic.Bool{}
|
||||||
|
d.fetching = &atomic.Bool{}
|
||||||
if d.TemplatePath == "" {
|
if d.TemplatePath == "" {
|
||||||
return errkit.New(" template-path is required for dynamic secret")
|
return errkit.New(" template-path is required for dynamic secret")
|
||||||
}
|
}
|
||||||
@ -97,9 +98,7 @@ func (d *Dynamic) Validate() error {
|
|||||||
func (d *Dynamic) SetLazyFetchCallback(callback LazyFetchSecret) {
|
func (d *Dynamic) SetLazyFetchCallback(callback LazyFetchSecret) {
|
||||||
d.fetchCallback = func(d *Dynamic) error {
|
d.fetchCallback = func(d *Dynamic) error {
|
||||||
err := callback(d)
|
err := callback(d)
|
||||||
d.fetched = true
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.error = err
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(d.Extracted) == 0 {
|
if len(d.Extracted) == 0 {
|
||||||
@ -184,9 +183,15 @@ func (d *Dynamic) applyValuesToSecret(secret *Secret) error {
|
|||||||
|
|
||||||
// GetStrategy returns the auth strategies for the dynamic secret
|
// GetStrategy returns the auth strategies for the dynamic secret
|
||||||
func (d *Dynamic) GetStrategies() []AuthStrategy {
|
func (d *Dynamic) GetStrategies() []AuthStrategy {
|
||||||
if !d.fetched {
|
if d.fetched.Load() {
|
||||||
|
if d.error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Try to fetch if not already fetched
|
||||||
_ = d.Fetch(true)
|
_ = d.Fetch(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.error != nil {
|
if d.error != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -203,12 +208,23 @@ func (d *Dynamic) GetStrategies() []AuthStrategy {
|
|||||||
// Fetch fetches the dynamic secret
|
// Fetch fetches the dynamic secret
|
||||||
// if isFatal is true, it will stop the execution if the secret could not be fetched
|
// if isFatal is true, it will stop the execution if the secret could not be fetched
|
||||||
func (d *Dynamic) Fetch(isFatal bool) error {
|
func (d *Dynamic) Fetch(isFatal bool) error {
|
||||||
d.m.Lock()
|
if d.fetched.Load() {
|
||||||
defer d.m.Unlock()
|
return d.error
|
||||||
if d.fetched {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to set fetching flag atomically
|
||||||
|
if !d.fetching.CompareAndSwap(false, true) {
|
||||||
|
// Already fetching, return current error
|
||||||
|
return d.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're the only one fetching, call the callback
|
||||||
d.error = d.fetchCallback(d)
|
d.error = d.fetchCallback(d)
|
||||||
|
|
||||||
|
// Mark as fetched and clear fetching flag
|
||||||
|
d.fetched.Store(true)
|
||||||
|
d.fetching.Store(false)
|
||||||
|
|
||||||
if d.error != nil && isFatal {
|
if d.error != nil && isFatal {
|
||||||
gologger.Fatal().Msgf("Could not fetch dynamic secret: %s\n", d.error)
|
gologger.Fatal().Msgf("Could not fetch dynamic secret: %s\n", d.error)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user