Make deepMatch report in linear time

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
This commit is contained in:
Peter Matseykanets
2021-10-14 18:45:25 +11:00
committed by Mike Farah
parent 2da2001651
commit dd259b4957
2 changed files with 81 additions and 17 deletions
+40
View File
@@ -0,0 +1,40 @@
package yqlib
import (
"strings"
"testing"
)
func TestDeepMatch(t *testing.T) {
var tests = []struct {
name string
pattern string
ok bool
}{
{"", "", true},
{"", "x", false},
{"x", "", false},
{"abc", "abc", true},
{"abc", "*", true},
{"abc", "*c", true},
{"abc", "*b", false},
{"abc", "a*", true},
{"abc", "b*", false},
{"a", "a*", true},
{"a", "*a", true},
{"axbxcxdxe", "a*b*c*d*e*", true},
{"axbxcxdxexxx", "a*b*c*d*e*", true},
{"abxbbxdbxebxczzx", "a*b?c*x", true},
{"abxbbxdbxebxczzy", "a*b?c*x", false},
{strings.Repeat("a", 100), "a*a*a*a*b", false},
{"xxx", "*x", true},
}
for _, tt := range tests {
t.Run(tt.name+" "+tt.pattern, func(t *testing.T) {
if want, got := tt.ok, deepMatch(tt.name, tt.pattern); want != got {
t.Errorf("Expected %v got %v", want, got)
}
})
}
}