| diff --git a/CMakeLists.txt b/CMakeLists.txt |
| index 4a4bbfa72fa..0478561e66c 100644 |
| --- a/CMakeLists.txt |
| +++ b/CMakeLists.txt |
| @@ -688,6 +688,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) |
| |
| @@ -1804,6 +1805,10 @@ IF(NOT WITHOUT_SERVER AND WITH_UNIT_TESTS) |
| ENDIF() |
| 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/cmake/os/Linux.cmake b/cmake/os/Linux.cmake |
| index 0e25e8eb..3ae74839 100644 |
| --- a/cmake/os/Linux.cmake |
| +++ b/cmake/os/Linux.cmake |
| @@ -103,7 +103,8 @@ IF(NOT WITH_ASAN AND |
| NOT WITH_LSAN AND |
| NOT WITH_MSAN AND |
| NOT WITH_TSAN AND |
| - NOT WITH_UBSAN) |
| + NOT WITH_UBSAN AND |
| + NOT FUZZING) |
| SET(LINK_FLAG_NO_UNDEFINED "-Wl,--no-undefined") |
| SET(LINK_FLAG_Z_DEFS "-z,defs") |
| ENDIF() |
| diff --git a/include/mysql.h b/include/mysql.h |
| index 4700d74b853..bdf9b765ffb 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 39ebd0fcb93..c041cc4690f 100644 |
| --- a/include/mysql.h.pp |
| +++ b/include/mysql.h.pp |
| @@ -486,7 +486,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 a6ccd1a607d..8dc0d46dd7f 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 334d1b7d3ef..c37c5ad930e 100644 |
| --- a/libmysql/CMakeLists.txt |
| +++ b/libmysql/CMakeLists.txt |
| @@ -345,11 +345,11 @@ IF(LINUX_STANDALONE AND KERBEROS_CUSTOM_LIBRARY) |
| ENDIF() |
| |
| IF(UNIX) |
| - 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) |
| CONFIGURE_FILE(libmysql.ver.in ${CMAKE_CURRENT_BINARY_DIR}/libmysql.ver) |
| MY_TARGET_LINK_OPTIONS(libmysql |
| "LINKER:--version-script=${CMAKE_CURRENT_BINARY_DIR}/libmysql.ver") |
| diff --git a/mysys/my_rnd.cc b/mysys/my_rnd.cc |
| index 2fc7820eaa3..248ea909db8 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 b8050f2b1a7..9a65178c5c4 100644 |
| --- a/sql-common/client.cc |
| +++ b/sql-common/client.cc |
| @@ -5892,6 +5892,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 50b76e2fa75..871006c2d8f 100644 |
| --- a/sql/mysqld.cc |
| +++ b/sql/mysqld.cc |
| @@ -6991,7 +6991,9 @@ int mysqld_main(int argc, char **argv) |
| |
| keyring_lockable_init(); |
| |
| +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
| my_init_signals(); |
| +#endif |
| |
| size_t guardize = 0; |
| #ifndef _WIN32 |
| @@ -7497,8 +7499,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 */ |
| @@ -7543,8 +7547,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) |
| @@ -7591,6 +7596,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(); |
| @@ -10500,6 +10509,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 7ecc10961ac..5f13f94eb02 100644 |
| --- a/storage/innobase/buf/buf0buf.cc |
| +++ b/storage/innobase/buf/buf0buf.cc |
| @@ -1476,18 +1476,14 @@ dberr_t buf_pool_init(ulint total_size, ulint n_instances) { |
| n = n_instances; |
| } |
| |
| - std::vector<std::thread> 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 35ab5f17f15..9b39bfdbdbf 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 368c8d7b581..50c3231a8b0 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..5b368d685cb |
| --- /dev/null |
| +++ b/vio/viofuzz.cc |
| @@ -0,0 +1,124 @@ |
| + |
| +#include "my_config.h" |
| + |
| +#include <errno.h> |
| +#include <fcntl.h> |
| +#include <sys/types.h> |
| +#include <time.h> |
| +#ifndef _WIN32 |
| +#include <netdb.h> |
| +#endif |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| + |
| +#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 <sys/filio.h> |
| +#endif |
| +#ifndef _WIN32 |
| +#include <netinet/tcp.h> |
| +#endif |
| +#ifdef HAVE_POLL_H |
| +#include <poll.h> |
| +#endif |
| +#ifdef HAVE_SYS_IOCTL_H |
| +#include <sys/ioctl.h> |
| +#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<size; i++) |
| + printf("%02x ", bufp[i]); |
| + printf("\n"); |
| +#endif //FUZZ_DEBUG |
| + return size; |
| +} |
| + |
| +size_t vio_write_buff_fuzz(Vio *vio, const uchar *bufp, size_t size) { |
| + DBUG_ENTER("vio_write_buff_fuzz\n"); |
| +#ifdef FUZZ_DEBUG |
| + printf("net srv %zu ", size); |
| + for (size_t i=0; i<size; i++) |
| + printf("%02x ", bufp[i]); |
| + printf("\n"); |
| +#endif //FUZZ_DEBUG |
| + return size; |
| +} |
| + |
| +bool vio_is_connected_fuzz(Vio *vio) { |
| + DBUG_ENTER("vio_is_connected_fuzz\n"); |
| + return (fuzzPos < fuzzSize); |
| +} |
| + |
| +bool vio_was_timeout_fuzz(Vio *vio) { |
| + DBUG_ENTER("vio_was_timeout_fuzz\n"); |
| + return false; |
| +} |
| + |
| +int vio_shutdown_fuzz(Vio *vio) { |
| + DBUG_ENTER("vio_shutdown_fuzz"); |
| + return 0; |
| +} |
| + |
| +int vio_keepalive_fuzz(Vio *vio, bool set_keep_alive) { |
| + DBUG_ENTER("vio_keepalive_fuzz\n"); |
| + return 0; |
| +} |
| +int vio_io_wait_fuzz(Vio *vio, enum enum_vio_io_event event, int timeout) { |
| + DBUG_ENTER("vio_io_wait_fuzz"); |
| + return 1; |
| +} |
| + |
| +int vio_fastsend_fuzz(Vio *vio) { |
| + DBUG_ENTER("vio_fastsend_fuzz\n"); |
| + return 0; |
| +} |
| + |
| +bool vio_should_retry_fuzz(Vio *vio) { |
| + DBUG_ENTER("vio_should_retry_fuzz\n"); |
| + return (fuzzPos < fuzzSize); |
| +} |