diff options
-rw-r--r-- | tests/fuzz/CMakeLists.txt | 11 | ||||
-rw-r--r-- | tests/fuzz/ssh_client_fuzzer.cpp | 157 |
2 files changed, 168 insertions, 0 deletions
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt index 72ca1f47..d8663b51 100644 --- a/tests/fuzz/CMakeLists.txt +++ b/tests/fuzz/CMakeLists.txt @@ -1,6 +1,16 @@ project(fuzzing CXX) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_executable(ssh_client_fuzzer ssh_client_fuzzer.cpp) + target_link_libraries(ssh_client_fuzzer + PRIVATE + ${LIBSSH_STATIC_LIBRARY}) + set_target_properties(ssh_client_fuzzer + PROPERTIES + COMPILE_FLAGS "-fsanitize=fuzzer" + LINK_FLAGS "-fsanitize=fuzzer") + + add_executable(ssh_server_fuzzer ssh_server_fuzzer.cpp) target_link_libraries(ssh_server_fuzzer PRIVATE @@ -11,5 +21,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") LINK_FLAGS "-fsanitize=fuzzer") # Run the fuzzer to make sure it works + add_test(ssh_client_fuzzer ${CMAKE_CURRENT_BINARY_DIR}/ssh_client_fuzzer -runs=1) add_test(ssh_server_fuzzer ${CMAKE_CURRENT_BINARY_DIR}/ssh_server_fuzzer -runs=1) endif() diff --git a/tests/fuzz/ssh_client_fuzzer.cpp b/tests/fuzz/ssh_client_fuzzer.cpp new file mode 100644 index 00000000..eabe294c --- /dev/null +++ b/tests/fuzz/ssh_client_fuzzer.cpp @@ -0,0 +1,157 @@ +/* + * Copyright 2019 Andreas Schneider <asn@cryptomilk.org> + * + * 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 "config.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> + +#define LIBSSH_STATIC 1 +#include <libssh/libssh.h> +#include <libssh/priv.h> +#include <libssh/callbacks.h> + +static int auth_callback(UNUSED_PARAM(const char *prompt), + char *buf, + size_t len, + UNUSED_PARAM(int echo), + int verify, + UNUSED_PARAM(void *userdata)) +{ + snprintf(buf, len, "secret"); + + return 0; +} + +struct ssh_callbacks_struct cb = { + .auth_function = auth_callback, + .userdata = NULL, +}; + +static void select_loop(ssh_session session, ssh_channel channel) +{ + ssh_connector connector_in, connector_out, connector_err; + + ssh_event event = ssh_event_new(); + + /* stdin */ + connector_in = ssh_connector_new(session); + ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT); + ssh_connector_set_in_fd(connector_in, 0); + ssh_event_add_connector(event, connector_in); + + /* stdout */ + connector_out = ssh_connector_new(session); + ssh_connector_set_out_fd(connector_out, 1); + ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT); + ssh_event_add_connector(event, connector_out); + + /* stderr */ + connector_err = ssh_connector_new(session); + ssh_connector_set_out_fd(connector_err, 2); + ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR); + ssh_event_add_connector(event, connector_err); + + while (ssh_channel_is_open(channel)) { + ssh_event_dopoll(event, 60000); + } + ssh_event_remove_connector(event, connector_in); + ssh_event_remove_connector(event, connector_out); + ssh_event_remove_connector(event, connector_err); + + ssh_connector_free(connector_in); + ssh_connector_free(connector_out); + ssh_connector_free(connector_err); + + ssh_event_free(event); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + ssh_session session = NULL; + ssh_channel channel = NULL; + char *banner = NULL; + const char *env = NULL; + int socket_fds[2] = {-1, -1}; + ssize_t nwritten; + int rc; + + /* Set up the socket to send data */ + rc = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds); + assert(rc == 0); + + nwritten = send(socket_fds[1], data, size, 0); + assert(nwritten == size); + + rc = shutdown(socket_fds[1], SHUT_WR); + assert(rc == 0); + + ssh_init(); + + session = ssh_new(); + assert(session != NULL); + + env = getenv("LIBSSH_VERBOSITY"); + if (env != NULL && strlen(env) > 0) { + ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY_STR, env); + } + rc = ssh_options_set(session, SSH_OPTIONS_FD, &socket_fds[0]); + assert(rc == 0); + rc = ssh_options_set(session, SSH_OPTIONS_HOST, "127.0.0.1"); + assert(rc == 0); + rc = ssh_options_set(session, SSH_OPTIONS_USER, "alice"); + assert(rc == 0); + + ssh_callbacks_init(&cb); + ssh_set_callbacks(session, &cb); + + rc = ssh_connect(session); + if (rc != SSH_OK) { + goto out; + } + + rc = ssh_userauth_none(session, NULL); + if (rc != SSH_OK) { + goto out; + } + + channel = ssh_channel_new(session); + assert(channel != NULL); + + rc = ssh_channel_open_session(channel); + if (rc != SSH_OK) { + goto out; + } + + rc = ssh_channel_request_exec(channel, "ls"); + assert(rc == SSH_OK); + + select_loop(session, channel); + +out: + ssh_channel_free(channel); + ssh_disconnect(session); + ssh_free(session); + + ssh_finalize(); + + close(socket_fds[0]); + close(socket_fds[1]); + + return 0; +} |