From: Vladislav Shpilevoy via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: tarantool-patches@dev.tarantool.org, gorcunov@gmail.com, sergepetrenko@tarantool.org Subject: [Tarantool-patches] [PATCH 2/2] swim: check types in __serialize methods Date: Sun, 4 Apr 2021 17:06:43 +0200 [thread overview] Message-ID: <a567247516e6b7e33d8abc50ed1bf6aff05d4fe4.1617548717.git.v.shpilevoy@tarantool.org> (raw) In-Reply-To: <cover.1617548717.git.v.shpilevoy@tarantool.org> In swim Lua code none of the __serialize methods checked the argument type assuming that nobody would call them directly and mess with the types. But it happened, and is not hard to fix, so the patch does it. The serialization functions are sanitized for the swim object, swim member, and member event. Closes #5952 --- changelogs/unreleased/swim-serialize-crash.md | 4 + src/lua/swim.lua | 41 +++++-- test/swim/gh-5952-swim-serialize.result | 101 ++++++++++++++++++ test/swim/gh-5952-swim-serialize.test.lua | 33 ++++++ 4 files changed, 169 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/swim-serialize-crash.md create mode 100644 test/swim/gh-5952-swim-serialize.result create mode 100644 test/swim/gh-5952-swim-serialize.test.lua diff --git a/changelogs/unreleased/swim-serialize-crash.md b/changelogs/unreleased/swim-serialize-crash.md new file mode 100644 index 000000000..e48b1f518 --- /dev/null +++ b/changelogs/unreleased/swim-serialize-crash.md @@ -0,0 +1,4 @@ +## bugfix/swim + +* Fix the crash on an attempt to pass an object of a wrong type to `__serialize` + method of a swim member in Lua (gh-5952). diff --git a/src/lua/swim.lua b/src/lua/swim.lua index f61aa6b58..027f07038 100644 --- a/src/lua/swim.lua +++ b/src/lua/swim.lua @@ -322,6 +322,16 @@ local function swim_check_member(m, func_name) return error(func_name..': first argument is not a SWIM member') end +local function swim_check_event(event, func_name) + if type(event) == 'table' then + local value = event[1] + if type(value) == 'number' then + return value + end + end + return error(func_name..': first argument is not a SWIM event') +end + -- -- Member methods. Most of them are one-liners, not much to -- comment. @@ -435,7 +445,8 @@ local function swim_member_uuid(m) end local function swim_member_serialize(m) - local _, size = swim_member_payload_raw(m.ptr) + local ptr = swim_check_member(m, 'member:__serialize()') + local _, size = swim_member_payload_raw(ptr) return { status = swim_member_status(m), uuid = swim_member_uuid(m), @@ -543,6 +554,7 @@ end -- serialized, for example, in a console. -- local function swim_serialize(s) + swim_check_instance(s, 'swim:__serialize()') return s.cfg.index end @@ -739,31 +751,40 @@ end local swim_member_event_index = { is_new = function(self) - return bit.band(self[1], capi.SWIM_EV_NEW) ~= 0 + local value = swim_check_event(self, 'event:is_new()') + return bit.band(value, capi.SWIM_EV_NEW) ~= 0 end, is_drop = function(self) - return bit.band(self[1], capi.SWIM_EV_DROP) ~= 0 + local value = swim_check_event(self, 'event:is_drop()') + return bit.band(value, capi.SWIM_EV_DROP) ~= 0 end, is_update = function(self) - return bit.band(self[1], capi.SWIM_EV_UPDATE) ~= 0 + local value = swim_check_event(self, 'event:is_update()') + return bit.band(value, capi.SWIM_EV_UPDATE) ~= 0 end, is_new_status = function(self) - return bit.band(self[1], capi.SWIM_EV_NEW_STATUS) ~= 0 + local value = swim_check_event(self, 'event:is_new_status()') + return bit.band(value, capi.SWIM_EV_NEW_STATUS) ~= 0 end, is_new_uri = function(self) - return bit.band(self[1], capi.SWIM_EV_NEW_URI) ~= 0 + local value = swim_check_event(self, 'event:is_new_uri()') + return bit.band(value, capi.SWIM_EV_NEW_URI) ~= 0 end, is_new_incarnation = function(self) - return bit.band(self[1], capi.SWIM_EV_NEW_INCARNATION) ~= 0 + local value = swim_check_event(self, 'event:is_new_incarnation()') + return bit.band(value, capi.SWIM_EV_NEW_INCARNATION) ~= 0 end, is_new_generation = function(self) - return bit.band(self[1], capi.SWIM_EV_NEW_GENERATION) ~= 0 + local value = swim_check_event(self, 'event:is_new_generation()') + return bit.band(value, capi.SWIM_EV_NEW_GENERATION) ~= 0 end, is_new_version = function(self) - return bit.band(self[1], capi.SWIM_EV_NEW_VERSION) ~= 0 + local value = swim_check_event(self, 'event:is_new_version()') + return bit.band(value, capi.SWIM_EV_NEW_VERSION) ~= 0 end, is_new_payload = function(self) - return bit.band(self[1], capi.SWIM_EV_NEW_PAYLOAD) ~= 0 + local value = swim_check_event(self, 'event:is_new_payload()') + return bit.band(value, capi.SWIM_EV_NEW_PAYLOAD) ~= 0 end, } diff --git a/test/swim/gh-5952-swim-serialize.result b/test/swim/gh-5952-swim-serialize.result new file mode 100644 index 000000000..0f9c3250b --- /dev/null +++ b/test/swim/gh-5952-swim-serialize.result @@ -0,0 +1,101 @@ +-- test-run result file version 2 +fiber = require('fiber') + | --- + | ... +swim = require('swim') + | --- + | ... +test_run = require('test_run').new() + | --- + | ... +test_run:cmd("push filter '\\.lua.*:[0-9]+: ' to '.lua:<line>: '") + | --- + | - true + | ... +test_run:cmd("push filter '127.0.0.1:[0-9]+$' to '127.0.0.1:<port>'") + | --- + | - true + | ... + +-- +-- gh-5952: invalid types in __serialize methods could lead to a crash. +-- + +s = swim.new({generation = 0}) + | --- + | ... +getmetatable(s):__serialize() + | --- + | - error: 'builtin/swim.lua:<line>: swim:__serialize(): first argument is not a SWIM instance' + | ... +getmetatable(s).__serialize(s) + | --- + | - [] + | ... + +s:cfg({uuid = uuid(1), uri = uri()}) + | --- + | - true + | ... +getmetatable(s):__serialize() + | --- + | - error: 'builtin/swim.lua:<line>: swim:__serialize(): first argument is not a SWIM instance' + | ... +getmetatable(s).__serialize(s) + | --- + | - uuid: 00000000-0000-1000-8000-000000000001 + | uri: 127.0.0.1:<port> + | ... + +self = s:self() + | --- + | ... +getmetatable(self):__serialize() + | --- + | - error: 'builtin/swim.lua:<line>: member:__serialize(): first argument is not a SWIM + | member' + | ... +getmetatable(self).__serialize(self) + | --- + | - uri: 127.0.0.1:<port> + | status: alive + | incarnation: cdata {generation = 0ULL, version = 1ULL} + | uuid: 00000000-0000-1000-8000-000000000001 + | payload_size: 0 + | ... + +event = nil + | --- + | ... +_ = s:on_member_event(function(m, e) event = e end) + | --- + | ... +s:set_payload(1) + | --- + | - true + | ... +test_run:wait_cond(function() return event ~= nil end) + | --- + | - true + | ... + +getmetatable(event):__serialize() + | --- + | - error: 'builtin/swim.lua:<line>: event:is_update(): first argument is not a SWIM event' + | ... +getmetatable(event).__serialize(event) + | --- + | - is_new_payload: true + | is_new_version: true + | is_new_incarnation: true + | is_update: true + | ... + +s:delete() + | --- + | ... + +test_run:cmd("clear filter") + | --- + | - true + | ... diff --git a/test/swim/gh-5952-swim-serialize.test.lua b/test/swim/gh-5952-swim-serialize.test.lua new file mode 100644 index 000000000..7bf75ba4f --- /dev/null +++ b/test/swim/gh-5952-swim-serialize.test.lua @@ -0,0 +1,33 @@ +fiber = require('fiber') +swim = require('swim') +test_run = require('test_run').new() +test_run:cmd("push filter '\\.lua.*:[0-9]+: ' to '.lua:<line>: '") +test_run:cmd("push filter '127.0.0.1:[0-9]+$' to '127.0.0.1:<port>'") + +-- +-- gh-5952: invalid types in __serialize methods could lead to a crash. +-- + +s = swim.new({generation = 0}) +getmetatable(s):__serialize() +getmetatable(s).__serialize(s) + +s:cfg({uuid = uuid(1), uri = uri()}) +getmetatable(s):__serialize() +getmetatable(s).__serialize(s) + +self = s:self() +getmetatable(self):__serialize() +getmetatable(self).__serialize(self) + +event = nil +_ = s:on_member_event(function(m, e) event = e end) +s:set_payload(1) +test_run:wait_cond(function() return event ~= nil end) + +getmetatable(event):__serialize() +getmetatable(event).__serialize(event) + +s:delete() + +test_run:cmd("clear filter") -- 2.24.3 (Apple Git-128)
next prev parent reply other threads:[~2021-04-04 15:07 UTC|newest] Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-04-04 15:06 [Tarantool-patches] [PATCH 0/2] Swim misusage crashes Vladislav Shpilevoy via Tarantool-patches 2021-04-04 15:06 ` [Tarantool-patches] [PATCH 1/2] swim: fix crash on bad member_by_uuid() call Vladislav Shpilevoy via Tarantool-patches 2021-04-04 15:06 ` Vladislav Shpilevoy via Tarantool-patches [this message] 2021-04-04 20:42 ` [Tarantool-patches] [PATCH 0/2] Swim misusage crashes Cyrill Gorcunov via Tarantool-patches 2021-04-05 9:05 ` Serge Petrenko via Tarantool-patches 2021-04-05 15:20 ` Kirill Yukhin via Tarantool-patches
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=a567247516e6b7e33d8abc50ed1bf6aff05d4fe4.1617548717.git.v.shpilevoy@tarantool.org \ --to=tarantool-patches@dev.tarantool.org \ --cc=gorcunov@gmail.com \ --cc=sergepetrenko@tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH 2/2] swim: check types in __serialize methods' \ /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