diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt index 9cc88616..6026600c 100644 --- a/tests/fuzz/CMakeLists.txt +++ b/tests/fuzz/CMakeLists.txt @@ -23,3 +23,4 @@ fuzzer(ssh_client_fuzzer) fuzzer(ssh_server_fuzzer) fuzzer(ssh_client_config_fuzzer) fuzzer(ssh_bind_config_fuzzer) +fuzzer(ssh_known_hosts_fuzzer) diff --git a/tests/fuzz/ssh_known_hosts_fuzzer.c b/tests/fuzz/ssh_known_hosts_fuzzer.c new file mode 100644 index 00000000..fabdc28f --- /dev/null +++ b/tests/fuzz/ssh_known_hosts_fuzzer.c @@ -0,0 +1,82 @@ +/* + * Copyright 2022 Jakub Jelen + * + * 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 +#include +#include +#include + +#define LIBSSH_STATIC 1 +#include "libssh/libssh.h" +#include "knownhosts.c" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char *hostname = NULL; + const uint8_t *hostname_end = NULL; + size_t hostname_len = 0; + char filename[256]; + struct ssh_list *entries = NULL; + struct ssh_iterator *it = NULL; + FILE *fp = NULL; + + /* Interpret the first part of the string (until the first NULL byte) + * as a hostname we are searching for in the file */ + hostname_end = memchr(data, '\0', size); + if (hostname_end == NULL) { + return 1; + } + hostname_len = hostname_end - data + 1; + if (hostname_len > 253) { + /* This is the maximum valid length of a hostname */ + return 1; + } + hostname = malloc(hostname_len); + if (hostname == NULL) { + return 1; + } + memcpy(hostname, data, hostname_len); + + snprintf(filename, sizeof(filename), "/tmp/libfuzzer.%d", getpid()); + fp = fopen(filename, "wb"); + if (!fp) { + free(hostname); + return 1; + } + fwrite(data + hostname_len, size - hostname_len, 1, fp); + fclose(fp); + + ssh_init(); + + ssh_known_hosts_read_entries(hostname, filename, &entries); + for (it = ssh_list_get_iterator(entries); + it != NULL; + it = ssh_list_get_iterator(entries)) { + struct ssh_knownhosts_entry *entry = NULL; + + entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it); + ssh_knownhosts_entry_free(entry); + ssh_list_remove(entries, it); + } + ssh_list_free(entries); + + ssh_finalize(); + + free(hostname); + unlink(filename); + + return 0; +} diff --git a/tests/fuzz/ssh_known_hosts_fuzzer_corpus/d7c0eade3f3b70d94b1a7090e09eb8607da0ace4 b/tests/fuzz/ssh_known_hosts_fuzzer_corpus/d7c0eade3f3b70d94b1a7090e09eb8607da0ace4 new file mode 100644 index 00000000..18e779e0 Binary files /dev/null and b/tests/fuzz/ssh_known_hosts_fuzzer_corpus/d7c0eade3f3b70d94b1a7090e09eb8607da0ace4 differ