@@ -519,6 +519,100 @@ static int make_iso8601_timestamp(char *buf, ulonglong utime= 0)
519
519
}
520
520
521
521
522
+ bool is_valid_log_name (const char *name, size_t len)
523
+ {
524
+ if (len > 3 )
525
+ {
526
+ const char *tail= name + len - 4 ;
527
+ if (my_strcasecmp (system_charset_info, tail, " .ini" ) == 0 ||
528
+ my_strcasecmp (system_charset_info, tail, " .cnf" ) == 0 )
529
+ {
530
+ return false ;
531
+ }
532
+ }
533
+ return true ;
534
+ }
535
+
536
+
537
+ /* *
538
+ Get the real log file name, and possibly reopen file.
539
+
540
+ The implementation is platform dependent due to differences in how this is
541
+ supported:
542
+
543
+ On Windows, we get the actual path based on the file descriptor. This path is
544
+ copied into the supplied buffer. The 'file' parameter is returned without
545
+ re-opening.
546
+
547
+ On other platforms, we use realpath() to get the path with symbolic links
548
+ expanded. Then, we close the file, and reopen the real path using the
549
+ O_NOFOLLOW flag. This will reject folowing symbolic links.
550
+
551
+ @param file File descriptor.
552
+ @param log_file_key Key for P_S instrumentation.
553
+ @param open_flags Flags to use for opening the file.
554
+ @param opened_file_name Name of the open fd.
555
+ @param [out] real_file_name Buffer for actual name of the fd.
556
+
557
+ @retval file descriptor to open file with 'real_file_name', or '-1'
558
+ in case of errors.
559
+ */
560
+
561
+ static File mysql_file_real_name_reopen (File file,
562
+ #ifdef HAVE_PSI_INTERFACE
563
+ PSI_file_key log_file_key,
564
+ #endif
565
+ int open_flags,
566
+ const char *opened_file_name,
567
+ char *real_file_name)
568
+ {
569
+ DBUG_ASSERT (file);
570
+ DBUG_ASSERT (opened_file_name);
571
+ DBUG_ASSERT (real_file_name);
572
+
573
+ #ifdef _WIN32
574
+ /* On Windows, O_NOFOLLOW is not supported. Verify real path from fd. */
575
+ DWORD real_length= GetFinalPathNameByHandle (my_get_osfhandle (file),
576
+ real_file_name,
577
+ FN_REFLEN,
578
+ FILE_NAME_OPENED);
579
+
580
+ /* May ret 0 if e.g. on a ramdisk. Ignore - return open file and name. */
581
+ if (real_length == 0 )
582
+ {
583
+ strcpy (real_file_name, opened_file_name);
584
+ return file;
585
+ }
586
+
587
+ if (real_length > FN_REFLEN)
588
+ {
589
+ mysql_file_close (file, MYF (0 ));
590
+ return -1 ;
591
+ }
592
+
593
+ return file;
594
+ #else
595
+ /* On *nix, get realpath, open realpath with O_NOFOLLOW. */
596
+ if (realpath (opened_file_name, real_file_name) == NULL )
597
+ {
598
+ (void ) mysql_file_close (file, MYF (0 ));
599
+ return -1 ;
600
+ }
601
+
602
+ if (mysql_file_close (file, MYF (0 )))
603
+ return -1 ;
604
+
605
+ /* Make sure the real path is not too long. */
606
+ if (strlen (real_file_name) > FN_REFLEN)
607
+ return -1 ;
608
+
609
+ return mysql_file_open (log_file_key, real_file_name,
610
+ open_flags | O_NOFOLLOW,
611
+ MYF (MY_WME));
612
+ #endif // _WIN32
613
+ }
614
+
615
+
522
616
bool File_query_log::open ()
523
617
{
524
618
File file= -1 ;
@@ -552,12 +646,36 @@ bool File_query_log::open()
552
646
553
647
db[0 ]= 0 ;
554
648
649
+ /* First, open the file to make sure it exists. */
555
650
if ((file= mysql_file_open (m_log_file_key,
556
651
log_file_name,
557
652
O_CREAT | O_BINARY | O_WRONLY | O_APPEND,
558
653
MYF (MY_WME))) < 0 )
559
654
goto err;
560
655
656
+ #ifdef _WIN32
657
+ char real_log_file_name[FN_REFLEN];
658
+ #else
659
+ /* File name must have room for PATH_MAX. Checked against F_REFLEN later. */
660
+ char real_log_file_name[PATH_MAX];
661
+ #endif // _Win32
662
+
663
+ /* Reopen and get real path. */
664
+ if ((file= mysql_file_real_name_reopen (file,
665
+ #ifdef HAVE_PSI_INTERFACE
666
+ m_log_file_key,
667
+ #endif
668
+ O_CREAT | O_BINARY | O_WRONLY | O_APPEND,
669
+ log_file_name, real_log_file_name)) < 0 )
670
+ goto err;
671
+
672
+ if (!is_valid_log_name (real_log_file_name, strlen (real_log_file_name)))
673
+ {
674
+ sql_print_error (" Invalid log file name after expanding symlinks: '%s'" ,
675
+ real_log_file_name);
676
+ goto err;
677
+ }
678
+
561
679
if ((pos= mysql_file_tell (file, MYF (MY_WME))) == MY_FILEPOS_ERROR)
562
680
{
563
681
if (my_errno () == ESPIPE)
0 commit comments