@@ -22,6 +22,7 @@ pub(crate) mod function {
22
22
NoMatch ,
23
23
AbortAll ,
24
24
AbortToStarStar ,
25
+ RecursionLimitReached ,
25
26
}
26
27
27
28
const STAR : u8 = b'*' ;
@@ -32,8 +33,13 @@ pub(crate) mod function {
32
33
const COLON : u8 = b':' ;
33
34
34
35
const NEGATE_CLASS : u8 = b'!' ;
36
+ /// Setting this limit to something reasonable means less compute time spent on unnecessarily complex patterns, or malicious ones.
37
+ const RECURSION_LIMIT : usize = 64 ;
35
38
36
- fn match_recursive ( pattern : & BStr , text : & BStr , mode : Mode ) -> Result {
39
+ fn match_recursive ( pattern : & BStr , text : & BStr , mode : Mode , depth : usize ) -> Result {
40
+ if depth == RECURSION_LIMIT {
41
+ return RecursionLimitReached ;
42
+ }
37
43
use self :: Result :: * ;
38
44
let possibly_lowercase = |c : & u8 | {
39
45
if mode. contains ( Mode :: IGNORE_CASE ) {
@@ -89,7 +95,12 @@ pub(crate) mod function {
89
95
} )
90
96
{
91
97
if next. map_or ( NoMatch , |( idx, _) | {
92
- match_recursive ( pattern[ idx + 1 ..] . as_bstr ( ) , text[ t_idx..] . as_bstr ( ) , mode)
98
+ match_recursive (
99
+ pattern[ idx + 1 ..] . as_bstr ( ) ,
100
+ text[ t_idx..] . as_bstr ( ) ,
101
+ mode,
102
+ depth + 1 ,
103
+ )
93
104
} ) == Match
94
105
{
95
106
return Match ;
@@ -152,7 +163,7 @@ pub(crate) mod function {
152
163
return NoMatch ;
153
164
}
154
165
}
155
- let res = match_recursive ( pattern[ p_idx..] . as_bstr ( ) , text[ t_idx..] . as_bstr ( ) , mode) ;
166
+ let res = match_recursive ( pattern[ p_idx..] . as_bstr ( ) , text[ t_idx..] . as_bstr ( ) , mode, depth + 1 ) ;
156
167
if res != NoMatch {
157
168
if !match_slash || res != AbortToStarStar {
158
169
return res;
@@ -352,6 +363,10 @@ pub(crate) mod function {
352
363
///
353
364
/// `mode` can be used to adjust the way the matching is performed.
354
365
pub fn wildmatch ( pattern : & BStr , value : & BStr , mode : Mode ) -> bool {
355
- match_recursive ( pattern, value, mode) == Result :: Match
366
+ let res = match_recursive ( pattern, value, mode, 0 ) ;
367
+ if res == Result :: RecursionLimitReached {
368
+ gix_features:: trace:: error!( "Recursion limit of {} reached for pattern '{pattern}'" , RECURSION_LIMIT ) ;
369
+ }
370
+ res == Result :: Match
356
371
}
357
372
}
0 commit comments