Skip to content

Commit 03217c3

Browse files
authored
Merge pull request #410 from liggitt/stack
Limit nesting depth
2 parents 908eaed + eec2489 commit 03217c3

7 files changed

+361
-6
lines changed

iter.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ type Iterator struct {
7474
buf []byte
7575
head int
7676
tail int
77+
depth int
7778
captureStartedAt int
7879
captured []byte
7980
Error error
@@ -88,6 +89,7 @@ func NewIterator(cfg API) *Iterator {
8889
buf: nil,
8990
head: 0,
9091
tail: 0,
92+
depth: 0,
9193
}
9294
}
9395

@@ -99,6 +101,7 @@ func Parse(cfg API, reader io.Reader, bufSize int) *Iterator {
99101
buf: make([]byte, bufSize),
100102
head: 0,
101103
tail: 0,
104+
depth: 0,
102105
}
103106
}
104107

@@ -110,6 +113,7 @@ func ParseBytes(cfg API, input []byte) *Iterator {
110113
buf: input,
111114
head: 0,
112115
tail: len(input),
116+
depth: 0,
113117
}
114118
}
115119

@@ -128,6 +132,7 @@ func (iter *Iterator) Reset(reader io.Reader) *Iterator {
128132
iter.reader = reader
129133
iter.head = 0
130134
iter.tail = 0
135+
iter.depth = 0
131136
return iter
132137
}
133138

@@ -137,6 +142,7 @@ func (iter *Iterator) ResetBytes(input []byte) *Iterator {
137142
iter.buf = input
138143
iter.head = 0
139144
iter.tail = len(input)
145+
iter.depth = 0
140146
return iter
141147
}
142148

@@ -320,3 +326,24 @@ func (iter *Iterator) Read() interface{} {
320326
return nil
321327
}
322328
}
329+
330+
// limit maximum depth of nesting, as allowed by https://tools.ietf.org/html/rfc7159#section-9
331+
const maxDepth = 10000
332+
333+
func (iter *Iterator) incrementDepth() (success bool) {
334+
iter.depth++
335+
if iter.depth <= maxDepth {
336+
return true
337+
}
338+
iter.ReportError("incrementDepth", "exceeded max depth")
339+
return false
340+
}
341+
342+
func (iter *Iterator) decrementDepth() (success bool) {
343+
iter.depth--
344+
if iter.depth >= 0 {
345+
return true
346+
}
347+
iter.ReportError("decrementDepth", "unexpected negative nesting")
348+
return false
349+
}

iter_array.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,32 @@ func (iter *Iterator) ReadArray() (ret bool) {
2828
func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
2929
c := iter.nextToken()
3030
if c == '[' {
31+
if !iter.incrementDepth() {
32+
return false
33+
}
3134
c = iter.nextToken()
3235
if c != ']' {
3336
iter.unreadByte()
3437
if !callback(iter) {
38+
iter.decrementDepth()
3539
return false
3640
}
3741
c = iter.nextToken()
3842
for c == ',' {
3943
if !callback(iter) {
44+
iter.decrementDepth()
4045
return false
4146
}
4247
c = iter.nextToken()
4348
}
4449
if c != ']' {
4550
iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c}))
51+
iter.decrementDepth()
4652
return false
4753
}
48-
return true
54+
return iter.decrementDepth()
4955
}
50-
return true
56+
return iter.decrementDepth()
5157
}
5258
if c == 'n' {
5359
iter.skipThreeBytes('u', 'l', 'l')

iter_object.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
112112
c := iter.nextToken()
113113
var field string
114114
if c == '{' {
115+
if !iter.incrementDepth() {
116+
return false
117+
}
115118
c = iter.nextToken()
116119
if c == '"' {
117120
iter.unreadByte()
@@ -121,6 +124,7 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
121124
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
122125
}
123126
if !callback(iter, field) {
127+
iter.decrementDepth()
124128
return false
125129
}
126130
c = iter.nextToken()
@@ -131,20 +135,23 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
131135
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
132136
}
133137
if !callback(iter, field) {
138+
iter.decrementDepth()
134139
return false
135140
}
136141
c = iter.nextToken()
137142
}
138143
if c != '}' {
139144
iter.ReportError("ReadObjectCB", `object not ended with }`)
145+
iter.decrementDepth()
140146
return false
141147
}
142-
return true
148+
return iter.decrementDepth()
143149
}
144150
if c == '}' {
145-
return true
151+
return iter.decrementDepth()
146152
}
147153
iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c}))
154+
iter.decrementDepth()
148155
return false
149156
}
150157
if c == 'n' {
@@ -159,39 +166,48 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
159166
func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
160167
c := iter.nextToken()
161168
if c == '{' {
169+
if !iter.incrementDepth() {
170+
return false
171+
}
162172
c = iter.nextToken()
163173
if c == '"' {
164174
iter.unreadByte()
165175
field := iter.ReadString()
166176
if iter.nextToken() != ':' {
167177
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
178+
iter.decrementDepth()
168179
return false
169180
}
170181
if !callback(iter, field) {
182+
iter.decrementDepth()
171183
return false
172184
}
173185
c = iter.nextToken()
174186
for c == ',' {
175187
field = iter.ReadString()
176188
if iter.nextToken() != ':' {
177189
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
190+
iter.decrementDepth()
178191
return false
179192
}
180193
if !callback(iter, field) {
194+
iter.decrementDepth()
181195
return false
182196
}
183197
c = iter.nextToken()
184198
}
185199
if c != '}' {
186200
iter.ReportError("ReadMapCB", `object not ended with }`)
201+
iter.decrementDepth()
187202
return false
188203
}
189-
return true
204+
return iter.decrementDepth()
190205
}
191206
if c == '}' {
192-
return true
207+
return iter.decrementDepth()
193208
}
194209
iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
210+
iter.decrementDepth()
195211
return false
196212
}
197213
if c == 'n' {

iter_skip_sloppy.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ func (iter *Iterator) skipNumber() {
2222

2323
func (iter *Iterator) skipArray() {
2424
level := 1
25+
if !iter.incrementDepth() {
26+
return
27+
}
2528
for {
2629
for i := iter.head; i < iter.tail; i++ {
2730
switch iter.buf[i] {
@@ -31,8 +34,14 @@ func (iter *Iterator) skipArray() {
3134
i = iter.head - 1 // it will be i++ soon
3235
case '[': // If open symbol, increase level
3336
level++
37+
if !iter.incrementDepth() {
38+
return
39+
}
3440
case ']': // If close symbol, increase level
3541
level--
42+
if !iter.decrementDepth() {
43+
return
44+
}
3645

3746
// If we have returned to the original level, we're done
3847
if level == 0 {
@@ -50,6 +59,10 @@ func (iter *Iterator) skipArray() {
5059

5160
func (iter *Iterator) skipObject() {
5261
level := 1
62+
if !iter.incrementDepth() {
63+
return
64+
}
65+
5366
for {
5467
for i := iter.head; i < iter.tail; i++ {
5568
switch iter.buf[i] {
@@ -59,8 +72,14 @@ func (iter *Iterator) skipObject() {
5972
i = iter.head - 1 // it will be i++ soon
6073
case '{': // If open symbol, increase level
6174
level++
75+
if !iter.incrementDepth() {
76+
return
77+
}
6278
case '}': // If close symbol, increase level
6379
level--
80+
if !iter.decrementDepth() {
81+
return
82+
}
6483

6584
// If we have returned to the original level, we're done
6685
if level == 0 {

0 commit comments

Comments
 (0)