1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-07-26 14:41:03 +03:00
Files
libssh/tests/unittests/torture_callbacks.c
Diego Roux 46a28cfc49 log: fixes legacy fallback for multiple sessions.
Legacy code in 'ssh_set_callbacks' will fallback to
'ssh_legacy_log_callback' (if the current log cb is
NULL) setting the user data to the current session.

However, if any other session is created afterwards,
it won't update the user data with the new session,
potentially leading to a use-after-free.

Fixes #238.

Signed-off-by: Diego Roux <diegoroux04@protonmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-04-29 08:42:26 +02:00

270 lines
7.1 KiB
C

#include "config.h"
#define LIBSSH_STATIC
#include "torture.h"
#include <errno.h>
#include <libssh/callbacks.h>
#include <libssh/misc.h>
#include <libssh/priv.h>
static int myauthcallback (const char *prompt, char *buf, size_t len,
int echo, int verify, void *userdata) {
(void) prompt;
(void) buf;
(void) len;
(void) echo;
(void) verify;
(void) userdata;
return 0;
}
static int setup(void **state)
{
struct ssh_callbacks_struct *cb;
cb = malloc(sizeof(struct ssh_callbacks_struct));
assert_non_null(cb);
ZERO_STRUCTP(cb);
cb->userdata = (void *) 0x0badc0de;
cb->auth_function = myauthcallback;
ssh_callbacks_init(cb);
*state = cb;
return 0;
}
static int teardown(void **state)
{
free(*state);
return 0;
}
static void torture_callbacks_size(void **state) {
struct ssh_callbacks_struct *cb = *state;
assert_int_not_equal(cb->size, 0);
}
static void torture_callbacks_exists(void **state) {
struct ssh_callbacks_struct *cb = *state;
assert_int_not_equal(ssh_callbacks_exists(cb, auth_function), 0);
assert_int_equal(ssh_callbacks_exists(cb, log_function), 0);
/*
* We redefine size so auth_function is outside the range of
* callbacks->size.
*/
cb->size = (unsigned char *) &cb->auth_function - (unsigned char *) cb;
assert_int_equal(ssh_callbacks_exists(cb, auth_function), 0);
/* Now make it one pointer bigger so we spill over the auth_function slot */
cb->size += sizeof(void *);
assert_int_not_equal(ssh_callbacks_exists(cb, auth_function), 0);
}
struct test_mock_state {
int executed;
};
static void test_mock_ssh_logging_callback(int priority,
const char *function,
const char *buffer,
void *userdata)
{
struct test_mock_state *t = (struct test_mock_state *)userdata;
check_expected(priority);
check_expected(function);
check_expected(buffer);
t->executed++;
}
static void torture_log_callback(void **state)
{
struct test_mock_state t = {
.executed = 0,
};
(void)state; /* unused */
ssh_set_log_callback(test_mock_ssh_logging_callback);
ssh_set_log_userdata(&t);
ssh_set_log_level(1);
expect_value(test_mock_ssh_logging_callback, priority, 1);
expect_string(test_mock_ssh_logging_callback, function, "torture_log_callback");
expect_string(test_mock_ssh_logging_callback, buffer, "torture_log_callback: test");
SSH_LOG(SSH_LOG_WARN, "test");
assert_int_equal(t.executed, 1);
}
static void cb1(ssh_session session, ssh_channel channel, void *userdata){
int *v = userdata;
(void) session;
(void) channel;
*v += 1;
}
static void cb2(ssh_session session, ssh_channel channel, int status, void *userdata){
int *v = userdata;
(void) session;
(void) channel;
(void) status;
*v += 10;
}
static void torture_callbacks_execute_list(void **state){
struct ssh_list *list = ssh_list_new();
int v = 0, w = 0;
struct ssh_channel_callbacks_struct c1 = {
.channel_eof_function = cb1,
.userdata = &v
};
struct ssh_channel_callbacks_struct c2 = {
.channel_exit_status_function = cb2,
.userdata = &v
};
struct ssh_channel_callbacks_struct c3 = {
.channel_eof_function = cb1,
.channel_exit_status_function = cb2,
.userdata = &w
};
(void)state;
assert_non_null(list);
ssh_callbacks_init(&c1);
ssh_callbacks_init(&c2);
ssh_callbacks_init(&c3);
ssh_list_append(list, &c1);
ssh_callbacks_execute_list(list,
ssh_channel_callbacks,
channel_eof_function,
NULL,
NULL);
assert_int_equal(v, 1);
v = 0;
ssh_list_append(list, &c2);
ssh_callbacks_execute_list(list,
ssh_channel_callbacks,
channel_eof_function,
NULL,
NULL);
assert_int_equal(v, 1);
ssh_callbacks_execute_list(list,
ssh_channel_callbacks,
channel_exit_status_function,
NULL,
NULL,
0);
assert_int_equal(v, 11);
v = 0;
w = 0;
ssh_list_append(list, &c3);
ssh_callbacks_execute_list(list,
ssh_channel_callbacks,
channel_eof_function,
NULL,
NULL);
assert_int_equal(v, 1);
assert_int_equal(w, 1);
ssh_callbacks_execute_list(list,
ssh_channel_callbacks,
channel_exit_status_function,
NULL,
NULL,
0);
assert_int_equal(v, 11);
assert_int_equal(w, 11);
ssh_list_free(list);
}
static int cb3(ssh_session session, ssh_channel channel, void *userdata){
int *v = userdata;
(void)session;
(void)channel;
*v = 1;
return 10;
}
static void torture_callbacks_iterate(void **state){
struct ssh_list *list = ssh_list_new();
int v = 0, w = 0;
struct ssh_channel_callbacks_struct c1 = {
.channel_eof_function = cb1,
.channel_shell_request_function = cb3,
.userdata = &v
};
struct ssh_channel_callbacks_struct c2 = {
.channel_eof_function = cb1,
.channel_shell_request_function = cb3,
.userdata = &v
};
(void)state; /* unused */
assert_non_null(list);
ssh_callbacks_init(&c1);
ssh_callbacks_init(&c2);
ssh_list_append(list, &c1);
ssh_list_append(list, &c2);
ssh_callbacks_iterate(list, ssh_channel_callbacks, channel_eof_function){
ssh_callbacks_iterate_exec(channel_eof_function, NULL, NULL);
}
ssh_callbacks_iterate_end();
assert_int_equal(v, 2);
v = 0;
ssh_callbacks_iterate(list, ssh_channel_callbacks, channel_shell_request_function){
w = ssh_callbacks_iterate_exec(channel_shell_request_function, NULL, NULL);
if (w) {
break;
}
}
ssh_callbacks_iterate_end();
assert_int_equal(w, 10);
assert_int_equal(v, 1);
ssh_list_free(list);
}
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(torture_callbacks_size,
setup,
teardown),
cmocka_unit_test_setup_teardown(torture_callbacks_exists,
setup,
teardown),
cmocka_unit_test(torture_log_callback),
cmocka_unit_test(torture_callbacks_execute_list),
cmocka_unit_test(torture_callbacks_iterate),
};
ssh_init();
torture_filter_tests(tests);
rc = cmocka_run_group_tests(tests, NULL, NULL);
ssh_finalize();
return rc;
}