Skip to content

Commit 902d05a

Browse files
MDEV-39213: json range syntax crash
Analysis: When json is being parsed, the step decreases without a out-of-bound check resulting in failure. Fix: Before decreasing the step, check if it will result into out of bound.
1 parent 200eb53 commit 902d05a

6 files changed

Lines changed: 42 additions & 18 deletions

File tree

mysql-test/main/func_json.result

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,12 @@ null<=>json_extract('1',json_object(null,'{ }',null,null),'{}')
17741774
Warnings:
17751775
Warning 4042 Syntax error in JSON path in argument 2 to function 'json_extract' at position 1
17761776
#
1777+
# MDEV-39213: json range syntax crash
1778+
#
1779+
SELECT JSON_EXISTS(CONCAT('[', REPEAT('[', 4000), 'Y', REPEAT(']', 4000), ', 1]'), '$[100]');
1780+
JSON_EXISTS(CONCAT('[', REPEAT('[', 4000), 'Y', REPEAT(']', 4000), ', 1]'), '$[100]')
1781+
NULL
1782+
#
17771783
# MDEV-35548 UBSAN: runtime error: index -1 out of bounds for type 'json_path_step_t[32]'
17781784
# (aka 'struct st_json_path_step_t[32]')
17791785
#

mysql-test/main/func_json.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,12 @@ FROM JSON_TABLE (@data, '$[*]' COLUMNS (data text PATH '$.Data')) AS t;
12381238

12391239
select null<=>json_extract('1',json_object(null,'{ }',null,null),'{}');
12401240

1241+
--echo #
1242+
--echo # MDEV-39213: json range syntax crash
1243+
--echo #
1244+
1245+
SELECT JSON_EXISTS(CONCAT('[', REPEAT('[', 4000), 'Y', REPEAT(']', 4000), ', 1]'), '$[100]');
1246+
12411247
--echo #
12421248
--echo # MDEV-35548 UBSAN: runtime error: index -1 out of bounds for type 'json_path_step_t[32]'
12431249
--echo # (aka 'struct st_json_path_step_t[32]')

sql/item_jsonfunc.cc

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ bool Item_func_json_exists::fix_length_and_dec()
549549
bool Item_func_json_exists::val_bool()
550550
{
551551
json_engine_t je;
552-
uint array_counters[JSON_DEPTH_LIMIT];
552+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
553553

554554
String *js= args[0]->val_json(&tmp_js);
555555

@@ -614,7 +614,7 @@ bool Json_path_extractor::extract(String *str, Item *item_js, Item *item_jp,
614614
{
615615
String *js= item_js->val_json(&tmp_js);
616616
int error= 0;
617-
uint array_counters[JSON_DEPTH_LIMIT];
617+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
618618

619619
if (!parsed)
620620
{
@@ -1368,7 +1368,7 @@ bool Item_func_json_contains::val_bool()
13681368

13691369
if (arg_count>2) /* Path specified. */
13701370
{
1371-
uint array_counters[JSON_DEPTH_LIMIT];
1371+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
13721372
if (!path.parsed)
13731373
{
13741374
String *s_p= args[2]->val_str(&tmp_path);
@@ -1505,7 +1505,7 @@ longlong Item_func_json_contains_path::val_int()
15051505
result= !mode_one;
15061506
for (n_arg=2; n_arg < arg_count; n_arg++)
15071507
{
1508-
uint array_counters[JSON_DEPTH_LIMIT];
1508+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
15091509
json_path_with_flags *c_path= paths + n_arg - 2;
15101510
if (!c_path->parsed)
15111511
{
@@ -1895,7 +1895,7 @@ String *Item_func_json_array_append::val_str(String *str)
18951895

18961896
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
18971897
{
1898-
uint array_counters[JSON_DEPTH_LIMIT];
1898+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
18991899
json_path_with_flags *c_path= paths + n_path;
19001900
if (!c_path->parsed)
19011901
{
@@ -2025,7 +2025,7 @@ String *Item_func_json_array_insert::val_str(String *str)
20252025

20262026
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
20272027
{
2028-
uint array_counters[JSON_DEPTH_LIMIT];
2028+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
20292029
json_path_with_flags *c_path= paths + n_path;
20302030
const char *item_pos;
20312031
uint n_item;
@@ -2821,7 +2821,7 @@ longlong Item_func_json_length::val_int()
28212821
String *js= args[0]->val_json(&tmp_js);
28222822
json_engine_t je;
28232823
uint length= 0;
2824-
uint array_counters[JSON_DEPTH_LIMIT];
2824+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
28252825
int err;
28262826

28272827
if ((null_value= args[0]->null_value))
@@ -3060,7 +3060,7 @@ String *Item_func_json_insert::val_str(String *str)
30603060

30613061
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
30623062
{
3063-
uint array_counters[JSON_DEPTH_LIMIT];
3063+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
30643064
json_path_with_flags *c_path= paths + n_path;
30653065
const char *v_to;
30663066
const json_path_step_t *lp;
@@ -3314,7 +3314,7 @@ String *Item_func_json_remove::val_str(String *str)
33143314

33153315
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg++, n_path++)
33163316
{
3317-
uint array_counters[JSON_DEPTH_LIMIT];
3317+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
33183318
json_path_with_flags *c_path= paths + n_path;
33193319
const char *rem_start= 0, *rem_end;
33203320
const json_path_step_t *lp;
@@ -3526,7 +3526,7 @@ String *Item_func_json_keys::val_str(String *str)
35263526
json_engine_t je;
35273527
String *js= args[0]->val_json(&tmp_js);
35283528
uint n_keys= 0;
3529-
uint array_counters[JSON_DEPTH_LIMIT];
3529+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
35303530

35313531
if ((args[0]->null_value))
35323532
goto null_return;

sql/json_table.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos)
550550
{
551551
json_engine_t je;
552552
json_path_step_t *cur_step;
553-
uint array_counters[JSON_DEPTH_LIMIT];
553+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
554554
int not_found;
555555
const uchar* node_start;
556556
const uchar* node_end;

strings/json_lib.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,14 +1371,26 @@ int json_find_path(json_engine_t *je,
13711371
json_skip_array_item(je);
13721372
break;
13731373
case JST_OBJ_END:
1374-
do
1375-
{
1376-
(*p_cur_step)--;
1377-
} while (*p_cur_step > p->steps &&
1378-
array_counters[*p_cur_step - p->steps] == SKIPPED_STEP_MARK);
1374+
/*
1375+
MSAN-safe block
1376+
*/
1377+
while (*p_cur_step > p->steps)
1378+
{
1379+
json_path_step_t *prev = *p_cur_step;
1380+
prev--;
1381+
1382+
if (prev < p->steps)
1383+
break;
1384+
1385+
*p_cur_step = prev;
1386+
1387+
if (array_counters[prev - p->steps] != SKIPPED_STEP_MARK)
1388+
break;
1389+
}
13791390
break;
13801391
case JST_ARRAY_END:
1381-
(*p_cur_step)--;
1392+
if (*p_cur_step > p->steps)
1393+
(*p_cur_step)--;
13821394
break;
13831395
default:
13841396
DBUG_ASSERT(0);

unittest/json_lib/json_lib-t.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ test_search()
140140
json_path_t p;
141141
json_path_step_t *cur_step;
142142
int n_matches, scal_values;
143-
uint array_counters[JSON_DEPTH_LIMIT];
143+
uint array_counters[JSON_DEPTH_LIMIT]= {0};
144144

145145
if (json_scan_start(&je, ci, s_e(fj0)) ||
146146
json_path_setup(&p, ci, s_e(fp0)))

0 commit comments

Comments
 (0)