54
54
#include <m_string.h>
55
55
#include <m_ctype.h>
56
56
#include <hash.h>
57
+ #include <ctype.h>
57
58
#include <stdarg.h>
58
59
59
60
#include "client_priv.h"
@@ -2328,6 +2329,82 @@ static char const* fix_identifier_with_newline(char const* object_name, my_bool*
2328
2329
}
2329
2330
2330
2331
2332
+ /*
2333
+ * fprintf_string:
2334
+ * -- Print the escaped version of the given char* row into the md_result_file.
2335
+ *
2336
+ * @param[in] row the row to be printed
2337
+ * @param[in] row_len length of the row
2338
+ * @param[in] quote quote character, like ' or ` etc.
2339
+ * @param[in] needs_newline whether to print newline after the row
2340
+ *
2341
+ * @retval void
2342
+ *
2343
+ */
2344
+ static void fprintf_string (char * row , ulong row_len , char quote ,
2345
+ my_bool needs_newline ) {
2346
+ // Create the buffer where we'll have sanitized row.
2347
+ char buffer [2048 ];
2348
+ char * pbuffer ;
2349
+ uint64_t curr_row_size ;
2350
+ pbuffer = & buffer [0 ];
2351
+
2352
+ curr_row_size = ((uint64_t )row_len ) * 2 + 1 ;
2353
+
2354
+ // We'll allocate dynamic memory only for huge rows
2355
+ if (curr_row_size > sizeof (buffer ))
2356
+ pbuffer = (char * )my_malloc (PSI_NOT_INSTRUMENTED , curr_row_size , MYF (0 ));
2357
+
2358
+ // Put the sanitized row in the buffer.
2359
+ mysql_real_escape_string_quote (mysql , pbuffer , row , row_len , '\'' );
2360
+
2361
+ // Opening quote
2362
+ fputc (quote , md_result_file );
2363
+
2364
+ // Print the row to the file.
2365
+ fputs (pbuffer , md_result_file );
2366
+
2367
+ // Closing quote
2368
+ fputc (quote , md_result_file );
2369
+
2370
+ // Add the new line
2371
+ if (needs_newline ) fputc ('\n' , md_result_file );
2372
+
2373
+ // Free the buffer if we have to.
2374
+ if (pbuffer != & buffer [0 ]) my_free (pbuffer );
2375
+ }
2376
+
2377
+ /*
2378
+ * is_string_integer:
2379
+ * Check if the given string is a valid integer or not.
2380
+ *
2381
+ * @param[in] str number to be checked
2382
+ * @param[in] str_len length of the string
2383
+ *
2384
+ * @retval TRUE if the string represents an integer
2385
+ * @retval FALSE if the string has non-digit characters
2386
+ */
2387
+ static my_bool is_string_integer (const char * str , ulong str_len ) {
2388
+ ulong start_index ;
2389
+ ulong i ;
2390
+
2391
+ // Empty strings are invalid numbers
2392
+ if (str_len == 0 ) return FALSE;
2393
+
2394
+ start_index = 0 ;
2395
+
2396
+ // For negative integers, start the index with 1
2397
+ if (str [0 ] == '-' ) {
2398
+ if (str_len == 1 ) return FALSE;
2399
+ start_index = 1 ;
2400
+ }
2401
+
2402
+ for (i = start_index ; i < str_len ; i ++ )
2403
+ if (!isdigit (str [i ])) return FALSE;
2404
+
2405
+ return TRUE;
2406
+ }
2407
+
2331
2408
/*
2332
2409
create_delimiter
2333
2410
Generate a new (null-terminated) string that does not exist in query
@@ -4440,6 +4517,7 @@ static int dump_tablespaces(char* ts_where)
4440
4517
MYSQL_RES * tableres ;
4441
4518
char buf [FN_REFLEN ];
4442
4519
DYNAMIC_STRING sqlbuf ;
4520
+ ulong * lengths ;
4443
4521
int first = 0 ;
4444
4522
/*
4445
4523
The following are used for parsing the EXTRA field
@@ -4500,24 +4578,33 @@ static int dump_tablespaces(char* ts_where)
4500
4578
buf [0 ]= 0 ;
4501
4579
while ((row = mysql_fetch_row (tableres )))
4502
4580
{
4581
+ lengths = mysql_fetch_lengths (tableres );
4503
4582
if (strcmp (buf , row [0 ]) != 0 )
4504
4583
first = 1 ;
4505
4584
if (first )
4506
4585
{
4586
+ /*
4587
+ * The print_comment below prints single line comments in the
4588
+ * md_result_file (--). The single line comment is terminated by a new
4589
+ * line, however because of the usage of mysql_real_escape_string_quote,
4590
+ * the new line character will get escaped too in the string, hence
4591
+ * another new line characters are being used at the end of the string
4592
+ * to terminate the single line comment.
4593
+ */
4594
+ mysql_real_escape_string_quote (mysql , buf , row [0 ], lengths [0 ], '\'' );
4507
4595
print_comment (md_result_file , 0 , "\n--\n-- Logfile group: %s\n--\n" ,
4508
- row [ 0 ] );
4509
-
4596
+ buf );
4597
+ buf [ 0 ] = 0 ;
4510
4598
fprintf (md_result_file , "\nCREATE" );
4511
4599
}
4512
4600
else
4513
4601
{
4514
4602
fprintf (md_result_file , "\nALTER" );
4515
4603
}
4516
- fprintf (md_result_file ,
4517
- " LOGFILE GROUP %s\n"
4518
- " ADD UNDOFILE '%s'\n" ,
4519
- row [0 ],
4520
- row [1 ]);
4604
+ fprintf (md_result_file , " LOGFILE GROUP " );
4605
+ fprintf_string (row [0 ], lengths [0 ], '`' , TRUE);
4606
+ fprintf (md_result_file , " ADD UNDOFILE " );
4607
+ fprintf_string (row [1 ], lengths [1 ], '\'' , TRUE);
4521
4608
if (first )
4522
4609
{
4523
4610
ubs = strstr (row [5 ],extra_format );
@@ -4527,15 +4614,15 @@ static int dump_tablespaces(char* ts_where)
4527
4614
endsemi = strstr (ubs ,";" );
4528
4615
if (endsemi )
4529
4616
endsemi [0 ]= '\0' ;
4617
+ if (!is_string_integer (ubs , (ulong )strlen (ubs ))) return 1 ;
4530
4618
fprintf (md_result_file ,
4531
4619
" UNDO_BUFFER_SIZE %s\n" ,
4532
4620
ubs );
4533
4621
}
4534
- fprintf (md_result_file ,
4535
- " INITIAL_SIZE %s\n"
4536
- " ENGINE=%s;\n" ,
4537
- row [3 ],
4538
- row [4 ]);
4622
+ if (!is_string_integer (row [3 ], lengths [3 ])) return 1 ;
4623
+ fprintf (md_result_file , " INITIAL_SIZE %s\n ENGINE=" , row [3 ]);
4624
+ fprintf_string (row [4 ], lengths [4 ], '`' , FALSE);
4625
+ fprintf (md_result_file , ";\n" );
4539
4626
check_io (md_result_file );
4540
4627
if (first )
4541
4628
{
@@ -4567,38 +4654,54 @@ static int dump_tablespaces(char* ts_where)
4567
4654
DBUG_RETURN (1 );
4568
4655
}
4569
4656
4657
+ DBUG_EXECUTE_IF ("tablespace_injection_test" , {
4658
+ mysql_free_result (tableres );
4659
+ mysql_query_with_error_report (
4660
+ mysql , & tableres ,
4661
+ "SELECT 'TN; /*' AS TABLESPACE_NAME, 'FN' AS FILE_NAME, 'LGN' AS "
4662
+ "LOGFILE_GROUP_NAME, 77 AS EXTENT_SIZE, 88 AS INITIAL_SIZE, "
4663
+ "'*/\nsystem touch foo;\n' AS ENGINE" );
4664
+ });
4665
+
4570
4666
buf [0 ]= 0 ;
4571
4667
while ((row = mysql_fetch_row (tableres )))
4572
4668
{
4669
+ lengths = mysql_fetch_lengths (tableres );
4573
4670
if (strcmp (buf , row [0 ]) != 0 )
4574
4671
first = 1 ;
4575
4672
if (first )
4576
4673
{
4577
- print_comment (md_result_file , 0 , "\n--\n-- Tablespace: %s\n--\n" , row [0 ]);
4674
+ /*
4675
+ * The print_comment below prints single line comments in the
4676
+ * md_result_file (--). The single line comment is terminated by a new
4677
+ * line, however because of the usage of mysql_real_escape_string_quote,
4678
+ * the new line character will get escaped too in the string, hence
4679
+ * another new line characters are being used at the end of the string
4680
+ * to terminate the single line comment.
4681
+ */
4682
+ mysql_real_escape_string_quote (mysql , buf , row [0 ], lengths [0 ], '\'' );
4683
+ print_comment (md_result_file , 0 , "\n--\n-- Tablespace: %s\n--\n" , buf );
4684
+ buf [0 ] = 0 ;
4578
4685
fprintf (md_result_file , "\nCREATE" );
4579
4686
}
4580
4687
else
4581
4688
{
4582
4689
fprintf (md_result_file , "\nALTER" );
4583
4690
}
4584
- fprintf (md_result_file ,
4585
- " TABLESPACE %s\n"
4586
- " ADD DATAFILE '%s'\n" ,
4587
- row [0 ],
4588
- row [1 ]);
4589
- if (first )
4590
- {
4591
- fprintf (md_result_file ,
4592
- " USE LOGFILE GROUP %s\n"
4593
- " EXTENT_SIZE %s\n" ,
4594
- row [2 ],
4595
- row [3 ]);
4691
+ fprintf (md_result_file , " TABLESPACE " );
4692
+ fprintf_string (row [0 ], lengths [0 ], '`' , TRUE);
4693
+ fprintf (md_result_file , " ADD DATAFILE " );
4694
+ fprintf_string (row [1 ], lengths [1 ], '\'' , TRUE);
4695
+ if (first ) {
4696
+ fprintf (md_result_file , " USE LOGFILE GROUP " );
4697
+ fprintf_string (row [2 ], lengths [2 ], '`' , TRUE);
4698
+ if (!is_string_integer (row [3 ], lengths [3 ])) return 1 ;
4699
+ fprintf (md_result_file , " EXTENT_SIZE %s\n" , row [3 ]);
4596
4700
}
4597
- fprintf (md_result_file ,
4598
- " INITIAL_SIZE %s\n"
4599
- " ENGINE=%s;\n" ,
4600
- row [4 ],
4601
- row [5 ]);
4701
+ if (!is_string_integer (row [4 ], lengths [4 ])) return 1 ;
4702
+ fprintf (md_result_file , " INITIAL_SIZE %s\n ENGINE=" , row [4 ]);
4703
+ fprintf_string (row [5 ], lengths [5 ], '`' , FALSE);
4704
+ fprintf (md_result_file , ";\n" );
4602
4705
check_io (md_result_file );
4603
4706
if (first )
4604
4707
{
0 commit comments