diff -uNr mysql-4.1.14-orig/mysql/include/my_sys.h mysql-4.1.14/mysql/include/my_sys.h --- mysql-4.1.14-orig/mysql/include/my_sys.h 2005-08-17 19:06:34.000000000 +0200 +++ mysql-4.1.14/mysql/include/my_sys.h 2006-04-09 01:10:47.000000000 +0200 @@ -573,6 +573,11 @@ const char *sFile, uint uLine, myf MyFlag); +/* implemented in my_memmem.c */ +extern void *my_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); + + #ifdef __WIN__ extern int my_access(const char *path, int amode); #else diff -uNr mysql-4.1.14-orig/mysql/mysql-test/t/mysql_client_test.opt mysql-4.1.14/mysql/mysql-test/t/mysql_client_test.opt --- mysql-4.1.14-orig/mysql/mysql-test/t/mysql_client_test.opt 1970-01-01 01:00:00.000000000 +0100 +++ mysql-4.1.14/mysql/mysql-test/t/mysql_client_test.opt 2006-04-09 01:20:53.000000000 +0200 @@ -0,0 +1,2 @@ +--log + diff -uNr mysql-4.1.14-orig/mysql/mysys/Makefile.am mysql-4.1.14/mysql/mysys/Makefile.am --- mysql-4.1.14-orig/mysql/mysys/Makefile.am 2005-08-17 19:06:33.000000000 +0200 +++ mysql-4.1.14/mysql/mysys/Makefile.am 2006-04-09 01:11:59.000000000 +0200 @@ -54,7 +54,8 @@ my_net.c my_semaphore.c my_port.c my_sleep.c \ charset.c charset-def.c my_bitmap.c my_bit.c md5.c \ my_gethostbyname.c rijndael.c my_aes.c sha1.c \ - my_handler.c my_netware.c my_windac.c my_access.c + my_handler.c my_netware.c \ + my_memmem.c my_windac.c my_access.c EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ thr_mutex.c thr_rwlock.c libmysys_a_LIBADD = @THREAD_LOBJECTS@ diff -uNr mysql-4.1.14-orig/mysql/mysys/mf_iocache2.c mysql-4.1.14/mysql/mysys/mf_iocache2.c --- mysql-4.1.14-orig/mysql/mysys/mf_iocache2.c 2005-08-17 19:06:28.000000000 +0200 +++ mysql-4.1.14/mysql/mysys/mf_iocache2.c 2006-04-09 01:27:05.000000000 +0200 @@ -245,6 +245,10 @@ uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args) { uint out_length=0; + uint minimum_width; /* as yet unimplemented */ + uint minimum_width_sign; + uint precision; /* as yet unimplemented for anything but %b */ + const char* backtrack; for (; *fmt ; fmt++) { @@ -265,17 +269,53 @@ fmt++; /* Found one '%' */ } + backtrack= fmt; + + minimum_width= 0; + precision= 0; + minimum_width_sign= 1; /* Skip if max size is used (to be compatible with printf) */ - while (my_isdigit(&my_charset_latin1, *fmt) || *fmt == '.' || *fmt == '-') + while (*fmt == '-') { fmt++; minimum_width_sign= -1; } + if (*fmt == '*') { + precision= (int) va_arg(args, int); + fmt++; + } else { + while (my_isdigit(&my_charset_latin1, *fmt)) { + minimum_width=(minimum_width * 10) + (*fmt - '0'); + fmt++; + } + } + minimum_width*= minimum_width_sign; + + if (*fmt == '.') { fmt++; + if (*fmt == '*') { + precision= (int) va_arg(args, int); + fmt++; + } else { + while (my_isdigit(&my_charset_latin1, *fmt)) { + precision=(precision * 10) + (*fmt - '0'); + fmt++; + } + } + } + if (*fmt == 's') /* String parameter */ { reg2 char *par = va_arg(args, char *); uint length = (uint) strlen(par); + /* TODO: implement minimum width and precision */ out_length+=length; if (my_b_write(info, par, length)) goto err; } + else if (*fmt == 'b') /* Sized buffer parameter, only precision makes sense */ + { + reg2 char *par = va_arg(args, char *); + out_length+=precision; + if (my_b_write(info, par, precision)) + goto err; + } else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */ { register int iarg; @@ -313,6 +353,9 @@ if (my_b_write(info, "%", 1)) goto err; out_length++; + if (my_b_write(info, backtrack, fmt-backtrack)) + goto err; + out_length+= fmt-backtrack; } } return out_length; diff -uNr mysql-4.1.14-orig/mysql/mysys/my_memmem.c mysql-4.1.14/mysql/mysys/my_memmem.c --- mysql-4.1.14-orig/mysql/mysys/my_memmem.c 1970-01-01 01:00:00.000000000 +0100 +++ mysql-4.1.14/mysql/mysys/my_memmem.c 2006-04-09 01:22:05.000000000 +0200 @@ -0,0 +1,23 @@ +#include "my_base.h" + +/* + my_memmem, port of a GNU extension. + + Returns a pointer to the beginning of the substring, needle, or NULL if the + substring is not found in haystack. +*/ +void *my_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen) +{ + const void *cursor; + const void *end_of_search_beginning = haystack + haystacklen - needlelen; + + for (cursor = haystack; cursor <= end_of_search_beginning; cursor++) { + if (memcmp(needle, cursor, needlelen) == 0) { + return((void *) cursor); + } + } + return(NULL); +} + + diff -uNr mysql-4.1.14-orig/mysql/sql/sql_parse.cc mysql-4.1.14/mysql/sql/sql_parse.cc --- mysql-4.1.14-orig/mysql/sql/sql_parse.cc 2005-08-17 19:06:28.000000000 +0200 +++ mysql-4.1.14/mysql/sql/sql_parse.cc 2006-04-09 01:19:16.000000000 +0200 @@ -1495,7 +1495,7 @@ if (alloc_query(thd, packet, packet_length)) break; // fatal error is set char *packet_end= thd->query + thd->query_length; - mysql_log.write(thd,command,"%s",thd->query); + mysql_log.write(thd,command, "%.*b", thd->query_length, thd->query); DBUG_PRINT("query",("%-.4096s",thd->query)); mysql_parse(thd,thd->query, thd->query_length); diff -uNr mysql-4.1.14-orig/mysql/strings/my_vsnprintf.c mysql-4.1.14/mysql/strings/my_vsnprintf.c --- mysql-4.1.14-orig/mysql/strings/my_vsnprintf.c 2005-08-17 19:06:28.000000000 +0200 +++ mysql-4.1.14/mysql/strings/my_vsnprintf.c 2006-04-09 01:17:49.000000000 +0200 @@ -27,6 +27,7 @@ %#[l]d %#[l]u %#[l]x + %#.#b Local format; note first # is ignored and second is REQUIRED %#.#s Note first # is ignored RETURN @@ -38,9 +39,18 @@ char *start=to, *end=to+n-1; uint length, width, pre_zero, have_long; + const char *backtrack; + /* + For the special case when we discover that we shouldn't have been + interpreting a percent-format. + + This is here so we can be forgiving about our special local formats. + */ + for (; *fmt ; fmt++) { - if (fmt[0] != '%') + backtrack = fmt; + if (*fmt != '%') { if (to == end) /* End of buffer */ break; @@ -80,6 +90,12 @@ to=strnmov(to,par,plen); continue; } + else if (*fmt == 'b') /* Buffer parameter */ + { + reg2 char *par = va_arg(ap, char *); + to=memmove(to, par, abs(width)); + continue; + } else if (*fmt == 'd' || *fmt == 'u'|| *fmt== 'x') /* Integer parameter */ { register long larg; diff -uNr mysql-4.1.14-orig/mysql/tests/Makefile.am mysql-4.1.14/mysql/tests/Makefile.am --- mysql-4.1.14-orig/mysql/tests/Makefile.am 2005-08-17 19:06:30.000000000 +0200 +++ mysql-4.1.14/mysql/tests/Makefile.am 2006-04-09 01:19:58.000000000 +0200 @@ -36,7 +36,7 @@ $(openssl_includes) LIBS = @CLIENT_LIBS@ LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysql/libmysqlclient.la -mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) +mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) -lmysys -L../mysys mysql_client_test_SOURCES= mysql_client_test.c insert_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) select_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) diff -uNr mysql-4.1.14-orig/mysql/tests/mysql_client_test.c mysql-4.1.14/mysql/tests/mysql_client_test.c --- mysql-4.1.14-orig/mysql/tests/mysql_client_test.c 2005-08-17 19:06:41.000000000 +0200 +++ mysql-4.1.14/mysql/tests/mysql_client_test.c 2006-04-09 01:30:40.000000000 +0200 @@ -11797,6 +11797,81 @@ } /* + Bug#17667: An attacker has the opportunity to bypass query logging. +*/ +static void test_bug17667() +{ + int rc; + myheader("test_bug17667"); + struct buffer_and_length { + const char *buffer; + const uint length; + } statements[]= { + { "drop table if exists bug17667", 29 }, + { "create table bug17667 (c varchar(20))", 37 }, + { "insert into bug17667 (c) values ('regular') /* NUL=\0 with comment */", 68 }, + { "insert into bug17667 (c) values ('NUL=\0 in value')", 50 }, + { "insert into bug17667 (c) values ('5 NULs=\0\0\0\0\0')", 48 }, + { "/* NUL=\0 with comment */ insert into bug17667 (c) values ('encore')", 67 }, + { "drop table bug17667", 19 }, + { NULL, 0 } }; + /* + Note that at this time, the docs say that NUL characters in string literals + are illegal. If we ever begin to disallow them, then this test will + fail. Note that NULs in comments is a seperate issue, which might still be + legal. + */ + + struct buffer_and_length *statement_cursor; + FILE *log_file; + + for (statement_cursor= statements; statement_cursor->buffer != NULL; + statement_cursor++) { + rc= mysql_real_query(mysql, statement_cursor->buffer, + statement_cursor->length); + myquery(rc); + } + + sleep(1); /* The server may need time to flush the data to the log. */ + log_file= fopen("var/log/master.log", "r"); + DIE_UNLESS(log_file != NULL); + if (log_file != NULL) { + + for (statement_cursor= statements; statement_cursor->buffer != NULL; + statement_cursor++) { + char line_buffer[MAX_TEST_QUERY_LENGTH*2]; + /* more than enough room for the query and some marginalia. */ + + do { + memset(line_buffer, '/', MAX_TEST_QUERY_LENGTH*2); + + DIE_UNLESS(fgets(line_buffer, MAX_TEST_QUERY_LENGTH*2, log_file) != + NULL); + /* If we reach EOF before finishing the statement list, then we failed. */ + + } while (my_memmem(line_buffer, MAX_TEST_QUERY_LENGTH*2, + statement_cursor->buffer, statement_cursor->length) == NULL); + } + + printf("success. All queries found intact in the log.\n"); + + } else { + fprintf(stderr, "Could not find the log file, var/log/master.log, so " + "test_bug17667 is \ninconclusive. Run test from the " + "mysql-test/mysql-test-run* program \nto set up the correct " + "environment for this test.\n\n"); + } + + if (log_file != NULL) + fclose(log_file); + +} + + + + + +/* Read and parse arguments and MySQL options from my.cnf */ @@ -12013,6 +12088,7 @@ { "test_bug9735", test_bug9735 }, { "test_bug11183", test_bug11183 }, { "test_bug12001", test_bug12001 }, + { "test_bug17667", test_bug17667 }, { 0, 0 } };