Commit a905ac34 authored by unknown's avatar unknown

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:
  fix off-by-one buffer-length argument to prevent stack smashing
sql/repl_failsafe.cc:
  fix off-by-one buffer-length argument to prevent stack smashing
sql/set_var.cc:
  fix off-by-one buffer-length argument to prevent stack smashing
  (already approved, backports #31588)
sql/sql_show.cc:
  misdimensioned buffers: functions further down the callstack
  expect bufsize of FN_REFLEN
sql/unireg.cc:
  When EXTRA_DEBUG is enabled, strmake() will write funny patterns to
  buffers it operates on to identify possibly overflows. This leads to
  badness in mysql_create_frm(), so we explicitly put any unused bytes
  (back) into a defined state. Not a bug-fix, but part of the strmake()
  bug detector.
strings/strmake.c:
  strmake() takes maximum string length rather than buffer-length
  (string length + 1 to accomodate \0 terminator) as argument.
  Since this is easy to get wrong, add extra debug code to identify
  off-by-ones so we can prevent stack smashing.
  
  Alternative "BAD_STRING_COMPILER" removed after checking
  with Monty.
parent 77d786b5
......@@ -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);
}
......
......@@ -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)
......
......@@ -1573,7 +1573,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
&not_used));
if (error_len)
{
strmake(buff, error, min(sizeof(buff), error_len));
strmake(buff, error, min(sizeof(buff) - 1, error_len));
goto err;
}
}
......
......@@ -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<Item> field_list;
char path[FN_LEN],*end;
char path[FN_REFLEN],*end;
List<char> 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<char> files;
List<Item> field_list;
char path[FN_LEN];
char path[FN_REFLEN];
char *file_name;
TABLE *table;
Protocol *protocol= thd->protocol;
......
......@@ -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,
......
......@@ -28,23 +28,25 @@
#include <my_global.h>
#include "m_string.h"
#ifdef BAD_STRING_COMPILER
char *strmake(char *dst,const char *src,uint length)
char *strmake(register char *dst, register 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 */
#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
char *strmake(register char *dst, register const char *src, uint length)
{
while (length--)
if (! (*dst++ = *src++))
return dst-1;
......
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