summaryrefslogtreecommitdiffstats
path: root/mysql-cve-2016-6662-c-2135853b.patch
diff options
context:
space:
mode:
Diffstat (limited to 'mysql-cve-2016-6662-c-2135853b.patch')
-rw-r--r--mysql-cve-2016-6662-c-2135853b.patch186
1 files changed, 186 insertions, 0 deletions
diff --git a/mysql-cve-2016-6662-c-2135853b.patch b/mysql-cve-2016-6662-c-2135853b.patch
new file mode 100644
index 0000000..3564e13
--- /dev/null
+++ b/mysql-cve-2016-6662-c-2135853b.patch
@@ -0,0 +1,186 @@
+From 2135853b41f2d124f1869371154b0f9ab9a7b2da Mon Sep 17 00:00:00 2001
+From: Honza Horak <hhorak@redhat.com>
+Date: Fri, 9 Dec 2016 17:48:50 +0100
+Subject: [PATCH 3/4] Bug#24388753: PRIVILEGE ESCALATION USING MYSQLD_SAFE
+
+ MySQL 5.1 upstream backport of:
+ https://github.com/mysql/mysql-server/commit/48bd8b16fe382be302c6f0b45931be5aa6f29a0e
+
+ The problem was that it was possible to write log files ending
+ in .ini/.cnf that later could be parsed as an options file.
+ This made it possible for users to specify startup options
+ without the permissions to do so.
+
+ This patch fixes the problem by disallowing general query log
+ and slow query log to be written to files ending in .ini and .cnf.
+---
+ sql/log.cc | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ sql/log.h | 10 ++++++++
+ sql/mysqld.cc | 16 ++++++++++++
+ sql/set_var.cc | 5 ++++
+ 4 files changed, 110 insertions(+), 2 deletions(-)
+
+diff --git a/sql/log.cc b/sql/log.cc
+index 60692b7..d53b487 100644
+--- a/sql/log.cc
++++ b/sql/log.cc
+@@ -1933,6 +1933,73 @@ bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
+ }
+
+
++bool is_valid_log_name(const char *name, size_t len)
++{
++ if (len > 3)
++ {
++ const char *tail= name + len - 4;
++ if (my_strcasecmp(system_charset_info, tail, ".ini") == 0 ||
++ my_strcasecmp(system_charset_info, tail, ".cnf") == 0)
++ {
++ return false;
++ }
++ }
++ return true;
++}
++
++
++/**
++ Get the real log file name, and possibly reopen file.
++
++ Use realpath() to get the path with symbolic links
++ expanded. Then, close the file, and reopen the real path using the
++ O_NOFOLLOW flag. This will reject following symbolic links.
++
++ @param file File descriptor.
++ @param open_flags Flags to use for opening the file.
++ @param opened_file_name Name of the open fd.
++
++ @retval file descriptor to open file with 'real_file_name', or '-1'
++ in case of errors.
++*/
++
++#ifndef _WIN32
++static File mysql_file_real_name_reopen(File file,
++ int open_flags,
++ const char *opened_file_name)
++{
++ DBUG_ASSERT(file);
++ DBUG_ASSERT(opened_file_name);
++
++ /* Buffer for realpath must have capacity for PATH_MAX. */
++ char real_file_name[PATH_MAX];
++
++ /* Get realpath, validate, open realpath with O_NOFOLLOW. */
++ if (realpath(opened_file_name, real_file_name) == NULL)
++ {
++ (void) my_close(file, MYF(0));
++ return -1;
++ }
++
++ if (my_close(file, MYF(0)))
++ return -1;
++
++ if (strlen(real_file_name) > FN_REFLEN)
++ return -1;
++
++ if (!is_valid_log_name(real_file_name, strlen(real_file_name)))
++ {
++ sql_print_error("Invalid log file name after expanding symlinks: '%s'",
++ real_file_name);
++ return -1;
++ }
++
++ return my_open(real_file_name,
++ open_flags | O_NOFOLLOW,
++ MYF(MY_WME | ME_WAITTANG));
++}
++#endif // _WIN32
++
+ /*
+ Open a (new) log file.
+
+@@ -1983,8 +2050,18 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
+ db[0]= 0;
+
+ if ((file= my_open(log_file_name, open_flags,
+- MYF(MY_WME | ME_WAITTANG))) < 0 ||
+- init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
++ MYF(MY_WME | ME_WAITTANG))) < 0)
++ goto err;
++
++#ifndef _WIN32
++ /* Reopen and validate path. */
++ if ((log_type_arg == LOG_UNKNOWN || log_type_arg == LOG_NORMAL) &&
++ (file= mysql_file_real_name_reopen(file,
++ open_flags,
++ log_file_name)) < 0)
++ goto err;
++#endif // _WIN32
++ if (init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
+ my_tell(file, MYF(MY_WME)), 0,
+ MYF(MY_WME | MY_NABP |
+ ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
+diff --git a/sql/log.h b/sql/log.h
+index 02721f1..5354447 100644
+--- a/sql/log.h
++++ b/sql/log.h
+@@ -605,4 +605,14 @@ extern TYPELIB binlog_format_typelib;
+
+ int query_error_code(THD *thd, bool not_killed);
+
++/**
++ Check given log name against certain blacklisted names/extensions.
++
++ @param name Log name to check
++ @param len Length of log name
++
++ @returns true if name is valid, false otherwise.
++*/
++bool is_valid_log_name(const char *name, size_t len);
++
+ #endif /* LOG_H */
+diff --git a/sql/mysqld.cc b/sql/mysqld.cc
+index 41cef57..aa1dab4 100644
+--- a/sql/mysqld.cc
++++ b/sql/mysqld.cc
+@@ -3458,6 +3458,22 @@ static int init_common_variables(const char *conf_file_name, int argc,
+ "--log_slow_queries option, log tables are used. "
+ "To enable logging to files use the --log-output=file option.");
+
++ if (opt_logname &&
++ !is_valid_log_name(opt_logname, strlen(opt_logname)))
++ {
++ sql_print_error("Invalid value for --general_log_file: %s",
++ opt_logname);
++ return 1;
++ }
++
++ if (opt_slow_logname &&
++ !is_valid_log_name(opt_slow_logname, strlen(opt_slow_logname)))
++ {
++ sql_print_error("Invalid value for --slow_query_log_file: %s",
++ opt_slow_logname);
++ return 1;
++ }
++
+ s= opt_logname ? opt_logname : make_default_log_name(buff, ".log");
+ sys_var_general_log_path.value= my_strdup(s, MYF(0));
+ sys_var_general_log_path.value_length= strlen(s);
+diff --git a/sql/set_var.cc b/sql/set_var.cc
+index f4035ed..73727c8 100644
+--- a/sql/set_var.cc
++++ b/sql/set_var.cc
+@@ -2493,6 +2493,11 @@ static int sys_check_log_path(THD *thd, set_var *var)
+ log_file_str= res->c_ptr();
+ bzero(&f_stat, sizeof(MY_STAT));
+
++ if (!is_valid_log_name(log_file_str, strlen(log_file_str)))
++ {
++ goto err;
++ }
++
+ path_length= unpack_filename(path, log_file_str);
+
+ if (!path_length)
+--
+2.7.4
+