@@ -28,6 +28,16 @@ import (
28
28
"github.com/open-policy-agent/opa/v1/ast/location"
29
29
)
30
30
31
+ // DefaultMaxParsingRecursionDepth is the default maximum recursion
32
+ // depth for the parser
33
+ const DefaultMaxParsingRecursionDepth = 100000
34
+
35
+ var maxParsingRecursionDepth = DefaultMaxParsingRecursionDepth
36
+
37
+ // ErrMaxParsingRecursionDepthExceeded is returned when the parser
38
+ // recursion exceeds the maximum allowed depth
39
+ var ErrMaxParsingRecursionDepthExceeded = errors .New ("max parsing recursion depth exceeded" )
40
+
31
41
var RegoV1CompatibleRef = Ref {VarTerm ("rego" ), StringTerm ("v1" )}
32
42
33
43
// RegoVersion defines the Rego syntax requirements for a module.
@@ -114,10 +124,12 @@ func (s *state) Text(offset, end int) []byte {
114
124
115
125
// Parser is used to parse Rego statements.
116
126
type Parser struct {
117
- r io.Reader
118
- s * state
119
- po ParserOptions
120
- cache parsedTermCache
127
+ r io.Reader
128
+ s * state
129
+ po ParserOptions
130
+ cache parsedTermCache
131
+ recursionDepth int
132
+ maxRecursionDepth int
121
133
}
122
134
123
135
type parsedTermCacheItem struct {
@@ -169,12 +181,19 @@ func (po *ParserOptions) EffectiveRegoVersion() RegoVersion {
169
181
// NewParser creates and initializes a Parser.
170
182
func NewParser () * Parser {
171
183
p := & Parser {
172
- s : & state {},
173
- po : ParserOptions {},
184
+ s : & state {},
185
+ po : ParserOptions {},
186
+ maxRecursionDepth : maxParsingRecursionDepth ,
174
187
}
175
188
return p
176
189
}
177
190
191
+ // WithMaxRecursionDepth sets the maximum recursion depth for the parser.
192
+ func (p * Parser ) WithMaxRecursionDepth (depth int ) * Parser {
193
+ p .maxRecursionDepth = depth
194
+ return p
195
+ }
196
+
178
197
// WithFilename provides the filename for Location details
179
198
// on parsed statements.
180
199
func (p * Parser ) WithFilename (filename string ) * Parser {
@@ -1031,6 +1050,10 @@ func (p *Parser) parseHead(defaultRule bool) (*Head, bool) {
1031
1050
}
1032
1051
1033
1052
func (p * Parser ) parseBody (end tokens.Token ) Body {
1053
+ if ! p .enter () {
1054
+ return nil
1055
+ }
1056
+ defer p .leave ()
1034
1057
return p .parseQuery (false , end )
1035
1058
}
1036
1059
@@ -1356,10 +1379,20 @@ func (p *Parser) parseExpr() *Expr {
1356
1379
// other binary operators (|, &, arithmetics), it constitutes the binding
1357
1380
// precedence.
1358
1381
func (p * Parser ) parseTermInfixCall () * Term {
1382
+ if ! p .enter () {
1383
+ return nil
1384
+ }
1385
+ defer p .leave ()
1386
+
1359
1387
return p .parseTermIn (nil , true , p .s .loc .Offset )
1360
1388
}
1361
1389
1362
1390
func (p * Parser ) parseTermInfixCallInList () * Term {
1391
+ if ! p .enter () {
1392
+ return nil
1393
+ }
1394
+ defer p .leave ()
1395
+
1363
1396
return p .parseTermIn (nil , false , p .s .loc .Offset )
1364
1397
}
1365
1398
@@ -1369,6 +1402,11 @@ var memberWithKeyRef = MemberWithKey.Ref()
1369
1402
var memberRef = Member .Ref ()
1370
1403
1371
1404
func (p * Parser ) parseTermIn (lhs * Term , keyVal bool , offset int ) * Term {
1405
+ if ! p .enter () {
1406
+ return nil
1407
+ }
1408
+ defer p .leave ()
1409
+
1372
1410
// NOTE(sr): `in` is a bit special: besides `lhs in rhs`, it also
1373
1411
// supports `key, val in rhs`, so it can have an optional second lhs.
1374
1412
// `keyVal` triggers if we attempt to parse a second lhs argument (`mhs`).
@@ -1411,6 +1449,11 @@ func (p *Parser) parseTermIn(lhs *Term, keyVal bool, offset int) *Term {
1411
1449
}
1412
1450
1413
1451
func (p * Parser ) parseTermRelation (lhs * Term , offset int ) * Term {
1452
+ if ! p .enter () {
1453
+ return nil
1454
+ }
1455
+ defer p .leave ()
1456
+
1414
1457
if lhs == nil {
1415
1458
lhs = p .parseTermOr (nil , offset )
1416
1459
}
@@ -1431,6 +1474,11 @@ func (p *Parser) parseTermRelation(lhs *Term, offset int) *Term {
1431
1474
}
1432
1475
1433
1476
func (p * Parser ) parseTermOr (lhs * Term , offset int ) * Term {
1477
+ if ! p .enter () {
1478
+ return nil
1479
+ }
1480
+ defer p .leave ()
1481
+
1434
1482
if lhs == nil {
1435
1483
lhs = p .parseTermAnd (nil , offset )
1436
1484
}
@@ -1452,6 +1500,11 @@ func (p *Parser) parseTermOr(lhs *Term, offset int) *Term {
1452
1500
}
1453
1501
1454
1502
func (p * Parser ) parseTermAnd (lhs * Term , offset int ) * Term {
1503
+ if ! p .enter () {
1504
+ return nil
1505
+ }
1506
+ defer p .leave ()
1507
+
1455
1508
if lhs == nil {
1456
1509
lhs = p .parseTermArith (nil , offset )
1457
1510
}
@@ -1473,6 +1526,11 @@ func (p *Parser) parseTermAnd(lhs *Term, offset int) *Term {
1473
1526
}
1474
1527
1475
1528
func (p * Parser ) parseTermArith (lhs * Term , offset int ) * Term {
1529
+ if ! p .enter () {
1530
+ return nil
1531
+ }
1532
+ defer p .leave ()
1533
+
1476
1534
if lhs == nil {
1477
1535
lhs = p .parseTermFactor (nil , offset )
1478
1536
}
@@ -1493,6 +1551,11 @@ func (p *Parser) parseTermArith(lhs *Term, offset int) *Term {
1493
1551
}
1494
1552
1495
1553
func (p * Parser ) parseTermFactor (lhs * Term , offset int ) * Term {
1554
+ if ! p .enter () {
1555
+ return nil
1556
+ }
1557
+ defer p .leave ()
1558
+
1496
1559
if lhs == nil {
1497
1560
lhs = p .parseTerm ()
1498
1561
}
@@ -1513,6 +1576,11 @@ func (p *Parser) parseTermFactor(lhs *Term, offset int) *Term {
1513
1576
}
1514
1577
1515
1578
func (p * Parser ) parseTerm () * Term {
1579
+ if ! p .enter () {
1580
+ return nil
1581
+ }
1582
+ defer p .leave ()
1583
+
1516
1584
if term , s := p .parsedTermCacheLookup (); s != nil {
1517
1585
p .restore (s )
1518
1586
return term
@@ -1665,6 +1733,10 @@ func (p *Parser) parseRawString() *Term {
1665
1733
var setConstructor = RefTerm (VarTerm ("set" ))
1666
1734
1667
1735
func (p * Parser ) parseCall (operator * Term , offset int ) (term * Term ) {
1736
+ if ! p .enter () {
1737
+ return nil
1738
+ }
1739
+ defer p .leave ()
1668
1740
1669
1741
loc := operator .Location
1670
1742
var end int
@@ -1694,6 +1766,10 @@ func (p *Parser) parseCall(operator *Term, offset int) (term *Term) {
1694
1766
}
1695
1767
1696
1768
func (p * Parser ) parseRef (head * Term , offset int ) (term * Term ) {
1769
+ if ! p .enter () {
1770
+ return nil
1771
+ }
1772
+ defer p .leave ()
1697
1773
1698
1774
loc := head .Location
1699
1775
var end int
@@ -1759,6 +1835,10 @@ func (p *Parser) parseRef(head *Term, offset int) (term *Term) {
1759
1835
}
1760
1836
1761
1837
func (p * Parser ) parseArray () (term * Term ) {
1838
+ if ! p .enter () {
1839
+ return nil
1840
+ }
1841
+ defer p .leave ()
1762
1842
1763
1843
loc := p .s .Loc ()
1764
1844
offset := p .s .loc .Offset
@@ -1830,6 +1910,11 @@ func (p *Parser) parseArray() (term *Term) {
1830
1910
}
1831
1911
1832
1912
func (p * Parser ) parseSetOrObject () (term * Term ) {
1913
+ if ! p .enter () {
1914
+ return nil
1915
+ }
1916
+ defer p .leave ()
1917
+
1833
1918
loc := p .s .Loc ()
1834
1919
offset := p .s .loc .Offset
1835
1920
@@ -1896,6 +1981,11 @@ func (p *Parser) parseSetOrObject() (term *Term) {
1896
1981
}
1897
1982
1898
1983
func (p * Parser ) parseSet (s * state , head * Term , potentialComprehension bool ) * Term {
1984
+ if ! p .enter () {
1985
+ return nil
1986
+ }
1987
+ defer p .leave ()
1988
+
1899
1989
switch p .s .tok {
1900
1990
case tokens .RBrace :
1901
1991
return SetTerm (head )
@@ -1925,6 +2015,11 @@ func (p *Parser) parseSet(s *state, head *Term, potentialComprehension bool) *Te
1925
2015
}
1926
2016
1927
2017
func (p * Parser ) parseObject (k * Term , potentialComprehension bool ) * Term {
2018
+ if ! p .enter () {
2019
+ return nil
2020
+ }
2021
+ defer p .leave ()
2022
+
1928
2023
// NOTE(tsandall): Assumption: this function is called after parsing the key
1929
2024
// of the head element and then receiving a colon token from the scanner.
1930
2025
// Advance beyond the colon and attempt to parse an object.
@@ -1978,6 +2073,11 @@ func (p *Parser) parseObject(k *Term, potentialComprehension bool) *Term {
1978
2073
}
1979
2074
1980
2075
func (p * Parser ) parseObjectFinish (key , val * Term , potentialComprehension bool ) * Term {
2076
+ if ! p .enter () {
2077
+ return nil
2078
+ }
2079
+ defer p .leave ()
2080
+
1981
2081
switch p .s .tok {
1982
2082
case tokens .RBrace :
1983
2083
return ObjectTerm ([2 ]* Term {key , val })
@@ -2759,3 +2859,21 @@ func init() {
2759
2859
maps .Copy (allFutureKeywords , futureKeywords )
2760
2860
maps .Copy (allFutureKeywords , futureKeywordsV0 )
2761
2861
}
2862
+
2863
+ // enter increments the recursion depth counter and checks if it exceeds the maximum.
2864
+ // Returns false if the maximum is exceeded, true otherwise.
2865
+ // If p.maxRecursionDepth is 0 or negative, the check is effectively disabled.
2866
+ func (p * Parser ) enter () bool {
2867
+ p .recursionDepth ++
2868
+ if p .maxRecursionDepth > 0 && p .recursionDepth > p .maxRecursionDepth {
2869
+ p .error (p .s .Loc (), ErrMaxParsingRecursionDepthExceeded .Error ())
2870
+ p .recursionDepth --
2871
+ return false
2872
+ }
2873
+ return true
2874
+ }
2875
+
2876
+ // leave decrements the recursion depth counter.
2877
+ func (p * Parser ) leave () {
2878
+ p .recursionDepth --
2879
+ }
0 commit comments