From 276d4c7888c46160a83a0233640b354c24894120 Mon Sep 17 00:00:00 2001 From: Catena cyber <35799796+catenacyber@users.noreply.github.com> Date: Thu, 1 Aug 2019 22:27:38 +0200 Subject: [PATCH] [mysql] Initial integration for mysql server (#2593) * Initial integration for mysql server --- projects/mysql-server/Dockerfile | 25 ++ projects/mysql-server/build.sh | 31 ++ projects/mysql-server/fix.diff | 363 ++++++++++++++++++ projects/mysql-server/project.yaml | 12 + projects/mysql-server/targets/CMakeLists.txt | 24 ++ projects/mysql-server/targets/README | 2 + projects/mysql-server/targets/fuzz_mysqld.cc | 98 +++++ .../mysql-server/targets/fuzz_mysqld.dict | 1 + .../mysql-server/targets/fuzz_mysqld.options | 2 + .../mysql-server/targets/fuzz_real_query.cc | 100 +++++ projects/mysql-server/targets/fuzz_server.cc | 55 +++ .../mysql-server/targets/fuzz_stmt_fetch.cc | 115 ++++++ projects/mysql-server/targets/init.sql | 2 + projects/mysql-server/targets/onefile.cc | 50 +++ 14 files changed, 880 insertions(+) create mode 100644 projects/mysql-server/Dockerfile create mode 100644 projects/mysql-server/build.sh create mode 100644 projects/mysql-server/fix.diff create mode 100644 projects/mysql-server/project.yaml create mode 100644 projects/mysql-server/targets/CMakeLists.txt create mode 100644 projects/mysql-server/targets/README create mode 100644 projects/mysql-server/targets/fuzz_mysqld.cc create mode 100644 projects/mysql-server/targets/fuzz_mysqld.dict create mode 100644 projects/mysql-server/targets/fuzz_mysqld.options create mode 100644 projects/mysql-server/targets/fuzz_real_query.cc create mode 100644 projects/mysql-server/targets/fuzz_server.cc create mode 100644 projects/mysql-server/targets/fuzz_stmt_fetch.cc create mode 100644 projects/mysql-server/targets/init.sql create mode 100644 projects/mysql-server/targets/onefile.cc diff --git a/projects/mysql-server/Dockerfile b/projects/mysql-server/Dockerfile new file mode 100644 index 000000000..85565f4e9 --- /dev/null +++ b/projects/mysql-server/Dockerfile @@ -0,0 +1,25 @@ +# Copyright 2018 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. +# +################################################################################ + +FROM gcr.io/oss-fuzz-base/base-builder +MAINTAINER secalert_us@oracle.com +RUN apt-get update +RUN apt-get install -y build-essential libssl-dev libncurses5-dev libncursesw5-dev make cmake perl bison pkg-config +RUN git clone --depth 1 https://github.com/mysql/mysql-server +WORKDIR $SRC +COPY build.sh $SRC/ +COPY fix.diff $SRC/ +COPY targets $SRC/mysql-server/fuzz diff --git a/projects/mysql-server/build.sh b/projects/mysql-server/build.sh new file mode 100644 index 000000000..e9ba0f06f --- /dev/null +++ b/projects/mysql-server/build.sh @@ -0,0 +1,31 @@ + +#!/bin/bash -eu +# Copyright 2018 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. +# +################################################################################ + +cd mysql-server +git apply ../fix.diff +mkdir build +cd build +cmake .. -DDOWNLOAD_BOOST=1 -DWITH_BOOST=$WORK -DWITH_SSL=system -DFUZZING=1 -DCMAKE_INSTALL_PREFIX=$OUT/mysql +make install +cp $OUT/mysql/bin/fuzz* $OUT/ +cp ../fuzz/fuzz*.options $OUT/ +cp ../fuzz/fuzz*.dict $OUT/ +cp ../fuzz/init.sql $OUT/ + +rm -Rf $OUT/mysql/data +$OUT/mysql/bin/mysqld --user=root --initialize-insecure --log-error-verbosity=5 --datadir=$OUT/mysql/data --basedir=$OUT/mysql/ diff --git a/projects/mysql-server/fix.diff b/projects/mysql-server/fix.diff new file mode 100644 index 000000000..865485cda --- /dev/null +++ b/projects/mysql-server/fix.diff @@ -0,0 +1,363 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 758df9761e8..837a8c6b071 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -461,6 +461,7 @@ ENDIF() + + OPTION(DISABLE_SHARED + "Don't build shared libraries, compile code as position-dependent" OFF) ++OPTION(FUZZING "Fuzzing" OFF) + IF(DISABLE_SHARED) + MESSAGE("Dynamic plugins are disabled.") + ENDIF() +@@ -1140,6 +1141,10 @@ IF(NOT WITHOUT_SERVER) + ADD_SUBDIRECTORY(sql) + ENDIF() + ++IF (FUZZING) ++ ADD_SUBDIRECTORY(fuzz) ++ENDIF() ++ + # scripts/mysql_config depends on client and server targets loaded above. + # It is referenced by some of the directories below, so we insert it here. + ADD_SUBDIRECTORY(scripts) +diff --git a/include/mysql.h b/include/mysql.h +index 561960cd925..a11ccb42299 100644 +--- a/include/mysql.h ++++ b/include/mysql.h +@@ -260,7 +260,8 @@ enum mysql_protocol_type { + MYSQL_PROTOCOL_TCP, + MYSQL_PROTOCOL_SOCKET, + MYSQL_PROTOCOL_PIPE, +- MYSQL_PROTOCOL_MEMORY ++ MYSQL_PROTOCOL_MEMORY, ++ MYSQL_PROTOCOL_FUZZ + }; + + enum mysql_ssl_mode { +diff --git a/include/violite.h b/include/violite.h +index b0c5c6958ba..7ef140dc163 100644 +--- a/include/violite.h ++++ b/include/violite.h +@@ -106,12 +106,14 @@ enum enum_vio_type : int { + */ + VIO_TYPE_PLUGIN = 7, + ++ VIO_TYPE_FUZZ = 8, ++ + FIRST_VIO_TYPE = VIO_TYPE_TCPIP, + /* + If a new type is added, please update LAST_VIO_TYPE. In addition, please + change get_vio_type_name() in vio/vio.c to return correct name for it. + */ +- LAST_VIO_TYPE = VIO_TYPE_PLUGIN ++ LAST_VIO_TYPE = VIO_TYPE_FUZZ + }; + + /** +@@ -457,4 +459,20 @@ struct Vio { + #define SSL_handle void * + #endif + ++ ++//Vio fuzzing ++bool vio_connect_fuzz(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, ++ int timeout); ++int vio_socket_timeout_fuzz(Vio *vio, uint which, bool b); ++void sock_initfuzz(const uint8_t *Data, size_t Size); ++size_t vio_read_buff_fuzz(Vio *vio, uchar *buf, size_t size); ++size_t vio_write_buff_fuzz(Vio *vio, const uchar *buf, size_t size); ++bool vio_is_connected_fuzz(Vio *vio); ++bool vio_was_timeout_fuzz(Vio *vio); ++int vio_shutdown_fuzz(Vio *vio); ++int vio_keepalive_fuzz(Vio *vio, bool set_keep_alive); ++int vio_io_wait_fuzz(Vio *vio, enum enum_vio_io_event event, int timeout); ++int vio_fastsend_fuzz(Vio *vio); ++bool vio_should_retry_fuzz(Vio *vio); ++ + #endif /* vio_violite_h_ */ +diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt +index 2606e908124..20a80adcd5b 100644 +--- a/libmysql/CMakeLists.txt ++++ b/libmysql/CMakeLists.txt +@@ -319,7 +319,7 @@ IF(NOT DISABLE_SHARED) + ENDIF() + + GET_TARGET_PROPERTY(libmysql_link_flags libmysql LINK_FLAGS) +- IF(LINK_FLAG_NO_UNDEFINED) ++ IF(LINK_FLAG_NO_UNDEFINED AND NOT FUZZING) + SET(libmysql_link_flags + "${libmysql_link_flags} ${LINK_FLAG_NO_UNDEFINED}") + SET(libmysql_link_flags +diff --git a/mysys_ssl/my_rnd.cc b/mysys_ssl/my_rnd.cc +index d4b3ec4b851..aaaf8bdb93c 100644 +--- a/mysys_ssl/my_rnd.cc ++++ b/mysys_ssl/my_rnd.cc +@@ -50,6 +50,9 @@ + */ + + double my_rnd(struct rand_struct *rand_st) { ++#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ++ return 65.43; ++#endif + rand_st->seed1 = (rand_st->seed1 * 3 + rand_st->seed2) % rand_st->max_value; + rand_st->seed2 = (rand_st->seed1 + rand_st->seed2 + 33) % rand_st->max_value; + return (((double)rand_st->seed1) / rand_st->max_value_dbl); +@@ -66,6 +69,12 @@ Fill a buffer with random bytes using the SSL library routines + */ + int my_rand_buffer(unsigned char *buffer, size_t buffer_size) { + int rc; ++#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ++ for (size_t i = 0; i < buffer_size; i++) ++ buffer[i] = i; ++ return 0; ++#endif ++ + rc = RAND_bytes(buffer, (int)buffer_size); + + if (!rc) { +@@ -89,6 +98,10 @@ int my_rand_buffer(unsigned char *buffer, size_t buffer_size) { + double my_rnd_ssl(struct rand_struct *rand_st) { + unsigned int res; + ++#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ++ return 34.56; ++#endif ++ + if (my_rand_buffer((unsigned char *)&res, sizeof(res))) + return my_rnd(rand_st); + +diff --git a/sql/mysqld.cc b/sql/mysqld.cc +index 13479e3c474..5d165982fe6 100644 +--- a/sql/mysqld.cc ++++ b/sql/mysqld.cc +@@ -6124,7 +6124,9 @@ int mysqld_main(int argc, char **argv) + unireg_abort(MYSQLD_ABORT_EXIT); // Will do exit + } + ++#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + my_init_signals(); ++#endif + + size_t guardize = 0; + #ifndef _WIN32 +@@ -6598,8 +6600,10 @@ int mysqld_main(int argc, char **argv) + unireg_abort(MYSQLD_ABORT_EXIT); + + #ifndef _WIN32 ++#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // Start signal handler thread. + start_signal_handler(); ++#endif + #endif + + /* set all persistent options */ +@@ -6771,6 +6775,10 @@ int mysqld_main(int argc, char **argv) + + (void)RUN_HOOK(server_state, before_handle_connection, (NULL)); + ++#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ++ return 0; ++#endif ++ + #if defined(_WIN32) + setup_conn_event_handler_threads(); + #else +@@ -9501,6 +9509,9 @@ static int get_options(int *argc_ptr, char ***argv_ptr) { + + if (opt_short_log_format) opt_specialflag |= SPECIAL_SHORT_LOG_FORMAT; + ++#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ++ Connection_handler_manager::thread_handling = Connection_handler_manager::SCHEDULER_NO_THREADS; ++#endif + if (Connection_handler_manager::init()) { + LogErr(ERROR_LEVEL, ER_CONNECTION_HANDLING_OOM); + return 1; +diff --git a/vio/CMakeLists.txt b/vio/CMakeLists.txt +index f46858dd4bf..09c0a62ef8c 100644 +--- a/vio/CMakeLists.txt ++++ b/vio/CMakeLists.txt +@@ -25,6 +25,7 @@ SET(VIO_SOURCES + viosocket.cc + viossl.cc + viosslfactories.cc ++ viofuzz.cc + ) + + IF(WIN32) +diff --git a/vio/vio.cc b/vio/vio.cc +index de46703eb82..01e8695f574 100644 +--- a/vio/vio.cc ++++ b/vio/vio.cc +@@ -300,6 +300,27 @@ static bool vio_init(Vio *vio, enum enum_vio_type type, my_socket sd, + return false; + } + #endif /* HAVE_OPENSSL */ ++ if (type == VIO_TYPE_FUZZ) { ++ vio->viodelete = vio_delete; ++ vio->vioerrno = vio_errno; ++ vio->read = vio_read_buff_fuzz; ++ vio->write = vio_write_buff_fuzz; ++ vio->fastsend = vio_fastsend_fuzz; ++ vio->viokeepalive = vio_keepalive_fuzz; ++ vio->should_retry = vio_should_retry_fuzz; ++ vio->was_timeout = vio_was_timeout_fuzz; ++ vio->vioshutdown = vio_shutdown_fuzz; ++ vio->peer_addr = vio_peer_addr; ++ vio->timeout = vio_socket_timeout_fuzz; ++ vio->io_wait = vio_io_wait_fuzz; ++ vio->is_connected = vio_is_connected_fuzz; ++ vio->has_data = vio->read_buffer ? vio_buff_has_data : has_no_data; ++ vio->is_blocking = vio_is_blocking; ++ vio->set_blocking = vio_set_blocking; ++ vio->set_blocking_flag = vio_set_blocking_flag; ++ vio->is_blocking_flag = false; ++ return false; ++ } + vio->viodelete = vio_delete; + vio->vioerrno = vio_errno; + vio->read = vio->read_buffer ? vio_read_buff : vio_read; +@@ -577,7 +598,8 @@ static const vio_string vio_type_names[] = {{"", 0}, + {STRING_WITH_LEN("SSL/TLS")}, + {STRING_WITH_LEN("Shared Memory")}, + {STRING_WITH_LEN("Internal")}, +- {STRING_WITH_LEN("Plugin")}}; ++ {STRING_WITH_LEN("Plugin")}, ++ {STRING_WITH_LEN("Fuzz")}}; + + void get_vio_type_name(enum enum_vio_type vio_type, const char **str, + int *len) { +diff --git a/vio/viofuzz.cc b/vio/viofuzz.cc +new file mode 100644 +index 00000000000..d8c2987d7be +--- /dev/null ++++ b/vio/viofuzz.cc +@@ -0,0 +1,128 @@ ++ ++#include "my_config.h" ++ ++#include ++#include ++#include ++#include ++#ifndef _WIN32 ++#include ++#endif ++#include ++#include ++ ++#include "my_compiler.h" ++#include "my_dbug.h" ++#include "my_inttypes.h" ++#include "my_io.h" ++#include "my_macros.h" ++#include "vio/vio_priv.h" ++ ++#ifdef FIONREAD_IN_SYS_FILIO ++#include ++#endif ++#ifndef _WIN32 ++#include ++#endif ++#ifdef HAVE_POLL_H ++#include ++#endif ++#ifdef HAVE_SYS_IOCTL_H ++#include ++#endif ++ ++static const uint8_t *fuzzBuffer; ++static size_t fuzzSize; ++static size_t fuzzPos; ++ ++ ++void sock_initfuzz(const uint8_t *Data, size_t Size) { ++ fuzzPos = 0; ++ fuzzSize = Size; ++ fuzzBuffer = Data; ++} ++ ++bool vio_connect_fuzz(Vio *vio, struct sockaddr *addr, socklen_t len, ++ int timeout) { ++ int ret, wait; ++ int retry_count = 0; ++ DBUG_ENTER("vio_socket_connect"); ++ ++ /* Only for socket-based transport types. */ ++ DBUG_ASSERT(vio->type == VIO_TYPE_SOCKET || vio->type == VIO_TYPE_TCPIP); ++ ++ /* Initiate the connection. */ ++ ret=0; ++ ++ DBUG_RETURN(MY_TEST(ret)); ++} ++ ++ ++int vio_socket_timeout_fuzz(Vio *vio, uint which, bool b) { ++ DBUG_ENTER("vio_socket_timeout_fuzz\n"); ++ return 0; ++} ++ ++ ++size_t vio_read_buff_fuzz(Vio *vio, uchar *bufp, size_t size) { ++ DBUG_ENTER("vio_read_buff_fuzz.\n"); ++ if (size > fuzzSize - fuzzPos) { ++ size = fuzzSize - fuzzPos; ++ } ++ if (fuzzPos < fuzzSize) { ++ memcpy(bufp, fuzzBuffer + fuzzPos, size); ++ } ++ fuzzPos += size; ++#ifdef FUZZ_DEBUG ++ printf("net cli %d ", size); ++ for (int i=0; i +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include "sql/sql_class.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 "violite.h" +#include + +using namespace std; +FILE *logfile = NULL; +Connection_handler_manager * chm; +extern int mysqld_main(int argc, char **argv); + +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; } +}; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 1) { + return 0; + } + if (logfile == NULL) { + my_progname = "fuzz_mysqld"; + /* first init was run with + * mysqld --user=root --initialize-insecure --log-error-verbosity=5 --datadir=/out/mysql/data/ --basedir=/out/mysql/ + */ + system("rm -Rf /tmp/mysql"); + system("cp -r /out/mysql/data /tmp/mysql"); + + char *fakeargv[] = {const_cast("fuzz_mysqld"), + const_cast("--user=root"), + const_cast("--secure-file-priv=NULL"), + const_cast("--log-error-verbosity=5"), + const_cast("--explicit_defaults_for_timestamp"), + //we should adapt vio_fuzz to give a socket to openssl in order to support ssl + const_cast("--skip-ssl"), + const_cast("--mysqlx=0"), + const_cast("--event-scheduler=DISABLED"), + const_cast("--thread_stack=1048576"), + const_cast("--datadir=/tmp/mysql/"), + const_cast("--basedir=/out/mysql/"), + const_cast("--init-file=/out/init.sql"), + 0}; + int fakeargc = 12; + mysqld_main(fakeargc, fakeargv); + + chm = Connection_handler_manager::get_instance(); + logfile = fopen("/dev/null", "w"); + } + // The fuzzing takes place on network data received from client + sock_initfuzz(Data,Size-1); + + Channel_info_fuzz *channel_info = new (std::nothrow) Channel_info_fuzz(Data[Size-1] & 0x80); + chm->process_new_connection(channel_info); + + return 0; +} diff --git a/projects/mysql-server/targets/fuzz_mysqld.dict b/projects/mysql-server/targets/fuzz_mysqld.dict new file mode 100644 index 000000000..33c97f6ed --- /dev/null +++ b/projects/mysql-server/targets/fuzz_mysqld.dict @@ -0,0 +1 @@ +user="root" diff --git a/projects/mysql-server/targets/fuzz_mysqld.options b/projects/mysql-server/targets/fuzz_mysqld.options new file mode 100644 index 000000000..329a6e27b --- /dev/null +++ b/projects/mysql-server/targets/fuzz_mysqld.options @@ -0,0 +1,2 @@ +[libfuzzer] +close_fd_mask = 3 diff --git a/projects/mysql-server/targets/fuzz_real_query.cc b/projects/mysql-server/targets/fuzz_real_query.cc new file mode 100644 index 000000000..15a72e763 --- /dev/null +++ b/projects/mysql-server/targets/fuzz_real_query.cc @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "violite.h" + +using namespace std; +FILE *logfile = NULL; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + MYSQL mysql; + long flags; + bool opt_cleartext = true; + unsigned int opt_ssl = SSL_MODE_DISABLED; + MYSQL_RES *result; + + if (Size < sizeof(unsigned long)) { + return 0; + } + if (logfile == NULL) { + logfile = fopen("/dev/null", "w"); + } + flags = * ((unsigned long *) (Data + Size - sizeof(unsigned long))); + mysql_init(&mysql); + mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, &opt_cleartext); + mysql_options(&mysql, MYSQL_OPT_SSL_MODE, &opt_ssl); + mysql.options.protocol = MYSQL_PROTOCOL_FUZZ; + // The fuzzing takes place on network data received from server + sock_initfuzz(Data,Size - sizeof(unsigned long)); + if (!mysql_real_connect(&mysql, "localhost", "root", "root", "dbname", 0, NULL, flags)) { + goto out; + } else { + fprintf(logfile, "The last inserted row id is: %llu\n", mysql_insert_id(&mysql)); + fprintf(logfile, "%llu affected rows\n", mysql_affected_rows(&mysql)); + mysql_info(&mysql); + } + + mysql_query(&mysql, "CREATE DATABASE fuzzbase"); + if (mysql_query(&mysql, "SELECT * FROM CARS")) { + goto out; + } + result = mysql_store_result(&mysql); + if (result != NULL) { + int num_fields = mysql_num_fields(result); + MYSQL_FIELD *field; + while((field = mysql_fetch_field(result))) { + fprintf(logfile, "%s\n", field->name); + } + MYSQL_ROW row = mysql_fetch_row(result); + unsigned long * lengths = mysql_fetch_lengths(result); + while (row ) { + for(int i = 0; i < num_fields; i++) { + fprintf(logfile, "length %lu, %s\n", lengths[i], row[i] ? row[i] : "NULL"); + } + row = mysql_fetch_row(result); + } + mysql_free_result(result); + } + result = mysql_list_dbs(&mysql, NULL); + if (result) { + mysql_free_result(result); + } + result = mysql_list_tables(&mysql, NULL); + if (result) { + mysql_free_result(result); + } + result = mysql_list_fields(&mysql, "sometable", NULL); + if (result) { + mysql_free_result(result); + } + result = mysql_list_processes(&mysql); + if (result) { + mysql_free_result(result); + } + mysql_ping(&mysql); + + if (mysql_change_user(&mysql, "user", "password", "new_database")) { + goto out; + } + if (mysql_query(&mysql, "INSERT INTO Fuzzers(Name) VALUES('myfuzzer')") == 0) { + fprintf(logfile, "The last inserted row id is: %llu\n", mysql_insert_id(&mysql)); + fprintf(logfile, "%llu affected rows\n", mysql_affected_rows(&mysql)); + mysql_info(&mysql); + } + mysql_get_host_info(&mysql); + mysql_get_proto_info(&mysql); + mysql_get_server_info(&mysql); + mysql_get_server_version(&mysql); + mysql_dump_debug_info(&mysql); + mysql_sqlstate(&mysql); + mysql_stat(&mysql); + +out: + mysql_close(&mysql); + return 0; +} diff --git a/projects/mysql-server/targets/fuzz_server.cc b/projects/mysql-server/targets/fuzz_server.cc new file mode 100644 index 000000000..e609d3e53 --- /dev/null +++ b/projects/mysql-server/targets/fuzz_server.cc @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "violite.h" + +using namespace std; +FILE *logfile = NULL; +Connection_handler * connection_handler; + +class Channel_info_fuzz : public Channel_info { + bool m_is_admin_conn; + + protected: + virtual Vio *create_and_init_vio() const { + Vio *vio = mysql_socket_vio_new(0, VIO_TYPE_FUZZ, 0); + return vio; + } + + public: + Channel_info_fuzz(bool is_admin_conn) : m_is_admin_conn(is_admin_conn) {} + + virtual THD *create_thd() { + THD *thd = Channel_info::create_thd(); + + if (thd != NULL) { + 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; } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 1) { + return 0; + } + if (logfile == NULL) { + connection_handler = new (std::nothrow) One_thread_connection_handler(); + logfile = fopen("/dev/null", "w"); + } + // The fuzzing takes place on network data received from server + sock_initfuzz(Data,Size-1); + + Channel_info_fuzz *channel_info = new (std::nothrow) Channel_info_fuzz(Data[Size-1] & 0x80); + connection_handler->add_connection(channel_info); + + return 0; +} diff --git a/projects/mysql-server/targets/fuzz_stmt_fetch.cc b/projects/mysql-server/targets/fuzz_stmt_fetch.cc new file mode 100644 index 000000000..fea90a6af --- /dev/null +++ b/projects/mysql-server/targets/fuzz_stmt_fetch.cc @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "violite.h" + +using namespace std; + +#define STRING_SIZE 50 + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + MYSQL mysql; + MYSQL_BIND bind[4]; + MYSQL_RES *prepare_meta_result; + MYSQL_TIME ts; + unsigned long length[4]; + int param_count, column_count, row_count; + short small_data; + int int_data; + char str_data[STRING_SIZE]; + bool is_null[4]; + bool error[4]; + + mysql_init(&mysql); + mysql.options.protocol = MYSQL_PROTOCOL_FUZZ; + // The fuzzing takes place on network data received from server + sock_initfuzz(Data,Size); + if (!mysql_real_connect(&mysql,"localhost","root","root","",0,NULL,0)) + { + return 0; + } + + MYSQL_STMT *stmt = mysql_stmt_init(&mysql); + if (!stmt) + { + mysql_stmt_close(stmt); + mysql_close(&mysql); + return 0; + } + if (mysql_stmt_prepare(stmt, "SELECT col1, col2, col3, col4 FROM Cars",(ulong)strlen("SELECT col1, col2, col3, col4 FROM Cars"))) + { + mysql_stmt_close(stmt); + mysql_close(&mysql); + return 0; + } + prepare_meta_result = mysql_stmt_result_metadata(stmt); + if (!prepare_meta_result) + { + mysql_stmt_close(stmt); + mysql_close(&mysql); + return 0; + } + + if (mysql_stmt_execute(stmt)) + { + mysql_stmt_close(stmt); + mysql_close(&mysql); + return 0; + } + column_count= mysql_num_fields(prepare_meta_result); + memset(bind, 0, sizeof(bind)); + /* INTEGER COLUMN */ + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)&int_data; + bind[0].is_null= &is_null[0]; + bind[0].length= &length[0]; + bind[0].error= &error[0]; + + /* STRING COLUMN */ + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (char *)str_data; + bind[1].buffer_length= STRING_SIZE; + bind[1].is_null= &is_null[1]; + bind[1].length= &length[1]; + bind[1].error= &error[1]; + + /* SMALLINT COLUMN */ + bind[2].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer= (char *)&small_data; + bind[2].is_null= &is_null[2]; + bind[2].length= &length[2]; + bind[2].error= &error[2]; + + /* TIMESTAMP COLUMN */ + bind[3].buffer_type= MYSQL_TYPE_TIMESTAMP; + bind[3].buffer= (char *)&ts; + bind[3].is_null= &is_null[3]; + bind[3].length= &length[3]; + bind[3].error= &error[3]; + + if (mysql_stmt_bind_result(stmt, bind)) + { + mysql_free_result(prepare_meta_result); + mysql_stmt_close(stmt); + mysql_close(&mysql); + return 0; + } + if (mysql_stmt_store_result(stmt)) + { + mysql_free_result(prepare_meta_result); + mysql_stmt_close(stmt); + mysql_close(&mysql); + return 0; + } + while (!mysql_stmt_fetch(stmt)) {} + + mysql_free_result(prepare_meta_result); + mysql_stmt_close(stmt); + mysql_close(&mysql); + return 0; +} diff --git a/projects/mysql-server/targets/init.sql b/projects/mysql-server/targets/init.sql new file mode 100644 index 000000000..a4ca5ce0a --- /dev/null +++ b/projects/mysql-server/targets/init.sql @@ -0,0 +1,2 @@ +CREATE USER 'fuzzuser'@'localhost' IDENTIFIED BY 'fuzzpass'; +ALTER USER 'root'@'localhost' IDENTIFIED BY 'mainpass'; diff --git a/projects/mysql-server/targets/onefile.cc b/projects/mysql-server/targets/onefile.cc new file mode 100644 index 000000000..bfffa709e --- /dev/null +++ b/projects/mysql-server/targets/onefile.cc @@ -0,0 +1,50 @@ +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int main(int argc, char** argv) +{ + FILE * fp; + uint8_t *Data; + size_t Size; + + if (argc != 2) { + return 1; + } + //opens the file, get its size, and reads it into a buffer + fp = fopen(argv[1], "rb"); + if (fp == NULL) { + return 2; + } + if (fseek(fp, 0L, SEEK_END) != 0) { + fclose(fp); + return 2; + } + Size = ftell(fp); + if (Size == (size_t) -1) { + fclose(fp); + return 2; + } + if (fseek(fp, 0L, SEEK_SET) != 0) { + fclose(fp); + return 2; + } + Data = (uint8_t*)malloc(Size*sizeof(uint8_t)); + if (Data == NULL) { + fclose(fp); + return 2; + } + if (fread(Data, Size, 1, fp) != 1) { + fclose(fp); + free(Data); + return 2; + } + + //lauch fuzzer + LLVMFuzzerTestOneInput(Data, Size); + free(Data); + fclose(fp); + return 0; +}