Compare commits

...

6 Commits

Author SHA1 Message Date
Praneeth Sarode
08cbbea461 pki: update RSA key generation to use default size when parameter is 0
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:04:57 +02:00
Praneeth Sarode
8c4e337ab7 pki: define RSA_DEFAULT_KEY_SIZE
Define a new constant for the default RSA key size for consistency.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:04:56 +02:00
Praneeth Sarode
8541b6584f test(buffer): add unit tests for ssh_buffer_dup function
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:04:18 +02:00
Praneeth Sarode
2f77727796 feat(buffer): add ssh_buffer_dup function to duplicate existing buffers
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:04:17 +02:00
Jakub Jelen
a3c5d3b256 tests: Rewrite all fuzzers to LLVMFuzzerInitialize and nalloc
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-09-25 15:03:07 +02:00
Philippe Antoine
59a502ede6 fuzz: test allocations failures
Signed-off-by: Philippe Antoine <p.antoine@catenacyber.fr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:03:04 +02:00
18 changed files with 733 additions and 52 deletions

View File

@@ -74,6 +74,8 @@ ssh_string ssh_buffer_get_ssh_string(ssh_buffer buffer);
uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len); uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len); uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
ssh_buffer ssh_buffer_dup(const ssh_buffer buffer);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -45,7 +45,9 @@
#define MAX_PUBKEY_SIZE 0x100000 /* 1M */ #define MAX_PUBKEY_SIZE 0x100000 /* 1M */
#define MAX_PRIVKEY_SIZE 0x400000 /* 4M */ #define MAX_PRIVKEY_SIZE 0x400000 /* 4M */
#define RSA_MIN_KEY_SIZE 768 #define RSA_MIN_KEY_SIZE 768
#define RSA_DEFAULT_KEY_SIZE 3072
#define SSH_KEY_FLAG_EMPTY 0x0 #define SSH_KEY_FLAG_EMPTY 0x0
#define SSH_KEY_FLAG_PUBLIC 0x0001 #define SSH_KEY_FLAG_PUBLIC 0x0001

View File

@@ -617,6 +617,53 @@ uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
return buffer->used - buffer->pos; return buffer->used - buffer->pos;
} }
/**
* @internal
*
* @brief Duplicate an existing buffer.
*
* Creates a new ssh_buffer and copies all data from the source buffer.
* The new buffer preserves the secure flag setting of the source.
*
* @param[in] buffer The buffer to duplicate. Can be NULL.
*
* @return A new buffer containing a copy of the data on success,
* NULL on failure or if buffer is NULL.
*
* @see ssh_buffer_free()
*/
ssh_buffer ssh_buffer_dup(const ssh_buffer buffer)
{
ssh_buffer new_buffer = NULL;
int rc;
if (buffer == NULL) {
return NULL;
}
buffer_verify(buffer);
new_buffer = ssh_buffer_new();
if (new_buffer == NULL) {
return NULL;
}
new_buffer->secure = buffer->secure;
if (ssh_buffer_get_len(buffer) > 0) {
rc = ssh_buffer_add_data(new_buffer,
ssh_buffer_get(buffer),
ssh_buffer_get_len(buffer));
if (rc != SSH_OK) {
ssh_buffer_free(new_buffer);
return NULL;
}
}
buffer_verify(new_buffer);
return new_buffer;
}
/** /**
* @internal * @internal
* *

View File

@@ -2182,6 +2182,7 @@ int ssh_pki_import_cert_file(const char *filename, ssh_key *pkey)
* *
* @param[in] parameter Parameter to the creation of key: * @param[in] parameter Parameter to the creation of key:
* rsa : length of the key in bits (e.g. 1024, 2048, 4096) * rsa : length of the key in bits (e.g. 1024, 2048, 4096)
* If parameter is 0, then the default size will be used.
* @param[out] pkey A pointer to store the allocated private key. You need * @param[out] pkey A pointer to store the allocated private key. You need
* to free the memory using ssh_key_free(). * to free the memory using ssh_key_free().
* *

View File

@@ -803,6 +803,10 @@ int pki_key_generate_rsa(ssh_key key, int parameter){
unsigned e = 65537; unsigned e = 65537;
#endif /* OPENSSL_VERSION_NUMBER */ #endif /* OPENSSL_VERSION_NUMBER */
if (parameter == 0) {
parameter = RSA_DEFAULT_KEY_SIZE;
}
#if OPENSSL_VERSION_NUMBER < 0x30000000L #if OPENSSL_VERSION_NUMBER < 0x30000000L
e = BN_new(); e = BN_new();
key_rsa = RSA_new(); key_rsa = RSA_new();

View File

@@ -1300,6 +1300,10 @@ pki_key_generate(ssh_key key, int parameter, const char *type_s, int type)
int pki_key_generate_rsa(ssh_key key, int parameter) int pki_key_generate_rsa(ssh_key key, int parameter)
{ {
if (parameter == 0) {
parameter = RSA_DEFAULT_KEY_SIZE;
}
return pki_key_generate(key, parameter, "rsa", SSH_KEYTYPE_RSA); return pki_key_generate(key, parameter, "rsa", SSH_KEYTYPE_RSA);
} }

View File

@@ -564,6 +564,10 @@ int pki_key_generate_rsa(ssh_key key, int parameter)
int rc; int rc;
const mbedtls_pk_info_t *info = NULL; const mbedtls_pk_info_t *info = NULL;
if (parameter == 0) {
parameter = RSA_DEFAULT_KEY_SIZE;
}
key->pk = malloc(sizeof(mbedtls_pk_context)); key->pk = malloc(sizeof(mbedtls_pk_context));
if (key->pk == NULL) { if (key->pk == NULL) {
return SSH_ERROR; return SSH_ERROR;

View File

@@ -10,6 +10,9 @@ macro(fuzzer name)
LINK_FLAGS "-fsanitize=fuzzer") LINK_FLAGS "-fsanitize=fuzzer")
# Run the fuzzer to make sure it works # Run the fuzzer to make sure it works
add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name} -runs=1) add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name} -runs=1)
# Run the fuzzer with nalloc to make sure it works
add_test(${name}_nalloc ${CMAKE_CURRENT_BINARY_DIR}/${name} -runs=1)
set_property(TEST ${name}_nalloc PROPERTY ENVIRONMENT NALLOC_FREQ 32)
else() else()
target_sources(${name} PRIVATE fuzzer.c) target_sources(${name} PRIVATE fuzzer.c)
# Run the fuzzer to make sure it works # Run the fuzzer to make sure it works

344
tests/fuzz/nallocinc.c Normal file
View File

@@ -0,0 +1,344 @@
/*
MIT License
Copyright (c) 2025 Catena cyber
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/* Nalloc fuzz : framework to make allocations and IO fail while fuzzing */
/* Environment variables to control nalloc fuzz behavior :
* NALLOC_VERBOSE: set it to log failed allocations with their stacktraces
* NALLOC_FREQ: set it to control how frequently allocations fail
* value 0 disables nalloc (no allocations fail)
* value 1..31 : allocations fail always (1) or very rarely (31 -> 1 / 2^31)
* value 32 : allocations fail at a random rate between 5 and 20 for each run
*/
#if defined(__clang__) && defined(__has_feature)
#if __has_feature(address_sanitizer)
#define NALLOC_ASAN 1
#endif
#endif
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
static const uint32_t nalloc_crc32_table[] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
// Nallocfuzz data to take a decision
uint32_t nalloc_random_state = 0;
__thread unsigned int nalloc_running = 0;
bool nalloc_initialized = false;
uint32_t nalloc_runs = 0;
// Nalloc fuzz parameters
uint32_t nalloc_bitmask = 0xFF;
bool nalloc_random_bitmask = true;
uint32_t nalloc_magic = 0x294cee63;
bool nalloc_verbose = false;
#ifdef NALLOC_ASAN
extern void __sanitizer_print_stack_trace(void);
#endif
// Generic init, using env variables to get parameters
void nalloc_init(const char *prog)
{
if (nalloc_initialized) {
return;
}
nalloc_initialized = true;
char *bitmask = getenv("NALLOC_FREQ");
if (bitmask) {
int shift = atoi(bitmask);
if (shift > 0 && shift < 31) {
nalloc_bitmask = 1 << shift;
nalloc_random_bitmask = false;
} else if (shift == 0) {
nalloc_random_bitmask = false;
nalloc_bitmask = 0;
}
} else if (prog == NULL || strstr(prog, "nalloc") == NULL) {
nalloc_random_bitmask = false;
nalloc_bitmask = 0;
return;
}
char *verbose = getenv("NALLOC_VERBOSE");
if (verbose) {
nalloc_verbose = true;
}
}
// add one byte to the CRC
static inline void nalloc_random_update(uint8_t b)
{
nalloc_random_state =
((uint32_t)((uint32_t)nalloc_random_state << 8)) ^
nalloc_crc32_table[((nalloc_random_state >> 24) ^ b) & 0xFF];
}
// Start the failure injections, using a buffer as seed
static int nalloc_start(const uint8_t *data, size_t size)
{
if (nalloc_random_bitmask) {
if (nalloc_random_state & 0x10) {
nalloc_bitmask = 0xFFFFFFFF;
} else {
nalloc_bitmask = 1 << (5 + (nalloc_random_state & 0xF));
}
} else if (nalloc_bitmask == 0) {
// nalloc disabled
return 2;
}
nalloc_random_state = 0;
for (size_t i = 0; i < size; i++) {
nalloc_random_update(data[i]);
}
if (__sync_fetch_and_add(&nalloc_running, 1)) {
__sync_fetch_and_sub(&nalloc_running, 1);
return 0;
}
nalloc_runs++;
return 1;
}
// Stop the failure injections
static void nalloc_end()
{
__sync_fetch_and_sub(&nalloc_running, 1);
}
static bool nalloc_backtrace_exclude(size_t size, const char *op)
{
if (nalloc_verbose) {
fprintf(stderr, "failed %s(%zu) \n", op, size);
#ifdef NALLOC_ASAN
__sanitizer_print_stack_trace();
#endif
}
return false;
}
//
static bool nalloc_fail(size_t size, const char *op)
{
// do not fail before thread init
if (nalloc_runs == 0) {
return false;
}
if (__sync_fetch_and_add(&nalloc_running, 1) != 1) {
// do not fail allocations outside of fuzzer input
// and do not fail inside of this function
__sync_fetch_and_sub(&nalloc_running, 1);
return false;
}
nalloc_random_update((uint8_t)size);
if (size >= 0x100) {
nalloc_random_update((uint8_t)(size >> 8));
if (size >= 0x10000) {
nalloc_random_update((uint8_t)(size >> 16));
// bigger may already fail or oom
}
}
if (((nalloc_random_state ^ nalloc_magic) & nalloc_bitmask) == 0) {
if (nalloc_backtrace_exclude(size, op)) {
__sync_fetch_and_sub(&nalloc_running, 1);
return false;
}
__sync_fetch_and_sub(&nalloc_running, 1);
return true;
}
__sync_fetch_and_sub(&nalloc_running, 1);
return false;
}
// ASAN interceptor for libc routines
#ifdef NALLOC_ASAN
extern void *__interceptor_malloc(size_t);
extern void *__interceptor_calloc(size_t, size_t);
extern void *__interceptor_realloc(void *, size_t);
extern void *__interceptor_reallocarray(void *, size_t, size_t);
extern ssize_t __interceptor_read(int, void *, size_t);
extern ssize_t __interceptor_write(int, const void *, size_t);
extern ssize_t __interceptor_recv(int, void *, size_t, int);
extern ssize_t __interceptor_send(int, const void *, size_t, int);
#define nalloc_malloc(s) __interceptor_malloc(s)
#define nalloc_calloc(s, n) __interceptor_calloc(s, n)
#define nalloc_realloc(p, s) __interceptor_realloc(p, s)
#define nalloc_reallocarray(p, s, n) __interceptor_reallocarray(p, s, n)
#define nalloc_read(f, b, s) __interceptor_read(f, b, s)
#define nalloc_write(f, b, s) __interceptor_write(f, b, s)
#define nalloc_recv(f, b, s, x) __interceptor_recv(f, b, s, x)
#define nalloc_send(f, b, s, x) __interceptor_send(f, b, s, x)
#else
extern void *__libc_malloc(size_t);
extern void *__libc_calloc(size_t, size_t);
extern void *__libc_realloc(void *, size_t);
extern void *__libc_reallocarray(void *, size_t, size_t);
extern ssize_t __read(int, void *, size_t);
extern ssize_t __write(int, const void *, size_t);
extern ssize_t __recv(int, void *, size_t, int);
extern ssize_t __send(int, const void *, size_t, int);
#define nalloc_malloc(s) __libc_malloc(s)
#define nalloc_calloc(s, n) __libc_calloc(s, n)
#define nalloc_realloc(p, s) __libc_realloc(p, s)
#define nalloc_reallocarray(p, s, n) __libc_reallocarray(p, s, n)
#define nalloc_read(f, b, s) __read(f, b, s)
#define nalloc_write(f, b, s) __write(f, b, s)
#define nalloc_recv(f, b, s, x) __recv(f, b, s, x)
#define nalloc_send(f, b, s, x) __send(f, b, s, x)
#endif
// nalloc standard function overwrites with pseudo-random failures
ssize_t read(int fd, void *buf, size_t count)
{
if (nalloc_fail(count, "read")) {
errno = EIO;
return -1;
}
return nalloc_read(fd, buf, count);
}
ssize_t write(int fd, const void *buf, size_t count)
{
if (nalloc_fail(count, "write")) {
errno = EIO;
return -1;
}
return nalloc_write(fd, buf, count);
}
ssize_t recv(int fd, void *buf, size_t count, int flags)
{
if (nalloc_fail(count, "recv")) {
errno = EIO;
return -1;
}
return nalloc_recv(fd, buf, count, flags);
}
ssize_t send(int fd, const void *buf, size_t count, int flags)
{
if (nalloc_fail(count, "send")) {
errno = EIO;
return -1;
}
return nalloc_send(fd, buf, count, flags);
}
void *calloc(size_t nmemb, size_t size)
{
if (nalloc_fail(size, "calloc")) {
errno = ENOMEM;
return NULL;
}
return nalloc_calloc(nmemb, size);
}
void *malloc(size_t size)
{
if (nalloc_fail(size, "malloc")) {
errno = ENOMEM;
return NULL;
}
return nalloc_malloc(size);
}
void *realloc(void *ptr, size_t size)
{
if (nalloc_fail(size, "realloc")) {
errno = ENOMEM;
return NULL;
}
return nalloc_realloc(ptr, size);
}
void *reallocarray(void *ptr, size_t nmemb, size_t size)
{
if (nalloc_fail(size, "reallocarray")) {
errno = ENOMEM;
return NULL;
}
return nalloc_reallocarray(ptr, nmemb, size);
}
#ifdef __cplusplus
} // extern "C" {
#endif

View File

@@ -24,6 +24,26 @@
#include "libssh/server.h" #include "libssh/server.h"
#include "libssh/bind_config.h" #include "libssh/bind_config.h"
#include "nallocinc.c"
static void _fuzz_finalize(void)
{
ssh_finalize();
}
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
(void)argc;
nalloc_init(*argv[0]);
ssh_init();
atexit(_fuzz_finalize);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{ {
ssh_bind bind = NULL; ssh_bind bind = NULL;
@@ -36,17 +56,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
strncpy(input, (const char *)data, size); strncpy(input, (const char *)data, size);
input[size] = '\0'; input[size] = '\0';
ssh_init(); assert(nalloc_start(data, size) > 0);
bind = ssh_bind_new(); bind = ssh_bind_new();
assert(bind != NULL); if (bind == NULL) {
goto out;
}
ssh_bind_config_parse_string(bind, input); ssh_bind_config_parse_string(bind, input);
ssh_bind_free(bind); ssh_bind_free(bind);
ssh_finalize();
out:
free(input); free(input);
nalloc_end();
return 0; return 0;
} }

View File

@@ -23,6 +23,26 @@
#include "libssh/libssh.h" #include "libssh/libssh.h"
#include "libssh/options.h" #include "libssh/options.h"
#include "nallocinc.c"
static void _fuzz_finalize(void)
{
ssh_finalize();
}
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
(void)argc;
nalloc_init(*argv[0]);
ssh_init();
atexit(_fuzz_finalize);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{ {
ssh_session session = NULL; ssh_session session = NULL;
@@ -35,10 +55,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
strncpy(input, (const char *)data, size); strncpy(input, (const char *)data, size);
input[size] = '\0'; input[size] = '\0';
ssh_init(); assert(nalloc_start(data, size) > 0);
session = ssh_new(); session = ssh_new();
assert(session != NULL); if (session == NULL) {
goto out;
}
/* Make sure we have default options set */ /* Make sure we have default options set */
ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL); ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
@@ -47,9 +69,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
ssh_config_parse_string(session, input); ssh_config_parse_string(session, input);
ssh_free(session); ssh_free(session);
ssh_finalize();
out:
free(input); free(input);
nalloc_end();
return 0; return 0;
} }

View File

@@ -24,6 +24,26 @@
#include <libssh/libssh.h> #include <libssh/libssh.h>
#include <libssh/callbacks.h> #include <libssh/callbacks.h>
#include "nallocinc.c"
static void _fuzz_finalize(void)
{
ssh_finalize();
}
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
(void)argc;
nalloc_init(*argv[0]);
ssh_init();
atexit(_fuzz_finalize);
return 0;
}
static int auth_callback(const char *prompt, static int auth_callback(const char *prompt,
char *buf, char *buf,
size_t len, size_t len,
@@ -113,33 +133,53 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
rc = shutdown(socket_fds[1], SHUT_WR); rc = shutdown(socket_fds[1], SHUT_WR);
assert(rc == 0); assert(rc == 0);
ssh_init(); assert(nalloc_start(data, size) > 0);
session = ssh_new(); session = ssh_new();
assert(session != NULL); if (session == NULL) {
goto out;
}
env = getenv("LIBSSH_VERBOSITY"); env = getenv("LIBSSH_VERBOSITY");
if (env != NULL && strlen(env) > 0) { if (env != NULL && strlen(env) > 0) {
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY_STR, env); ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY_STR, env);
} }
rc = ssh_options_set(session, SSH_OPTIONS_FD, &socket_fds[0]); rc = ssh_options_set(session, SSH_OPTIONS_FD, &socket_fds[0]);
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "127.0.0.1"); rc = ssh_options_set(session, SSH_OPTIONS_HOST, "127.0.0.1");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_USER, "alice"); rc = ssh_options_set(session, SSH_OPTIONS_USER, "alice");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, "none"); rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, "none");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, "none"); rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, "none");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, "none"); rc = ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, "none");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, "none"); rc = ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, "none");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &no); rc = ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &no);
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &timeout); rc = ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &timeout);
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
ssh_callbacks_init(&cb); ssh_callbacks_init(&cb);
ssh_set_callbacks(session, &cb); ssh_set_callbacks(session, &cb);
@@ -176,10 +216,9 @@ out:
ssh_disconnect(session); ssh_disconnect(session);
ssh_free(session); ssh_free(session);
ssh_finalize();
close(socket_fds[0]); close(socket_fds[0]);
close(socket_fds[1]); close(socket_fds[1]);
nalloc_end();
return 0; return 0;
} }

View File

@@ -23,6 +23,26 @@
#include "libssh/libssh.h" #include "libssh/libssh.h"
#include "knownhosts.c" #include "knownhosts.c"
#include "nallocinc.c"
static void _fuzz_finalize(void)
{
ssh_finalize();
}
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
(void)argc;
nalloc_init(*argv[0]);
ssh_init();
atexit(_fuzz_finalize);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{ {
char *hostname = NULL; char *hostname = NULL;
@@ -59,7 +79,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
fwrite(data + hostname_len, size - hostname_len, 1, fp); fwrite(data + hostname_len, size - hostname_len, 1, fp);
fclose(fp); fclose(fp);
ssh_init(); assert(nalloc_start(data, size) > 0);
ssh_known_hosts_read_entries(hostname, filename, &entries); ssh_known_hosts_read_entries(hostname, filename, &entries);
for (it = ssh_list_get_iterator(entries); for (it = ssh_list_get_iterator(entries);
@@ -78,5 +98,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
free(hostname); free(hostname);
unlink(filename); unlink(filename);
nalloc_end();
return 0; return 0;
} }

View File

@@ -25,28 +25,48 @@
#include "libssh/libssh.h" #include "libssh/libssh.h"
#include "libssh/priv.h" #include "libssh/priv.h"
#include "nallocinc.c"
static void _fuzz_finalize(void)
{
ssh_finalize();
}
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
(void)argc;
nalloc_init(*argv[0]);
ssh_init();
atexit(_fuzz_finalize);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{ {
ssh_key pkey = NULL; ssh_key pkey = NULL;
uint8_t *input = NULL; uint8_t *input = NULL;
int rc; int rc;
assert(nalloc_start(data, size) > 0);
input = bin_to_base64(data, size); input = bin_to_base64(data, size);
if (input == NULL) { if (input == NULL) {
return 1; goto out;
} }
ssh_init();
rc = ssh_pki_import_privkey_base64((char *)input, NULL, NULL, NULL, &pkey); rc = ssh_pki_import_privkey_base64((char *)input, NULL, NULL, NULL, &pkey);
free(input); free(input);
if (rc != SSH_OK) { if (rc != SSH_OK) {
return 1; goto out;
} }
ssh_key_free(pkey); ssh_key_free(pkey);
ssh_finalize(); out:
nalloc_end();
return 0; return 0;
} }

View File

@@ -15,6 +15,7 @@
*/ */
#include "config.h" #include "config.h"
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -23,6 +24,26 @@
#include "libssh/libssh.h" #include "libssh/libssh.h"
#include "libssh/misc.h" #include "libssh/misc.h"
#include "nallocinc.c"
static void _fuzz_finalize(void)
{
ssh_finalize();
}
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
(void)argc;
nalloc_init(*argv[0]);
ssh_init();
atexit(_fuzz_finalize);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{ {
ssh_key pkey = NULL; ssh_key pkey = NULL;
@@ -31,8 +52,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
int rc; int rc;
ssize_t sz; ssize_t sz;
ssh_init();
filename = strdup("/tmp/libssh_pubkey_XXXXXX"); filename = strdup("/tmp/libssh_pubkey_XXXXXX");
if (filename == NULL) { if (filename == NULL) {
return -1; return -1;
@@ -51,18 +70,18 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
return -1; return -1;
} }
assert(nalloc_start(data, size) > 0);
rc = ssh_pki_import_pubkey_file(filename, &pkey); rc = ssh_pki_import_pubkey_file(filename, &pkey);
if (rc != SSH_OK) { if (rc != SSH_OK) {
unlink(filename); goto out;
free(filename);
return 1;
} }
ssh_key_free(pkey); ssh_key_free(pkey);
out:
unlink(filename); unlink(filename);
free(filename); free(filename);
nalloc_end();
ssh_finalize();
return 0; return 0;
} }

View File

@@ -31,6 +31,8 @@
#include <libssh/callbacks.h> #include <libssh/callbacks.h>
#include <libssh/server.h> #include <libssh/server.h>
#include "nallocinc.c"
static const char kRSAPrivateKeyPEM[] = static const char kRSAPrivateKeyPEM[] =
"-----BEGIN RSA PRIVATE KEY-----\n" "-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEowIBAAKCAQEArAOREUWlBXJAKZ5hABYyxnRayDZP1bJeLbPVK+npxemrhHyZ\n" "MIIEowIBAAKCAQEArAOREUWlBXJAKZ5hABYyxnRayDZP1bJeLbPVK+npxemrhHyZ\n"
@@ -68,6 +70,24 @@ struct session_data_struct {
bool authenticated; bool authenticated;
}; };
static void _fuzz_finalize(void)
{
ssh_finalize();
}
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
(void)argc;
nalloc_init(*argv[0]);
ssh_init();
atexit(_fuzz_finalize);
return 0;
}
static int auth_none(ssh_session session, const char *user, void *userdata) static int auth_none(ssh_session session, const char *user, void *userdata)
{ {
struct session_data_struct *sdata = struct session_data_struct *sdata =
@@ -125,6 +145,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
bool no = false; bool no = false;
const char *env = NULL; const char *env = NULL;
int rc; int rc;
ssh_bind sshbind = NULL;
ssh_session session = NULL;
ssh_event event = NULL;
/* Our struct holding information about the session. */ /* Our struct holding information about the session. */
struct session_data_struct sdata = { struct session_data_struct sdata = {
@@ -161,35 +184,54 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
rc = shutdown(socket_fds[1], SHUT_WR); rc = shutdown(socket_fds[1], SHUT_WR);
assert(rc == 0); assert(rc == 0);
assert(nalloc_start(data, size) > 0);
/* Set up the libssh server */ /* Set up the libssh server */
ssh_bind sshbind = ssh_bind_new(); sshbind = ssh_bind_new();
assert(sshbind != NULL); if (sshbind == NULL) {
goto out;
ssh_session session = ssh_new(); }
assert(session != NULL);
session = ssh_new();
if (session == NULL) {
goto out;
}
env = getenv("LIBSSH_VERBOSITY"); env = getenv("LIBSSH_VERBOSITY");
if (env != NULL && strlen(env) > 0) { if (env != NULL && strlen(env) > 0) {
rc = ssh_bind_options_set(sshbind, rc = ssh_bind_options_set(sshbind,
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
env); env);
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
} }
rc = ssh_bind_options_set(sshbind, rc = ssh_bind_options_set(sshbind,
SSH_BIND_OPTIONS_HOSTKEY, SSH_BIND_OPTIONS_HOSTKEY,
"/tmp/libssh_fuzzer_private_key"); "/tmp/libssh_fuzzer_private_key");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_CIPHERS_C_S, "none"); rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_CIPHERS_C_S, "none");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_CIPHERS_S_C, "none"); rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_CIPHERS_S_C, "none");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HMAC_C_S, "none"); rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HMAC_C_S, "none");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HMAC_S_C, "none"); rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HMAC_S_C, "none");
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_PROCESS_CONFIG, &no); rc = ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_PROCESS_CONFIG, &no);
assert(rc == 0); if (rc != SSH_OK) {
goto out;
}
ssh_set_auth_methods(session, SSH_AUTH_METHOD_NONE); ssh_set_auth_methods(session, SSH_AUTH_METHOD_NONE);
@@ -197,10 +239,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
ssh_set_server_callbacks(session, &server_cb); ssh_set_server_callbacks(session, &server_cb);
rc = ssh_bind_accept_fd(sshbind, session, socket_fds[0]); rc = ssh_bind_accept_fd(sshbind, session, socket_fds[0]);
assert(rc == SSH_OK); if (rc != SSH_OK) {
goto out;
}
ssh_event event = ssh_event_new(); event = ssh_event_new();
assert(event != NULL); if (event == NULL) {
goto out;
}
if (ssh_handle_key_exchange(session) == SSH_OK) { if (ssh_handle_key_exchange(session) == SSH_OK) {
ssh_event_add_session(event, session); ssh_event_add_session(event, session);
@@ -219,6 +265,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
} }
} }
out:
nalloc_end();
ssh_event_free(event); ssh_event_free(event);
close(socket_fds[0]); close(socket_fds[0]);

View File

@@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -21,6 +22,8 @@
#define LIBSSH_STATIC 1 #define LIBSSH_STATIC 1
#include "libssh/libssh.h" #include "libssh/libssh.h"
#include "nallocinc.c"
static void _fuzz_finalize(void) static void _fuzz_finalize(void)
{ {
ssh_finalize(); ssh_finalize();
@@ -29,7 +32,8 @@ static void _fuzz_finalize(void)
int LLVMFuzzerInitialize(int *argc, char ***argv) int LLVMFuzzerInitialize(int *argc, char ***argv)
{ {
(void)argc; (void)argc;
(void)argv;
nalloc_init(*argv[0]);
ssh_init(); ssh_init();
@@ -46,9 +50,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
char *signature = NULL; char *signature = NULL;
int rc; int rc;
assert(nalloc_start(data, size) > 0);
signature = (char *)malloc(size + 1); signature = (char *)malloc(size + 1);
if (signature == NULL) { if (signature == NULL) {
return 1; goto out;
} }
strncpy(signature, (const char *)data, size); strncpy(signature, (const char *)data, size);
signature[size] = '\0'; signature[size] = '\0';
@@ -56,9 +62,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
rc = sshsig_verify(input, sizeof(input), signature, namespace, &pkey); rc = sshsig_verify(input, sizeof(input), signature, namespace, &pkey);
free(signature); free(signature);
if (rc != SSH_OK) { if (rc != SSH_OK) {
return 1; goto out;
} }
ssh_key_free(pkey); ssh_key_free(pkey);
out:
nalloc_end();
return 0; return 0;
} }

View File

@@ -6,6 +6,8 @@
#define DEBUG_BUFFER #define DEBUG_BUFFER
#include "buffer.c" #include "buffer.c"
#include <string.h>
#define LIMIT (8*1024*1024) #define LIMIT (8*1024*1024)
static int setup(void **state) { static int setup(void **state) {
@@ -300,6 +302,69 @@ static void torture_ssh_buffer_bignum(void **state)
SSH_BUFFER_FREE(buffer); SSH_BUFFER_FREE(buffer);
} }
static void torture_ssh_buffer_dup(void **state)
{
ssh_buffer buffer = *state;
ssh_buffer dup_buffer = NULL;
ssh_buffer null_buffer = NULL;
const char *test_data = "test data";
size_t test_data_len = strlen(test_data);
int rc;
/* test NULL buffer */
dup_buffer = ssh_buffer_dup(NULL);
assert_null(dup_buffer);
/* test empty buffer */
dup_buffer = ssh_buffer_dup(buffer);
assert_non_null(dup_buffer);
assert_int_equal(ssh_buffer_get_len(dup_buffer), 0);
assert_true(dup_buffer->secure);
SSH_BUFFER_FREE(dup_buffer);
/* test buffer with data */
rc = ssh_buffer_add_data(buffer, test_data, test_data_len);
assert_int_equal(rc, SSH_OK);
dup_buffer = ssh_buffer_dup(buffer);
assert_non_null(dup_buffer);
assert_int_equal(ssh_buffer_get_len(dup_buffer), test_data_len);
assert_memory_equal(ssh_buffer_get(dup_buffer), test_data, test_data_len);
assert_true(dup_buffer->secure);
/* test independence of buffers - modify original buffer */
rc = ssh_buffer_add_data(buffer, " more data", 10);
assert_int_equal(rc, SSH_OK);
assert_int_equal(ssh_buffer_get_len(buffer), test_data_len + 10);
assert_int_equal(ssh_buffer_get_len(dup_buffer), test_data_len);
/* test independence of buffers - modify duplicated buffer */
rc = ssh_buffer_add_data(dup_buffer, " different", 10);
assert_int_equal(rc, SSH_OK);
assert_int_equal(ssh_buffer_get_len(dup_buffer), test_data_len + 10);
assert_int_equal(ssh_buffer_get_len(buffer), test_data_len + 10);
assert_memory_not_equal(ssh_buffer_get(buffer),
ssh_buffer_get(dup_buffer),
test_data_len + 10);
SSH_BUFFER_FREE(dup_buffer);
/* test duplicating non-secure buffer */
null_buffer = ssh_buffer_new();
assert_non_null(null_buffer);
rc = ssh_buffer_add_data(null_buffer, "non-secure data", 15);
assert_int_equal(rc, SSH_OK);
dup_buffer = ssh_buffer_dup(null_buffer);
assert_non_null(dup_buffer);
assert_int_equal(ssh_buffer_get_len(dup_buffer), 15);
assert_memory_equal(ssh_buffer_get(dup_buffer), "non-secure data", 15);
assert_false(dup_buffer->secure);
SSH_BUFFER_FREE(dup_buffer);
SSH_BUFFER_FREE(null_buffer);
}
int torture_run_tests(void) { int torture_run_tests(void) {
int rc; int rc;
struct CMUnitTest tests[] = { struct CMUnitTest tests[] = {
@@ -326,6 +391,9 @@ int torture_run_tests(void) {
setup, setup,
teardown), teardown),
cmocka_unit_test(torture_ssh_buffer_bignum), cmocka_unit_test(torture_ssh_buffer_bignum),
cmocka_unit_test_setup_teardown(torture_ssh_buffer_dup,
setup,
teardown),
}; };
ssh_init(); ssh_init();