From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> To: tarantool-patches@freelists.org Cc: vdavydov.dev@gmail.com Subject: [PATCH 1/1] iproto: protect from false-correct size in msg header Date: Mon, 18 Jun 2018 22:53:01 +0300 [thread overview] Message-ID: <c3d064b141e17e8c5fbc4d852e61615c8b4edd4a.1529351502.git.v.shpilevoy@tarantool.org> (raw) Consider this packet: msgpack = require('msgpack') data = msgpack.encode(18400000000000000000)..'aaaaaaa' Tarantool interprets 18400000000000000000 as size of a coming iproto request, and tries with no any checks to allocate buffer of such size. It calculates needed capacity like this: capacity = start_value; while (capacity < size) capacity *= 2; Here it is possible that on i-th iteration 'capacity' < 'size', but 'capacity * 2' overflows 64 bits and becomes < 'size' again, so this loop never ends and occupies 100% CPU. Strictly speaking overflow has undefined behavior. On the original system it led to nullifying 'capacity'. Such size is improbable as a real packet gabarits, but can appear as a result of parsing of some invalid packet, first bytes of which accidentally appears to be valid MessagePack uint. This is how the bug emerged on the real system. Lets restrict the maximal packet size to 2GB. Closes #3464 --- Branch: https://github.com/tarantool/tarantool/tree/gerold103/gh-3464-iproto-100-cpu Issue: https://github.com/tarantool/tarantool/issues/3464 src/box/iproto.cc | 15 +++++++++++++-- test/box/net.box.result | 22 ++++++++++++++++++++++ test/box/net.box.test.lua | 10 ++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/box/iproto.cc b/src/box/iproto.cc index 0b92c316e..d3765eb1d 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -64,7 +64,10 @@ #include "cfg.h" /* The number of iproto messages in flight */ -enum { IPROTO_MSG_MAX = 768 }; +enum { + IPROTO_MSG_MAX = 768, + IPROTO_PACKET_SIZE_MAX = 2UL * 1024 * 1024 * 1024, +}; /** * Network readahead. A signed integer to avoid @@ -524,8 +527,16 @@ iproto_connection_input_buffer(struct iproto_connection *con) /* The type code is checked in iproto_enqueue_batch() */ if (con->parse_size) { const char *pos = old_ibuf->wpos - con->parse_size; - if (mp_check_uint(pos, old_ibuf->wpos) <= 0) + if (mp_check_uint(pos, old_ibuf->wpos) <= 0) { to_read = mp_decode_uint(&pos); + if (to_read > IPROTO_PACKET_SIZE_MAX) { + const char *err = + tt_sprintf("too big packet size in "\ + "the header: %llu", + (unsigned long long)to_read); + tnt_raise(ClientError, ER_INVALID_MSGPACK, err); + } + } } if (ibuf_unused(old_ibuf) >= to_read) diff --git a/test/box/net.box.result b/test/box/net.box.result index aa418b87d..7180f7f66 100644 --- a/test/box/net.box.result +++ b/test/box/net.box.result @@ -2360,6 +2360,28 @@ box.internal.collation.drop('test') space:drop() --- ... +-- +-- gh-3464: iproto hangs in 100% CPU when too big packet size +-- is received due to size_t overflow. +-- +c = net:connect(box.cfg.listen) +--- +... +data = msgpack.encode(18400000000000000000)..'aaaaaaa' +--- +... +c._transport.perform_request(nil, nil, 'inject', nil, data) +--- +- 77 +- Peer closed +... +c:close() +--- +... +test_run:grep_log('default', 'too big packet size in the header') ~= nil +--- +- true +... box.schema.user.revoke('guest', 'read,write,execute', 'universe') --- ... diff --git a/test/box/net.box.test.lua b/test/box/net.box.test.lua index 4cadd3b29..1e716ca89 100644 --- a/test/box/net.box.test.lua +++ b/test/box/net.box.test.lua @@ -961,4 +961,14 @@ c:close() box.internal.collation.drop('test') space:drop() +-- +-- gh-3464: iproto hangs in 100% CPU when too big packet size +-- is received due to size_t overflow. +-- +c = net:connect(box.cfg.listen) +data = msgpack.encode(18400000000000000000)..'aaaaaaa' +c._transport.perform_request(nil, nil, 'inject', nil, data) +c:close() +test_run:grep_log('default', 'too big packet size in the header') ~= nil + box.schema.user.revoke('guest', 'read,write,execute', 'universe') -- 2.15.1 (Apple Git-101)
next reply other threads:[~2018-06-18 19:53 UTC|newest] Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-06-18 19:53 Vladislav Shpilevoy [this message] 2018-06-19 11:57 ` Vladimir Davydov 2018-06-25 13:55 ` [tarantool-patches] " Konstantin Osipov 2018-06-25 14:00 ` [tarantool-patches] [PATCH v2 " Vladislav Shpilevoy 2018-06-25 17:17 ` [tarantool-patches] " Konstantin Osipov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=c3d064b141e17e8c5fbc4d852e61615c8b4edd4a.1529351502.git.v.shpilevoy@tarantool.org \ --to=v.shpilevoy@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=vdavydov.dev@gmail.com \ --subject='Re: [PATCH 1/1] iproto: protect from false-correct size in msg header' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox