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