Commit b615c3df authored by Nisha Gopalakrishnan's avatar Nisha Gopalakrishnan

BUG#25451091:CREATE TABLE DATA DIRECTORY / INDEX DIRECTORY

             SYMLINK CHECK RACE CONDITIONS

ANALYSIS:
=========
A potential defect exists in the handling of CREATE
TABLE .. DATA DIRECTORY/ INDEX DIRECTORY which gives way to
the user to gain access to another user table or a system
table.

FIX:
====
The lstat and fstat output of the target files are now
stored which help in determining the identity of the target
files thus preventing the unauthorized access to other
files.
parent 67bec60c
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -49,6 +49,7 @@ typedef struct my_aio_result {
#ifdef _WIN32
#include <malloc.h> /*for alloca*/
#endif
#include <sys/stat.h>
#define MY_INIT(name) { my_progname= name; my_init(); }
......@@ -491,6 +492,16 @@ typedef struct st_io_cache /* Used when cacheing files */
typedef int (*qsort2_cmp)(const void *, const void *, const void *);
/*
Subset of struct stat fields filled by stat/lstat/fstat that uniquely
identify a file
*/
typedef struct st_file_id
{
dev_t st_dev;
ino_t st_ino;
} ST_FILE_ID;
/* defines for mf_iocache */
/* Test if buffer is inited */
......@@ -569,8 +580,9 @@ extern File my_create(const char *FileName,int CreateFlags,
extern int my_close(File Filedes,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_is_symlink(const char *filename, ST_FILE_ID *file_id);
extern int my_realpath(char *to, const char *filename, myf MyFlags);
extern int my_is_same_file(File file, const ST_FILE_ID *file_id);
extern File my_create_with_symlink(const char *linkname, const char *filename,
int createflags, int access_flags,
myf MyFlags);
......
/* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -99,11 +99,18 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags)
#endif
int my_is_symlink(const char *filename __attribute__((unused)))
int my_is_symlink(const char *filename __attribute__((unused)),
ST_FILE_ID *file_id)
{
#if defined (HAVE_LSTAT) && defined (S_ISLNK)
struct stat stat_buff;
return !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode);
int result= !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode);
if (file_id && !result)
{
file_id->st_dev= stat_buff.st_dev;
file_id->st_ino= stat_buff.st_ino;
}
return result;
#elif defined (_WIN32)
DWORD dwAttr = GetFileAttributes(filename);
return (dwAttr != INVALID_FILE_ATTRIBUTES) &&
......@@ -164,3 +171,20 @@ int my_realpath(char *to, const char *filename, myf MyFlags)
#endif
return 0;
}
/**
Return non-zero if the file descriptor and a previously lstat-ed file
identified by file_id point to the same file
*/
int my_is_same_file(File file, const ST_FILE_ID *file_id)
{
MY_STAT stat_buf;
if (my_fstat(file, &stat_buf, MYF(0)) == -1)
{
my_errno= errno;
return 0;
}
return (stat_buf.st_dev == file_id->st_dev)
&& (stat_buf.st_ino == file_id->st_ino);
}
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -29,7 +29,7 @@ int mi_delete_table(const char *name)
#endif
fn_format(from,name,"",MI_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
if (my_is_symlink(from) && (*myisam_test_invalid_symlink)(from))
if (my_is_symlink(from, NULL) && (*myisam_test_invalid_symlink)(from))
{
/*
Symlink is pointing to file in data directory.
......@@ -44,7 +44,7 @@ int mi_delete_table(const char *name)
DBUG_RETURN(my_errno);
}
fn_format(from,name,"",MI_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
if (my_is_symlink(from) && (*myisam_test_invalid_symlink)(from))
if (my_is_symlink(from, NULL) && (*myisam_test_invalid_symlink)(from))
{
/*
Symlink is pointing to file in data directory.
......
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -78,6 +78,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
ulonglong max_key_file_length, max_data_file_length;
ST_FILE_ID file_id= {0, 0};
DBUG_ENTER("mi_open");
LINT_INIT(m_info);
......@@ -89,11 +90,15 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
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)))
if (my_is_symlink(name_buff, &file_id))
{
my_errno= HA_WRONG_CREATE_OPTION;
DBUG_RETURN (NULL);
if (realpath_err ||
(*myisam_test_invalid_symlink)(name_buff) ||
my_is_symlink(name_buff, &file_id))
{
my_errno= HA_WRONG_CREATE_OPTION;
DBUG_RETURN (NULL);
}
}
mysql_mutex_lock(&THR_LOCK_myisam);
......@@ -113,17 +118,28 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
my_errno= HA_ERR_CRASHED;
goto err;
});
DEBUG_SYNC_C("before_opening_indexfile");
if ((kfile= mysql_file_open(mi_key_file_kfile,
name_buff,
(open_mode= O_RDWR) | O_SHARE, MYF(0))) < 0)
(open_mode= O_RDWR) | O_SHARE | O_NOFOLLOW,
MYF(0))) < 0)
{
if ((errno != EROFS && errno != EACCES) ||
mode != O_RDONLY ||
(kfile= mysql_file_open(mi_key_file_kfile,
name_buff,
(open_mode= O_RDONLY) | O_SHARE, MYF(0))) < 0)
(open_mode= O_RDONLY) | O_SHARE | O_NOFOLLOW,
MYF(0))) < 0)
goto err;
}
if (!my_is_same_file(kfile, &file_id))
{
mysql_file_close(kfile, MYF(0));
my_errno= HA_WRONG_CREATE_OPTION;
goto err;
}
share->mode=open_mode;
errpos=1;
if (mysql_file_read(kfile, share->state.header.file_version, head_length,
......@@ -1206,14 +1222,16 @@ int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *org_name,
{
char *data_name= share->data_file_name;
char real_data_name[FN_REFLEN];
ST_FILE_ID file_id= {0, 0};
if (org_name)
{
fn_format(real_data_name,org_name,"",MI_NAME_DEXT,4);
if (my_is_symlink(real_data_name))
if (my_is_symlink(real_data_name, &file_id))
{
if (my_realpath(real_data_name, real_data_name, MYF(0)) ||
(*myisam_test_invalid_symlink)(real_data_name))
(*myisam_test_invalid_symlink)(real_data_name) ||
my_is_symlink(real_data_name, &file_id))
{
my_errno= HA_WRONG_CREATE_OPTION;
return 1;
......@@ -1221,9 +1239,19 @@ int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *org_name,
data_name= real_data_name;
}
}
DEBUG_SYNC_C("before_opening_datafile");
info->dfile= mysql_file_open(mi_key_file_dfile,
data_name, share->mode | O_SHARE, MYF(MY_WME));
return info->dfile >= 0 ? 0 : 1;
data_name, share->mode | O_SHARE | O_NOFOLLOW,
MYF(MY_WME));
if (info->dfile < 0)
return 1;
if (org_name && !my_is_same_file(info->dfile, &file_id))
{
mysql_file_close(info->dfile, MYF(0));
my_errno= HA_WRONG_CREATE_OPTION;
return 1;
}
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment