190 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* Copyright 2020 Google Inc.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|       http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| //#include <stdint.h>
 | |
| //#include <stdlib.h>
 | |
| //#include <stdio.h>
 | |
| //#include <string>
 | |
| //#include <iostream>
 | |
| //#include <mysql.h>
 | |
| //#include <mysql/client_plugin.h>
 | |
| //#include <mysqld_error.h>
 | |
| #include "sql/sql_class.h"
 | |
| #include "sql/protocol_classic.h"
 | |
| #include "sql/conn_handler/channel_info.h"
 | |
| #include "sql/conn_handler/connection_handler.h"
 | |
| #include "sql/conn_handler/connection_handler_manager.h"
 | |
| #include "sql/conn_handler/init_net_server_extension.h"
 | |
| #include "sql/conn_handler/connection_handler_impl.h"
 | |
| #include "sql/mysqld.h"
 | |
| #include "sql/set_var.h"
 | |
| #include "sql/rpl_handler.h"
 | |
| #include "sql/log.h"
 | |
| #include "sql/opt_costconstantcache.h"
 | |
| #include "sql/sql_plugin.h"
 | |
| #include "sql/sql_thd_internal_api.h"
 | |
| #include "sql/mysqld_thd_manager.h"
 | |
| #include "sql/sql_parse.h"
 | |
| #include "mysql/psi/mysql_socket.h"
 | |
| #include "violite.h"
 | |
| #include "util_fuzz.h"
 | |
| #include <stdlib.h>
 | |
| #include <libgen.h>
 | |
| 
 | |
| using namespace std;
 | |
| FILE *logfile = NULL;
 | |
| Connection_handler_manager * chm;
 | |
| extern int mysqld_main(int argc, char **argv);
 | |
| char *filepath = NULL;
 | |
| 
 | |
| extern "C" int LLVMFuzzerInitialize(const int* argc, char*** argv) {
 | |
|     filepath = dirname(strdup((*argv)[0]));
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| // FIXME: Fix this buffer with succesful authenticated connection for mysql 8.21.
 | |
| const uint8_t startConn[] =
 | |
| "\xa6\x00\x00\x01\x85\xa6\xff\x01\x00\x00\x00\x01\x2d\x00\x00\x00" \
 | |
| "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
 | |
| "\x00\x00\x00\x00\x72\x6f\x6f\x74\x00\x01\x00\x6d\x79\x73\x71\x6c" \
 | |
| "\x5f\x63\x6c\x65\x61\x72\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00" \
 | |
| "\x69\x04\x5f\x70\x69\x64\x05\x35\x34\x30\x30\x31\x03\x5f\x6f\x73" \
 | |
| "\x08\x6f\x73\x78\x31\x30\x2e\x31\x33\x09\x5f\x70\x6c\x61\x74\x66" \
 | |
| "\x6f\x72\x6d\x06\x78\x38\x36\x5f\x36\x34\x0f\x5f\x63\x6c\x69\x65" \
 | |
| "\x6e\x74\x5f\x76\x65\x72\x73\x69\x6f\x6e\x06\x38\x2e\x30\x2e\x31" \
 | |
| "\x36\x0c\x5f\x63\x6c\x69\x65\x6e\x74\x5f\x6e\x61\x6d\x65\x08\x6c" \
 | |
| "\x69\x62\x6d\x79\x73\x71\x6c\x0c\x70\x72\x6f\x67\x72\x61\x6d\x5f" \
 | |
| "\x6e\x61\x6d\x65\x05\x6d\x79\x73\x71\x6c"
 | |
| "\x00\x00\x00\x03"
 | |
| ;
 | |
| 
 | |
| 
 | |
| class Channel_info_fuzz : public Channel_info {
 | |
|     bool m_is_admin_conn;
 | |
| 
 | |
|     protected:
 | |
|     virtual Vio *create_and_init_vio() const {
 | |
|         Vio *vio = vio_new(0, VIO_TYPE_FUZZ, VIO_LOCALHOST);
 | |
|         return vio;
 | |
|     }
 | |
| 
 | |
|     public:
 | |
|     Channel_info_fuzz(bool is_admin_conn) : m_is_admin_conn(is_admin_conn) {}
 | |
| 
 | |
|     virtual THD *create_thd() {
 | |
|         Vio *vio_tmp = create_and_init_vio();
 | |
|         if (vio_tmp == NULL) return NULL;
 | |
| 
 | |
|         THD *thd = new (std::nothrow) THD();
 | |
|         if (thd == NULL) {
 | |
|             vio_delete(vio_tmp);
 | |
|             return NULL;
 | |
|         }
 | |
|         thd->get_protocol_classic()->init_net(vio_tmp);
 | |
|         thd->set_admin_connection(m_is_admin_conn);
 | |
|         init_net_server_extension(thd);
 | |
|         return thd;
 | |
|     }
 | |
| 
 | |
|     virtual bool is_admin_connection() const { return m_is_admin_conn; }
 | |
| };
 | |
| 
 | |
| #define MAX_SIZE 256
 | |
| 
 | |
| 
 | |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
 | |
|     if (Size < 1) {
 | |
|         return 0;
 | |
|     }
 | |
|     if (logfile == NULL) {
 | |
|         my_progname = "fuzz_docommand";
 | |
|         /* first init was run with
 | |
|          * mysqld --user=root --initialize-insecure --log-error-verbosity=5 --datadir=/out/mysql/data/ --basedir=/out/mysql/
 | |
|          */
 | |
|         utilfuzz_rmrf("/tmp/mysql_docommand");
 | |
|         char command[MAX_SIZE];
 | |
|         char argbase[MAX_SIZE];
 | |
|         char arginitfile[MAX_SIZE];
 | |
|         snprintf(command, MAX_SIZE-1, "%s/mysql/data", filepath);
 | |
|         utilfuzz_cpr(command, "/tmp/mysql_docommand");
 | |
| 
 | |
|         snprintf(argbase, MAX_SIZE-1, "--basedir=%s/mysql/", filepath);
 | |
|         snprintf(arginitfile, MAX_SIZE-1, "--init-file=%s/initnopw.sql", filepath);
 | |
| 
 | |
|         char *fakeargv[] = {const_cast<char *>("fuzz_docommand"),
 | |
|             const_cast<char *>("--user=root"),
 | |
|             const_cast<char *>("--secure-file-priv=NULL"),
 | |
|             const_cast<char *>("--log-error-verbosity=5"),
 | |
|             const_cast<char *>("--explicit_defaults_for_timestamp"),
 | |
|             //we should adapt vio_fuzz to give a socket to openssl in order to support ssl
 | |
|             const_cast<char *>("--skip-ssl"),
 | |
|             const_cast<char *>("--mysqlx=0"),
 | |
|             const_cast<char *>("--event-scheduler=DISABLED"),
 | |
|             const_cast<char *>("--performance_schema=OFF"),
 | |
|             const_cast<char *>("--thread_stack=1048576"),
 | |
|             const_cast<char *>("--datadir=/tmp/mysql_docommand/"),
 | |
|             const_cast<char *>("--port=3301"),
 | |
|             const_cast<char *>("--socket=/tmp/docommand.sock"),
 | |
|             const_cast<char *>(argbase),
 | |
|             const_cast<char *>(arginitfile),
 | |
|             0};
 | |
|         int fakeargc = 15;
 | |
|         mysqld_main(fakeargc, fakeargv);
 | |
| 
 | |
|         chm = Connection_handler_manager::get_instance();
 | |
|         logfile = fopen("/dev/null", "w");
 | |
|     }
 | |
|     Channel_info_fuzz * channel_info = new (std::nothrow) Channel_info_fuzz(true);
 | |
|     sock_initfuzz(startConn,sizeof(startConn));
 | |
|     if (my_thread_init()) {
 | |
|         channel_info->send_error_and_close_channel(ER_OUT_OF_RESOURCES, 0, false);
 | |
|         abort();
 | |
|     }
 | |
| 
 | |
|     THD *thd_fuzz = channel_info->create_thd();
 | |
|     if (thd_fuzz == NULL) {
 | |
|         channel_info->send_error_and_close_channel(ER_OUT_OF_RESOURCES, 0, false);
 | |
|         abort();
 | |
|     }
 | |
| 
 | |
|     thd_fuzz->set_new_thread_id();
 | |
|     thd_set_thread_stack(thd_fuzz, (char *)&thd_fuzz);
 | |
|     thd_fuzz->store_globals();
 | |
|     mysql_thread_set_psi_id(thd_fuzz->thread_id());
 | |
|     mysql_socket_set_thread_owner(
 | |
|                                   thd_fuzz->get_protocol_classic()->get_vio()->mysql_socket);
 | |
|     Global_THD_manager *thd_manager = Global_THD_manager::get_instance();
 | |
|     thd_manager->add_thd(thd_fuzz);
 | |
|     if (thd_prepare_connection(thd_fuzz)) {
 | |
|         abort();
 | |
|     }
 | |
|     delete channel_info;
 | |
| 
 | |
|     // The fuzzing takes place on network data received from client
 | |
|     sock_initfuzz(Data,Size);
 | |
| 
 | |
|     while (thd_connection_alive(thd_fuzz)) {
 | |
|         if (do_command(thd_fuzz)) break;
 | |
|     }
 | |
|     end_connection(thd_fuzz);
 | |
|     close_connection(thd_fuzz, 0, false, false);
 | |
|     thd_fuzz->release_resources();
 | |
|     thd_manager->remove_thd(thd_fuzz);
 | |
|     delete thd_fuzz;
 | |
| 
 | |
|     return 0;
 | |
| }
 |