From d22600168b78adfb7acbb773298d7dd7cce110f3 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 13 Jul 2026 14:16:19 +1000 Subject: [PATCH] MDEV-39813 ST_GeomFromGeoJSON does not control recursion depth Using stack_p wasn't a portable concept in 12.3 when JSON parsing got unlimited depth. To let ST_GeomFromGeoJSON was already a recursive function, needed because object order of "type" may be after the "geometries", but with json_engine_t no longer enforcing the depth, some stack checking was required. Use the check_stack_depth function to allow excessively deep GeoJSON objects to error. As this is cleaned up the gis-json test can be enabled. The exceeding stack depth is moved to lotofstack.test. --- mysql-test/main/disabled.def | 1 - mysql-test/main/gis-json.result | 13 ------------- mysql-test/main/gis-json.test | 10 ---------- mysql-test/main/lotofstack.result | 11 +++++++++++ mysql-test/main/lotofstack.test | 18 ++++++++++++++++++ sql/spatial.cc | 8 +++----- 6 files changed, 32 insertions(+), 29 deletions(-) diff --git a/mysql-test/main/disabled.def b/mysql-test/main/disabled.def index ff0f3ab1781c4..a38906361c562 100644 --- a/mysql-test/main/disabled.def +++ b/mysql-test/main/disabled.def @@ -16,4 +16,3 @@ mysql_embedded : Bug#12561297 2011-05-14 Anitha Dependent on PB2 chang file_contents : MDEV-6526 these files are not installed anymore max_statement_time : cannot possibly work, depends on timing partition_open_files_limit : open_files_limit check broken by MDEV-18360 -gis-json : MDEV-39813 infinite recursion diff --git a/mysql-test/main/gis-json.result b/mysql-test/main/gis-json.result index 49ec773945866..9cb7cb774a2ec 100644 --- a/mysql-test/main/gis-json.result +++ b/mysql-test/main/gis-json.result @@ -123,19 +123,6 @@ Warning 4048 Incorrect GeoJSON format specified for st_geomfromgeojson function. # # End of 10.2 tests # -# -# MDEV-39813 ST_GeomFromGeoJSON does not control recursion depth -# -SELECT ST_GeomFromGeoJSON( -concat( -repeat('{"type":"GeometryCollection","geometries":[', 2000), -'{"type":"Point","coordinates":[0,0]}', -repeat(']}', 2000) -)) as exp; -exp -NULL -Warnings: -Warning 4040 Limit of 32 on JSON nested structures depth is reached in argument 1 to function 'st_geomfromgeojson' at position 473 # End of 10.6 tests # # MDEV-34079: ST_AsGeoJSON returns incorrect value for empty geometry diff --git a/mysql-test/main/gis-json.test b/mysql-test/main/gis-json.test index ca402d1c2ef43..022672ab9b669 100644 --- a/mysql-test/main/gis-json.test +++ b/mysql-test/main/gis-json.test @@ -59,16 +59,6 @@ SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"type": ["POINT"], "coINates": [0,0] }')) --echo # End of 10.2 tests --echo # ---echo # ---echo # MDEV-39813 ST_GeomFromGeoJSON does not control recursion depth ---echo # - -SELECT ST_GeomFromGeoJSON( - concat( - repeat('{"type":"GeometryCollection","geometries":[', 2000), - '{"type":"Point","coordinates":[0,0]}', - repeat(']}', 2000) - )) as exp; --echo # End of 10.6 tests diff --git a/mysql-test/main/lotofstack.result b/mysql-test/main/lotofstack.result index 6f776eb67336c..1e17487cde820 100644 --- a/mysql-test/main/lotofstack.result +++ b/mysql-test/main/lotofstack.result @@ -104,3 +104,14 @@ drop table t3| # SELECT ST_GeomFromText(CONCAT(REPEAT('GEOMETRYCOLLECTION(',5000),'POINT(1 1)',REPEAT(')',5000))); # End of 10.6 tests +# +# MDEV-39813 ST_GeomFromGeoJSON does not control recursion depth +# +set @len = 3000; +SELECT ST_GeomFromGeoJSON( +concat( +repeat('{"type":"GeometryCollection", "geometries":[', @len), +'{"type":"Point","coordinates":[0,0]}', +repeat(']}', @len) +)) as exp; +# End of 12.3 tests diff --git a/mysql-test/main/lotofstack.test b/mysql-test/main/lotofstack.test index 20d9789b99ca8..2c5d082168aaf 100644 --- a/mysql-test/main/lotofstack.test +++ b/mysql-test/main/lotofstack.test @@ -148,3 +148,21 @@ SELECT ST_GeomFromText(CONCAT(REPEAT('GEOMETRYCOLLECTION(',5000),'POINT(1 1)',RE --enable_result_log --echo # End of 10.6 tests + + +--echo # +--echo # MDEV-39813 ST_GeomFromGeoJSON does not control recursion depth +--echo # + +set @len = 3000; +--disable_result_log +--error ER_STACK_OVERRUN_NEED_MORE +SELECT ST_GeomFromGeoJSON( + concat( + repeat('{"type":"GeometryCollection", "geometries":[', @len), + '{"type":"Point","coordinates":[0,0]}', + repeat(']}', @len) + )) as exp; +--enable_result_log + +--echo # End of 12.3 tests diff --git a/sql/spatial.cc b/sql/spatial.cc index 15e43cbbe5e0c..d30cd58fbf2e6 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -587,8 +587,10 @@ Geometry *Geometry::create_from_json(Geometry_buffer *buffer, uint key_len; int fcoll_type_found= 0, feature_type_found= 0; + if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) + return NULL; + const uint32_t *killed_ptr= (uint32_t *) je->killed_ptr; - int stack_p; if (json_read_value(je)) goto err_return; @@ -754,10 +756,8 @@ Geometry *Geometry::create_from_json(Geometry_buffer *buffer, create_geom: - stack_p= je->stack_p; json_scan_start(je, je->s.cs, coord_start, je->s.str_end); je->killed_ptr= killed_ptr; - je->stack_p= stack_p; if (res->reserve(1 + 4, 512)) goto err_return; @@ -771,10 +771,8 @@ Geometry *Geometry::create_from_json(Geometry_buffer *buffer, return result; handle_geometry_key: - stack_p= je->stack_p; json_scan_start(je, je->s.cs, geometry_start, je->s.str_end); je->killed_ptr= killed_ptr; - je->stack_p= stack_p; return create_from_json(buffer, je, er_on_3D, res); err_return: