mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-14 15:18:06 +00:00
dd259b4957
The current implementation of the deepMatch() has the exponential runtime. Given the long enough input and the pattern with multiple wildcards it takes a while if ever to complete which can potentially be used maliciously to cause a denial of service (cpu and memory consumption). E.g. running this in the root of this repository time yq eval '.jobs.publishDocker.steps.[] | select (.run == "****outputs")' .github/workflows/release.yml gives on my laptop 25.11s user 0.06s system 99% cpu 25.182 total Whereas the updated implementation gives 0.01s user 0.01s system 36% cpu 0.049 total There are numerous similar CVEs reported for glob evaluation in different shells/ftp-servers/libraries. The replacement implementation with the linear runtime is shamelessly taken verbatim from the briliant article by Russ Cox https://research.swtch.com/glob
59 lines
1.2 KiB
Go
59 lines
1.2 KiB
Go
package yqlib
|
|
|
|
func matchKey(name string, pattern string) (matched bool) {
|
|
if pattern == "" {
|
|
return name == pattern
|
|
}
|
|
log.Debug("pattern: %v", pattern)
|
|
if pattern == "*" {
|
|
log.Debug("wild!")
|
|
return true
|
|
}
|
|
return deepMatch(name, pattern)
|
|
}
|
|
|
|
// deepMatch reports whether the name matches the pattern in linear time.
|
|
// Source https://research.swtch.com/glob
|
|
func deepMatch(name, pattern string) bool {
|
|
px := 0
|
|
nx := 0
|
|
nextPx := 0
|
|
nextNx := 0
|
|
for px < len(pattern) || nx < len(name) {
|
|
if px < len(pattern) {
|
|
c := pattern[px]
|
|
switch c {
|
|
default: // ordinary character
|
|
if nx < len(name) && name[nx] == c {
|
|
px++
|
|
nx++
|
|
continue
|
|
}
|
|
case '?': // single-character wildcard
|
|
if nx < len(name) {
|
|
px++
|
|
nx++
|
|
continue
|
|
}
|
|
case '*': // zero-or-more-character wildcard
|
|
// Try to match at nx.
|
|
// If that doesn't work out,
|
|
// restart at nx+1 next.
|
|
nextPx = px
|
|
nextNx = nx + 1
|
|
px++
|
|
continue
|
|
}
|
|
}
|
|
// Mismatch. Maybe restart.
|
|
if 0 < nextNx && nextNx <= len(name) {
|
|
px = nextPx
|
|
nx = nextNx
|
|
continue
|
|
}
|
|
return false
|
|
}
|
|
// Matched all of pattern to all of name. Success.
|
|
return true
|
|
}
|