From: Anton Chevychalov Date: Thu, 22 Sep 2016 14:16:17 +0000 (+0300) Subject: Fix CVE-2016-6662 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F72%2F26772%2F1;p=packages%2Ftrusty%2Fmysql-wsrep-5.6.git Fix CVE-2016-6662 Fix CVE-2016-6662 using debian patch. Change-Id: I6e362b1f1512bc64ddb37fc4d0e8c3bcde453146 Closes-Bug: #1622767 --- diff --git a/debian/changelog b/debian/changelog index e86798b7..12180b5c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +mysql-wsrep-5.6 (5.6.30-0~u14.04+mos2) mos; urgency=high + + * SECURITY UPDATE: Fix CVE-2016-6662 + - https://security-tracker.debian.org/tracker/CVE-2016-6662 + + -- Anton Chevychalov Thu, 22 Sep 2016 17:01:53 +0300 + mysql-wsrep-5.6 (5.6.30-0~u14.04+mos1) mos; urgency=high * SECURITY UPDATE: Update to 5.6.30 to fix security issues (LP: #1572559) diff --git a/debian/patches/debian_patches_CVE-2016-6662.patch b/debian/patches/debian_patches_CVE-2016-6662.patch new file mode 100644 index 00000000..dba4f7d3 --- /dev/null +++ b/debian/patches/debian_patches_CVE-2016-6662.patch @@ -0,0 +1,403 @@ +--- a/scripts/mysqld_safe.sh ++++ b/scripts/mysqld_safe.sh +@@ -281,8 +281,17 @@ + --core-file-size=*) core_file_size="$val" ;; + --ledir=*) ledir="$val" ;; + --malloc-lib=*) set_malloc_lib "$val" ;; +- --mysqld=*) MYSQLD="$val" ;; ++ --mysqld=*) ++ if [ -z "$pick_args" ]; then ++ log_error "--mysqld option can only be used as command line option, found in config file" ++ exit 1 ++ fi ++ MYSQLD="$val" ;; + --mysqld-version=*) ++ if [ -z "$pick_args" ]; then ++ log_error "--mysqld-version option can only be used as command line option, found in config file" ++ exit 1 ++ fi + if test -n "$val" + then + MYSQLD="mysqld-$val" +@@ -377,37 +386,23 @@ + } + + +-mysql_config= +-get_mysql_config() { +- if [ -z "$mysql_config" ]; then +- mysql_config=`echo "$0" | sed 's,/[^/][^/]*$,/mysql_config,'` +- if [ ! -x "$mysql_config" ]; then +- log_error "Can not run mysql_config $@ from '$mysql_config'" +- exit 1 +- fi +- fi +- +- "$mysql_config" "$@" +-} +- +- + # set_malloc_lib LIB + # - If LIB is empty, do nothing and return +-# - If LIB is 'tcmalloc', look for tcmalloc shared library in /usr/lib +-# then pkglibdir. tcmalloc is part of the Google perftools project. ++# - If LIB is 'tcmalloc', look for tcmalloc shared library in $malloc_dirs. ++# tcmalloc is part of the Google perftools project. + # - If LIB is an absolute path, assume it is a malloc shared library + # + # Put LIB in mysqld_ld_preload, which will be added to LD_PRELOAD when + # running mysqld. See ld.so for details. + set_malloc_lib() { ++ # This list is kept intentionally simple. ++ malloc_dirs="/usr/lib /usr/lib64 /usr/lib/i386-linux-gnu /usr/lib/x86_64-linux-gnu" + malloc_lib="$1" + + if [ "$malloc_lib" = tcmalloc ]; then + pkglibdir=`get_mysql_config --variable=pkglibdir` + malloc_lib= +- # This list is kept intentionally simple. Simply set --malloc-lib +- # to a full path if another location is desired. +- for libdir in /usr/lib "$pkglibdir" "$pkglibdir/mysql"; do ++ for libdir in `echo $malloc_dirs`; do + for flavor in _minimal '' _and_profiler _debug; do + tmp="$libdir/libtcmalloc$flavor.so" + #log_notice "DEBUG: Checking for malloc lib '$tmp'" +@@ -418,7 +413,7 @@ + done + + if [ -z "$malloc_lib" ]; then +- log_error "no shared library for --malloc-lib=tcmalloc found in /usr/lib or $pkglibdir" ++ log_error "no shared library for --malloc-lib=tcmalloc found in $malloc_dirs" + exit 1 + fi + fi +@@ -429,9 +424,21 @@ + case "$malloc_lib" in + /*) + if [ ! -r "$malloc_lib" ]; then +- log_error "--malloc-lib '$malloc_lib' can not be read and will not be used" ++ log_error "--malloc-lib can not be read and will not be used" + exit 1 + fi ++ ++ # Restrict to a the list in $malloc_dirs above ++ case "`dirname "$malloc_lib"`" in ++ /usr/lib) ;; ++ /usr/lib64) ;; ++ /usr/lib/i386-linux-gnu) ;; ++ /usr/lib/x86_64-linux-gnu) ;; ++ *) ++ log_error "--malloc-lib must be located in one of the directories: $malloc_dirs" ++ exit 1 ++ ;; ++ esac + ;; + *) + log_error "--malloc-lib must be an absolute path or 'tcmalloc'; " \ +@@ -647,7 +654,7 @@ + log_notice "Logging to '$err_log'." + logging=file + +- if [ ! -f "$err_log" ]; then # if error log already exists, ++ if [ ! -f "$err_log" -a ! -h "$err_log" ]; then # if error log already exists, + touch "$err_log" # we just append. otherwise, + chmod "$fmode" "$err_log" # fix the permissions here! + fi +@@ -672,7 +679,7 @@ + USER_OPTION="--user=$user" + fi + # Change the err log to the right user, if it is in use +- if [ $want_syslog -eq 0 ]; then ++ if [ $want_syslog -eq 0 -a ! -h "$err_log" ]; then + touch "$err_log" + chown $user "$err_log" + fi +@@ -692,9 +699,11 @@ + mysql_unix_port_dir=`dirname $safe_mysql_unix_port` + if [ ! -d $mysql_unix_port_dir ] + then +- mkdir $mysql_unix_port_dir +- chown $user $mysql_unix_port_dir +- chmod 755 $mysql_unix_port_dir ++ if [ ! -h $mysql_unix_port_dir ]; then ++ mkdir $mysql_unix_port_dir ++ chown $user $mysql_unix_port_dir ++ chmod 755 $mysql_unix_port_dir ++ fi + fi + + # If the user doesn't specify a binary, we assume name "mysqld" +@@ -806,7 +815,9 @@ + exit 1 + fi + fi +- rm -f "$pid_file" ++ if [ ! -h "$pid_file" ]; then ++ rm -f "$pid_file" ++ fi + if test -f "$pid_file" + then + log_error "Fatal error: Can't remove the pid file: +@@ -861,7 +872,13 @@ + + while true + do +- rm -f $safe_mysql_unix_port "$pid_file" # Some extra safety ++ # Some extra safety ++ if [ ! -h "$safe_mysql_unix_port" ]; then ++ rm -f "$safe_mysql_unix_port" ++ fi ++ if [ ! -h "$pid_file" ]; then ++ rm -f "$pid_file" ++ fi + + start_time=`date +%M%S` + +@@ -879,7 +896,7 @@ + eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url $nohup_redir" + fi + +- if [ $want_syslog -eq 0 -a ! -f "$err_log" ]; then ++ if [ $want_syslog -eq 0 -a ! -f "$err_log" -a ! -h "$err_log" ]; then + touch "$err_log" # hypothetical: log was renamed but not + chown $user "$err_log" # flushed yet. we'd recreate it with + chmod "$fmode" "$err_log" # wrong owner next time we log, so set +--- a/sql/log.cc ++++ b/sql/log.cc +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. ++/* Copyright (c) 2000, 2016, 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 +@@ -1496,6 +1496,78 @@ + } + + ++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 log_file_key Key for P_S instrumentation. ++ @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, ++#ifdef HAVE_PSI_INTERFACE ++ PSI_file_key log_file_key, ++#endif ++ 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) mysql_file_close(file, MYF(0)); ++ return -1; ++ } ++ ++ if (mysql_file_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 mysql_file_open(log_file_key, real_file_name, ++ open_flags | O_NOFOLLOW, ++ MYF(MY_WME | ME_WAITTANG)); ++} ++#endif // _WIN32 ++ ++ + /* + Open a (new) log file. + +@@ -1566,6 +1638,18 @@ + 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, ++#ifdef HAVE_PSI_INTERFACE ++ log_file_key, ++#endif ++ open_flags, ++ log_file_name)) < 0) ++ goto err; ++#endif // _WIN32 ++ + if ((pos= mysql_file_tell(file, MYF(MY_WME))) == MY_FILEPOS_ERROR) + { + if (my_errno == ESPIPE) +--- a/sql/log.h ++++ b/sql/log.h +@@ -610,6 +610,16 @@ + + char *make_log_name(char *buff, const char *name, const char* log_ext); + ++/** ++ 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); ++ + extern LOGGER logger; + + #endif /* LOG_H */ +--- a/sql/mysqld.cc ++++ b/sql/mysqld.cc +@@ -4225,11 +4225,22 @@ + "--general-log-file option, log tables are used. " + "To enable logging to files use the --log-output=file option."); + +- if (opt_slow_log && opt_slow_logname && !(log_output_options & LOG_FILE) +- && !(log_output_options & LOG_NONE)) +- sql_print_warning("Although a path was specified for the " +- "--slow-query-log-file 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; ++ } ++ + + if (!opt_logname || !*opt_logname) + opt_logname= make_default_log_name(logname_path, ".log"); +--- a/sql/sys_vars.cc ++++ b/sql/sys_vars.cc +@@ -3686,6 +3686,14 @@ + if (!var->save_result.string_value.str) + return true; + ++ if (!is_valid_log_name(var->save_result.string_value.str, ++ var->save_result.string_value.length)) ++ { ++ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), ++ self->name.str, var->save_result.string_value.str); ++ return true; ++ } ++ + if (var->save_result.string_value.length > FN_REFLEN) + { // path is too long + my_error(ER_PATH_LENGTH, MYF(0), self->name.str); +@@ -3732,7 +3740,7 @@ + return false; + } + static bool fix_log(char** logname, const char* default_logname, +- const char*ext, bool enabled, void (*reopen)(char*)) ++ const char*ext, bool enabled, bool (*reopen)(char*)) + { + if (!*logname) // SET ... = DEFAULT + { +@@ -3744,16 +3752,17 @@ + } + logger.lock_exclusive(); + mysql_mutex_unlock(&LOCK_global_system_variables); ++ bool error= false; + if (enabled) +- reopen(*logname); ++ error= reopen(*logname); + logger.unlock(); + mysql_mutex_lock(&LOCK_global_system_variables); +- return false; ++ return error; + } +-static void reopen_general_log(char* name) ++static bool reopen_general_log(char* name) + { + logger.get_log_file_handler()->close(0); +- logger.get_log_file_handler()->open_query_log(name); ++ return logger.get_log_file_handler()->open_query_log(name); + } + static bool fix_general_log_file(sys_var *self, THD *thd, enum_var_type type) + { +@@ -3766,10 +3775,10 @@ + IN_FS_CHARSET, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(check_log_path), ON_UPDATE(fix_general_log_file)); + +-static void reopen_slow_log(char* name) ++static bool reopen_slow_log(char* name) + { + logger.get_slow_log_file_handler()->close(0); +- logger.get_slow_log_file_handler()->open_slow_log(name); ++ return logger.get_slow_log_file_handler()->open_slow_log(name); + } + static bool fix_slow_log_file(sys_var *self, THD *thd, enum_var_type type) + { +--- a/support-files/mysql.server.sh ++++ b/support-files/mysql.server.sh +@@ -255,11 +255,6 @@ + if test -r "$basedir/my.cnf" + then + extra_args="-e $basedir/my.cnf" +-else +- if test -r "$datadir/my.cnf" +- then +- extra_args="-e $datadir/my.cnf" +- fi + fi + + parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server` +@@ -289,7 +284,7 @@ + then + # Give extra arguments to mysqld with the my.cnf file. This script + # may be overwritten at next upgrade. +- $bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 & ++ $bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null & + wait_for_pid created "$!" "$mysqld_pid_file_path"; return_value=$? + + # Make lock for RedHat / SuSE diff --git a/debian/patches/series b/debian/patches/series index c92237ff..164bca36 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -3,3 +3,4 @@ scripts__mysqld_safe.sh__signals.patch fix_standalone_tests.patch kfreebsd_tests.patch fix-mysqlhotcopy-test-failure.patch +debian_patches_CVE-2016-6662.patch