From d15d1aaa5d5fad5797df9d11332d946d957906b8 Mon Sep 17 00:00:00 2001 From: urso Date: Thu, 3 Dec 2015 17:07:09 +0100 Subject: [PATCH] fix redis parser panic Fix regression in redis command parsing accessing the array out of bounds if command has no arguments. --- packetbeat/protos/redis/redis_parse.go | 22 ++++++++++++++-------- packetbeat/protos/redis/redis_test.go | 13 +++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/packetbeat/protos/redis/redis_parse.go b/packetbeat/protos/redis/redis_parse.go index fa8284c716dd..de423469af1b 100644 --- a/packetbeat/protos/redis/redis_parse.go +++ b/packetbeat/protos/redis/redis_parse.go @@ -334,8 +334,12 @@ func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (string, bool, boo } if count < 0 { return "nil", false, true, true + } else if count == 0 { + // should not happen, but handle just in case ParseInt did return 0 + return "[]", false, true, true } + // invariant: count > 0 content := make([]string, 0, count) // read sub elements @@ -353,17 +357,19 @@ func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (string, bool, boo content = append(content, value) } - if depth == 0 && isRedisCommand(content[0]) { // we've got a request + // handle top-level request command + if depth == 0 && isRedisCommand(content[0]) { p.message.IsRequest = true p.message.Method = content[0] - p.message.Path = content[1] - } + if len(content) > 1 { + p.message.Path = content[1] + } - var value string - if depth == 0 && p.message.IsRequest { - value = strings.Join(content, " ") - } else { - value = "[" + strings.Join(content, ", ") + "]" + value := strings.Join(content, " ") + return value, iserror, true, true } + + // return redis array + value := "[" + strings.Join(content, ", ") + "]" return value, iserror, true, true } diff --git a/packetbeat/protos/redis/redis_test.go b/packetbeat/protos/redis/redis_test.go index 587016426e12..5f748de24992 100644 --- a/packetbeat/protos/redis/redis_test.go +++ b/packetbeat/protos/redis/redis_test.go @@ -19,6 +19,19 @@ func parse(content []byte) (*redisMessage, bool, bool) { return st.parser.message, ok, complete } +func TestRedisParser_NoArgsRequest(t *testing.T) { + message := []byte("*1\r\n" + + "$4\r\n" + + "INFO\r\n") + msg, ok, complete := parse(message) + + assert.True(t, ok) + assert.True(t, complete) + assert.True(t, msg.IsRequest) + assert.Equal(t, "INFO", msg.Message) + assert.Equal(t, len(message), msg.Size) +} + func TestRedisParser_ArrayRequest(t *testing.T) { message := []byte("*3\r\n" + "$3\r\n" +