diff --git a/CMakeLists.txt b/CMakeLists.txt index 3667900243c..337344e124d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -597,6 +597,7 @@ IF(WITH_JEMALLOC AND (WITH_TCMALLOC OR WITH_TCMALLOC_DEBUG)) MESSAGE(FATAL_ERROR "Specify only *one* of WITH_TCMALLOC and WITH_JEMALLOC") ENDIF() +OPTION(FUZZING "Fuzzing" OFF) OPTION(ENABLED_PROFILING "Enable profiling" ON) OPTION(WITHOUT_SERVER OFF) @@ -1587,6 +1588,10 @@ IF(NOT WITHOUT_SERVER AND WITH_UNIT_TESTS) TARGET_LINK_LIBRARIES(server_unittest_library ${ICU_LIBRARIES}) 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 b805bffdf88..23d2311299e 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -262,7 +262,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/mysql.h.pp b/include/mysql.h.pp index ce785802ad9..4f048082335 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -485,7 +485,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 { SSL_MODE_DISABLED = 1, diff --git a/include/violite.h b/include/violite.h index c04e82505a7..2498ba0053c 100644 --- a/include/violite.h +++ b/include/violite.h @@ -108,12 +108,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 }; /** @@ -444,4 +446,20 @@ struct Vio { #define SSL_handle SSL * + +//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 4956a0dc2d8..bab0aa3b504 100644 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -353,11 +353,11 @@ IF(UNIX) ADD_INSTALL_RPATH_FOR_OPENSSL(libmysql) - IF(LINK_FLAG_Z_DEFS) + IF(LINK_FLAG_Z_DEFS AND NOT FUZZING) MY_TARGET_LINK_OPTIONS(libmysql "LINKER:${LINK_FLAG_Z_DEFS}") ENDIF() - IF(LINUX) + IF(LINUX AND NOT FUZZING) MY_TARGET_LINK_OPTIONS(libmysql "LINKER:--version-script=${CMAKE_CURRENT_BINARY_DIR}/libmysql.ver") ENDIF() diff --git a/mysys/mf_tempfile.cc b/mysys/mf_tempfile.cc index f4f5dffba9a..26ab2ce0917 100644 --- a/mysys/mf_tempfile.cc +++ b/mysys/mf_tempfile.cc @@ -320,6 +320,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix, set_my_errno(ENAMETOOLONG); return file; } + sprintf(prefix_buff, "%sXXXXXX", prefix ? prefix : "tmp."); my_stpcpy(convert_dirname(to, dir, NullS), prefix_buff); file = mkstemp(to); file_info::RegisterFilename(file, to, file_info::OpenType::FILE_BY_MKSTEMP); diff --git a/mysys/my_rnd.cc b/mysys/my_rnd.cc index 8253e3967d4..034c71de600 100644 --- a/mysys/my_rnd.cc +++ b/mysys/my_rnd.cc @@ -48,6 +48,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); @@ -64,6 +67,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) { @@ -85,6 +94,9 @@ int my_rand_buffer(unsigned char *buffer, size_t buffer_size) { double my_rnd_ssl(bool *failed) { unsigned int res; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + return 34.56; +#endif if (my_rand_buffer((unsigned char *)&res, sizeof(res))) { *failed = true; return 0; diff --git a/sql-common/client.cc b/sql-common/client.cc index 61404be555b..721802cb60c 100644 --- a/sql-common/client.cc +++ b/sql-common/client.cc @@ -5774,6 +5774,12 @@ static mysql_state_machine_status csm_begin_connect(mysql_async_connect *ctx) { } } #endif /* _WIN32 */ +if (!net->vio && + (mysql->options.protocol == MYSQL_PROTOCOL_FUZZ)) { + net->vio = + vio_new(0, VIO_TYPE_FUZZ, 0); + ctx->host_info = (char *)ER_CLIENT(CR_LOCALHOST_CONNECTION); +} #if defined(HAVE_SYS_UN_H) if (!net->vio && (!mysql->options.protocol || diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 519926135ed..db75dc7f5e5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6862,7 +6862,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 @@ -7347,8 +7349,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 */ @@ -7393,8 +7397,9 @@ int mysqld_main(int argc, char **argv) } start_handle_manager(); - +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION create_compress_gtid_table_thread(); +#endif LogEvent() .type(LOG_TYPE_ERROR) @@ -7441,6 +7446,10 @@ int mysqld_main(int argc, char **argv) (void)RUN_HOOK(server_state, before_handle_connection, (nullptr)); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + return 0; +#endif + #if defined(_WIN32) if (mysqld_socket_acceptor != nullptr) mysqld_socket_acceptor->check_and_spawn_admin_connection_handler_thread(); @@ -10281,6 +10290,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/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index fba0684f322..8352dacbc03 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1487,18 +1487,14 @@ dberr_t buf_pool_init(ulint total_size, ulint n_instances) { n = n_instances; } - std::vector threads; - std::mutex m; for (ulint id = i; id < n; ++id) { - threads.emplace_back(std::thread(buf_pool_create, &buf_pool_ptr[id], size, - id, &m, std::ref(errs[id]))); + buf_pool_create(&buf_pool_ptr[id], size, + id, &m, std::ref(errs[id])); } for (ulint id = i; id < n; ++id) { - threads[id - i].join(); - if (errs[id] != DB_SUCCESS) { err = errs[id]; } diff --git a/vio/CMakeLists.txt b/vio/CMakeLists.txt index d44eebce63a..975bc878e17 100644 --- a/vio/CMakeLists.txt +++ b/vio/CMakeLists.txt @@ -27,6 +27,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 38e3d90f20e..abbc9a52478 100644 --- a/vio/vio.cc +++ b/vio/vio.cc @@ -284,6 +284,26 @@ static bool vio_init(Vio *vio, enum enum_vio_type type, my_socket sd, vio->is_blocking_flag = true; break; + case 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; + default: vio->viodelete = vio_delete; vio->vioerrno = vio_errno; @@ -568,7 +588,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..83f22a5dbb9 --- /dev/null +++ b/vio/viofuzz.cc @@ -0,0 +1,124 @@ + +#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) { + 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. */ + return 0; +} + + +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 %zu ", size); + for (size_t i=0; i