Index: driver/catalog.c =================================================================== --- driver/catalog.c (revision 1110) +++ driver/catalog.c (working copy) @@ -46,6 +46,7 @@ #define valid_input_parameter(A) ((A) && A[0]) #define escape_input_parameter(A,B) if (B && B[0]) myodbc_remove_escape(A,B) +#define NAME_BUFFER_SIZE NAME_LEN + 1 /* @type : internal @purpose : returns the next token @@ -76,19 +77,48 @@ /* @type : internal @purpose : gets valid input buffer + + Bug#36275: added maxBuf parameter and verification, and memory allocation if + "to" is NULL. In this case maxBuf ignored. + User is responsible to release allocated in this function (better w/ help of + myodbc_release_buffer) */ -static char *myodbc_get_valid_buffer(char *to, SQLCHAR *from, int length) +static char *myodbc_get_valid_buffer(char *to, SQLCHAR *from, int length, unsigned int maxBuf) { if ( !from ) - return "\0"; - if ( length == SQL_NTS ) - length= strlen( (char *)from ); + { + from= "\0"; + /* Just in case non-zero length w/ NULL pointer... */ + length= 0; + } + else if ( length == SQL_NTS ) + length= strlen( (char *)from ); + + if (to == NULL) + to= my_malloc(length+1, MYF(MY_ZEROFILL)); + else if (maxBuf > 0U) + length= min((int)(maxBuf-1),length); + strmake( to, (char *)from, length ); return to; } /* + Just pair function to release buffer if it was alocated in myodbc_get_valid_buffer +*/ +static void myodbc_release_buffers( char **str[]) +{ + int i; + for (i= 0;str[i]; ++i) + { + if (*str[i]) + my_free(*str[i], MYF(0)); + } + +} + +/* @type : internal @purpose : appends wild card to the query */ @@ -350,24 +380,28 @@ SQLCHAR FAR *szTableType, SQLSMALLINT cbTableType) { - char Qualifier_buff[NAME_LEN+1], - Owner_buff[NAME_LEN+1], - Name_buff[NAME_LEN+1], - Type_buff[NAME_LEN+1], - *TableQualifier, - *TableOwner, - *TableName, - *TableType; + char *TableQualifier= NULL, + *TableOwner= NULL, + *TableName= NULL, + *TableType= NULL, + **alocedBuffers[]= {&TableQualifier, &TableOwner, &TableName, &TableType, NULL}; STMT FAR *stmt= (STMT FAR*) hstmt; my_bool all_dbs= 1, user_tables, views; CLEAR_STMT_ERROR(hstmt); my_SQLFreeStmt(hstmt,MYSQL_RESET); - TableQualifier= myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier, cbTableQualifier ); - TableOwner= myodbc_get_valid_buffer( Owner_buff, szTableOwner, cbTableOwner ); - TableName= myodbc_get_valid_buffer( Name_buff, szTableName, cbTableName ); + TableQualifier= myodbc_get_valid_buffer( NULL, szTableQualifier, cbTableQualifier, 0 ); + TableOwner= myodbc_get_valid_buffer( NULL, szTableOwner, cbTableOwner, 0 ); + TableName= myodbc_get_valid_buffer( NULL, szTableName, cbTableName, 0 ); + if (!(TableQualifier && TableOwner && TableName)) + { + set_mem_error(&stmt->dbc->mysql); + myodbc_release_buffers(alocedBuffers); + return SQL_ERROR; + } + escape_input_parameter(&stmt->dbc->mysql, TableQualifier); escape_input_parameter(&stmt->dbc->mysql, TableOwner); escape_input_parameter(&stmt->dbc->mysql, TableName); @@ -386,6 +420,7 @@ if (!stmt->result) { + myodbc_release_buffers(alocedBuffers); return handle_connection_error(stmt); } @@ -397,6 +432,7 @@ MYF(0)); if (!stmt->array) { + myodbc_release_buffers(alocedBuffers); set_mem_error(&stmt->dbc->mysql); return handle_connection_error(stmt); } @@ -409,18 +445,27 @@ !TableName[0] ) { /* Return set of allowed Table owners */ + myodbc_release_buffers(alocedBuffers); return create_fake_resultset(stmt, SQLTABLES_owner_values, sizeof(SQLTABLES_owner_values), 1, SQLTABLES_fields, SQLTABLES_FIELDS); } - TableType= myodbc_get_valid_buffer( Type_buff, szTableType, cbTableType ); + TableType= myodbc_get_valid_buffer( NULL, szTableType, cbTableType, 0 ); + if (TableType == NULL) + { + myodbc_release_buffers(alocedBuffers); + set_mem_error(&stmt->dbc->mysql); + return SQL_ERROR; + } + if ( !TableQualifier[0] && !TableOwner[0] && !TableName[0] && (!strcmp(TableType,"%") || !myodbc_casecmp(TableType,"SQL_ALL_TABLE_TYPES",19)) ) { /* Return set of TableType qualifiers */ + myodbc_release_buffers(alocedBuffers); return create_fake_resultset(stmt, (MYSQL_ROW)SQLTABLES_type_values, sizeof(SQLTABLES_type_values), sizeof(SQLTABLES_type_values) / @@ -468,6 +513,7 @@ default: rc= handle_connection_error(stmt); pthread_mutex_unlock(&stmt->dbc->lock); + myodbc_release_buffers(alocedBuffers); return rc; } } @@ -494,6 +540,7 @@ row_count), MYF(MY_ZEROFILL)))) { + myodbc_release_buffers(alocedBuffers); set_mem_error(&stmt->dbc->mysql); return handle_connection_error(stmt); } @@ -531,9 +578,11 @@ } mysql_link_fields(stmt, SQLTABLES_fields, SQLTABLES_FIELDS); + myodbc_release_buffers(alocedBuffers); return SQL_SUCCESS; empty_set: + myodbc_release_buffers(alocedBuffers); return create_empty_fake_resultset(stmt, SQLTABLES_values, sizeof(SQLTABLES_values), SQLTABLES_fields, @@ -999,12 +1048,13 @@ STMT FAR *stmt= (STMT FAR*) hstmt; MYSQL FAR *mysql= &stmt->dbc->mysql; DBC FAR *dbc= stmt->dbc; - char Qualifier_buff[NAME_LEN+1], - Table_buff[NAME_LEN+1], + char Qualifier_buff[NAME_BUFFER_SIZE],Table_buff[NAME_BUFFER_SIZE], *TableQualifier, *TableName; - TableQualifier= myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier, cbTableQualifier ); - TableName= myodbc_get_valid_buffer( Table_buff, szTableName, cbTableName ); + TableQualifier= myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier + , cbTableQualifier,NAME_BUFFER_SIZE ); + TableName= myodbc_get_valid_buffer( Table_buff, szTableName + , cbTableName, NAME_BUFFER_SIZE ); CLEAR_STMT_ERROR(hstmt); my_SQLFreeStmt(hstmt,MYSQL_RESET); @@ -1166,16 +1216,26 @@ SQLCHAR FAR *szTableName, SQLSMALLINT cbTableName) { - char Qualifier_buff[NAME_LEN+1],Name_buff[NAME_LEN+1], - *TableQualifier,*TableName; + char Qualifier_buff[NAME_BUFFER_SIZE], + *TableQualifier= NULL, + *TableName= NULL, + **alocedBuffers[]= {&TableName, NULL}; char **data, **row; MEM_ROOT *alloc; STMT FAR *stmt= (STMT FAR*) hstmt; uint row_count; - TableQualifier= myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier, cbTableQualifier ); - TableName= myodbc_get_valid_buffer( Name_buff, szTableName, cbTableName ); + TableQualifier= myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier, + cbTableQualifier, NAME_BUFFER_SIZE); + TableName= myodbc_get_valid_buffer( NULL, szTableName, cbTableName, 0); + if (TableName == NULL) + { + set_mem_error(&stmt->dbc->mysql); + myodbc_release_buffers(alocedBuffers); + return SQL_ERROR; + } + escape_input_parameter(&stmt->dbc->mysql, TableQualifier); escape_input_parameter(&stmt->dbc->mysql, TableName); @@ -1188,6 +1248,7 @@ { SQLRETURN rc= handle_connection_error(stmt); pthread_mutex_unlock(&stmt->dbc->lock); + myodbc_release_buffers(alocedBuffers); return rc; } pthread_mutex_unlock(&stmt->dbc->lock); @@ -1200,6 +1261,7 @@ if (!stmt->result_array) { set_mem_error(&stmt->dbc->mysql); + myodbc_release_buffers(alocedBuffers); return handle_connection_error(stmt); } alloc= &stmt->result->field_alloc; @@ -1208,7 +1270,7 @@ while ( (row= mysql_fetch_row(stmt->result)) ) { char *grants= row[4]; - char token[NAME_LEN+1]; + char token[NAME_BUFFER_SIZE]; const char *grant= (const char *)grants; for ( ;; ) @@ -1234,6 +1296,7 @@ } stmt->result->row_count= row_count; mysql_link_fields(stmt,SQLTABLES_priv_fields,SQLTABLES_PRIV_FIELDS); + myodbc_release_buffers(alocedBuffers); return SQL_SUCCESS; } @@ -1315,17 +1378,26 @@ SQLSMALLINT cbColumnName) { STMT FAR *stmt=(STMT FAR*) hstmt; - char Qualifier_buff[NAME_LEN+1],Table_buff[NAME_LEN+1], - Column_buff[NAME_LEN+1], - *TableQualifier,*TableName, *ColumnName; + char Qualifier_buff[NAME_BUFFER_SIZE],Table_buff[NAME_BUFFER_SIZE], + *TableQualifier,*TableName, *ColumnName= NULL, + **alocedBuffers[]={&ColumnName, NULL}; char **row, **data; MEM_ROOT *alloc; uint row_count; - TableQualifier=myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier, cbTableQualifier ); - TableName= myodbc_get_valid_buffer( Table_buff, szTableName, cbTableName ); - ColumnName= myodbc_get_valid_buffer( Column_buff, szColumnName, cbColumnName ); + TableQualifier=myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier, + cbTableQualifier, NAME_BUFFER_SIZE ); + TableName= myodbc_get_valid_buffer( Table_buff, szTableName, cbTableName, + NAME_BUFFER_SIZE); + ColumnName= myodbc_get_valid_buffer( NULL, szColumnName, cbColumnName, 0 ); + if (ColumnName == NULL) + { + set_mem_error(&stmt->dbc->mysql); + myodbc_release_buffers(alocedBuffers); + return SQL_ERROR; + } + escape_input_parameter(&stmt->dbc->mysql, TableQualifier); escape_input_parameter(&stmt->dbc->mysql, TableName); escape_input_parameter(&stmt->dbc->mysql, ColumnName); @@ -1340,6 +1412,7 @@ { SQLRETURN rc= handle_connection_error(stmt); pthread_mutex_unlock(&stmt->dbc->lock); + myodbc_release_buffers(alocedBuffers); return rc; } pthread_mutex_unlock(&stmt->dbc->lock); @@ -1348,6 +1421,7 @@ if (!stmt->result_array) { set_mem_error(&stmt->dbc->mysql); + myodbc_release_buffers(alocedBuffers); return handle_connection_error(stmt); } alloc= &stmt->result->field_alloc; @@ -1356,7 +1430,7 @@ while ( (row= mysql_fetch_row(stmt->result)) ) { char *grants= row[5]; - char token[NAME_LEN+1]; + char token[NAME_BUFFER_SIZE]; const char *grant= (const char *)grants; for ( ;; ) @@ -1383,6 +1457,7 @@ } stmt->result->row_count= row_count; mysql_link_fields(stmt,SQLCOLUMNS_priv_fields,SQLCOLUMNS_PRIV_FIELDS); + myodbc_release_buffers(alocedBuffers); return SQL_SUCCESS; } @@ -1635,15 +1710,17 @@ SQLCHAR FAR *szTableName, SQLSMALLINT cbTableName) { - char Qualifier_buff[NAME_LEN+1],Table_buff[NAME_LEN+1], + char Qualifier_buff[NAME_BUFFER_SIZE],Table_buff[NAME_BUFFER_SIZE], *TableQualifier,*TableName; STMT FAR *stmt= (STMT FAR*) hstmt; MYSQL_ROW row; char **data; uint row_count; - TableQualifier= myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier, cbTableQualifier ); - TableName= myodbc_get_valid_buffer( Table_buff, szTableName, cbTableName ); + TableQualifier= myodbc_get_valid_buffer( Qualifier_buff, szTableQualifier, + cbTableQualifier, NAME_BUFFER_SIZE ); + TableName= myodbc_get_valid_buffer( Table_buff, szTableName, + cbTableName, NAME_BUFFER_SIZE ); escape_input_parameter(&stmt->dbc->mysql, TableQualifier); escape_input_parameter(&stmt->dbc->mysql, TableName); @@ -2163,3 +2240,5 @@ "MySQL server does not provide the requested information", 4000); } + +#undef NAME_BUFFER_SIZE Index: test/my_catalog.c =================================================================== --- test/my_catalog.c (revision 1110) +++ test/my_catalog.c (working copy) @@ -233,6 +233,7 @@ ok_sql(hstmt, "CREATE TABLE test_colprev3(a INT,b INT,c INT, d INT)"); (void)SQLExecDirect(hstmt, (SQLCHAR *)"DROP USER my_colpriv", SQL_NTS); + ok_sql(hstmt, "CREATE USER my_colpriv"); ok_sql(hstmt, "GRANT SELECT(a,b),INSERT(d),UPDATE(c) ON test_colprev1 TO my_colpriv"); ok_sql(hstmt, "GRANT SELECT(c,a),UPDATE(a,b) ON test_colprev3 TO my_colpriv"); @@ -1099,6 +1100,16 @@ */ DECLARE_TEST(t_bug14407) { + /*SQLSMALLINT pCatalog=4, pSchema=4, pTable=8; + + ok_stmt(hstmt, SQLColumns(hstmt, + (SQLCHAR *)"test", ((pCatalog) ? pCatalog : SQL_NTS), + (SQLCHAR *)"test", ((pSchema) ? pSchema : SQL_NTS), + (SQLCHAR *)"bug28841", ((pTable) ? pTable : SQL_NTS), + NULL, + 0)); + //my_print_non_format_result(hSTMS); + myresult(hstmt);*/ SQLCHAR col[10]; SQLSMALLINT nullable; @@ -1204,7 +1215,6 @@ return OK; } - /** Bug #12805: ADO failed to retrieve the length of LONGBLOB columns */ @@ -1269,7 +1279,24 @@ } +/** +Bug #36275: SQLTables buffer overrun +*/ +DECLARE_TEST(t_bug36275) +{ + SQLRETURN rc= 0; + + rc= SQLTables(hstmt, "non_existent", SQL_NTS, + "non_existent", SQL_NTS, + "non_existent", SQL_NTS, + "'TABLE','VIEW','SYNONYM','ALIAS','GLOBAL TEMPORARY',\ + 'LOCAL TEMPORARY'", SQL_NTS); + + return OK; +} + BEGIN_TESTS + ADD_TEST(my_columns_null) ADD_TEST(my_drop_table) ADD_TEST(my_table_dbs) @@ -1295,7 +1322,8 @@ ADD_TEST(t_bug32989) ADD_TEST(t_bug33298) ADD_TEST(t_bug12805) + ADD_TEST(t_bug36275) END_TESTS -RUN_TESTS +RUN_TESTS \ No newline at end of file