1 #include "includes.h"
2 
3 #include "includes.h"
4 #include "fuzz.h"
5 #include "dbutil.h"
6 #include "runopts.h"
7 #include "crypto_desc.h"
8 #include "session.h"
9 #include "dbrandom.h"
10 #include "bignum.h"
11 #include "atomicio.h"
12 #include "fuzz-wrapfd.h"
13 
14 struct dropbear_fuzz_options fuzz;
15 
16 static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param);
17 static void load_fixed_hostkeys(void);
18 static void load_fixed_client_key(void);
19 
fuzz_common_setup(void)20 void fuzz_common_setup(void) {
21 	disallow_core();
22     fuzz.fuzzing = 1;
23     fuzz.wrapfds = 1;
24     fuzz.do_jmp = 1;
25     fuzz.input = m_malloc(sizeof(buffer));
26     _dropbear_log = fuzz_dropbear_log;
27     crypto_init();
28     fuzz_seed();
29     /* let any messages get flushed */
30     setlinebuf(stdout);
31 }
32 
fuzz_set_input(const uint8_t * Data,size_t Size)33 int fuzz_set_input(const uint8_t *Data, size_t Size) {
34 
35     fuzz.input->data = (unsigned char*)Data;
36     fuzz.input->size = Size;
37     fuzz.input->len = Size;
38     fuzz.input->pos = 0;
39 
40     memset(&ses, 0x0, sizeof(ses));
41     memset(&svr_ses, 0x0, sizeof(svr_ses));
42     memset(&cli_ses, 0x0, sizeof(cli_ses));
43     wrapfd_setup(fuzz.input);
44 
45     fuzz_seed();
46 
47     return DROPBEAR_SUCCESS;
48 }
49 
50 #if DEBUG_TRACE
fuzz_dropbear_log(int UNUSED (priority),const char * format,va_list param)51 static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
52     if (debug_trace) {
53         char printbuf[1024];
54         vsnprintf(printbuf, sizeof(printbuf), format, param);
55         fprintf(stderr, "%s\n", printbuf);
56     }
57 }
58 #else
fuzz_dropbear_log(int UNUSED (priority),const char * UNUSED (format),va_list UNUSED (param))59 static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
60     /* No print */
61 }
62 #endif /* DEBUG_TRACE */
63 
fuzz_svr_setup(void)64 void fuzz_svr_setup(void) {
65     fuzz_common_setup();
66 
67     _dropbear_exit = svr_dropbear_exit;
68 
69     char *argv[] = {
70 		"dropbear",
71         "-E",
72     };
73 
74     int argc = sizeof(argv) / sizeof(*argv);
75     svr_getopts(argc, argv);
76 
77     load_fixed_hostkeys();
78 }
79 
fuzz_cli_setup(void)80 void fuzz_cli_setup(void) {
81     fuzz_common_setup();
82 
83 	_dropbear_exit = cli_dropbear_exit;
84 	_dropbear_log = cli_dropbear_log;
85 
86     char *argv[] = {
87 		"dbclient",
88 		"-y",
89         "localhost",
90         "uptime"
91     };
92 
93     int argc = sizeof(argv) / sizeof(*argv);
94     cli_getopts(argc, argv);
95 
96     load_fixed_client_key();
97     /* Avoid password prompt */
98     setenv(DROPBEAR_PASSWORD_ENV, "password", 1);
99 }
100 
101 #include "fuzz-hostkeys.c"
102 
load_fixed_client_key(void)103 static void load_fixed_client_key(void) {
104 
105     buffer *b = buf_new(3000);
106     sign_key *key;
107     enum signkey_type keytype;
108 
109     key = new_sign_key();
110     keytype = DROPBEAR_SIGNKEY_ANY;
111     buf_putbytes(b, keyed25519, keyed25519_len);
112     buf_setpos(b, 0);
113     if (buf_get_priv_key(b, key, &keytype) == DROPBEAR_FAILURE) {
114         dropbear_exit("failed fixed ed25519 hostkey");
115     }
116     list_append(cli_opts.privkeys, key);
117 
118     buf_free(b);
119 }
120 
load_fixed_hostkeys(void)121 static void load_fixed_hostkeys(void) {
122 
123     buffer *b = buf_new(3000);
124     enum signkey_type type;
125 
126     TRACE(("load fixed hostkeys"))
127 
128     svr_opts.hostkey = new_sign_key();
129 
130     buf_setlen(b, 0);
131     buf_putbytes(b, keyr, keyr_len);
132     buf_setpos(b, 0);
133     type = DROPBEAR_SIGNKEY_RSA;
134     if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
135         dropbear_exit("failed fixed rsa hostkey");
136     }
137 
138     buf_setlen(b, 0);
139     buf_putbytes(b, keyd, keyd_len);
140     buf_setpos(b, 0);
141     type = DROPBEAR_SIGNKEY_DSS;
142     if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
143         dropbear_exit("failed fixed dss hostkey");
144     }
145 
146     buf_setlen(b, 0);
147     buf_putbytes(b, keye, keye_len);
148     buf_setpos(b, 0);
149     type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
150     if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
151         dropbear_exit("failed fixed ecdsa hostkey");
152     }
153 
154     buf_setlen(b, 0);
155     buf_putbytes(b, keyed25519, keyed25519_len);
156     buf_setpos(b, 0);
157     type = DROPBEAR_SIGNKEY_ED25519;
158     if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
159         dropbear_exit("failed fixed ed25519 hostkey");
160     }
161 
162     buf_free(b);
163 }
164 
fuzz_kex_fakealgos(void)165 void fuzz_kex_fakealgos(void) {
166     ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
167 }
168 
fuzz_get_socket_address(int UNUSED (fd),char ** local_host,char ** local_port,char ** remote_host,char ** remote_port,int UNUSED (host_lookup))169 void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
170                         char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
171     if (local_host) {
172         *local_host = m_strdup("fuzzlocalhost");
173     }
174     if (local_port) {
175         *local_port = m_strdup("1234");
176     }
177     if (remote_host) {
178         *remote_host = m_strdup("fuzzremotehost");
179     }
180     if (remote_port) {
181         *remote_port = m_strdup("9876");
182     }
183 }
184 
185 /* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
fuzz_fake_send_kexdh_reply(void)186 void fuzz_fake_send_kexdh_reply(void) {
187     assert(!ses.dh_K);
188     m_mp_alloc_init_multi(&ses.dh_K, NULL);
189     mp_set_ul(ses.dh_K, 12345678uL);
190     finish_kexhashbuf();
191 }
192 
193 /* fake version of spawn_command() */
fuzz_spawn_command(int * ret_writefd,int * ret_readfd,int * ret_errfd,pid_t * ret_pid)194 int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
195     *ret_writefd = wrapfd_new();
196     *ret_readfd = wrapfd_new();
197     if (ret_errfd) {
198         *ret_errfd = wrapfd_new();
199     }
200     *ret_pid = 999;
201     return DROPBEAR_SUCCESS;
202 }
203 
fuzz_run_preauth(const uint8_t * Data,size_t Size,int skip_kexmaths)204 int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
205     static int once = 0;
206     if (!once) {
207         fuzz_svr_setup();
208         fuzz.skip_kexmaths = skip_kexmaths;
209         once = 1;
210     }
211 
212     if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
213         return 0;
214     }
215 
216     /*
217       get prefix, allowing for future extensibility. input format is
218       string prefix
219           uint32 wrapfd seed
220           ... to be extended later
221       [bytes] ssh input stream
222     */
223 
224     /* be careful to avoid triggering buffer.c assertions */
225     if (fuzz.input->len < 8) {
226         return 0;
227     }
228     size_t prefix_size = buf_getint(fuzz.input);
229     if (prefix_size != 4) {
230         return 0;
231     }
232     uint32_t wrapseed = buf_getint(fuzz.input);
233     wrapfd_setseed(wrapseed);
234 
235     int fakesock = wrapfd_new();
236 
237     m_malloc_set_epoch(1);
238     if (setjmp(fuzz.jmp) == 0) {
239         svr_session(fakesock, fakesock);
240         m_malloc_free_epoch(1, 0);
241     } else {
242         m_malloc_free_epoch(1, 1);
243         TRACE(("dropbear_exit longjmped"))
244         /* dropbear_exit jumped here */
245     }
246 
247     return 0;
248 }
249 
fuzz_run_client(const uint8_t * Data,size_t Size,int skip_kexmaths)250 int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths) {
251     static int once = 0;
252     if (!once) {
253         fuzz_cli_setup();
254         fuzz.skip_kexmaths = skip_kexmaths;
255         once = 1;
256     }
257 
258     if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
259         return 0;
260     }
261 
262     /*
263       get prefix, allowing for future extensibility. input format is
264       string prefix
265           uint32 wrapfd seed
266           ... to be extended later
267       [bytes] ssh input stream
268     */
269 
270     /* be careful to avoid triggering buffer.c assertions */
271     if (fuzz.input->len < 8) {
272         return 0;
273     }
274     size_t prefix_size = buf_getint(fuzz.input);
275     if (prefix_size != 4) {
276         return 0;
277     }
278     uint32_t wrapseed = buf_getint(fuzz.input);
279     wrapfd_setseed(wrapseed);
280 
281     int fakesock = wrapfd_new();
282 
283     m_malloc_set_epoch(1);
284     if (setjmp(fuzz.jmp) == 0) {
285         cli_session(fakesock, fakesock, NULL, 0);
286         m_malloc_free_epoch(1, 0);
287     } else {
288         m_malloc_free_epoch(1, 1);
289         TRACE(("dropbear_exit longjmped"))
290         /* dropbear_exit jumped here */
291     }
292 
293     return 0;
294 }
295 
fuzz_get_algo(const algo_type * algos,const char * name)296 const void* fuzz_get_algo(const algo_type *algos, const char* name) {
297     const algo_type *t;
298     for (t = algos; t->name; t++) {
299         if (strcmp(t->name, name) == 0) {
300             return t->data;
301         }
302     }
303     assert(0);
304 }
305 
fuzz_dump(const unsigned char * data,size_t len)306 void fuzz_dump(const unsigned char* data, size_t len) {
307     TRACE(("dump %zu", len))
308     if (fuzz.dumping) {
309         assert(atomicio(vwrite, fuzz.recv_dumpfd, (void*)data, len) == len);
310     }
311 }
312