@@ -519,6 +519,100 @@ static int make_iso8601_timestamp(char *buf, ulonglong utime= 0)
519519}
520520
521521
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+ 
522616bool  File_query_log::open ()
523617{
524618  File file= -1 ;
@@ -552,12 +646,36 @@ bool File_query_log::open()
552646
553647  db[0 ]= 0 ;
554648
649+   /*  First, open the file to make sure it exists. */ 
555650  if  ((file= mysql_file_open (m_log_file_key,
556651                             log_file_name,
557652                             O_CREAT | O_BINARY | O_WRONLY | O_APPEND,
558653                             MYF (MY_WME))) < 0 )
559654    goto  err;
560655
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+ 
561679  if  ((pos= mysql_file_tell (file, MYF (MY_WME))) == MY_FILEPOS_ERROR)
562680  {
563681    if  (my_errno () == ESPIPE)
0 commit comments