From 77a57fda87dca6d0d7d4627d512a630f89a91c96 Mon Sep 17 00:00:00 2001 From: tidwall Date: Fri, 8 Oct 2021 07:42:49 -0700 Subject: [PATCH] Limit the complexity of "like" queries that match on a pattern. This commit adds the uses the MatchLimit function, which it the same as Match but will limit the complexity of the input pattern. This is to avoid long running matches, specifically to avoid ReDos attacks from arbritary inputs. --- gjson.go | 17 +++++++++++++---- gjson_test.go | 5 +++++ go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/gjson.go b/gjson.go index 973c8af..95d210b 100644 --- a/gjson.go +++ b/gjson.go @@ -1089,9 +1089,9 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } if rp.wild { if kesc { - pmatch = match.Match(unescape(key), rp.part) + pmatch = matchLimit(unescape(key), rp.part) } else { - pmatch = match.Match(key, rp.part) + pmatch = matchLimit(key, rp.part) } } else { if kesc { @@ -1176,6 +1176,15 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } return i, false } + +// matchLimit will limit the complexity of the match operation to avoid ReDos +// attacks from arbritary inputs. +// See the github.com/tidwall/match.MatchLimit function for more information. +func matchLimit(str, pattern string) bool { + matched, _ := match.MatchLimit(str, pattern, 10000) + return matched +} + func queryMatches(rp *arrayPathResult, value Result) bool { rpv := rp.query.value if len(rpv) > 0 && rpv[0] == '~' { @@ -1213,9 +1222,9 @@ func queryMatches(rp *arrayPathResult, value Result) bool { case ">=": return value.Str >= rpv case "%": - return match.Match(value.Str, rpv) + return matchLimit(value.Str, rpv) case "!%": - return !match.Match(value.Str, rpv) + return !matchLimit(value.Str, rpv) } case Number: rpvn, _ := strconv.ParseFloat(rpv, 64) diff --git a/gjson_test.go b/gjson_test.go index 1ec68a4..fb74d50 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -2024,6 +2024,11 @@ func TestVariousFuzz(t *testing.T) { testJSON = `[#.@pretty.@join:{""[]""preserve"3,"][{]]]` Get(testJSON, testJSON) + // Issue #237 + testJSON1 := `["*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,,,,,"]` + testJSON2 := `#[%"*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,,,,,""*,*"]` + Get(testJSON1, testJSON2) + } func TestSubpathsWithMultipaths(t *testing.T) { diff --git a/go.mod b/go.mod index 30ed7f0..6f64083 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,6 @@ module github.com/tidwall/gjson go 1.12 require ( - github.com/tidwall/match v1.1.0 + github.com/tidwall/match v1.1.1 github.com/tidwall/pretty v1.2.0 ) diff --git a/go.sum b/go.sum index f4dcaab..be39c8c 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -github.com/tidwall/match v1.1.0 h1:VfI2e2aXLvytih7WUVyO9uvRC+RcXlaTrMbHuQWnFmk= -github.com/tidwall/match v1.1.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=