Skip to content

Commit 277e703

Browse files
libcmcuadros
authored andcommitted
Add bounds checks to rfc5424 parser (#62)
Several bounds checks are missing from rfc5424 parser, which can cause "index out of range" panic. We see this index out of range panics in our production environment while streaming logs from a 3rd party CDN server.
1 parent 42e2f02 commit 277e703

File tree

3 files changed

+35
-9
lines changed

3 files changed

+35
-9
lines changed

internal/syslogparser/rfc5424/rfc5424.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ func (p *Parser) parseVersion() (int, error) {
193193
func (p *Parser) parseTimestamp() (time.Time, error) {
194194
var ts time.Time
195195

196+
if p.cursor >= p.l {
197+
return ts, ErrInvalidTimeFormat
198+
}
199+
196200
if p.buff[p.cursor] == NILVALUE {
197201
p.cursor++
198202
return ts, nil
@@ -203,7 +207,7 @@ func (p *Parser) parseTimestamp() (time.Time, error) {
203207
return ts, err
204208
}
205209

206-
if p.buff[p.cursor] != 'T' {
210+
if p.cursor >= p.l || p.buff[p.cursor] != 'T' {
207211
return ts, ErrInvalidTimeFormat
208212
}
209213

@@ -272,7 +276,7 @@ func parseFullDate(buff []byte, cursor *int, l int) (fullDate, error) {
272276
return fd, err
273277
}
274278

275-
if buff[*cursor] != '-' {
279+
if *cursor >= l || buff[*cursor] != '-' {
276280
return fd, syslogparser.ErrTimestampUnknownFormat
277281
}
278282

@@ -283,7 +287,7 @@ func parseFullDate(buff []byte, cursor *int, l int) (fullDate, error) {
283287
return fd, err
284288
}
285289

286-
if buff[*cursor] != '-' {
290+
if *cursor >= l || buff[*cursor] != '-' {
287291
return fd, syslogparser.ErrTimestampUnknownFormat
288292
}
289293

@@ -371,7 +375,7 @@ func parsePartialTime(buff []byte, cursor *int, l int) (partialTime, error) {
371375
return pt, err
372376
}
373377

374-
if buff[*cursor] != ':' {
378+
if *cursor >= l || buff[*cursor] != ':' {
375379
return pt, ErrInvalidTimeFormat
376380
}
377381

@@ -392,7 +396,7 @@ func parsePartialTime(buff []byte, cursor *int, l int) (partialTime, error) {
392396

393397
// ----
394398

395-
if buff[*cursor] != '.' {
399+
if *cursor >= l || buff[*cursor] != '.' {
396400
return pt, nil
397401
}
398402

@@ -458,7 +462,7 @@ func parseSecFrac(buff []byte, cursor *int, l int) (float64, error) {
458462
// TIME-OFFSET = "Z" / TIME-NUMOFFSET
459463
func parseTimeOffset(buff []byte, cursor *int, l int) (*time.Location, error) {
460464

461-
if buff[*cursor] == 'Z' {
465+
if *cursor >= l || buff[*cursor] == 'Z' {
462466
*cursor++
463467
return time.UTC, nil
464468
}
@@ -498,7 +502,7 @@ func getHourMinute(buff []byte, cursor *int, l int) (int, int, error) {
498502
return 0, 0, err
499503
}
500504

501-
if buff[*cursor] != ':' {
505+
if *cursor >= l || buff[*cursor] != ':' {
502506
return 0, 0, ErrInvalidTimeFormat
503507
}
504508

@@ -588,8 +592,8 @@ func parseUpToLen(buff []byte, cursor *int, l int, maxLen int, e error) (string,
588592

589593
if found {
590594
result = string(buff[*cursor:to])
591-
} else if (to > max) {
592-
to = max; // don't go past max
595+
} else if to > max {
596+
to = max // don't go past max
593597
}
594598

595599
*cursor = to

internal/syslogparser/rfc5424/rfc5424_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,14 @@ func (s *Rfc5424TestSuite) TestParser_Valid(c *C) {
137137
}
138138
}
139139

140+
func (s *Rfc5424TestSuite) TestParser_Truncated(c *C) {
141+
msg := "<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts."
142+
for i := range msg {
143+
p := NewParser([]byte(msg[:i]))
144+
p.Parse()
145+
}
146+
}
147+
140148
func (s *Rfc5424TestSuite) TestParseHeader_Valid(c *C) {
141149
ts := time.Date(2003, time.October, 11, 22, 14, 15, 3*10e5, time.UTC)
142150
tsString := "2003-10-11T22:14:15.003Z"
@@ -293,6 +301,13 @@ func (s *Rfc5424TestSuite) TestParseTimestamp_NilValue(c *C) {
293301
s.assertTimestamp(c, *ts, buff, 1, nil)
294302
}
295303

304+
func (s *Rfc5424TestSuite) TestParseTimestamp_Empty(c *C) {
305+
buff := []byte("")
306+
ts := new(time.Time)
307+
308+
s.assertTimestamp(c, *ts, buff, 0, ErrInvalidTimeFormat)
309+
}
310+
296311
func (s *Rfc5424TestSuite) TestFindNextSpace_NoSpace(c *C) {
297312
buff := []byte("aaaaaa")
298313

internal/syslogparser/syslogparser.go

+7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ var (
2828
ErrVersionNotFound = &ParserError{"Can not find version"}
2929

3030
ErrTimestampUnknownFormat = &ParserError{"Timestamp format unknown"}
31+
32+
ErrHostnameTooShort = &ParserError{"Hostname field too short"}
3133
)
3234

3335
type LogParser interface {
@@ -180,6 +182,11 @@ func Parse2Digits(buff []byte, cursor *int, l int, min int, max int, e error) (i
180182

181183
func ParseHostname(buff []byte, cursor *int, l int) (string, error) {
182184
from := *cursor
185+
186+
if from >= l {
187+
return "", ErrHostnameTooShort
188+
}
189+
183190
var to int
184191

185192
for to = from; to < l; to++ {

0 commit comments

Comments
 (0)