Coverage Report

Created: 2025-07-04 06:59

/src/libssh/tests/fuzz/ssh_client_fuzzer.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019 Andreas Schneider <asn@cryptomilk.org>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <assert.h>
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <signal.h>
21
#include <stdbool.h>
22
23
#define LIBSSH_STATIC 1
24
#include <libssh/libssh.h>
25
#include <libssh/callbacks.h>
26
27
static int auth_callback(const char *prompt,
28
                         char *buf,
29
                         size_t len,
30
                         int echo,
31
                         int verify,
32
                         void *userdata)
33
0
{
34
0
    (void)prompt;   /* unused */
35
0
    (void)echo;     /* unused */
36
0
    (void)verify;   /* unused */
37
0
    (void)userdata; /* unused */
38
39
0
    snprintf(buf, len, "secret");
40
41
0
    return 0;
42
0
}
43
44
struct ssh_callbacks_struct cb = {
45
    .userdata = NULL,
46
    .auth_function = auth_callback,
47
};
48
49
static void select_loop(ssh_session session, ssh_channel channel)
50
0
{
51
0
    ssh_connector connector_in, connector_out, connector_err;
52
53
0
    ssh_event event = ssh_event_new();
54
55
    /* stdin */
56
0
    connector_in = ssh_connector_new(session);
57
0
    ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
58
0
    ssh_connector_set_in_fd(connector_in, 0);
59
0
    ssh_event_add_connector(event, connector_in);
60
61
    /* stdout */
62
0
    connector_out = ssh_connector_new(session);
63
0
    ssh_connector_set_out_fd(connector_out, 1);
64
0
    ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
65
0
    ssh_event_add_connector(event, connector_out);
66
67
    /* stderr */
68
0
    connector_err = ssh_connector_new(session);
69
0
    ssh_connector_set_out_fd(connector_err, 2);
70
0
    ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
71
0
    ssh_event_add_connector(event, connector_err);
72
73
0
    while (ssh_channel_is_open(channel)) {
74
0
        ssh_event_dopoll(event, 60000);
75
0
    }
76
0
    ssh_event_remove_connector(event, connector_in);
77
0
    ssh_event_remove_connector(event, connector_out);
78
0
    ssh_event_remove_connector(event, connector_err);
79
80
0
    ssh_connector_free(connector_in);
81
0
    ssh_connector_free(connector_out);
82
0
    ssh_connector_free(connector_err);
83
84
0
    ssh_event_free(event);
85
0
}
86
87
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
88
3.49k
{
89
3.49k
    ssh_session session = NULL;
90
3.49k
    ssh_channel channel = NULL;
91
3.49k
    const char *env = NULL;
92
3.49k
    int socket_fds[2] = {-1, -1};
93
3.49k
    ssize_t nwritten;
94
3.49k
    bool no = false;
95
3.49k
    int rc;
96
3.49k
    long timeout = 1; /* use short timeout to avoid timeouts during fuzzing */
97
98
    /* This is the maximum that can be handled by the socket buffer before the
99
     * other side will read some data. Other option would be feeding the socket
100
     * from different thread which would not mind if it would be blocked, but I
101
     * believe all the important inputs should fit into this size */
102
3.49k
    if (size > 219264) {
103
1
        return -1;
104
1
    }
105
106
    /* Set up the socket to send data */
107
3.49k
    rc = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds);
108
3.49k
    assert(rc == 0);
109
110
3.49k
    nwritten = send(socket_fds[1], data, size, 0);
111
3.49k
    assert((size_t)nwritten == size);
112
113
3.49k
    rc = shutdown(socket_fds[1], SHUT_WR);
114
3.49k
    assert(rc == 0);
115
116
3.49k
    ssh_init();
117
118
3.49k
    session = ssh_new();
119
3.49k
    assert(session != NULL);
120
121
3.49k
    env = getenv("LIBSSH_VERBOSITY");
122
3.49k
    if (env != NULL && strlen(env) > 0) {
123
0
        ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY_STR, env);
124
0
    }
125
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_FD, &socket_fds[0]);
126
3.49k
    assert(rc == 0);
127
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_HOST, "127.0.0.1");
128
3.49k
    assert(rc == 0);
129
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_USER, "alice");
130
3.49k
    assert(rc == 0);
131
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, "none");
132
3.49k
    assert(rc == 0);
133
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, "none");
134
3.49k
    assert(rc == 0);
135
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, "none");
136
3.49k
    assert(rc == 0);
137
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, "none");
138
3.49k
    assert(rc == 0);
139
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &no);
140
3.49k
    assert(rc == 0);
141
3.49k
    rc = ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &timeout);
142
3.49k
    assert(rc == 0);
143
144
3.49k
    ssh_callbacks_init(&cb);
145
3.49k
    ssh_set_callbacks(session, &cb);
146
147
3.49k
    rc = ssh_connect(session);
148
3.49k
    if (rc != SSH_OK) {
149
3.48k
        goto out;
150
3.48k
    }
151
152
8
    rc = ssh_userauth_none(session, NULL);
153
8
    if (rc != SSH_OK) {
154
8
        goto out;
155
8
    }
156
157
0
    channel = ssh_channel_new(session);
158
0
    if (channel == NULL) {
159
0
        goto out;
160
0
    }
161
162
0
    rc = ssh_channel_open_session(channel);
163
0
    if (rc != SSH_OK) {
164
0
        goto out;
165
0
    }
166
167
0
    rc = ssh_channel_request_exec(channel, "ls");
168
0
    if (rc != SSH_OK) {
169
0
        goto out;
170
0
    }
171
172
0
    select_loop(session, channel);
173
174
3.49k
out:
175
3.49k
    ssh_channel_free(channel);
176
3.49k
    ssh_disconnect(session);
177
3.49k
    ssh_free(session);
178
179
3.49k
    ssh_finalize();
180
181
3.49k
    close(socket_fds[0]);
182
3.49k
    close(socket_fds[1]);
183
184
3.49k
    return 0;
185
0
}