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.
This commit is contained in:
tidwall 2021-10-08 07:42:49 -07:00
parent 590010fdac
commit 77a57fda87
4 changed files with 21 additions and 7 deletions

View File

@ -1089,9 +1089,9 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
} }
if rp.wild { if rp.wild {
if kesc { if kesc {
pmatch = match.Match(unescape(key), rp.part) pmatch = matchLimit(unescape(key), rp.part)
} else { } else {
pmatch = match.Match(key, rp.part) pmatch = matchLimit(key, rp.part)
} }
} else { } else {
if kesc { if kesc {
@ -1176,6 +1176,15 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
} }
return i, false 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 { func queryMatches(rp *arrayPathResult, value Result) bool {
rpv := rp.query.value rpv := rp.query.value
if len(rpv) > 0 && rpv[0] == '~' { if len(rpv) > 0 && rpv[0] == '~' {
@ -1213,9 +1222,9 @@ func queryMatches(rp *arrayPathResult, value Result) bool {
case ">=": case ">=":
return value.Str >= rpv return value.Str >= rpv
case "%": case "%":
return match.Match(value.Str, rpv) return matchLimit(value.Str, rpv)
case "!%": case "!%":
return !match.Match(value.Str, rpv) return !matchLimit(value.Str, rpv)
} }
case Number: case Number:
rpvn, _ := strconv.ParseFloat(rpv, 64) rpvn, _ := strconv.ParseFloat(rpv, 64)

View File

@ -2024,6 +2024,11 @@ func TestVariousFuzz(t *testing.T) {
testJSON = `[#.@pretty.@join:{""[]""preserve"3,"][{]]]` testJSON = `[#.@pretty.@join:{""[]""preserve"3,"][{]]]`
Get(testJSON, testJSON) Get(testJSON, testJSON)
// Issue #237
testJSON1 := `["*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,,,,,"]`
testJSON2 := `#[%"*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,,,,,""*,*"]`
Get(testJSON1, testJSON2)
} }
func TestSubpathsWithMultipaths(t *testing.T) { func TestSubpathsWithMultipaths(t *testing.T) {

2
go.mod
View File

@ -3,6 +3,6 @@ module github.com/tidwall/gjson
go 1.12 go 1.12
require ( require (
github.com/tidwall/match v1.1.0 github.com/tidwall/match v1.1.1
github.com/tidwall/pretty v1.2.0 github.com/tidwall/pretty v1.2.0
) )

4
go.sum
View File

@ -1,4 +1,4 @@
github.com/tidwall/match v1.1.0 h1:VfI2e2aXLvytih7WUVyO9uvRC+RcXlaTrMbHuQWnFmk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 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 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=