Below is the list of changes that have just been committed into a local
5.1 repository of andrey. When andrey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-12-17 17:51:22+01:00, andrey@stripped +6 -0
Fix for bug#29605
(--local-infile=0 checks can be bypassed by sending a FETCH LOCAL FILE response)
The query sent to the server is checked whether it's a LOAD DATA LOCAL INFILE in case
the server sends a request to the client to send a local file.
BitKeeper/etc/ignore@stripped, 2007-12-17 17:51:20+01:00, andrey@stripped +2
-0
Added tests/mysql_client_test.c.orig libmysqld/lib_sql.cc.orig to the ignore list
include/mysql.h@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +1 -1
Add additional parameter to the read_query_result hook.
It's needed for checking the validity of a LOAD DATA LOCAL INFILE
response from a server.
libmysql/libmysql.c@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +4 -4
Pass the query to the read_query_result() hook wherever
appropriate. It's not possible for prepared statements.
libmysqld/lib_sql.cc@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +15
-7
emb_read_query_result() was used twice as a hook for
read_query_result of MYSQL_METHODS. Because of the added second
parameter to the hook a new function with old's emb_read_query_result()
signature was added.
In the embedded server scenario we are sure the server is not fake. Thus
the response from LOAD DATA LOCAL INFILE is not inspected.
sql-common/client.c@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +71
-4
If the server sends a request to the client
for sending a file, in case of LOAD DATA LOCAL INFILE,
the client should check that the query is really that one.
If not, the server is a fake and tries to steal user-readable
file from the client.
tests/mysql_client_test.c@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped
+1 -1
Modify the test to compile with the new definition
of MYSQL_METHODS
diff -Nrup a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore
--- a/BitKeeper/etc/ignore 2007-12-13 12:49:43 +01:00
+++ b/BitKeeper/etc/ignore 2007-12-17 17:51:20 +01:00
@@ -3012,3 +3012,5 @@ win/vs8cache.txt
ylwrap
zlib/*.ds?
zlib/*.vcproj
+tests/mysql_client_test.c.orig
+libmysqld/lib_sql.cc.orig
diff -Nrup a/include/mysql.h b/include/mysql.h
--- a/include/mysql.h 2007-11-26 19:09:34 +01:00
+++ b/include/mysql.h 2007-12-17 17:51:19 +01:00
@@ -752,7 +752,7 @@ enum enum_stmt_attr_type
typedef struct st_mysql_methods
{
- my_bool (*read_query_result)(MYSQL *mysql);
+ my_bool (*read_query_result)(MYSQL *mysql, const char *query);
my_bool (*advanced_command)(MYSQL *mysql,
enum enum_server_command command,
const unsigned char *header,
diff -Nrup a/libmysql/libmysql.c b/libmysql/libmysql.c
--- a/libmysql/libmysql.c 2007-12-12 16:20:53 +01:00
+++ b/libmysql/libmysql.c 2007-12-17 17:51:19 +01:00
@@ -342,7 +342,7 @@ my_bool STDCALL mysql_master_query(MYSQL
DBUG_ENTER("mysql_master_query");
if (mysql_master_send_query(mysql, q, length))
DBUG_RETURN(1);
- DBUG_RETURN((*mysql->methods->read_query_result)(mysql));
+ DBUG_RETURN((*mysql->methods->read_query_result)(mysql, q));
}
my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
@@ -365,7 +365,7 @@ my_bool STDCALL mysql_slave_query(MYSQL
DBUG_ENTER("mysql_slave_query");
if (mysql_slave_send_query(mysql, q, length))
DBUG_RETURN(1);
- DBUG_RETURN((*mysql->methods->read_query_result)(mysql));
+ DBUG_RETURN((*mysql->methods->read_query_result)(mysql, q));
}
@@ -2468,7 +2468,7 @@ static my_bool execute(MYSQL_STMT *stmt,
res= test(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
(uchar*) packet, length, 1, NULL) ||
- (*mysql->methods->read_query_result)(mysql));
+ (*mysql->methods->read_query_result)(mysql, NULL));
stmt->affected_rows= mysql->affected_rows;
stmt->server_status= mysql->server_status;
stmt->insert_id= mysql->insert_id;
@@ -5181,6 +5181,6 @@ MYSQL_RES * STDCALL mysql_use_result(MYS
my_bool STDCALL mysql_read_query_result(MYSQL *mysql)
{
- return (*mysql->methods->read_query_result)(mysql);
+ return (*mysql->methods->read_query_result)(mysql, NULL);
}
diff -Nrup a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
--- a/libmysqld/lib_sql.cc 2007-12-14 14:01:09 +01:00
+++ b/libmysqld/lib_sql.cc 2007-12-17 17:51:19 +01:00
@@ -38,7 +38,8 @@ C_MODE_START
#include <sql_common.h>
#include "embedded_priv.h"
-static my_bool emb_read_query_result(MYSQL *mysql);
+static my_bool emb_read_query_result(MYSQL *mysql, const char *query);
+static my_bool emb_next_result(MYSQL *mysql);
/*
@@ -172,7 +173,7 @@ emb_read_rows(MYSQL *mysql, MYSQL_FIELD
static MYSQL_FIELD *emb_list_fields(MYSQL *mysql)
{
MYSQL_DATA *res;
- if (emb_read_query_result(mysql))
+ if (emb_read_query_result(mysql, NULL))
return 0;
res= ((THD*) mysql->thd)->cur_data;
((THD*) mysql->thd)->cur_data= 0;
@@ -194,7 +195,7 @@ static my_bool emb_read_prepare_result(M
if (thd->first_data)
{
- if (emb_read_query_result(mysql))
+ if (emb_read_query_result(mysql, NULL))
return 1;
stmt->field_count= mysql->field_count;
mysql->status= MYSQL_STATUS_READY;
@@ -227,7 +228,14 @@ static void emb_fetch_lengths(ulong *to,
*to= *column ? *(uint *)((*column) - sizeof(uint)) : 0;
}
-static my_bool emb_read_query_result(MYSQL *mysql)
+
+static my_bool emb_next_result(MYSQL *mysql)
+{
+ return emb_read_query_result(mysql, NULL);
+}
+
+
+static my_bool emb_read_query_result(MYSQL *mysql, const char *query)
{
THD *thd= (THD*) mysql->thd;
MYSQL_DATA *res= thd->first_data;
@@ -283,7 +291,7 @@ static int emb_stmt_execute(MYSQL_STMT *
res= test(emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE, 0, 0,
header, sizeof(header), 1, stmt) ||
- emb_read_query_result(stmt->mysql));
+ emb_read_query_result(stmt->mysql, NULL));
stmt->affected_rows= stmt->mysql->affected_rows;
stmt->insert_id= stmt->mysql->insert_id;
stmt->server_status= stmt->mysql->server_status;
@@ -404,7 +412,7 @@ MYSQL_METHODS embedded_methods=
emb_unbuffered_fetch,
emb_free_embedded_thd,
emb_read_statistics,
- emb_read_query_result,
+ emb_next_result,
emb_read_change_user_result,
emb_read_rows_from_cursor
};
@@ -629,7 +637,7 @@ int check_embedded_connection(MYSQL *mys
sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0));
result= check_user(thd, COM_CONNECT, NULL, 0, db, true);
net_end_statement(thd);
- emb_read_query_result(mysql);
+ emb_read_query_result(mysql, NULL);
return result;
}
diff -Nrup a/sql-common/client.c b/sql-common/client.c
--- a/sql-common/client.c 2007-12-12 16:20:56 +01:00
+++ b/sql-common/client.c 2007-12-17 17:51:19 +01:00
@@ -1706,7 +1706,7 @@ static int ssl_verify_server_cert(Vio *v
before calling mysql_real_connect !
*/
-static my_bool cli_read_query_result(MYSQL *mysql);
+static my_bool cli_read_query_result(MYSQL *mysql, const char *query);
static MYSQL_RES *cli_use_result(MYSQL *mysql);
static MYSQL_METHODS client_methods=
@@ -2688,7 +2688,59 @@ void STDCALL mysql_close(MYSQL *mysql)
}
-static my_bool cli_read_query_result(MYSQL *mysql)
+static my_bool is_real_load_data_local(const char *q)
+{
+#define LD_STATE_NORMAL 1
+#define LD_STATE_IN_ML_COM 2
+#define LD_STATE_IN_SL_COM 3
+ int ld_state= LD_STATE_NORMAL;
+ const char *pattern= "LOADDATALOCALINFILE";
+ q--;
+ while (*++q && *pattern) {
+ if (ld_state == LD_STATE_NORMAL)
+ {
+ /*
+ If the current char is not NULL, then the next address
+ will contain either a char or a NULL. Thus, we won't touch
+ memory beyound the string boundaries as the string should be
+ NULL terminated.
+ */
+ if ((*q == '/' && *(q+1) == '*'))
+ {
+ ld_state= LD_STATE_IN_ML_COM;
+ ++q;
+ }
+ else if ((*q == '-' && *(q+1) == '-') || *q == '#')
+ {
+ ld_state = LD_STATE_IN_SL_COM;
+ ++q;
+ }
+ else if (my_charset_latin1.to_upper[(uchar )*q] !=
+ my_charset_latin1.to_lower[(uchar )*q])
+ {
+ if (my_charset_latin1.to_upper[(uchar )*q] != *pattern++)
+ break;
+ }
+ }
+ else
+ {
+ /* \r is not tested as the server doesn't consider it as EOL */
+ if ((ld_state == LD_STATE_IN_ML_COM && *q == '*' && *(q + 1) ==
'/') ||
+ (ld_state == LD_STATE_IN_SL_COM && *q == '\n'))
+ {
+ ld_state= LD_STATE_NORMAL;
+ ++q;
+ }
+ }
+ }
+ return *pattern == '\0';
+#undef LOAD_DATA_STATE_NORMAL
+#undef LD_STATE_IN_ML_COMMENT
+#undef LD_STATE_IN_SL_COMMENT
+}
+
+
+static my_bool cli_read_query_result(MYSQL *mysql, const char *query)
{
uchar *pos;
ulong field_count;
@@ -2736,7 +2788,22 @@ get_info:
#ifdef MYSQL_CLIENT
if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
{
- int error=handle_local_infile(mysql,(char*) pos);
+ int error = 0;
+ if (query && is_real_load_data_local(query) == FALSE) /* Is the server fake
*/
+ {
+ /* Send empty packet to mark end of file */
+ if (my_net_write(&mysql->net, (const uchar*) "", 0) ||
net_flush(&mysql->net))
+ {
+ set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
+ DBUG_RETURN(1);
+ }
+ /* Tell the user that something wrong has happened */
+ set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
+ error = 1;
+ }
+ else
+ error= handle_local_infile(mysql,(char*) pos);
+
if ((length= cli_safe_read(mysql)) == packet_error || error)
DBUG_RETURN(1);
goto get_info; /* Get info packet */
@@ -2798,7 +2865,7 @@ mysql_real_query(MYSQL *mysql, const cha
if (mysql_send_query(mysql,query,length))
DBUG_RETURN(1);
- DBUG_RETURN((int) (*mysql->methods->read_query_result)(mysql));
+ DBUG_RETURN((int) (*mysql->methods->read_query_result)(mysql, query));
}
diff -Nrup a/tests/mysql_client_test.c b/tests/mysql_client_test.c
--- a/tests/mysql_client_test.c 2007-12-13 13:43:36 +01:00
+++ b/tests/mysql_client_test.c 2007-12-17 17:51:19 +01:00
@@ -13556,7 +13556,7 @@ static void test_bug9478()
rc= ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
(uchar*) buff,
sizeof(buff), 0,0,1,NULL) ||
- (*mysql->methods->read_query_result)(mysql));
+ (*mysql->methods->read_query_result)(mysql, NULL));
DIE_UNLESS(rc);
if (!opt_silent && i == 0)
printf("Got error (as expected): %s\n", mysql_error(mysql));
| Thread |
|---|
| • bk commit into 5.1 tree (andrey:1.2647) BUG#29605 | andrey | 17 Dec |