Commit 69657f97 authored by Alexey Botchkov's avatar Alexey Botchkov
Browse files

Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.

            
            test_if_data_home_dir fixed to look into real path.
            Checks added to mi_open for symlinks into data home directory.

per-file messages:
        include/my_sys.h
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          my_is_symlink interface added
        include/myisam.h
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          myisam_test_invalid_symlink interface added
        myisam/mi_check.c
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          mi_open_datafile calls modified
        myisam/mi_open.c
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          code added to mi_open to check for symlinks into data home directory.
          mi_open_datafile now accepts 'original' file path to check if it's
          an allowed symlink.
        myisam/mi_static.c
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          myisam_test_invlaid_symlink defined
        myisam/myisamchk.c
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          mi_open_datafile call modified
        myisam/myisamdef.h
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          mi_open_datafile interface modified - 'real_path' parameter added
        mysql-test/r/symlink.test
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          error codes corrected as some patch now rejected pointing inside datahome
        mysql-test/r/symlink.result
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          error messages corrected in the result
        mysys/my_symlink.c
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          my_is_symlink() implementsd
          my_realpath() now returns the 'realpath' even if a file isn't a symlink
        sql/mysql_priv.h
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          test_if_data_home_dir interface
        sql/mysqld.cc
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          myisam_test_invalid_symlik set with the 'test_if_data_home_dir'
        sql/sql_parse.cc
          Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY.
          
          error messages corrected
          test_if_data_home_dir code fixed
parent 9bc9ddd5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -574,6 +574,7 @@ extern int my_close(File Filedes,myf MyFlags);
extern File my_dup(File file, myf MyFlags);
extern int my_mkdir(const char *dir, int Flags, myf MyFlags);
extern int my_readlink(char *to, const char *filename, myf MyFlags);
extern int my_is_symlink(const char *filename);
extern int my_realpath(char *to, const char *filename, myf MyFlags);
extern File my_create_with_symlink(const char *linkname, const char *filename,
				   int createflags, int access_flags,
+4 −0
Original line number Diff line number Diff line
@@ -267,6 +267,10 @@ extern my_bool myisam_flush,myisam_delay_key_write,myisam_single_user;
extern my_off_t myisam_max_temp_length;
extern ulong myisam_bulk_insert_tree_size, myisam_data_pointer_size;

/* usually used to check if a symlink points into the mysql data home */
/* which is normally forbidden                                        */
extern int (*myisam_test_invalid_symlink)(const char *filename);

	/* Prototypes for myisam-functions */

extern int mi_close(struct st_myisam_info *file);
+3 −3
Original line number Diff line number Diff line
@@ -1732,7 +1732,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
			    DATA_TMP_EXT, share->base.raid_chunks,
			    (param->testflag & T_BACKUP_DATA ?
			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
	  mi_open_datafile(info,share,-1))
	  mi_open_datafile(info,share,name,-1))
	got_error=1;
    }
  }
@@ -2519,7 +2519,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
			    DATA_TMP_EXT, share->base.raid_chunks,
			    (param->testflag & T_BACKUP_DATA ?
			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
	  mi_open_datafile(info,share,-1))
	  mi_open_datafile(info,share,name,-1))
	got_error=1;
    }
  }
@@ -3050,7 +3050,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
			    DATA_TMP_EXT, share->base.raid_chunks,
			    (param->testflag & T_BACKUP_DATA ?
			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
	  mi_open_datafile(info,share,-1))
	  mi_open_datafile(info,share,name,-1))
	got_error=1;
    }
  }
+34 −8
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ MI_INFO *test_if_reopen(char *filename)

MI_INFO *mi_open(const char *name, int mode, uint open_flags)
{
  int lock_error,kfile,open_mode,save_errno,have_rtree=0;
  int lock_error,kfile,open_mode,save_errno,have_rtree=0, realpath_err;
  uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
    key_parts,unique_key_parts,fulltext_keys,uniques;
  char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
@@ -94,7 +94,16 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
  head_length=sizeof(share_buff.state.header);
  bzero((byte*) &info,sizeof(info));

  my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
  realpath_err= my_realpath(name_buff,
                  fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
  if (my_is_symlink(org_name) &&
      (realpath_err || (*myisam_test_invalid_symlink)(name_buff)))
  {
    my_errno= HA_WRONG_CREATE_OPTION;
    DBUG_RETURN (NULL);
  }


  pthread_mutex_lock(&THR_LOCK_myisam);
  if (!(old_info=test_if_reopen(name_buff)))
  {
@@ -463,7 +472,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
      lock_error=1;			/* Database unlocked */
    }

    if (mi_open_datafile(&info, share, -1))
    if (mi_open_datafile(&info, share, name, -1))
      goto err;
    errpos=5;

@@ -534,7 +543,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
      my_errno=EACCES;				/* Can't open in write mode */
      goto err;
    }
    if (mi_open_datafile(&info, share, old_info->dfile))
    if (mi_open_datafile(&info, share, name, old_info->dfile))
      goto err;
    errpos=5;
    have_rtree= old_info->rtree_recursion_state != NULL;
@@ -1191,12 +1200,30 @@ The argument file_to_dup is here for the future if there would on some OS
exist a dup()-like call that would give us two different file descriptors.
*************************************************************************/

int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup __attribute__((unused)))
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *org_name,
                     File file_to_dup __attribute__((unused)))
{
  char *data_name= share->data_file_name;
  char real_data_name[FN_REFLEN];

  if (org_name)
  {
    fn_format(real_data_name,org_name,"",MI_NAME_DEXT,4);
    if (my_is_symlink(real_data_name))
    {
      if (my_realpath(real_data_name, real_data_name, MYF(0)) ||
          (*myisam_test_invalid_symlink)(real_data_name))
      {
        my_errno= HA_WRONG_CREATE_OPTION;
        return 1;
      }
      data_name= real_data_name;
    }
  }
#ifdef USE_RAID
  if (share->base.raid_type)
  {
    info->dfile=my_raid_open(share->data_file_name,
    info->dfile=my_raid_open(data_name,
			     share->mode | O_SHARE,
			     share->base.raid_type,
			     share->base.raid_chunks,
@@ -1205,8 +1232,7 @@ int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup __attr
  }
  else
#endif
    info->dfile=my_open(share->data_file_name, share->mode | O_SHARE,
			MYF(MY_WME));
    info->dfile=my_open(data_name, share->mode | O_SHARE, MYF(MY_WME));
  return info->dfile >= 0 ? 0 : 1;
}

+9 −0
Original line number Diff line number Diff line
@@ -41,6 +41,15 @@ my_off_t myisam_max_temp_length= MAX_FILE_SIZE;
ulong    myisam_bulk_insert_tree_size=8192*1024;
ulong    myisam_data_pointer_size=4;


static int always_valid(const char *filename)
{
  return 0;
}

int (*myisam_test_invalid_symlink)(const char *filename)= always_valid;


/*
  read_vec[] is used for converting between P_READ_KEY.. and SEARCH_
  Position is , == , >= , <= , > , <
Loading