/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 | } |