From 1a95ed1df2bdd26444a973e07ffd84c045deb734 Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Mon, 26 Nov 2007 08:20:40 +0100 Subject: [PATCH] Bug#31752: check strmake() bounds strmake() calls are easy to get wrong. Add checks in extra debug mode to identify possible exploits. Remove some dead code. Remove some off-by-one errors identified with new checks. --- sql/log.cc | 2 +- sql/repl_failsafe.cc | 2 +- sql/set_var.cc | 2 +- sql/sql_show.cc | 4 ++-- sql/unireg.cc | 3 +++ strings/strmake.c | 32 +++++++++++++++++--------------- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index b91ec2b3dee..5a4f02a827b 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -966,7 +966,7 @@ void MYSQL_LOG::make_log_name(char* buf, const char* log_ident) if (dir_len > FN_REFLEN) dir_len=FN_REFLEN-1; strnmov(buf, log_file_name, dir_len); - strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len); + strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len -1); } diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 4c8703226a6..4ea90346638 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -926,7 +926,7 @@ int load_master_data(THD* thd) 0, (SLAVE_IO | SLAVE_SQL))) send_error(thd, ER_MASTER_INFO); strmake(active_mi->master_log_name, row[0], - sizeof(active_mi->master_log_name)); + sizeof(active_mi->master_log_name) -1); active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error); /* at least in recent versions, the condition below should be false */ if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE) diff --git a/sql/set_var.cc b/sql/set_var.cc index 520ee5c9f70..1d18eba30a8 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1573,7 +1573,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) ¬_used)); if (error_len) { - strmake(buff, error, min(sizeof(buff), error_len)); + strmake(buff, error, min(sizeof(buff) - 1, error_len)); goto err; } } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bf0e254d3e4..be658c8fe5d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -136,7 +136,7 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) { Item_string *field=new Item_string("",0,thd->charset()); List field_list; - char path[FN_LEN],*end; + char path[FN_REFLEN],*end; List files; char *file_name; Protocol *protocol= thd->protocol; @@ -457,7 +457,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) Item *item; List files; List field_list; - char path[FN_LEN]; + char path[FN_REFLEN]; char *file_name; TABLE *table; Protocol *protocol= thd->protocol; diff --git a/sql/unireg.cc b/sql/unireg.cc index e5ee0222f20..795198fc55f 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -140,6 +140,9 @@ bool mysql_create_frm(THD *thd, my_string file_name, strmake((char*) forminfo+47,create_info->comment ? create_info->comment : "", 60); forminfo[46]=(uchar) strlen((char*)forminfo+47); // Length of comment +#ifdef EXTRA_DEBUG + memset((char*) forminfo+47 + forminfo[46], 0, 61 - forminfo[46]); +#endif if (my_pwrite(file,(byte*) fileinfo,64,0L,MYF_RW) || my_pwrite(file,(byte*) keybuff,key_info_length, diff --git a/strings/strmake.c b/strings/strmake.c index d2252f648f6..47d8a04e361 100644 --- a/strings/strmake.c +++ b/strings/strmake.c @@ -28,23 +28,25 @@ #include #include "m_string.h" -#ifdef BAD_STRING_COMPILER - -char *strmake(char *dst,const char *src,uint length) -{ - reg1 char *res; - - if ((res=memccpy(dst,src,0,length))) - return res-1; - dst[length]=0; - return dst+length; -} - -#define strmake strmake_overlapp /* Use orginal for overlapping str */ -#endif - char *strmake(register char *dst, register const char *src, uint length) { +#ifdef EXTRA_DEBUG + /* + 'length' is the maximum length of the string; the buffer needs + to be one character larger to accomodate the terminating '\0'. + This is easy to get wrong, so we make sure we write to the + entire length of the buffer to identify incorrect buffer-sizes. + We only initialise the "unused" part of the buffer here, a) for + efficiency, and b) because dst==src is allowed, so initialising + the entire buffer would overwrite the source-string. Also, we + write a character rather than '\0' as this makes spotting these + problems in the results easier. + */ + uint n= strlen(src) + 1; + if (n <= length) + memset(dst + n, (int) 'Z', length - n + 1); +#endif + while (length--) if (! (*dst++ = *src++)) return dst-1;