diff options
-rw-r--r-- | include/my_sys.h | 1 | ||||
-rw-r--r-- | mysys/my_access.c | 61 | ||||
-rw-r--r-- | mysys/my_fopen.c | 5 | ||||
-rw-r--r-- | mysys/my_open.c | 7 | ||||
-rw-r--r-- | sql/set_var.cc | 3 |
5 files changed, 77 insertions, 0 deletions
diff --git a/include/my_sys.h b/include/my_sys.h index f6cd9dada99..6bdb95e9707 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -649,6 +649,7 @@ extern File my_sopen(const char *path, int oflag, int shflag, int pmode); #endif extern int check_if_legal_filename(const char *path); extern int check_if_legal_tablename(const char *path); +extern my_bool is_filename_allowed(const char *name, size_t length); #if defined(__WIN__) && defined(__NT__) extern int nt_share_delete(const char *name,myf MyFlags); diff --git a/mysys/my_access.c b/mysys/my_access.c index 43917da7f98..4734fbac8ba 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -156,6 +156,67 @@ int check_if_legal_tablename(const char *name) } +#ifdef __WIN__ +/** + Checks if the drive letter supplied is valid or not. Valid drive + letters are A to Z, both lower case and upper case. + + @param drive_letter : The drive letter to validate. + + @return TRUE if the drive exists, FALSE otherwise. +*/ +static my_bool does_drive_exists(char drive_letter) +{ + DWORD drive_mask= GetLogicalDrives(); + drive_letter= toupper(drive_letter); + + return (drive_letter >= 'A' && drive_letter <= 'Z') && + (drive_mask & (0x1 << (drive_letter - 'A'))); +} +#endif + +/** + Verifies if the file name supplied is allowed or not. On Windows + file names with a colon (:) are not allowed because such file names + store data in Alternate Data Streams which can be used to hide + the data. + + @param name contains the file name with or without path + @param length contains the length of file name + + @return TRUE if the file name is allowed, FALSE otherwise. +*/ +my_bool is_filename_allowed(const char *name __attribute__((unused)), + size_t length __attribute__((unused))) +{ +#ifdef __WIN__ + /* + For Windows, check if the file name contains : character. + Start from end of path and search if the file name contains : + */ + const char* ch = NULL; + for(ch= name + length - 1; ch >= name; --ch) + { + if (FN_LIBCHAR == *ch || '/' == *ch) + break; + else if (':' == *ch) + { + /* + File names like C:foobar.txt are allowed since the syntax means + file foobar.txt in current directory of C drive. However file + names likes CC:foobar are not allowed since this syntax means ADS + foobar in file CC. + */ + return ((ch - name == 1) && does_drive_exists(*name)); + } + } + return TRUE; +#else + /* For other platforms, file names can contain colon : */ + return TRUE; +#endif +} /* is_filename_allowed */ + #if defined(__WIN__) || defined(__EMX__) diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index 72991490d75..75c5ec6ff8b 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -56,6 +56,11 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags) errno= EACCES; fd= 0; } + else if (!is_filename_allowed(filename, strlen(filename)))
+ { + errno= EINVAL; + fd= 0; + } else #endif { diff --git a/mysys/my_open.c b/mysys/my_open.c index fe7f65c450b..9060bb404e8 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -218,6 +218,13 @@ File my_sopen(const char *path, int oflag, int shflag, int pmode) DWORD fileattrib; /* OS file attribute flags */ SECURITY_ATTRIBUTES SecurityAttributes; + if (!is_filename_allowed(path, strlen(path))) + { + errno= EINVAL; + _doserrno= 0L; /* not an OS error */ + return -1; + } + SecurityAttributes.nLength= sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor= NULL; SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT); diff --git a/sql/set_var.cc b/sql/set_var.cc index bbc47c2d7e8..269eea844aa 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2502,6 +2502,9 @@ static int sys_check_log_path(THD *thd, set_var *var) goto err; } + if (!is_filename_allowed(log_file_str, strlen(log_file_str))) + goto err;
+
if (my_stat(path, &f_stat, MYF(0))) { /* |