From 9dfb4fdf994a56c604643b6b858ab1811e5d4f81 Mon Sep 17 00:00:00 2001 From: Dmitry Ivanov <ivadmi5@gmail.com> Date: Mon, 3 Mar 2025 22:02:39 +0300 Subject: [PATCH] fix: check tuple metadata size in tuple_validate_raw This check is needed to prevent the following scenario: ``` box.cfg() box.schema.space.create("test") box.space.test:create_index("primary", { unique = true, parts = { { field = 1, type = "str" } } }) local t = { "pk1", {}, "value" } for i = 1, 9000 do table.insert(t[2], { i }) end box.space.test:insert(t) -- This succeeds, but shouldn't! box.space.test:create_index("broken", { parts = { { path = "[*][1]", type = "unsigned", field = 2 } } }) -- This fails with an error due to metadata update... box.space.test:update("pk1", { { "=", 3, "new value" } }) ``` ``` 2025-03-03 10:26:13.519 [41046] main tuple.h:473 E> ER_TUPLE_METADATA_IS_TOO_BIG: Can't create tuple: metadata size 36022 is too big ``` NO_DOC=picodata NO_CHANGELOG=picodata --- src/box/tuple.c | 9 +++++ .../tuple_validate_raw_regression_test.lua | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 test/box-luatest/tuple_validate_raw_regression_test.lua diff --git a/src/box/tuple.c b/src/box/tuple.c index 4bbddac1c9..0e315fe5c9 100644 --- a/src/box/tuple.c +++ b/src/box/tuple.c @@ -162,6 +162,15 @@ tuple_validate_raw(struct tuple_format *format, const char *tuple) size_t region_svp = region_used(region); struct field_map_builder builder; int rc = tuple_field_map_create(format, tuple, true, &builder); + if (rc != 0) + goto end; + + uint32_t field_map_size = field_map_build_size(&builder); + size_t data_offset = sizeof(struct tuple) + field_map_size; + rc = tuple_check_data_offset(data_offset); + if (rc != 0) + goto end; +end: region_truncate(region, region_svp); return rc; } diff --git a/test/box-luatest/tuple_validate_raw_regression_test.lua b/test/box-luatest/tuple_validate_raw_regression_test.lua new file mode 100644 index 0000000000..04206ca073 --- /dev/null +++ b/test/box-luatest/tuple_validate_raw_regression_test.lua @@ -0,0 +1,39 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group() + +g.before_each(function(cg) + cg.server = server:new{box_cfg = {}} + cg.server:start() +end) + +g.after_each(function(cg) + cg.server:stop() +end) + + +g.test_key_def_tuple_hash = function(cg) + cg.server:exec(function() + box.schema.space.create("test") + box.space.test:create_index("primary", { + unique = true, parts = { { field = 1, type = "str" } } + }) + + local tup = { "pk1", {}, "value" } + for i = 1, 9000 do + table.insert(tup[2], { i }) + end + box.space.test:insert(tup) + + local bad_operation = function() + box.space.test:create_index("broken", { + parts = { { path = "[*][1]", type = "unsigned", field = 2 } } + }) + end + + t.assert_error_msg_matches( + "Can't create tuple: metadata size .+ is too big", + bad_operation) + end) +end -- GitLab