1 //#include <stdint.h>
2 //#include <stdlib.h>
3 //#include <stdio.h>
4 //#include <string>
5 //#include <iostream>
6 //#include <mysql.h>
7 //#include <mysql/client_plugin.h>
8 //#include <mysqld_error.h>
9 #include "sql/sql_class.h"
10 #include "sql/protocol_classic.h"
11 #include "sql/conn_handler/channel_info.h"
12 #include "sql/conn_handler/connection_handler.h"
13 #include "sql/conn_handler/connection_handler_manager.h"
14 #include "sql/conn_handler/init_net_server_extension.h"
15 #include "sql/conn_handler/connection_handler_impl.h"
16 #include "sql/mysqld.h"
17 #include "sql/set_var.h"
18 #include "sql/rpl_handler.h"
19 #include "sql/log.h"
20 #include "sql/opt_costconstantcache.h"
21 #include "sql/sql_plugin.h"
22 #include "sql/sql_thd_internal_api.h"
23 #include "sql/mysqld_thd_manager.h"
24 #include "mysql/psi/mysql_socket.h"
25 #include "violite.h"
26 #include "util_fuzz.h"
27 #include <stdlib.h>
28 #include <libgen.h>
29
30 using namespace std;
31 FILE *logfile = NULL;
32 extern int mysqld_main(int argc, char **argv);
33 char *filepath = NULL;
34
LLVMFuzzerInitialize(const int * argc,char *** argv)35 extern "C" int LLVMFuzzerInitialize(const int* argc, char*** argv) {
36 filepath = dirname(strdup((*argv)[0]));
37 return 0;
38 }
39
40 class Channel_info_fuzz : public Channel_info {
41 bool m_is_admin_conn;
42
43 protected:
create_and_init_vio() const44 virtual Vio *create_and_init_vio() const {
45 Vio *vio = vio_new(0, VIO_TYPE_FUZZ, VIO_LOCALHOST);
46 return vio;
47 }
48
49 public:
Channel_info_fuzz(bool is_admin_conn)50 Channel_info_fuzz(bool is_admin_conn) : m_is_admin_conn(is_admin_conn) {}
51
create_thd()52 virtual THD *create_thd() {
53 Vio *vio_tmp = create_and_init_vio();
54 if (vio_tmp == NULL) return NULL;
55
56 THD *thd = new (std::nothrow) THD();
57 if (thd == NULL) {
58 vio_delete(vio_tmp);
59 return NULL;
60 }
61 thd->get_protocol_classic()->init_net(vio_tmp);
62 thd->set_admin_connection(m_is_admin_conn);
63 init_net_server_extension(thd);
64 return thd;
65 }
66
is_admin_connection() const67 virtual bool is_admin_connection() const { return m_is_admin_conn; }
68 };
69
try_connection(Channel_info * channel_info)70 static void try_connection(Channel_info *channel_info) {
71 if (my_thread_init()) {
72 channel_info->send_error_and_close_channel(ER_OUT_OF_RESOURCES, 0, false);
73 return;
74 }
75
76 THD *thd = channel_info->create_thd();
77 if (thd == NULL) {
78 channel_info->send_error_and_close_channel(ER_OUT_OF_RESOURCES, 0, false);
79 return;
80 }
81
82 thd->set_new_thread_id();
83
84 /*
85 handle_one_connection() is normally the only way a thread would
86 start and would always be on the very high end of the stack ,
87 therefore, the thread stack always starts at the address of the
88 first local variable of handle_one_connection, which is thd. We
89 need to know the start of the stack so that we could check for
90 stack overruns.
91 */
92 thd_set_thread_stack(thd, (char *)&thd);
93 thd->store_globals();
94
95 mysql_thread_set_psi_id(thd->thread_id());
96 mysql_socket_set_thread_owner(
97 thd->get_protocol_classic()->get_vio()->mysql_socket);
98
99 Global_THD_manager *thd_manager = Global_THD_manager::get_instance();
100 thd_manager->add_thd(thd);
101
102 if (!thd_prepare_connection(thd)) {
103 //authentication bypass
104 abort();
105 }
106 delete channel_info;
107 close_connection(thd, 0, false, false);
108 thd->release_resources();
109 thd_manager->remove_thd(thd);
110 delete thd;
111 }
112
113
114 #define MAX_SIZE 256
115
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)116 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
117 if (Size < 1) {
118 return 0;
119 }
120 if (logfile == NULL) {
121 my_progname = "fuzz_mysqld";
122 /* first init was run with
123 * mysqld --user=root --initialize-insecure --log-error-verbosity=5 --datadir=/out/mysql/data/ --basedir=/out/mysql/
124 */
125 utilfuzz_rmrf("/tmp/mysqld");
126 char command[MAX_SIZE];
127 char argbase[MAX_SIZE];
128 char arginitfile[MAX_SIZE];
129 snprintf(command, MAX_SIZE-1, "%s/mysql/data", filepath);
130 utilfuzz_cpr(command, "/tmp/mysqld");
131
132 snprintf(argbase, MAX_SIZE-1, "--basedir=%s/mysql/", filepath);
133 snprintf(arginitfile, MAX_SIZE-1, "--init-file=%s/init.sql", filepath);
134 char *fakeargv[] = {const_cast<char *>("fuzz_mysqld"),
135 const_cast<char *>("--user=root"),
136 const_cast<char *>("--secure-file-priv=NULL"),
137 const_cast<char *>("--log-error-verbosity=5"),
138 const_cast<char *>("--explicit_defaults_for_timestamp"),
139 //we should adapt vio_fuzz to give a socket to openssl in order to support ssl
140 const_cast<char *>("--skip-ssl"),
141 const_cast<char *>("--mysqlx=0"),
142 const_cast<char *>("--event-scheduler=DISABLED"),
143 const_cast<char *>("--performance_schema=OFF"),
144 const_cast<char *>("--thread_stack=1048576"),
145 const_cast<char *>("--datadir=/tmp/mysqld/"),
146 const_cast<char *>("--port=3303"),
147 const_cast<char *>("--socket=/tmp/mysqld.sock"),
148 const_cast<char *>(argbase),
149 const_cast<char *>(arginitfile),
150 0};
151 int fakeargc = 15;
152 mysqld_main(fakeargc, fakeargv);
153 //terminate_compress_gtid_table_thread();
154
155 logfile = fopen("/dev/null", "w");
156 }
157 // The fuzzing takes place on network data received from client
158 sock_initfuzz(Data,Size-1);
159
160 Channel_info_fuzz *channel_info = new (std::nothrow) Channel_info_fuzz(Data[Size-1] & 0x80);
161 try_connection(channel_info);
162
163 return 0;
164 }
165