Compare commits

..

154 Commits

Author SHA1 Message Date
Matt Johnston
4318631dd6 Bump to 2019.78 2019-03-27 21:47:34 +08:00
Matt Johnston
7bc6280613 Fix regression where TTY modes weren't reset for client 2019-03-24 20:41:02 +08:00
Matt Johnston
e9231f73c2 Added signature for changeset 07b0d56d186d 2019-03-23 21:54:23 +08:00
Matt Johnston
4fd40e61f7 Added tag DROPBEAR_2019.77 for changeset 6d1bbe7d5fa5 2019-03-23 21:54:21 +08:00
Matt Johnston
71f818262c 2019.77 2019-03-23 21:46:29 +08:00
Matt Johnston
07f790db5a use "openssl sha256" 2019-03-23 21:45:00 +08:00
Matt Johnston
78a3388b98 Update config.sub to 2019-01-05 and config.guess to 2019-03-04 2019-03-23 21:19:02 +08:00
Matt Johnston
6fecc91d10 fix constness build error 2019-03-21 00:21:38 +08:00
Matt Johnston
8b4f60a7a1 limit password length to 100 2019-03-21 00:09:07 +08:00
Matt Johnston
01cd1bd11f Increase MAX_USERNAME_LEN to 100 2019-03-20 23:47:25 +08:00
Christian Hohnstädt
f6df3e1fec dropbearconvert: keyimport.c: fix BER encoding of secp521r1 keys (#69)
keysizes >= 128 octets will be encoded with a 3 byte header
which must be accounted by the optional-header

Reproduce:

master:~/build/dropbear$ ./dropbearkey -t ecdsa -s 521 -f K
Generating 521 bit ecdsa key, this may take a while...

master:~/build/dropbear$ ./dropbearconvert d o K L
Key is a ecdsa-sha2-nistp521 key
Wrote key to 'L'

master:~/build/dropbear$ openssl ec < L
read EC key
unable to load Key
139769806448384:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:crypto/asn1/asn1_lib.c:91:
2019-03-20 23:42:47 +08:00
xcko
553087b7a6 support openssh long option -o Port=XXXX (#68) 2019-03-20 23:08:25 +08:00
karel-m
16fb0b0d53 cygwin competibility fix (#64) 2019-03-20 23:05:37 +08:00
Andre McCurdy
493ab8fd81 drop obsolete definition for MAX_KEXHASHBUF (#65)
The last code to make use of MAX_KEXHASHBUF was removed in 2005:

  736f370dce

Signed-off-by: Andre McCurdy <armccurdy@gmail.com>
2019-03-20 23:01:41 +08:00
Matt Johnston
0afcfafbb9 Add a sanity check for DROPBEAR_SVR_MULTIUSER==0 mode 2019-03-20 22:57:06 +08:00
Patrick Stewart
0af22aa8e4 Support servers without multiple user support (#76) 2019-03-20 22:44:49 +08:00
Konstantin Demin
2fd3b9f560 packet: remove stale comment about "packet_type" (#63)
clean up after 7f15910541

Signed-off-by: Konstantin Demin <rockdrilla@gmail.com>
2019-03-20 22:33:15 +08:00
François Perrad
2de3bc9353 fix some gcc warnings (#73)
* tweak string size

fix gcc8 warnings

```
svr-agentfwd.c: In function 'bindagent':
svr-agentfwd.c:254:53: warning: '%s' directive output may be truncated writing up to 107 bytes into a region of size between 0 and 107 [-Wformat-truncation=]
  snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", path, sockfile);
                                                     ^~         ~~~~~~~~
svr-agentfwd.c:254:2: note: 'snprintf' output between 2 and 216 bytes into a destination of size 108
  snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", path, sockfile);
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

* cleanup signed/unsigned comparison

fix gcc8 warnings
```
scp.c: In function 'do_local_cmd':
scp.c:132:17: warning: comparison of integer expressions of different signedness: 'u_int' {aka 'unsigned int'} and 'int' [-Wsign-compare]
   for (i = 0; i < a->num; i++)
                 ^
scpmisc.c: In function 'addargs':
scpmisc.c:161:25: warning: comparison of integer expressions of different signedness: 'int' and 'u_int' {aka 'unsigned int'} [-Wsign-compare]
  } else if (args->num+2 >= nalloc)
                         ^~
scpmisc.c: In function 'replacearg':
scpmisc.c:183:12: warning: comparison of integer expressions of different signedness: 'u_int' {aka 'unsigned int'} and 'int' [-Wsign-compare]
  if (which >= args->num)
            ^~
scpmisc.c: In function 'freeargs':
scpmisc.c:196:17: warning: comparison of integer expressions of different signedness: 'u_int' {aka 'unsigned int'} and 'int' [-Wsign-compare]
   for (i = 0; i < args->num; i++)
                 ^
```

see https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/misc.h.diff?r1=1.16&r2=1.17
2019-03-20 22:25:15 +08:00
François Perrad
28b6111db0 use strlcpy & strlcat (#74)
* refactor checkpubkeyperms() with safe BSD functions

fix gcc8 warnings
```
svr-authpubkey.c: In function 'checkpubkeyperms':
svr-authpubkey.c:427:2: warning: 'strncat' specified bound 5 equals source length [-Wstringop-overflow=]
  strncat(filename, "/.ssh", 5); /* strlen("/.ssh") == 5 */
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
svr-authpubkey.c:433:2: warning: 'strncat' specified bound 16 equals source length [-Wstringop-overflow=]
  strncat(filename, "/authorized_keys", 16);
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

see https://www.sudo.ws/todd/papers/strlcpy.html

* restore strlcpy in xstrdup

see original https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/xmalloc.c?rev=1.16
2019-03-20 22:09:19 +08:00
vincentto13
a0aa274981 Fix for issue successfull login of disabled user (#78)
This commit introduces fix for scenario:
1. Root login disabled on dropbear
2. PAM authentication model enabled

While login as root user, after prompt for password
user is being notified about login failrue, but
after second attempt of prompt for password within
same session, login becames succesfull.

Signed-off-by: Pawel Rapkiewicz <pawel.rapkiewicz@gmail.com>
2019-03-20 22:03:40 +08:00
Michael Jones
b016ebedfd Add missing word to readme (#77) 2019-03-20 21:56:19 +08:00
François Perrad
cb945f9f67 add missing initializer (#71) 2019-01-07 23:09:45 +08:00
Matt Johnston
df0f1297eb merge 2018-11-14 22:58:35 +08:00
Matt Johnston
fe992bf4ea Split ChanType closehandler() and cleanup() so that dbclient doesn't
lose exit status messages
2018-11-14 22:57:56 +08:00
Matt Johnston
ffde4a524f Remove some cluttering TRACE printouts 2018-11-14 22:52:04 +08:00
Matt Johnston
7e03e4d443 Remove incorrect _POSIX_C_SOURCE 2018-11-06 07:25:53 +08:00
Matt Johnston
02ffdd09dc - Add adaptive authentication failure delay
- Rework monotonic_now/gettime_wrapper and use clock_gettime on more platforms
2018-11-05 23:36:34 +08:00
Matt Johnston
6f6ef4834c merge remote forward fix 2018-09-07 23:02:53 +08:00
Matt Johnston
d2e71ade72 FIx remote forward listeners 2018-09-07 23:02:20 +08:00
Matt Johnston
892c5fc1c8 Merge writev #include fix 2018-08-26 22:26:42 +08:00
Matt Johnston
e7504b3311 make writev #include consistent for variable declarations too 2018-08-23 23:59:24 +08:00
Matt Johnston
ad3eacf3d6 Merge bugfix delay invalid users 2018-08-23 23:43:45 +08:00
Matt Johnston
52adbb34c3 Wait to fail invalid usernames 2018-08-23 23:43:12 +08:00
Matt Johnston
90f04384ee fix error message to say localoptions.h 2018-08-23 22:10:07 +08:00
Matt Johnston
195934be96 avoid extended regex features to avoid caring about sed -r vs -E 2018-07-24 20:19:05 +08:00
Matt Johnston
d740dc5489 Fix leaks in kex fuzzers 2018-03-09 23:16:37 +08:00
Matt Johnston
76933e6c0a move dictionaries to corpus repo 2018-03-09 20:43:11 +08:00
Matt Johnston
38c9408cf8 avoid leak of ecdh public key 2018-03-08 23:51:33 +08:00
Matt Johnston
397af3e6a6 kexhashbuf was much to small in kex fuzzers 2018-03-08 23:23:19 +08:00
Matt Johnston
933bc5f8a7 Disable wrapfds outside of fuzzed code 2018-03-08 23:22:53 +08:00
Matt Johnston
ba94bcd2e8 It turns out you can't have a single-quote in an #error 2018-03-08 22:37:54 +08:00
Matt Johnston
56855744b8 Only advertise a single server ecdsa key when -R (generate as required) is
specified. Fixes -R now that default ecdsa key size has changed.
2018-03-08 22:25:33 +08:00
Matt Johnston
b4b11c8155 #error if no ecc size is chosen 2018-03-08 22:22:11 +08:00
Matt Johnston
f82933108d reduce fuzzer-kexdh params count again, still hitting timeout 2018-03-07 22:50:32 +08:00
Matt Johnston
27828c742c don't allow null characters in authorized_keys 2018-03-07 22:16:21 +08:00
Matt Johnston
ed4c38ba46 fix leak in option handling 2018-03-07 22:14:36 +08:00
Matt Johnston
e9edbe8bb2 avoid leak of pubkey_options 2018-03-06 22:18:20 +08:00
Matt Johnston
4fd3160179 fix uninitialised memory in fuzzer codepath 2018-03-06 22:02:19 +08:00
Matt Johnston
a60725740b workaround memory sanitizer FD_ZERO false positives 2018-03-06 21:51:51 +08:00
Matt Johnston
5d065258da reduce number of dh parameters so fuzzer doesn't timeout 2018-03-06 21:00:09 +08:00
Matt Johnston
149b21d7cf ciphers/hashes/kex algorithms won't have string lengths, also use
dictionary for fuzzer-preauth_nomaths
2018-03-05 21:02:26 +08:00
Matt Johnston
145fb96989 Don't read uninitialised value.
From 1d03522625
2018-03-05 16:50:24 +08:00
Matt Johnston
084ff9b4c8 reduce number of params so it doesn't hit a timeout 2018-03-05 16:29:57 +08:00
Matt Johnston
6b05aa4275 fix some links 2018-03-05 14:14:26 +08:00
Matt Johnston
366fc8f335 notes on the fuzzer 2018-03-05 14:07:11 +08:00
Matt Johnston
35f479bd87 Add kexdh and kexecdh fuzzers 2018-03-05 11:50:31 +08:00
Matt Johnston
9d11cad5dc dictionary for fuzzer-preauth 2018-03-05 00:59:17 +08:00
Matt Johnston
0233dcebb4 try and improve the odds of useful fuzzer activity 2018-03-04 22:11:23 +08:00
Matt Johnston
f7dedab4a7 - fuzzer-pubkey needs to free algoname, fix build
- improve dictionary with lengths
2018-03-04 21:44:09 +08:00
Matt Johnston
129c440362 add a dictionary for fuzzer-pubkey 2018-03-04 19:38:34 +08:00
Matt Johnston
abee8093b3 use random keyblob from the fuzzer instead 2018-03-04 19:19:45 +08:00
Matt Johnston
2583b180c9 travis fuzz build clang++ 2018-03-04 17:17:37 +08:00
Matt Johnston
1e1e477d85 set up CXX for fuzzing build 2018-03-04 17:08:21 +08:00
Matt Johnston
85eda7d943 try fix travis sanitizer 2018-03-04 15:18:20 +08:00
Matt Johnston
4b36e24735 print config.log on failure 2018-03-04 15:09:41 +08:00
Matt Johnston
a5eac0a065 add -fsanitize=address for fuzz test again 2018-03-04 15:00:51 +08:00
Matt Johnston
7f15910541 get rid of unused packet_type in encrypted write queue 2018-03-04 14:57:18 +08:00
Matt Johnston
625b38d7af merge 2018-03-03 11:11:04 +08:00
Matt Johnston
b9edf939f4 add cryptlib for all targets in fuzz build 2018-03-03 11:08:26 +08:00
François Perrad
257bba00ac some linting after fuzz merge (#60)
* fix prototype

* remove extra comma

* use m_free after m_strdup
2018-03-03 11:06:45 +08:00
Matt Johnston
8d0b48f165 Fix CFLAGS for configure 2018-03-03 10:10:16 +08:00
Matt Johnston
ce1f9cdf7c no werror for fuzzing clang 2018-03-02 00:11:27 +08:00
Matt Johnston
e612aec5d9 Attempt to fix m_free for libtomcrypt/libtommath 2018-03-02 00:02:06 +08:00
Matt Johnston
5bd0c0d25a avoid fsanitize=address for fuzzing 2018-03-01 23:47:46 +08:00
Matt Johnston
26ad6853d2 Only use malloc wrapper if fuzzing 2018-03-01 23:46:24 +08:00
Matt Johnston
8a4f7fe4f8 avoid volatile cast warning 2018-03-01 23:46:07 +08:00
Matt Johnston
294e98c397 don't try clang-5.0 2018-03-01 22:58:39 +08:00
Matt Johnston
c1a2dcb25d add fuzzers to travis 2018-03-01 22:54:57 +08:00
Matt Johnston
a0972e0ac6 mention localoptions.h being build directory, fix underscore in CHANGES 2018-03-01 22:12:30 +08:00
Matt Johnston
8062a4e8d6 mention localoptions.h being build directory, fix underscore in CHANGES 2018-03-01 22:12:30 +08:00
Matt Johnston
a0ab5e86b5 more portable for which hg test 2018-02-28 23:42:57 +08:00
Matt Johnston
a1dcaf82a0 Merge fuzzing branch 2018-02-28 22:12:05 +08:00
Matt Johnston
78e17f6ee9 merge from main
--HG--
branch : fuzz
2018-02-28 22:11:39 +08:00
Matt Johnston
5ebc48b3f2 clean some fuzzing conditionals
--HG--
branch : fuzz
2018-02-28 22:10:43 +08:00
François Perrad
1ae4237920 fix #endif (#59) 2018-02-28 15:10:14 +01:00
Matt Johnston
5ca12d8332 avoid extended regex features to avoid caring about sed -r vs -E 2018-07-24 20:19:05 +08:00
François Perrad
7f8702d3d6 fix #endif (#59) 2018-02-28 22:10:14 +08:00
Matt Johnston
5f2447edbb Fix to be able to compile normal(ish) binaries with --enable-fuzz
--HG--
branch : fuzz
2018-02-28 22:02:12 +08:00
Matt Johnston
c658b275fd - #if not #ifdef for DROPBEAR_FUZZ
- fix some unused variables

--HG--
branch : fuzz
2018-02-28 21:40:08 +08:00
Matt Johnston
9bbce01e1b merge from main
--HG--
branch : fuzz
2018-02-28 21:28:59 +08:00
Matt Johnston
bbe02dc3cf Added signature for changeset 2f0c3f3361d3 2018-02-27 22:49:06 +08:00
Matt Johnston
3d76aecaa6 Added tag DROPBEAR_2018.76 for changeset 1c66ca4f3791 2018-02-27 22:48:42 +08:00
Matt Johnston
5df73215f8 merge from main
--HG--
branch : fuzz
2018-02-26 22:44:48 +08:00
Matt Johnston
573838a027 print hg revid
--HG--
branch : fuzz
2018-02-21 21:59:52 +08:00
Matt Johnston
05f4e29a52 The fuzzer has managed to generated DSS key/signature pairs that
verify. Avoid false positives from bogus keys that wouldn't be used

--HG--
branch : fuzz
2018-02-21 21:49:24 +08:00
Matt Johnston
dbc0520992 compile fixes
--HG--
branch : fuzz
2018-02-21 21:03:42 +08:00
Matt Johnston
dcb41e91eb limit rsa->e size to 64 bits
--HG--
branch : fuzz
2018-02-17 19:41:44 +08:00
Matt Johnston
7e8094d53a merge from main
--HG--
branch : fuzz
2018-02-17 19:29:51 +08:00
Matt Johnston
f7a664f127 fix bad assertion
--HG--
branch : fuzz
2018-01-23 23:27:40 +08:00
Matt Johnston
89bdf3b0b9 add fuzzer-preauth_nomaths
--HG--
branch : fuzz
2018-01-23 23:05:47 +08:00
Matt Johnston
597f7eb5e9 merge up to date
--HG--
branch : fuzz
2018-01-23 22:46:07 +08:00
Matt Johnston
5cd003d9e6 check dss g range
--HG--
branch : fuzz
2017-08-14 00:00:10 +08:00
Matt Johnston
4b7105dfea fix DROBPEAR_FUZZ auth delay
--HG--
branch : fuzz
2017-06-30 21:10:57 +08:00
Matt Johnston
6ac5ea2a9f merge from main (libtommath/libtomcrypt/curve25510-donna updates)
--HG--
branch : fuzz
2017-06-24 22:51:45 +08:00
Matt Johnston
17a9b8802f fix dss debug printing
--HG--
branch : fuzz
2017-06-24 10:34:58 +08:00
Matt Johnston
9b6f7fc9af merge from main
--HG--
branch : fuzz
2017-06-24 10:34:19 +08:00
Matt Johnston
5ac4a71000 merge from main
--HG--
branch : fuzz
2017-06-24 00:47:07 +08:00
Matt Johnston
b967dc1fa5 merge
--HG--
branch : fuzz
2017-06-23 21:31:49 +08:00
Matt Johnston
2cbe70ba34 verify debug printing
--HG--
branch : fuzz
2017-06-20 20:07:25 +08:00
Matt Johnston
8e1ea0f27b increase min DSS and RSA lengths
--HG--
branch : fuzz
2017-06-16 22:35:32 +08:00
Matt Johnston
e3246ceb7e check p and q lengths
--HG--
branch : fuzz
2017-06-16 22:35:18 +08:00
Matt Johnston
88ce30beb6 merge from main
--HG--
branch : fuzz
2017-06-14 23:31:42 +08:00
Matt Johnston
723ec19eed fix checkmac always failing pre-kex
--HG--
branch : fuzz
2017-06-11 21:39:40 +08:00
Matt Johnston
937e6cb91e fuzzer-preauth don't call getpwnam(), bring back longjmp
--HG--
branch : fuzz
2017-06-02 00:03:51 +08:00
Matt Johnston
81b64ea0b5 Add a flag whether to longjmp, missed that last commit
--HG--
branch : fuzz
2017-06-01 21:30:26 +08:00
Matt Johnston
ea0e23c172 don't longjmp for fuzzer-preauth (temporary to debug asan)
--HG--
branch : fuzz
2017-05-30 22:50:52 +08:00
Matt Johnston
4d07aa315b Disable setnonblocking(), get_socket_address(), set_sock_priority()
for fuzzing

--HG--
branch : fuzz
2017-05-26 22:10:51 +08:00
Matt Johnston
2e298b25e4 fix building with DEBUG_TRACE
--HG--
branch : fuzz
2017-05-26 22:09:30 +08:00
Matt Johnston
25607c04a7 add m_mp_free_multi, be more careful freeing when failing to load keys
--HG--
branch : fuzz
2017-05-26 21:08:43 +08:00
Matt Johnston
cbd5be1b82 add fuzzer-verify
--HG--
branch : fuzz
2017-05-26 00:20:01 +08:00
Matt Johnston
f24d93d4e4 fix null pointer crash
--HG--
branch : fuzz
2017-05-26 00:19:53 +08:00
Matt Johnston
65baa71b58 linked list dbmalloc now
add non-free m_malloc_free_epoch() argument for leak detection

--HG--
branch : fuzz
2017-05-26 00:19:39 +08:00
Matt Johnston
b8fa712847 rearrange, all fuzzers now call fuzzer_set_input()
--HG--
branch : fuzz
2017-05-25 22:21:49 +08:00
Matt Johnston
095b067857 limit input size
--HG--
branch : fuzz
2017-05-25 22:21:23 +08:00
Matt Johnston
87c4586d61 fuzzing has a constant time
--HG--
branch : fuzz
2017-05-25 22:20:10 +08:00
Matt Johnston
b17254925d Just use memset, it should'be be optimised out in a separate file
--HG--
branch : fuzz
2017-05-25 22:19:46 +08:00
Matt Johnston
cf2c4f44a2 fuzzers disable logging by default
--HG--
branch : fuzz
2017-05-25 00:12:07 +08:00
Matt Johnston
2bc55ff428 don't exit encountering short lines
--HG--
branch : fuzz
2017-05-25 00:10:18 +08:00
Matt Johnston
ee5769f31f avoid NULL argument to base64 decode
--HG--
branch : fuzz
2017-05-25 00:09:40 +08:00
Matt Johnston
3a8517b06f create fuzzer .options files
--HG--
branch : fuzz
2017-05-23 22:43:52 +08:00
Matt Johnston
0363d3c32e fuzzer-pubkey
--HG--
branch : fuzz
2017-05-23 22:43:34 +08:00
Matt Johnston
a582c4cdb6 split out checkpubkey_line() separately
--HG--
branch : fuzz
2017-05-23 22:29:21 +08:00
Matt Johnston
a43b6b0323 define SIZE_T_MAX
--HG--
branch : fuzz
2017-05-22 22:09:46 +08:00
Matt Johnston
84a143a605 remove unneeded check
--HG--
branch : fuzz
2017-05-22 22:09:38 +08:00
Matt Johnston
114438e669 zlib can use m_malloc/m_free too
--HG--
branch : fuzz
2017-05-22 22:09:26 +08:00
Matt Johnston
50bde9976b seed_fuzz() prototype
--HG--
branch : fuzz
2017-05-21 18:53:44 +08:00
Matt Johnston
18ea116827 -v for debug_trace
--HG--
branch : fuzz
2017-05-21 18:53:33 +08:00
Matt Johnston
30d3ccd419 Fix null pointer dereference found by libfuzzer
--HG--
branch : fuzz
2017-05-21 18:53:09 +08:00
Matt Johnston
fb8fb7fed0 add dbmalloc epoch cleanup
--HG--
branch : fuzz
2017-05-21 10:54:11 +08:00
Matt Johnston
1abd239b9d ignore wrapfd_close for unknown
--HG--
branch : fuzz
2017-05-21 10:48:18 +08:00
Matt Johnston
9f1c8b2f8f make buf_getstring fail prior to malloc if the buffer is short
--HG--
branch : fuzz
2017-05-20 23:39:01 +08:00
Matt Johnston
c169423051 glaring wrapfd problems fixed
--HG--
branch : fuzz
2017-05-20 22:47:19 +08:00
Matt Johnston
fdc6f32392 closer to working
--HG--
branch : fuzz
2017-05-20 13:23:16 +08:00
Matt Johnston
e7cdb2ebe5 add wrapfd. improve fuzzer in makefile
--HG--
branch : fuzz
2017-05-19 00:48:46 +08:00
Matt Johnston
4dae8edb76 merge main to fuzz
--HG--
branch : fuzz
2017-05-18 23:45:10 +08:00
Matt Johnston
a3e01b8884 better harness
--HG--
branch : fuzz
2017-05-18 23:38:30 +08:00
Matt Johnston
6d33a2b0bb setup svr_dropbear_exit
--HG--
branch : fuzz
2017-05-18 23:36:54 +08:00
Matt Johnston
beaff53a79 rename fuzzer -> fuzz-target, add list-fuzz-targets
--HG--
branch : fuzz
2017-05-14 00:00:21 +08:00
Matt Johnston
b9b308f2fe Use CXX to link fuzzer, also link with $FUZZLIB
--HG--
branch : fuzz
2017-05-13 23:46:01 +08:00
Matt Johnston
a7bfd792f7 crypto_init()
--HG--
branch : fuzz
2017-05-13 23:45:51 +08:00
Matt Johnston
06fd9e3771 fix buf->pos when shrinking
--HG--
branch : fuzz
2017-05-13 23:44:12 +08:00
Matt Johnston
fb719e3d0b fuzz harness
--HG--
branch : fuzz
2017-05-13 22:50:54 +08:00
Matt Johnston
9f24cdf74c copy over some fuzzing code from AFL branch
--HG--
branch : fuzz
2017-05-12 23:14:54 +08:00
Matt Johnston
d7471c4f87 notsocket changes from afl branch
--HG--
branch : fuzz
2017-05-12 22:14:49 +08:00
79 changed files with 3996 additions and 2084 deletions

2
.hgignore Normal file
View File

@@ -0,0 +1,2 @@
.*\.o
.*~

View File

@@ -23,3 +23,5 @@ fd1981f41c626a969f07b4823848deaefef3c8aa 0 iQIcBAABCgAGBQJW4W2TAAoJEESTFJTynGdzu
70705edee9dd29cd3d410f19fbd15cc3489313e2 0 iQIcBAABCgAGBQJW7CQRAAoJEESTFJTynGdzTj0QAJL38CKSZthBAeI9c6B+IlwIeT6kPZaPqk1pkycCTWOe87NiNU9abrsF+JrjTuRQiO1EpM2IvfQEIXTijUcMxvld3PnzrZDDv6UvBLtOkn3i++HSVRO0MOuTKI8gFDEPUxRtcaCKXEbqYnf1OTK25FT09Vb//qP9mK1thvlLJmbV+D2a9MkMK66rom1d1h+347IsuwsM+ycHjB80VVAQLA7VYLC5YIwmL17dSmcQLvetfikAMwwmUE+KES4qiLSaqOcAWcKcU67RZzgMMv5o0rESlQmv1nj0mHZtHoUR71sd21emPaRXLOr0oT5YogWUphKq2qVthRn2B06+vd3hPdtn92CmJw9j7zT2jl4OeSjNm9qfAajsRzHIANssFxkGAb7w/LxcMoO29JC+01iUUJMdOVm+4Ns6wGI7qxssWPKdB+VbQUDlHrXLR+sopO524uhkYoWB6DVfTj4R6tImaHtj5/VXON0lsYaLGj8cSH60emL6nNQ0lYV/bSlk6l0s+0x3uXGZnp9oKA+vqMzHfG3vJeMm6KUqtFVjUsYx+q8nHm5/SlWxj1EwnkH8s8ELKZAUXjd76nWEwJ7JFRNRSQWvjOUh3/rsOo4JopzZXPsjCjm+Vql9TG0X6hB21noai32oD5RvfhtR/NX6sXNS5TKZz/j/cMsMnAAsSKb6W7Jm
9030ffdbe5625e35ed7189ab84a41dfc8d413e9c 0 iQIcBAABCgAGBQJXkOg0AAoJEESTFJTynGdzc1kP/3vSKCnhOOvjCjnpTQadYcCUq8vTNnfLHYVu0R4ItPa/jT6RmxoaYP+lZnLnnBx9+aX7kzwHsa9BUX3MbMEyLrOzX2I+bDJbNPhQyupyCuPYlf5Q9KVcO9YlpbsC4q5XBzCn3j2+pT8kSfi9uD8fgY3TgE4w9meINrfQAealfjwMLT8S/I49/ni0r+usSfk/dnSShJYDUO7Ja0VWbJea/GkkZTu30bCnMUZPjRApipU3hPP63WFjkSMT1rp2mAXbWqyr9lf8z32yxzM9nMSjq4ViRFzFlkGtE3EVRJ4PwkO7JuiWAMPJpiQcEr+r52cCsmWhiGyHuINo01MwoMO9/n6uL1WVa3mJcE9se3xBOvfgDu2FRFGCAdm1tef+AGVo9EG1uJXi0sX2yUc6DMeuYaRWrXMMlZh7zp9cuNU9Y/lLui9RFmq66yeXG3Z2B72doju3Ig5QGrNNw2AOsSzeHdAtOp6ychqPcl9QfIeJQG18KyPSefZKM3G8YRKBRIwXFEH6iZJe5ZIP4iXrHDMn2JqtTRtDqKR8VNDAgb9z4Ffx8QRxFyj5JzTTMM1GddHb9udLvTQlO0ULYG7hCSMRNzvUBE2aTw8frjLRyfyyg3QpDu/hz8op8s1ecE8rTCD8RuX9DiiylNozypPtGNS+UDbAmkc1PCWaRpPVl+9K6787
5c9207ceedaea794f958224c19214d66af6e2d56 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlkdtooACgkQRJMUlPKcZ3P6ZxAAmLy/buZB/d96DJF/pViRWt/fWdjQFC4MqWfeSLW02OZ8Qkm1vPL3ln6WPHC2thy3xZWVg2uan3pLk/XXnsIFu8Q7r1EAfFFpvlMUmdl7asE8V6ilaeqmiI7bIvGMFbf4cZkQliLjiFkJX56tFHRCNi+rb7WgRuru3/GzPXUq2AvXZvFpFJgik0B72TxVlmCKeBRZq1FvP0UhAH48RJWYJksdEyzh2paMfjX9ZO5Q2SFFrmPw6k2ArdJFC1AYcgceZC84y06RKJ0WiSntUPlEUXgQbQVVWbtQDhjfJXMr/beuroNdT/vsRraLVkAzvhaDXNnHlAJNLQxci+AcLpnzZhxMW+ax7RRtrpXGxRN4cs0lBGUcSkaDybFqMYXwEjXAE8w6fdJRWCIlxctkAW/iNEO4kAG97hI2Qwcw5oU2Ymnv09zyGR+XJE35pJqPulJHExdwanJHvmjH0QF7TNFS82yxS5dKnP954cj3Lu9SWGYWjxQJRmLtOwb+lqqol4VTxG7Ois4uef9/Tpp9skeMZXVeNlpn2wrp6iFcX3uiiVDg9VKkl3ig6UqCiqQSuiIN87RXwUOeHXlCnW3adz3Xei0ziBrwLSql7lBIHGEAlUUNmJ3CrR8IwQtcynGEMKfNIeZ/XK+uNlm9cJIqZf1fzqc8KexlyS9AS0i/kiYZTr4=
2f0c3f3361d3ea4eb9129ed8810699fda7e7a8ee 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlqVb+IACgkQRJMUlPKcZ3OENA//R9HsOUJQB2QZjRgAvqgLn2AMLUvmWb2etTZEc3Nps957Fw1F4kjh6VGfIpWuytfsDx1W8qRx09ikTdb3YteMWCuX8/aFreSPrioYmzrAEcxkZdA7B/jciqU0iXuHiJ9saKk5TR70aNp+iRy0hjAgiYEsVMF9YKHzULOJcHr70x9XVKquubQkwNqJA+/b2JbK2j46wM5nVK/alGSI2kMmEzXmAHQxsvf1OLMvgH8ou/l0xsg/CuFEK299XKfZAbsFEXrjuoWZ1aSa6rTeOWsWli5T+czyyJHI4Eu0Sz/gaR8+MPhJSYes8YjvzEdv32rRMDVOdBq4e+HoTgFt/THYABP6/R1H5fX3Lm4K8u9F9SwJbb/YKRAIrfWDob8ApnGFHk2dyYO20Fskbbg6b1pC7ulDWsufu8lYkQyMlTc3dR6P4eTB6mKO4x+gMG6tIYZ60fiULoEnMJCgegPtevmz+TG1rzdjh3ljiw9Dxz5lNtL+W7sBKKHwhyG0u+bavgmvBMKNL/rdHEM+0yCIz1U6Lb8sVaST1E4zbdm7cWHbSozBij3G0GBSkLFEq7ZLlh8wco9rELRh0Y9fFsWY9j6H/PTOu0GfHrYluFb9WGywHAquQY8j2croRx+MrvTbR1wZrbevPNm9gqk3vgOiDWu7KwxLLqcj+dEQ7tccptVYtbM=
07b0d56d186d7eeef4106137a3eba554959ba0e3 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlyWOo8ACgkQRJMUlPKcZ3O+MQ//c5oeDUvZuFiI4FHZqfIK/59YAciTP+9TQmoWDVSuOdkd9ZYJA7b7DCusqP2TWFEIl9M7i5hTLTMD21xuEQQtfOSP6EXpUw6JNdh/lsJs7EDlFANtwkdEozAQozFKnXbJEV3y9WldEWUlmPFjt4fJQIuG10SU7MTJHcSaQddJCh3I1//F4EvgRe+OqyrFwKekGiFdvfjcIFN3lQmk6K1Sc0MgyIO/VVZm/AQpBi0Dlg0yOl+EDcxxlmeSInbvLceWSP6op35I4dE5YWH1UetjzIsr5AIM15/k3viAKDDefY1EMAzK9b7YAF4BLw0a6XoQu0apvcWaALE/bJzWNSg/QbCm2JAZzk21WLLvR+AELzPfKXrHX3o0h51lpQ4rs7EWKUm43dJPoWkcFNOU+BDsNzffcJgChbRs48ut89DYLiGmSxhRxE77VPbA+klgTGdctOTLd8psseRlGYCuGe8zeota80bV9fUZ9WJZHwNgEWGowKUoTjy6l5k9OH3iQuQX3OXoy78ufRgWDulE7noVTMhXurQ8a0Jf2k/MW9dcnqGVkWitCFKPEvZwVmWyW2AWsdMcBJnFFGzDsNSxWTtCF9XcxieDO1IB8vGwYcb1TwEVuVzvR/wwvc3PgVikF+4Qv2NqdoQc1yn2PkocY2hwXyIZUAwz7erNumlTbeC/JK8=

View File

@@ -55,3 +55,5 @@ cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
309e1c4a87682b6ca7d80b8555a1db416c3cb7ac DROPBEAR_2016.73
0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74
c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
1c66ca4f3791c82501c88e7637312182c7294978 DROPBEAR_2018.76
6d1bbe7d5fa5827c7eae28bca044d691f7efa785 DROPBEAR_2019.77

View File

@@ -9,20 +9,26 @@ matrix:
- os: linux
compiler: gcc
env: WEXTRAFLAGS=-Werror
sudo: false
- env: MULTI=1 WEXTRAFLAGS=-Werror
# libtom has some warnings, so no WEXTRAFLAGS
- env: BUNDLEDLIBTOM=--enable-bundled-libtom WEXTRAFLAGS=""
- env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=""
- env: NOWRITEV=1 WEXTRAFLAGS=-Werror
# libtomcrypt 1.18.1 fixes clang problems, distro doesn't have that yet
- os: linux
compiler: clang
env: BUNDLEDLIBTOM=--enable-bundled-libtom WEXTRAFLAGS=""
env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=""
- os: osx
compiler: clang
env: WEXTRAFLAGS=""
# Note: the fuzzing malloc wrapper doesn't replace free() in system libtomcrypt, so need bundled.
- env: DO_FUZZ=1 CONFIGURE_FLAGS="--enable-fuzz --disable-harden --enable-bundled-libtom" WEXTRAFLAGS="" LDFLAGS=-fsanitize=address EXTRACFLAGS=-fsanitize=address CXX=clang++
compiler: clang
# sanitizers need ptrace which is privileged https://github.com/travis-ci/travis-ci/issues/9033
sudo: required
# container-based builds
sudo: false
addons:
apt:
packages:
@@ -30,24 +36,28 @@ addons:
- zlib1g-dev
- libtomcrypt-dev
- libtommath-dev
- mercurial
before_install:
- if [ "$CC" = "clang" ]; then WEXTRAFLAGS="$WEXTRAFLAGS -Wno-error=incompatible-library-redeclaration" ; fi # workaround
script:
- autoconf && autoheader && ./configure "$BUNDLEDLIBTOM" CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS" --prefix="$HOME/inst"
install:
- autoconf
- autoheader
- ./configure $CONFIGURE_FLAGS CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS $EXTRACFLAGS" --prefix="$HOME/inst" || (cat config.log; exit 1)
- if [ "$NOWRITEV" = "1" ]; then sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h ; fi
- make -j3
- test -z $DO_FUZZ || make fuzzstandalone
# avoid concurrent install, osx/freebsd is racey (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=208093)
- make install
after_success:
script:
- ~/inst/bin/dropbearkey -t rsa -f testrsa
- ~/inst/bin/dropbearkey -t dss -f testdss
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
- test -z $DO_FUZZ || ./fuzzers_test.sh
branches:
only:

49
CHANGES
View File

@@ -1,13 +1,58 @@
2019.78 - 27 March 2019
- Fix dbclient regression in 2019.77. After exiting the terminal would be left
in a bad state. Reported by Ryan Woodsmall
2019.77 - 23 March 2019
- Fix server -R option with ECDSA - only advertise one key size which will be accepted.
Reported by Peter Krefting, 2018.76 regression.
- Fix server regression in 2018.76 where multiple client -R forwards were all forwarded
to the first destination. Reported by Iddo Samet.
- Make failure delay more consistent to avoid revealing valid usernames, set server password
limit of 100 characters. Problem reported by usd responsible disclosure team
- Change handling of failed authentication to avoid disclosing valid usernames,
CVE-2018-15599.
- Fix dbclient to reliably return the exit code from the remote server.
Reported by W. Mike Petullo
- Fix export of 521-bit ECDSA keys, from Christian Hohnstädt
- Add -o Port=xxx option to work with sshfs, from xcko
- Merged fuzzing code, see FUZZER-NOTES.md
- Add a DROPBEAR_SVR_MULTIUSER=0 compile option to run on
single-user Linux kernels (CONFIG_MULTIUSER disabled). From Patrick Stewart
- Increase allowed username to 100 characters, reported by W. Mike Petullo
- Update config.sub and config.guess, should now work with RISC-V
- Cygwin compile fix from karel-m
- Don't require GNU sed (accidentally in 2018.76), reported by Samuel Hsu
- Fix for IRIX and writev(), reported by Kazuo Kuroi
- Other fixes and cleanups from François Perrad, Andre McCurdy, Konstantin Demin,
Michael Jones, Pawel Rapkiewicz
2018.76 - 27 February 2018
> > > Configuration/compatibility changes
IMPORTANT
Custom configuration is now specified in local_options.h rather than options.h
Custom configuration is now specified in localoptions.h rather than options.h
Available options and defaults can be seen in default_options.h
To migrate your configuration, compare your customised options.h against the
upstream options.h from your relevant version. Any customised options should
be put in localoptions.h
be put in localoptions.h in the build directory.
- "configure --enable-static" should now be used instead of "make STATIC=1"
This will avoid 'hardened build' flags that conflict with static binaries

74
FUZZER-NOTES.md Normal file
View File

@@ -0,0 +1,74 @@
# Fuzzing Dropbear
Dropbear is process-per-session so it assumes calling `dropbear_exit()`
is fine at any point to clean up. This makes fuzzing a bit trickier.
A few pieces of wrapping infrastructure are used to work around this.
The [libfuzzer](http://llvm.org/docs/LibFuzzer.html#fuzz-target) harness
expects a long running process to continually run a test function with
a string of crafted input. That process should not leak resources or exit.
## longjmp
When dropbear runs in fuzz mode it sets up a
[`setjmp()`](http://man7.org/linux/man-pages/man3/setjmp.3.html) target prior
to launching the code to be fuzzed, and then [`dropbear_exit()`](dbutil.c#L125)
calls `longjmp()` back there. This avoids exiting though it doesn't free
memory or other resources.
## malloc Wrapper
Dropbear normally uses a [`m_malloc()`](dbmalloc.c) function that is the same as `malloc()` but
exits if allocation fails. In fuzzing mode this is replaced with a tracking allocator
that stores all allocations in a linked list. After the `longjmp()` occurs the fuzzer target
calls [`m_malloc_free_epoch(1, 1)`](dbmalloc.c) to clean up any unreleased memory.
If the fuzz target runs to completion it calls `m_malloc_free_epoch(1, 0)` which will reset
the tracked allocations but will not free memory - that allows libfuzzer's leak checking
to detect leaks in normal operation.
## File Descriptor Input
As a network process Dropbear reads and writes from a socket. The wrappers for
`read()`/`write()`/`select()` in [fuzz-wrapfd.c](fuzz-wrapfd.c) will read from the
fuzzer input that has been set up with `wrapfd_add()`. `write()` output is
currently discarded.
These also test error paths such as EINTR and short reads with certain probabilities.
This allows running the entire dropbear server process with network input provided by the
fuzzer, without many modifications to the main code. At the time of writing this
only runs the pre-authentication stages, though post-authentication could be run similarly.
## Encryption and Randomness
When running in fuzzing mode Dropbear uses a [fixed seed](dbrandom.c#L185)
every time so that failures can be reproduced.
Since the fuzzer cannot generate valid encrypted input the packet decryption and
message authentication calls are disabled, see [packet.c](packet.c).
MAC failures are set to occur with a low probability to test that error path.
## Fuzzers
Current fuzzers are
- [fuzzer-preauth](fuzzer-preauth.c) - the fuzzer input is treated as a stream of session input. This will
test key exchange, packet ordering, authentication attempts etc.
- [fuzzer-preauth_nomaths](fuzzer-preauth_nomaths.c) - the same as fuzzer-preauth but with asymmetric crypto
routines replaced with dummies for faster runtime. corpora are shared
between fuzzers by [oss-fuzz](https://github.com/google/oss-fuzz) so this
will help fuzzer-preauth too.
- [fuzzer-verify](fuzzer-verify.c) - read a key and signature from fuzzer input and verify that signature.
It would not be expected to pass, though some keys with bad parameters are
able to validate with a trivial signature - extra checks are added for that.
- [fuzzer-pubkey](fuzzer-pubkey.c) - test parsing of an `authorized_keys` line.
- [fuzzer-kexdh](fuzzer-kexdh.c) - test Diffie-Hellman key exchange where the fuzz input is the
ephemeral public key that would be received over the network. This is testing `mp_expt_mod()`
and and other libtommath routines.
- [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh.
This is testing libtommath ECC routines.

View File

@@ -3,6 +3,8 @@ Basic Dropbear build instructions:
- Edit localoptions.h to set which features you want. Available options
are described in default_options.h, these will be overridden by
anything set in localoptions.h
localoptions.h should be located in the build directory if you are
building out of tree.
- If using a Mercurial or Git checkout, "autoconf; autoheader"

View File

@@ -36,6 +36,7 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
queue.o \
atomicio.o compat.o fake-rfc2553.o \
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
dbmalloc.o \
gensignkey.o gendss.o genrsa.o
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
@@ -59,11 +60,25 @@ CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
scpobjs=$(SCPOBJS)
ifeq (@DROPBEAR_FUZZ@, 1)
allobjs = $(COMMONOBJS) fuzz-common.o fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@
allobjs:=$(subst svr-main.o, ,$(allobjs))
allobjs:=$(subst cli-main.o, ,$(allobjs))
allobjs:=$(sort $(allobjs))
dropbearobjs=$(allobjs) svr-main.o
dbclientobjs=$(allobjs) cli-main.o
dropbearkeyobjs=$(allobjs) $(KEYOBJS)
dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
# CXX only set when fuzzing
CXX=@CXX@
else
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
scpobjs=$(SCPOBJS)
endif
VPATH=@srcdir@
srcdir=@srcdir@
@@ -180,7 +195,7 @@ dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS)
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
# scp doesn't use the libs so is special.
scp: $(SCPOBJS) $(HEADERS) Makefile
@@ -236,3 +251,58 @@ distclean: clean tidy
tidy:
-rm -f *~ *.gcov */*~
## Fuzzing targets
# list of fuzz targets
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh
FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
list-fuzz-targets:
@echo $(FUZZ_TARGETS)
# fuzzers that don't use libfuzzer, just a standalone harness that feeds inputs
fuzzstandalone: FUZZLIB=fuzz-harness.o
fuzzstandalone: fuzz-harness.o fuzz-targets
# exclude svr-main.o to avoid duplicate main
svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
# build all the fuzzers. This will require fail to link unless built with
# make fuzz-targets FUZZLIB=-lFuzzer.a
# or similar - the library provides main().
fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
fuzzer-preauth: fuzzer-preauth.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-pubkey: fuzzer-pubkey.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-verify: fuzzer-verify.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexdh: fuzzer-kexdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexecdh: fuzzer-kexecdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-%.options: Makefile
echo "[libfuzzer]" > $@
echo "max_len = 50000" >> $@
# run this to update hardcoded hostkeys for for fuzzing.
# hostkeys.c is checked in to hg.
fuzz-hostkeys:
dropbearkey -t rsa -f keyr
dropbearkey -t dss -f keyd
dropbearkey -t ecdsa -size 256 -f keye
echo > hostkeys.c
/usr/bin/xxd -i -a keyr >> hostkeys.c
/usr/bin/xxd -i -a keye >> hostkeys.c
/usr/bin/xxd -i -a keyd >> hostkeys.c

2
README
View File

@@ -51,7 +51,7 @@ dropbearkey's '-y' option.
============================================================================
To run the server, you need to server keys, this is one-off:
To run the server, you need to generate server keys, this is one-off:
./dropbearkey -t rsa -f dropbear_rsa_host_key
./dropbearkey -t dss -f dropbear_dss_host_key
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key

11
auth.h
View File

@@ -37,9 +37,9 @@ void recv_msg_userauth_request(void);
void send_msg_userauth_failure(int partial, int incrfail);
void send_msg_userauth_success(void);
void send_msg_userauth_banner(const buffer *msg);
void svr_auth_password(void);
void svr_auth_pubkey(void);
void svr_auth_pam(void);
void svr_auth_password(int valid_user);
void svr_auth_pubkey(int valid_user);
void svr_auth_pam(int valid_user);
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
int svr_pubkey_allows_agentfwd(void);
@@ -78,7 +78,7 @@ char* getpass_or_cancel(const char* prompt);
void cli_auth_pubkey_cleanup(void);
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
#define MAX_USERNAME_LEN 100 /* arbitrary for the moment */
#define AUTH_TYPE_NONE 1
#define AUTH_TYPE_PUBKEY (1 << 1)
@@ -108,11 +108,14 @@ struct AuthState {
unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
client and server (though has differing
meanings). */
unsigned int perm_warn; /* Server only, set if bad permissions on
~/.ssh/authorized_keys have already been
logged. */
unsigned int checkusername_failed; /* Server only, set if checkusername
has already failed */
struct timespec auth_starttime; /* Server only, time of receiving current
SSH_MSG_USERAUTH_REQUEST */
/* These are only used for the server */
uid_t pw_uid;

View File

@@ -209,6 +209,7 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
unsigned int len;
char* ret;
void* src = NULL;
len = buf_getint(buf);
if (len > MAX_STRING_LEN) {
dropbear_exit("String too long");
@@ -217,8 +218,9 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
if (retlen != NULL) {
*retlen = len;
}
src = buf_getptr(buf, len);
ret = m_malloc(len+1);
memcpy(ret, buf_getptr(buf, len), len);
memcpy(ret, src, len);
buf_incrpos(buf, len);
ret[len] = '\0';

View File

@@ -69,10 +69,6 @@ struct Channel {
int sent_close, recv_close;
int recv_eof, sent_eof;
/* Set after running the ChanType-specific close hander
* to ensure we don't run it twice (nor type->checkclose()). */
int close_handler_done;
struct dropbear_progress_connection *conn_pending;
int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */
@@ -95,10 +91,17 @@ struct ChanType {
int sepfds; /* Whether this channel has separate pipes for in/out or not */
const char *name;
/* Sets up the channel */
int (*inithandler)(struct Channel*);
/* Called to check whether a channel should close, separately from the FD being closed.
Used for noticing process exiting */
int (*check_close)(const struct Channel*);
/* Handler for ssh_msg_channel_request */
void (*reqhandler)(struct Channel*);
/* Called prior to sending ssh_msg_channel_close, used for sending exit status */
void (*closehandler)(const struct Channel*);
/* Frees resources, called just prior to channel being removed */
void (*cleanup)(const struct Channel*);
};
/* Callback for connect_remote */

View File

@@ -52,6 +52,7 @@ const struct ChanType cli_chan_agent = {
new_agent_chan,
NULL,
NULL,
NULL,
NULL
};

View File

@@ -52,6 +52,7 @@ const struct ChanType clichansess = {
NULL, /* checkclosehandler */
cli_chansessreq, /* reqhandler */
cli_closechansess, /* closehandler */
NULL, /* cleanup */
};
static void cli_chansessreq(struct Channel *channel) {
@@ -387,7 +388,8 @@ static const struct ChanType cli_chan_netcat = {
cli_init_netcat, /* inithandler */
NULL,
NULL,
cli_closechansess
cli_closechansess,
NULL,
};
void cli_send_netcat_request() {

View File

@@ -214,7 +214,7 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.always_accept_key = 1;
break;
case 'p': /* remoteport */
next = &cli_opts.remoteport;
next = (char**)&cli_opts.remoteport;
break;
#if DROPBEAR_CLI_PUBKEY_AUTH
case 'i': /* an identityfile */
@@ -891,6 +891,7 @@ static void add_extendedopt(const char* origstr) {
#ifndef DISABLE_SYSLOG
"\tUseSyslog\n"
#endif
"\tPort\n"
);
exit(EXIT_SUCCESS);
}
@@ -909,5 +910,10 @@ static void add_extendedopt(const char* origstr) {
}
#endif
if (match_extendedopt(&optstr, "Port") == DROPBEAR_SUCCESS) {
cli_opts.remoteport = optstr;
return;
}
dropbear_log(LOG_WARNING, "Ignoring unknown configuration option '%s'", origstr);
}

View File

@@ -356,6 +356,7 @@ static void cli_session_cleanup(void) {
}
static void cli_finished() {
TRACE(("cli_finised()"))
session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,

View File

@@ -40,6 +40,7 @@ const struct ChanType cli_chan_tcpremote = {
newtcpforwarded,
NULL,
NULL,
NULL,
NULL
};
#endif
@@ -55,6 +56,7 @@ static const struct ChanType cli_chan_tcplocal = {
tcp_prio_inithandler,
NULL,
NULL,
NULL,
NULL
};
#endif
@@ -135,7 +137,7 @@ static int cli_localtcp(const char* listenaddr,
tcpinfo->chantype = &cli_chan_tcplocal;
tcpinfo->tcp_type = direct;
ret = listen_tcpfwd(tcpinfo);
ret = listen_tcpfwd(tcpinfo, NULL);
if (ret == DROPBEAR_FAILURE) {
m_free(tcpinfo);

View File

@@ -144,7 +144,6 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->index = i;
newchan->sent_close = newchan->recv_close = 0;
newchan->sent_eof = newchan->recv_eof = 0;
newchan->close_handler_done = 0;
newchan->remotechan = remotechan;
newchan->transwindow = transwindow;
@@ -286,7 +285,7 @@ static void check_close(struct Channel *channel) {
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
if (!channel->flushing
&& !channel->close_handler_done
&& !channel->sent_close
&& channel->type->check_close
&& channel->type->check_close(channel))
{
@@ -298,7 +297,7 @@ static void check_close(struct Channel *channel) {
channel, to ensure that the shell has exited (and the exit status
retrieved) before we close things up. */
if (!channel->type->check_close
|| channel->close_handler_done
|| channel->sent_close
|| channel->type->check_close(channel)) {
close_allowed = 1;
}
@@ -385,10 +384,8 @@ void channel_connect_done(int result, int sock, void* user_data, const char* UNU
static void send_msg_channel_close(struct Channel *channel) {
TRACE(("enter send_msg_channel_close %p", (void*)channel))
if (channel->type->closehandler
&& !channel->close_handler_done) {
if (channel->type->closehandler) {
channel->type->closehandler(channel);
channel->close_handler_done = 1;
}
CHECKCLEARTOWRITE();
@@ -661,10 +658,8 @@ static void remove_channel(struct Channel * channel) {
m_close(channel->errfd);
}
if (!channel->close_handler_done
&& channel->type->closehandler) {
channel->type->closehandler(channel);
channel->close_handler_done = 1;
if (channel->type->cleanup) {
channel->type->cleanup(channel);
}
if (channel->conn_pending) {
@@ -690,13 +685,7 @@ void recv_msg_channel_request() {
TRACE(("enter recv_msg_channel_request %p", (void*)channel))
if (channel->sent_close) {
TRACE(("leave recv_msg_channel_request: already closed channel"))
return;
}
if (channel->type->reqhandler
&& !channel->close_handler_done) {
if (channel->type->reqhandler) {
channel->type->reqhandler(channel);
} else {
int wantreply;
@@ -1011,6 +1000,11 @@ cleanup:
void send_msg_channel_failure(const struct Channel *channel) {
TRACE(("enter send_msg_channel_failure"))
if (channel->sent_close) {
TRACE(("Skipping sending msg_channel_failure for closed channel"))
return;
}
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
@@ -1024,6 +1018,10 @@ void send_msg_channel_failure(const struct Channel *channel) {
void send_msg_channel_success(const struct Channel *channel) {
TRACE(("enter send_msg_channel_success"))
if (channel->sent_close) {
TRACE(("Skipping sending msg_channel_success for closed channel"))
return;
}
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);

View File

@@ -48,7 +48,6 @@ static void read_kex_algos(void);
/* helper function for gen_new_keys */
static void hashkeys(unsigned char *out, unsigned int outlen,
const hash_state * hs, const unsigned char X);
static void finish_kexhashbuf(void);
/* Send our list of algorithms we can use */
@@ -391,6 +390,14 @@ int is_compress_recv() {
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
}
static void* dropbear_zalloc(void* UNUSED(opaque), uInt items, uInt size) {
return m_calloc(items, size);
}
static void dropbear_zfree(void* UNUSED(opaque), void* ptr) {
m_free(ptr);
}
/* Set up new zlib compression streams, close the old ones. Only
* called from gen_new_keys() */
static void gen_new_zstream_recv() {
@@ -399,8 +406,8 @@ static void gen_new_zstream_recv() {
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->recv.zstream->zalloc = Z_NULL;
ses.newkeys->recv.zstream->zfree = Z_NULL;
ses.newkeys->recv.zstream->zalloc = dropbear_zalloc;
ses.newkeys->recv.zstream->zfree = dropbear_zfree;
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
dropbear_exit("zlib error");
@@ -423,8 +430,8 @@ static void gen_new_zstream_trans() {
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->trans.zstream->zalloc = Z_NULL;
ses.newkeys->trans.zstream->zfree = Z_NULL;
ses.newkeys->trans.zstream->zalloc = dropbear_zalloc;
ses.newkeys->trans.zstream->zfree = dropbear_zfree;
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
@@ -687,6 +694,9 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
/* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K);
ecc_free(Q_them);
m_free(Q_them);
/* calculate the hash H to sign */
finish_kexhashbuf();
}
@@ -761,8 +771,7 @@ void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buff
#endif /* DROPBEAR_CURVE25519 */
static void finish_kexhashbuf(void) {
void finish_kexhashbuf(void) {
hash_state hs;
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
@@ -943,6 +952,12 @@ static void read_kex_algos() {
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
}
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
fuzz_kex_fakealgos();
}
#endif
/* reserved for future extensions */
buf_getint(ses.payload);

View File

@@ -68,6 +68,16 @@ void common_session_init(int sock_in, int sock_out) {
/* Sets it to lowdelay */
update_channel_prio();
#if !DROPBEAR_SVR_MULTIUSER
/* A sanity check to prevent an accidental configuration option
leaving multiuser systems exposed */
errno = 0;
getuid();
if (errno != ENOSYS) {
dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
}
#endif
now = monotonic_now();
ses.connect_time = now;
ses.last_packet_time_keepalive_recv = now;
@@ -75,14 +85,18 @@ void common_session_init(int sock_in, int sock_out) {
ses.last_packet_time_any_sent = 0;
ses.last_packet_time_keepalive_sent = 0;
#if DROPBEAR_FUZZ
if (!fuzz.fuzzing)
#endif
{
if (pipe(ses.signal_pipe) < 0) {
dropbear_exit("Signal pipe failed");
}
setnonblocking(ses.signal_pipe[0]);
setnonblocking(ses.signal_pipe[1]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
}
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
ses.transseq = 0;
@@ -148,13 +162,19 @@ void session_loop(void(*loophandler)(void)) {
timeout.tv_sec = select_timeout();
timeout.tv_usec = 0;
FD_ZERO(&writefd);
FD_ZERO(&readfd);
DROPBEAR_FD_ZERO(&writefd);
DROPBEAR_FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL);
/* We get woken up when signal handlers write to this pipe.
SIGCHLD in svr-chansession is the only one currently. */
#if DROPBEAR_FUZZ
if (!fuzz.fuzzing)
#endif
{
FD_SET(ses.signal_pipe[0], &readfd);
}
/* set up for channels which can be read/written */
setchannelfds(&readfd, &writefd, writequeue_has_space);
@@ -195,8 +215,8 @@ void session_loop(void(*loophandler)(void)) {
* want to iterate over channels etc for reading, to handle
* server processes exiting etc.
* We don't want to read/write FDs. */
FD_ZERO(&writefd);
FD_ZERO(&readfd);
DROPBEAR_FD_ZERO(&writefd);
DROPBEAR_FD_ZERO(&readfd);
}
/* We'll just empty out the pipe if required. We don't do
@@ -298,6 +318,16 @@ void session_cleanup() {
buf_free(dequeue(&ses.writequeue));
}
m_free(ses.newkeys);
#ifndef DISABLE_ZLIB
if (ses.keys->recv.zstream != NULL) {
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
dropbear_exit("Crypto error");
}
m_free(ses.keys->recv.zstream);
}
#endif
m_free(ses.remoteident);
m_free(ses.authstate.pw_dir);
m_free(ses.authstate.pw_name);
@@ -327,7 +357,7 @@ void session_cleanup() {
void send_session_identification() {
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
writebuf_enqueue(writebuf, 0);
writebuf_enqueue(writebuf);
}
static void read_session_identification() {
@@ -387,7 +417,7 @@ static int ident_readln(int fd, char* buf, int count) {
return -1;
}
FD_ZERO(&fds);
DROPBEAR_FD_ZERO(&fds);
/* select since it's a non-blocking fd */

939
config.guess vendored

File diff suppressed because it is too large Load Diff

2752
config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,13 @@ AC_PREREQ(2.59)
AC_INIT
AC_CONFIG_SRCDIR(buffer.c)
# Record which revision is being built
if test -s "`which hg`" && test -d "$srcdir/.hg"; then
hgrev=`hg id -i -R "$srcdir"`
AC_MSG_NOTICE([Source directory Mercurial base revision $hgrev])
fi
ORIGCFLAGS="$CFLAGS"
# Checks for programs.
AC_PROG_CC
@@ -29,7 +36,7 @@ AC_DEFUN(DB_TRYADDCFLAGS,
}])
# set compile flags prior to other tests
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
if test -z "$ORIGCFLAGS" && test "$GCC" = "yes"; then
AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
CFLAGS="-Os -W -Wall"
fi
@@ -315,7 +322,24 @@ AC_ARG_ENABLE(shadow,
AC_MSG_NOTICE(Using shadow passwords if available)
]
)
AC_ARG_ENABLE(fuzz,
[ --enable-fuzz Build fuzzing. Not recommended for deployment.],
[
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
AC_MSG_NOTICE(Enabling fuzzing)
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
AC_PROG_CXX
],
[
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
DROPBEAR_FUZZ=0
]
)
AC_SUBST(DROPBEAR_FUZZ)
AC_SUBST(CXX)
# Checks for header files.
AC_HEADER_STDC
@@ -473,6 +497,9 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
AC_CHECK_FUNCS(setutxent utmpxname)
AC_CHECK_FUNCS(logout updwtmp logwtmp)
# POSIX monotonic time
AC_CHECK_FUNCS(clock_gettime)
# OS X monotonic time
AC_CHECK_HEADERS([mach/mach_time.h])
AC_CHECK_FUNCS(mach_absolute_time)

View File

@@ -9,16 +9,9 @@ void m_burn(void *data, unsigned int len) {
#elif defined(HAVE_EXPLICIT_BZERO)
explicit_bzero(data, len);
#else
/* Based on the method in David Wheeler's
* "Secure Programming for Linux and Unix HOWTO". May not be safe
* against link-time optimisation. */
volatile char *p = data;
if (data == NULL)
return;
while (len--) {
*p++ = 0x0;
}
/* This must be volatile to avoid compiler optimisation */
volatile void *p = data;
memset((void*)p, 0x0, len);
#endif
}

182
dbmalloc.c Normal file
View File

@@ -0,0 +1,182 @@
#include "dbmalloc.h"
#include "dbutil.h"
void * m_calloc(size_t nmemb, size_t size) {
if (SIZE_T_MAX / nmemb < size) {
dropbear_exit("m_calloc failed");
}
return m_malloc(nmemb*size);
}
void * m_strdup(const char * str) {
char* ret;
unsigned int len;
len = strlen(str);
ret = m_malloc(len+1);
if (ret == NULL) {
dropbear_exit("m_strdup failed");
}
memcpy(ret, str, len+1);
return ret;
}
#if !DROPBEAR_TRACKING_MALLOC
/* Simple wrappers around malloc etc */
void * m_malloc(size_t size) {
void* ret;
if (size == 0) {
dropbear_exit("m_malloc failed");
}
ret = calloc(1, size);
if (ret == NULL) {
dropbear_exit("m_malloc failed");
}
return ret;
}
void * m_realloc(void* ptr, size_t size) {
void *ret;
if (size == 0) {
dropbear_exit("m_realloc failed");
}
ret = realloc(ptr, size);
if (ret == NULL) {
dropbear_exit("m_realloc failed");
}
return ret;
}
#else
/* For fuzzing */
struct dbmalloc_header {
unsigned int epoch;
struct dbmalloc_header *prev;
struct dbmalloc_header *next;
};
static void put_alloc(struct dbmalloc_header *header);
static void remove_alloc(struct dbmalloc_header *header);
/* end of the linked list */
static struct dbmalloc_header* staple;
unsigned int current_epoch = 0;
void m_malloc_set_epoch(unsigned int epoch) {
current_epoch = epoch;
}
void m_malloc_free_epoch(unsigned int epoch, int dofree) {
struct dbmalloc_header* header;
struct dbmalloc_header* nextheader = NULL;
struct dbmalloc_header* oldstaple = staple;
staple = NULL;
/* free allocations from this epoch, create a new staple-anchored list from
the remainder */
for (header = oldstaple; header; header = nextheader)
{
nextheader = header->next;
if (header->epoch == epoch) {
if (dofree) {
free(header);
}
} else {
header->prev = NULL;
header->next = NULL;
put_alloc(header);
}
}
}
static void put_alloc(struct dbmalloc_header *header) {
assert(header->next == NULL);
assert(header->prev == NULL);
if (staple) {
staple->prev = header;
}
header->next = staple;
staple = header;
}
static void remove_alloc(struct dbmalloc_header *header) {
if (header->prev) {
header->prev->next = header->next;
}
if (header->next) {
header->next->prev = header->prev;
}
if (staple == header) {
staple = header->next;
}
header->prev = NULL;
header->next = NULL;
}
static struct dbmalloc_header* get_header(void* ptr) {
char* bptr = ptr;
return (struct dbmalloc_header*)&bptr[-sizeof(struct dbmalloc_header)];
}
void * m_malloc(size_t size) {
char* mem = NULL;
struct dbmalloc_header* header = NULL;
if (size == 0 || size > 1e9) {
dropbear_exit("m_malloc failed");
}
size = size + sizeof(struct dbmalloc_header);
mem = calloc(1, size);
if (mem == NULL) {
dropbear_exit("m_malloc failed");
}
header = (struct dbmalloc_header*)mem;
put_alloc(header);
header->epoch = current_epoch;
return &mem[sizeof(struct dbmalloc_header)];
}
void * m_realloc(void* ptr, size_t size) {
char* mem = NULL;
struct dbmalloc_header* header = NULL;
if (size == 0 || size > 1e9) {
dropbear_exit("m_realloc failed");
}
header = get_header(ptr);
remove_alloc(header);
size = size + sizeof(struct dbmalloc_header);
mem = realloc(header, size);
if (mem == NULL) {
dropbear_exit("m_realloc failed");
}
header = (struct dbmalloc_header*)mem;
put_alloc(header);
return &mem[sizeof(struct dbmalloc_header)];
}
void m_free_direct(void* ptr) {
struct dbmalloc_header* header = NULL;
if (!ptr) {
return;
}
header = get_header(ptr);
remove_alloc(header);
free(header);
}
#endif /* DROPBEAR_TRACKING_MALLOC */

27
dbmalloc.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef DBMALLOC_H_
#define DBMALLOC_H_
#include "stdint.h"
#include "stdlib.h"
#include "options.h"
void * m_malloc(size_t size);
void * m_calloc(size_t nmemb, size_t size);
void * m_strdup(const char * str);
void * m_realloc(void* ptr, size_t size);
#if DROPBEAR_TRACKING_MALLOC
void m_free_direct(void* ptr);
void m_malloc_set_epoch(unsigned int epoch);
void m_malloc_free_epoch(unsigned int epoch, int dofree);
#else
/* plain wrapper */
#define m_free_direct free
#endif
#define m_free(X) do {m_free_direct(X); (X) = NULL;} while (0)
#endif /* DBMALLOC_H_ */

View File

@@ -27,7 +27,7 @@
#include "dbutil.h"
#include "bignum.h"
#include "dbrandom.h"
#include "runopts.h"
/* this is used to generate unique output from the same hashpool */
static uint32_t counter = 0;
@@ -88,7 +88,7 @@ process_file(hash_state *hs, const char *filename,
timeout.tv_sec = 2;
timeout.tv_usec = 0;
FD_ZERO(&read_fds);
DROPBEAR_FD_ZERO(&read_fds);
FD_SET(readfd, &read_fds);
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
if (res == 0)
@@ -145,6 +145,12 @@ void addrandom(const unsigned char * buf, unsigned int len)
{
hash_state hs;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return;
}
#endif
/* hash in the new seed data */
sha1_init(&hs);
/* existing state (zeroes on startup) */
@@ -157,6 +163,11 @@ void addrandom(const unsigned char * buf, unsigned int len)
static void write_urandom()
{
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return;
}
#endif
#if !DROPBEAR_USE_PRNGD
/* This is opportunistic, don't worry about failure */
unsigned char buf[INIT_SEED_SIZE];
@@ -170,6 +181,18 @@ static void write_urandom()
#endif
}
#if DROPBEAR_FUZZ
void fuzz_seed(void) {
hash_state hs;
sha1_init(&hs);
sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
}
#endif
/* Initialise the prng from /dev/urandom or prngd. This function can
* be called multiple times */
void seedrandom() {
@@ -180,8 +203,15 @@ void seedrandom() {
struct timeval tv;
clock_t clockval;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return;
}
#endif
/* hash in the new seed data */
sha1_init(&hs);
/* existing state */
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));

143
dbutil.c
View File

@@ -120,6 +120,13 @@ static void generic_dropbear_exit(int exitcode, const char* format,
_dropbear_log(LOG_INFO, fmtbuf, param);
#if DROPBEAR_FUZZ
/* longjmp before cleaning up svr_opts */
if (fuzz.do_jmp) {
longjmp(fuzz.jmp, 1);
}
#endif
exit(exitcode);
}
@@ -392,6 +399,7 @@ void printhex(const char * label, const unsigned char * buf, int len) {
void printmpint(const char *label, mp_int *mp) {
buffer *buf = buf_new(1000);
buf_putmpint(buf, mp);
fprintf(stderr, "%d bits ", mp_count_bits(mp));
printhex(label, buf->data, buf->len);
buf_free(buf);
@@ -520,57 +528,26 @@ void m_close(int fd) {
}
}
void * m_malloc(size_t size) {
void* ret;
if (size == 0) {
dropbear_exit("m_malloc failed");
}
ret = calloc(1, size);
if (ret == NULL) {
dropbear_exit("m_malloc failed");
}
return ret;
}
void * m_strdup(const char * str) {
char* ret;
ret = strdup(str);
if (ret == NULL) {
dropbear_exit("m_strdup failed");
}
return ret;
}
void * m_realloc(void* ptr, size_t size) {
void *ret;
if (size == 0) {
dropbear_exit("m_realloc failed");
}
ret = realloc(ptr, size);
if (ret == NULL) {
dropbear_exit("m_realloc failed");
}
return ret;
}
void setnonblocking(int fd) {
TRACE(("setnonblocking: %d", fd))
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return;
}
#endif
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
if (errno == ENODEV) {
/* Some devices (like /dev/null redirected in)
* can't be set to non-blocking */
TRACE(("ignoring ENODEV for setnonblocking"))
} else {
{
dropbear_exit("Couldn't set nonblocking");
}
}
}
TRACE(("leave setnonblocking"))
}
@@ -628,61 +605,67 @@ int constant_time_memcmp(const void* a, const void *b, size_t n)
return c;
}
#if defined(__linux__) && defined(SYS_clock_gettime)
/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to
reach userspace include headers */
#ifndef CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE 6
/* higher-resolution monotonic timestamp, falls back to gettimeofday */
void gettime_wrapper(struct timespec *now) {
struct timeval tv;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
/* time stands still when fuzzing */
now->tv_sec = 5;
now->tv_nsec = 0;
}
#endif
/* Some old toolchains know SYS_clock_gettime but not CLOCK_MONOTONIC */
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 1
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
/* POSIX monotonic clock. Newer Linux, BSD, MacOSX >10.12 */
if (clock_gettime(CLOCK_MONOTONIC, now) == 0) {
return;
}
#endif
static clockid_t get_linux_clock_source() {
struct timespec ts;
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
return CLOCK_MONOTONIC_COARSE;
}
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) {
return CLOCK_MONOTONIC;
}
return -1;
}
#endif
time_t monotonic_now() {
#if defined(__linux__) && defined(SYS_clock_gettime)
static clockid_t clock_source = -2;
if (clock_source == -2) {
/* First run, find out which one works.
-1 will fall back to time() */
clock_source = get_linux_clock_source();
}
if (clock_source >= 0) {
struct timespec ts;
if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) {
/* Intermittent clock failures should not happen */
dropbear_exit("Clock broke");
{
/* Old linux toolchain - kernel might support it but not the build headers */
/* Also glibc <2.17 requires -lrt which we neglect to add */
static int linux_monotonic_failed = 0;
if (!linux_monotonic_failed) {
/* CLOCK_MONOTONIC isn't in some headers */
int clock_source_monotonic = 1;
if (syscall(SYS_clock_gettime, clock_source_monotonic, now) == 0) {
return;
} else {
/* Don't try again */
linux_monotonic_failed = 1;
}
return ts.tv_sec;
}
#endif /* linux clock_gettime */
}
#endif /* linux fallback clock_gettime */
#if defined(HAVE_MACH_ABSOLUTE_TIME)
/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
{
/* OS X pre 10.12, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
static mach_timebase_info_data_t timebase_info;
uint64_t scaled_time;
if (timebase_info.denom == 0) {
mach_timebase_info(&timebase_info);
}
return mach_absolute_time() * timebase_info.numer / timebase_info.denom
/ 1e9;
scaled_time = mach_absolute_time() * timebase_info.numer / timebase_info.denom;
now->tv_sec = scaled_time / 1000000000;
now->tv_nsec = scaled_time % 1000000000;
}
#endif /* osx mach_absolute_time */
/* Fallback for everything else - this will sometimes go backwards */
return time(NULL);
gettimeofday(&tv, NULL);
now->tv_sec = tv.tv_sec;
now->tv_nsec = 1000*tv.tv_usec;
}
/* second-resolution monotonic timestamp */
time_t monotonic_now() {
struct timespec ts;
gettime_wrapper(&ts);
return ts.tv_sec;
}
void fsync_parent_dir(const char* fn) {
@@ -700,6 +683,6 @@ void fsync_parent_dir(const char* fn) {
TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
}
free(fn_dir);
m_free(fn_dir);
#endif
}

View File

@@ -30,6 +30,7 @@
#include "buffer.h"
#include "queue.h"
#include "dbhelpers.h"
#include "dbmalloc.h"
#ifndef DISABLE_SYSLOG
void startsyslog(const char *ident);
@@ -66,10 +67,6 @@ int buf_readfile(buffer* buf, const char* filename);
int buf_getline(buffer * line, FILE * authfile);
void m_close(int fd);
void * m_malloc(size_t size);
void * m_strdup(const char * str);
void * m_realloc(void* ptr, size_t size);
#define m_free(X) do {free(X); (X) = NULL;} while (0)
void setnonblocking(int fd);
void disallow_core(void);
int m_str_to_uint(const char* str, unsigned int *val);
@@ -86,9 +83,18 @@ int constant_time_memcmp(const void* a, const void *b, size_t n);
/* Returns a time in seconds that doesn't go backwards - does not correspond to
a real-world clock */
time_t monotonic_now(void);
/* Higher resolution clock_gettime(CLOCK_MONOTONIC) wrapper */
void gettime_wrapper(struct timespec *now);
char * expand_homedir_path(const char *inpath);
void fsync_parent_dir(const char* fn);
#if DROPBEAR_MSAN
/* FD_ZERO seems to leave some memory uninitialized. clear it to avoid false positives */
#define DROPBEAR_FD_ZERO(fds) do { memset((fds), 0x0, sizeof(fd_set)); FD_ZERO(fds); } while(0)
#else
#define DROPBEAR_FD_ZERO(fds) FD_ZERO(fds)
#endif
#endif /* DROPBEAR_DBUTIL_H_ */

12
debian/changelog vendored
View File

@@ -1,3 +1,15 @@
dropbear (2019.78-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 27 Mar 2019 22:51:57 +0800
dropbear (2019.77-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Sat, 23 Mar 2019 22:51:57 +0800
dropbear (2018.76-0.1) unstable; urgency=low
* New upstream release.

View File

@@ -39,7 +39,9 @@
/*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
ses.writepayload->pos == 0)*/
#ifndef CHECKCLEARTOWRITE
#define CHECKCLEARTOWRITE()
#endif
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
* output when Dropbear forks. This will allow it gprof to be used.
@@ -54,6 +56,7 @@
/* you don't need to touch this block */
#if DEBUG_TRACE
extern int debug_trace;
#define TRACE(X) dropbear_trace X;
#define TRACE2(X) dropbear_trace2 X;
#else /*DEBUG_TRACE*/

View File

@@ -6,8 +6,8 @@
default_options.h documents compile-time options, and provides default values.
Local customisation should be added to localoptions.h which is
used if it exists. Options defined there will override any options in this
file.
used if it exists in the build directory. Options defined there will override
any options in this file.
Options can also be defined with -DDROPBEAR_XXX=[0,1] in Makefile CFLAGS
@@ -196,6 +196,11 @@ group1 in Dropbear server too */
* authorized_keys file into account */
#define DROPBEAR_SVR_PUBKEY_OPTIONS 1
/* Set this to 0 if your system does not have multiple user support.
(Linux kernel CONFIG_MULTIUSER option)
The resulting binary will not run on a normal system. */
#define DROPBEAR_SVR_MULTIUSER 1
/* Client authentication options */
#define DROPBEAR_CLI_PASSWORD_AUTH 1
#define DROPBEAR_CLI_PUBKEY_AUTH 1

25
dss.c
View File

@@ -73,6 +73,18 @@ int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
goto out;
}
/* test 1 < g < p */
if (mp_cmp_d(key->g, 1) != MP_GT) {
dropbear_log(LOG_WARNING, "Bad DSS g");
ret = DROPBEAR_FAILURE;
goto out;
}
if (mp_cmp(key->g, key->p) != MP_LT) {
dropbear_log(LOG_WARNING, "Bad DSS g");
ret = DROPBEAR_FAILURE;
goto out;
}
ret = DROPBEAR_SUCCESS;
TRACE(("leave buf_get_dss_pub_key: success"))
out:
@@ -172,6 +184,13 @@ int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_
goto out;
}
#if DEBUG_DSS_VERIFY
printmpint("dss verify p", key->p);
printmpint("dss verify q", key->q);
printmpint("dss verify g", key->g);
printmpint("dss verify y", key->y);
#endif
/* hash the data */
sha1_init(&hs);
sha1_process(&hs, data_buf->data, data_buf->len);
@@ -181,6 +200,9 @@ int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_
/* w = (s')-1 mod q */
/* let val1 = s' */
bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
#if DEBUG_DSS_VERIFY
printmpint("dss verify s'", &val1);
#endif
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, s' >= q"))
@@ -198,6 +220,9 @@ int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_
/* u1 = ((SHA(M')w) mod q */
/* let val1 = SHA(M') = msghash */
bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
#if DEBUG_DSS_VERIFY
printmpint("dss verify r'", &val1);
#endif
/* let val3 = u1 = ((SHA(M')w) mod q */
if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {

View File

@@ -16,7 +16,7 @@
#elif DROPBEAR_ECC_521
#define ECDSA_DEFAULT_SIZE 521
#else
#define ECDSA_DEFAULT_SIZE 0
#error ECDSA cannot be enabled without enabling at least one size (256, 384, 521)
#endif
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);

201
fuzz-common.c Normal file
View File

@@ -0,0 +1,201 @@
#include "includes.h"
#include "includes.h"
#include "fuzz.h"
#include "dbutil.h"
#include "runopts.h"
#include "crypto_desc.h"
#include "session.h"
#include "dbrandom.h"
#include "bignum.h"
#include "fuzz-wrapfd.h"
struct dropbear_fuzz_options fuzz;
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param);
static void load_fixed_hostkeys(void);
void fuzz_common_setup(void) {
fuzz.fuzzing = 1;
fuzz.wrapfds = 1;
fuzz.do_jmp = 1;
fuzz.input = m_malloc(sizeof(buffer));
_dropbear_log = fuzz_dropbear_log;
crypto_init();
fuzz_seed();
/* let any messages get flushed */
setlinebuf(stdout);
}
int fuzz_set_input(const uint8_t *Data, size_t Size) {
fuzz.input->data = (unsigned char*)Data;
fuzz.input->size = Size;
fuzz.input->len = Size;
fuzz.input->pos = 0;
memset(&ses, 0x0, sizeof(ses));
memset(&svr_ses, 0x0, sizeof(svr_ses));
wrapfd_setup();
fuzz_seed();
return DROPBEAR_SUCCESS;
}
#if DEBUG_TRACE
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
if (debug_trace) {
char printbuf[1024];
vsnprintf(printbuf, sizeof(printbuf), format, param);
fprintf(stderr, "%s\n", printbuf);
}
}
#else
static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
/* No print */
}
#endif /* DEBUG_TRACE */
void fuzz_svr_setup(void) {
fuzz_common_setup();
_dropbear_exit = svr_dropbear_exit;
char *argv[] = {
"-E",
};
int argc = sizeof(argv) / sizeof(*argv);
svr_getopts(argc, argv);
/* user lookups might be slow, cache it */
fuzz.pw_name = m_strdup("person");
fuzz.pw_dir = m_strdup("/tmp");
fuzz.pw_shell = m_strdup("/bin/zsh");
fuzz.pw_passwd = m_strdup("!!zzznope");
load_fixed_hostkeys();
}
static void load_fixed_hostkeys(void) {
#include "fuzz-hostkeys.c"
buffer *b = buf_new(3000);
enum signkey_type type;
TRACE(("load fixed hostkeys"))
svr_opts.hostkey = new_sign_key();
buf_setlen(b, 0);
buf_putbytes(b, keyr, keyr_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_RSA;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed rsa hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keyd, keyd_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_DSS;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed dss hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keye, keye_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed ecdsa hostkey");
}
buf_free(b);
}
void fuzz_kex_fakealgos(void) {
ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
}
void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
if (local_host) {
*local_host = m_strdup("fuzzlocalhost");
}
if (local_port) {
*local_port = m_strdup("1234");
}
if (remote_host) {
*remote_host = m_strdup("fuzzremotehost");
}
if (remote_port) {
*remote_port = m_strdup("9876");
}
}
/* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
void fuzz_fake_send_kexdh_reply(void) {
assert(!ses.dh_K);
m_mp_alloc_init_multi(&ses.dh_K, NULL);
mp_set_int(ses.dh_K, 12345678);
finish_kexhashbuf();
}
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
static int once = 0;
if (!once) {
fuzz_svr_setup();
fuzz.skip_kexmaths = skip_kexmaths;
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
/*
get prefix. input format is
string prefix
uint32 wrapfd seed
... to be extended later
[bytes] ssh input stream
*/
/* be careful to avoid triggering buffer.c assertions */
if (fuzz.input->len < 8) {
return 0;
}
size_t prefix_size = buf_getint(fuzz.input);
if (prefix_size != 4) {
return 0;
}
uint32_t wrapseed = buf_getint(fuzz.input);
wrapfd_setseed(wrapseed);
int fakesock = 20;
wrapfd_add(fakesock, fuzz.input, PLAIN);
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
svr_session(fakesock, fakesock);
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}
const void* fuzz_get_algo(const algo_type *algos, const char* name) {
const algo_type *t;
for (t = algos; t->name; t++) {
if (strcmp(t->name, name) == 0) {
return t->data;
}
}
assert(0);
}

48
fuzz-harness.c Normal file
View File

@@ -0,0 +1,48 @@
#include "includes.h"
#include "buffer.h"
#include "dbutil.h"
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
int main(int argc, char ** argv) {
int i;
buffer *input = buf_new(100000);
for (i = 1; i < argc; i++) {
printf("arg %s\n", argv[i]);
#if DEBUG_TRACE
if (strcmp(argv[i], "-v") == 0) {
debug_trace = 1;
TRACE(("debug printing on"))
}
#endif
}
int old_fuzz_wrapfds = 0;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
/* ignore arguments */
continue;
}
char* fn = argv[i];
buf_setlen(input, 0);
buf_readfile(input, fn);
buf_setpos(input, 0);
fuzz.wrapfds = old_fuzz_wrapfds;
printf("Running %s once \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len);
printf("Running %s twice \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len);
printf("Done %s\n", fn);
/* Disable wrapfd so it won't interfere with buf_readfile() above */
old_fuzz_wrapfds = fuzz.wrapfds;
fuzz.wrapfds = 0;
}
printf("Finished\n");
return 0;
}

129
fuzz-hostkeys.c Normal file
View File

@@ -0,0 +1,129 @@
unsigned char keyr[] = {
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00,
0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xb1,
0x06, 0x95, 0xc9, 0xa8, 0x38, 0xb9, 0x99, 0x91, 0xb5, 0x17, 0x39, 0xb9,
0xfa, 0xa4, 0x49, 0xf8, 0x2a, 0x4c, 0x14, 0xbd, 0xb6, 0x85, 0xdb, 0x38,
0x99, 0x44, 0xfa, 0xd6, 0xaa, 0x67, 0xef, 0x00, 0x75, 0x2b, 0x6a, 0x5c,
0x1b, 0x50, 0xa8, 0x52, 0xf9, 0xa7, 0xee, 0xe2, 0xb3, 0x80, 0x38, 0x92,
0x20, 0x86, 0x7c, 0xe5, 0x89, 0xb3, 0x06, 0xe4, 0x3b, 0xd1, 0xe2, 0x45,
0xea, 0xc1, 0xd5, 0x8e, 0x05, 0xfb, 0x90, 0x29, 0xd9, 0x41, 0xb3, 0x05,
0x31, 0x1e, 0xcc, 0xeb, 0x89, 0xdc, 0xd2, 0x6a, 0x99, 0x23, 0xbd, 0x7a,
0xbe, 0x8c, 0xe3, 0x3f, 0xa1, 0xe8, 0xf5, 0xb4, 0x51, 0x40, 0xb4, 0xb1,
0xc1, 0x16, 0x9f, 0x07, 0xbb, 0x99, 0xaa, 0x4b, 0x8f, 0x11, 0x19, 0x3c,
0x18, 0xbd, 0x6e, 0xce, 0x14, 0x54, 0x2c, 0x16, 0x4a, 0x5f, 0x89, 0xe4,
0x6b, 0x9f, 0x55, 0x68, 0xcc, 0x09, 0x8e, 0x4b, 0x92, 0xc8, 0x87, 0xfe,
0x09, 0xed, 0x53, 0x6e, 0xff, 0x5f, 0x15, 0x0d, 0x19, 0x9d, 0xa6, 0x54,
0xd2, 0xea, 0x59, 0x4f, 0xa1, 0x7c, 0xf6, 0xf5, 0x7f, 0x32, 0x23, 0xed,
0x72, 0xa8, 0x96, 0x17, 0x87, 0x06, 0xf2, 0xc7, 0xcd, 0xda, 0x4a, 0x10,
0xd1, 0xfd, 0xb8, 0xf1, 0xaf, 0x25, 0x55, 0x32, 0x45, 0x39, 0x95, 0xec,
0x0c, 0xa9, 0xf0, 0x47, 0x8b, 0x66, 0xe0, 0xb7, 0xa2, 0xf6, 0x35, 0x50,
0x27, 0xe7, 0x2f, 0x90, 0x35, 0x5b, 0xd5, 0x62, 0x19, 0xb4, 0x41, 0xd4,
0x52, 0xe7, 0x7f, 0x97, 0xfc, 0x5b, 0x4a, 0x5b, 0x19, 0x06, 0x65, 0x2d,
0x23, 0x29, 0x15, 0x8b, 0x05, 0xaf, 0xbe, 0xd3, 0x4a, 0x27, 0x5b, 0xc9,
0xc0, 0xd0, 0xd2, 0xba, 0x8b, 0x00, 0x7a, 0x2f, 0x39, 0xa0, 0x13, 0xb9,
0xe6, 0xf5, 0x4b, 0x21, 0x54, 0x57, 0xb3, 0xf9, 0x6c, 0x6f, 0xd0, 0x17,
0xf4, 0x50, 0x9d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xf2, 0xda, 0x5f, 0xfb,
0xe2, 0xda, 0xfc, 0xe0, 0xdf, 0x3a, 0x0e, 0x14, 0x18, 0xc1, 0xd9, 0x1f,
0x43, 0xe3, 0x65, 0x3e, 0x07, 0xe7, 0x8d, 0xdc, 0x1d, 0x11, 0xc1, 0xd6,
0xc0, 0xd8, 0xda, 0x53, 0xf5, 0x04, 0x73, 0x51, 0x1b, 0x26, 0xef, 0x4e,
0xf5, 0xce, 0x3d, 0x77, 0x21, 0x94, 0xd0, 0xc7, 0xc1, 0xda, 0x19, 0x7d,
0xf8, 0xc5, 0x4c, 0xc8, 0xee, 0x7d, 0xd1, 0xbb, 0x02, 0x90, 0x2b, 0xff,
0x4e, 0x4d, 0xd7, 0x9d, 0x72, 0x0c, 0x60, 0x0f, 0x4b, 0x83, 0xf5, 0xc2,
0x26, 0xd6, 0x22, 0xb8, 0x60, 0x3a, 0xf9, 0x2f, 0x92, 0x2a, 0x2e, 0x14,
0xa7, 0x56, 0x1c, 0x56, 0x05, 0x41, 0x92, 0xac, 0xb1, 0x4e, 0x44, 0x1e,
0x70, 0x42, 0xda, 0xc7, 0xc8, 0x9c, 0xae, 0x29, 0x2d, 0x0c, 0x3a, 0xff,
0x9b, 0xb6, 0xad, 0xb4, 0xfb, 0x49, 0x28, 0x96, 0x74, 0xf5, 0x94, 0x74,
0xb7, 0x40, 0x93, 0x2b, 0x34, 0x29, 0xd2, 0x8a, 0xf3, 0x99, 0xf9, 0xe9,
0xd8, 0xcc, 0x48, 0x1d, 0x3e, 0xc1, 0x82, 0x35, 0x4f, 0xef, 0xb1, 0x81,
0x3c, 0xe1, 0xa1, 0x03, 0x65, 0xac, 0x21, 0x21, 0x40, 0x61, 0xfb, 0xd3,
0x54, 0xac, 0xa1, 0xf2, 0xf0, 0x61, 0xd9, 0x01, 0x4e, 0xc2, 0x28, 0xb1,
0x7c, 0x27, 0x6e, 0x56, 0x68, 0x69, 0x8f, 0xc5, 0xfd, 0xca, 0x39, 0x6e,
0x22, 0x09, 0xf1, 0xb4, 0xd5, 0xac, 0xb8, 0xe0, 0x1b, 0x21, 0x86, 0xf4,
0xc8, 0x15, 0xc6, 0x1f, 0x21, 0xae, 0xcb, 0xab, 0x5a, 0x09, 0x30, 0x9e,
0xdd, 0x6c, 0x38, 0x59, 0xec, 0x59, 0x3a, 0x08, 0xee, 0x46, 0x7b, 0x78,
0x23, 0xbc, 0xfc, 0xe2, 0xda, 0xe8, 0x1a, 0x65, 0xe6, 0xe0, 0x78, 0xd3,
0xb0, 0x03, 0x2e, 0xf1, 0xb8, 0xca, 0x8e, 0x90, 0x75, 0xaf, 0xf7, 0xa8,
0x48, 0xed, 0x82, 0xc9, 0xcf, 0x44, 0x56, 0xfc, 0x05, 0xfd, 0x6b, 0x00,
0x00, 0x00, 0x81, 0x00, 0xfc, 0x94, 0xdf, 0x42, 0xc7, 0x9a, 0xa2, 0xff,
0x32, 0xdf, 0x06, 0xb6, 0x4d, 0x90, 0x31, 0x28, 0x28, 0xdb, 0x03, 0xf9,
0xa6, 0xb3, 0xa2, 0x91, 0x4c, 0xdf, 0x6e, 0xf6, 0xb9, 0x44, 0x3b, 0xdd,
0x17, 0xc1, 0xc8, 0x1d, 0xd1, 0xc0, 0xc0, 0x30, 0x22, 0xbe, 0x24, 0x2e,
0x0e, 0xdf, 0xe0, 0x18, 0x37, 0x3e, 0xb8, 0x7f, 0xb2, 0x50, 0x34, 0xc4,
0x08, 0x5e, 0x69, 0x1f, 0xd5, 0xc9, 0xce, 0x47, 0x7d, 0x75, 0x5e, 0x3b,
0x87, 0xdd, 0x46, 0x35, 0x01, 0x0f, 0x17, 0x8a, 0xf1, 0xf1, 0xc4, 0xa9,
0x94, 0xa7, 0x6e, 0xce, 0x80, 0xe3, 0x17, 0x2e, 0xb0, 0xef, 0x63, 0xa7,
0x11, 0x86, 0x96, 0x4a, 0x63, 0x2d, 0x9e, 0x92, 0x62, 0x43, 0x43, 0x72,
0xa5, 0xdc, 0xa0, 0xcd, 0x19, 0x93, 0xd7, 0xe0, 0x80, 0x41, 0x27, 0xea,
0xe4, 0xe8, 0xc1, 0x91, 0x9e, 0x13, 0xb3, 0x9c, 0xd1, 0xed, 0xcb, 0xbf,
0x00, 0x00, 0x00, 0x81, 0x00, 0xb3, 0x6b, 0xee, 0xa4, 0x70, 0x4e, 0xfb,
0xf9, 0x7e, 0x2e, 0x74, 0x5d, 0x3e, 0x8b, 0x3f, 0xff, 0x8c, 0xde, 0x68,
0x38, 0xda, 0xce, 0xc0, 0x66, 0x4b, 0xca, 0x35, 0xc3, 0x97, 0xa8, 0xf0,
0x00, 0x8e, 0xb3, 0x46, 0x60, 0xd0, 0x4d, 0x7e, 0x7b, 0xdf, 0x17, 0x7b,
0x2f, 0xc4, 0x16, 0xee, 0x45, 0xdb, 0xa5, 0x5d, 0xc0, 0x72, 0xe9, 0xc6,
0x91, 0x0f, 0xd9, 0x30, 0x74, 0x6c, 0xde, 0x93, 0xb5, 0xb6, 0xaf, 0x52,
0x53, 0x3c, 0x08, 0x55, 0xea, 0xb8, 0x66, 0x07, 0xbe, 0xce, 0xf9, 0x80,
0x8d, 0xe0, 0xca, 0xdc, 0x63, 0xe8, 0x58, 0x94, 0x22, 0x4f, 0x08, 0x66,
0x13, 0x9e, 0x63, 0x2e, 0x92, 0x7a, 0xb6, 0x66, 0x94, 0x9b, 0x71, 0x66,
0xd3, 0x08, 0xc9, 0x89, 0xea, 0x78, 0x35, 0x0d, 0xf2, 0x25, 0x55, 0xd4,
0xb0, 0x9b, 0xea, 0x18, 0x77, 0xf6, 0x25, 0x02, 0xb4, 0x5e, 0x71, 0xea,
0xa3
};
unsigned int keyr_len = 805;
unsigned char keye[] = {
0x00, 0x00, 0x00, 0x13, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68,
0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
0x00, 0x00, 0x08, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
0x00, 0x00, 0x41, 0x04, 0x0a, 0x00, 0x6c, 0x7c, 0x1c, 0xc4, 0x03, 0x44,
0x46, 0x70, 0xba, 0x00, 0x7c, 0x79, 0x89, 0x7b, 0xc3, 0xd6, 0x32, 0x98,
0x34, 0xe7, 0x1c, 0x60, 0x04, 0x73, 0xd9, 0xb5, 0x7e, 0x94, 0x04, 0x04,
0xea, 0xc8, 0xb8, 0xfb, 0xd4, 0x70, 0x9f, 0x29, 0xa7, 0x8d, 0x9a, 0x64,
0x3a, 0x8c, 0x45, 0x23, 0x37, 0x5a, 0x2b, 0x4f, 0x54, 0x91, 0x80, 0xf1,
0xac, 0x3a, 0xf5, 0x6d, 0xfa, 0xe8, 0x76, 0x20, 0x00, 0x00, 0x00, 0x21,
0x00, 0xc2, 0xaf, 0xbe, 0xdc, 0x06, 0xff, 0x3d, 0x08, 0x9b, 0x73, 0xe0,
0x3c, 0x58, 0x28, 0x70, 0x9b, 0x23, 0x39, 0x51, 0xd7, 0xbc, 0xa7, 0x1a,
0xf5, 0xb4, 0x23, 0xd3, 0xf6, 0x17, 0xa6, 0x9c, 0x02
};
unsigned int keye_len = 141;
unsigned char keyd[] = {
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x64, 0x73, 0x73, 0x00,
0x00, 0x00, 0x81, 0x00, 0xb0, 0x02, 0x19, 0x8b, 0xf3, 0x46, 0xf9, 0xc5,
0x47, 0x78, 0x3d, 0x7f, 0x04, 0x10, 0x0a, 0x43, 0x8e, 0x00, 0x9e, 0xa4,
0x30, 0xfd, 0x47, 0xb9, 0x05, 0x9e, 0x95, 0xaa, 0x37, 0x9a, 0x91, 0xbf,
0xf8, 0xb9, 0xe0, 0x8d, 0x97, 0x49, 0x87, 0xe2, 0xe6, 0x90, 0xc1, 0xe4,
0x61, 0x57, 0x77, 0xfd, 0x91, 0x1d, 0xe1, 0x4b, 0xa0, 0xb2, 0xbc, 0xa1,
0x6a, 0x6a, 0xdd, 0x31, 0xda, 0xe7, 0x54, 0x03, 0xfd, 0x48, 0x62, 0x8a,
0x1d, 0x1d, 0xe2, 0x26, 0x76, 0x29, 0x08, 0xab, 0x65, 0x88, 0x74, 0x02,
0x1e, 0xa9, 0x29, 0x1b, 0x69, 0x3b, 0xb4, 0x5f, 0x62, 0x80, 0xa3, 0xa6,
0x4b, 0xc3, 0x0e, 0x89, 0x24, 0xe4, 0x8a, 0x31, 0xae, 0x89, 0x7a, 0x7a,
0x58, 0x44, 0x46, 0x77, 0x62, 0x33, 0xa2, 0x5d, 0x17, 0x0e, 0x0b, 0x64,
0xee, 0x1a, 0x02, 0xbd, 0xf8, 0x27, 0x86, 0xe1, 0x87, 0x92, 0x84, 0xc7,
0x00, 0x00, 0x00, 0x15, 0x00, 0xb3, 0x8b, 0x81, 0x39, 0x9c, 0xba, 0xe1,
0x1d, 0x9a, 0x8b, 0x89, 0xb3, 0x08, 0x9b, 0x12, 0xa8, 0x7b, 0xea, 0x25,
0x8d, 0x00, 0x00, 0x00, 0x80, 0x76, 0x3f, 0x72, 0xb2, 0xef, 0xc3, 0x16,
0xd8, 0x09, 0x36, 0x23, 0x03, 0xf9, 0x5c, 0xac, 0x8b, 0x51, 0x35, 0x2e,
0x36, 0xba, 0x39, 0xd0, 0x57, 0x19, 0x4f, 0x14, 0x8b, 0xea, 0x32, 0xfc,
0x86, 0x41, 0xea, 0x85, 0x71, 0x4d, 0x52, 0x0c, 0xff, 0xc1, 0xd3, 0xd5,
0xcd, 0x2e, 0x37, 0xcc, 0xe1, 0xcc, 0x22, 0x38, 0xa8, 0x47, 0x16, 0x34,
0x3b, 0x32, 0x9c, 0x2f, 0x0f, 0xcd, 0x5f, 0x7f, 0x06, 0x64, 0x89, 0xc5,
0x02, 0x4f, 0x9a, 0x70, 0x11, 0xf0, 0xaa, 0xe1, 0x7a, 0x75, 0x49, 0x8d,
0x0f, 0x8d, 0x5b, 0x54, 0xe2, 0xe7, 0x10, 0x6e, 0xe5, 0xbd, 0xb7, 0x62,
0xf7, 0x40, 0x59, 0x39, 0x31, 0xd9, 0x13, 0x7b, 0xa3, 0xdf, 0x0d, 0x31,
0x52, 0x43, 0xe0, 0xaf, 0x19, 0x12, 0x15, 0x12, 0x34, 0x01, 0x6f, 0xcf,
0x62, 0x21, 0xe4, 0xc8, 0x34, 0x69, 0xc9, 0x85, 0xe3, 0xde, 0xd7, 0x0c,
0xac, 0x00, 0x00, 0x00, 0x80, 0x41, 0xa3, 0xc5, 0xa4, 0x89, 0x86, 0xc8,
0x17, 0xf3, 0x8e, 0x68, 0x72, 0xbe, 0x13, 0x8b, 0x63, 0xe3, 0x07, 0xe3,
0xd5, 0xa4, 0xa2, 0xd3, 0x2c, 0x2f, 0xbe, 0x16, 0x71, 0xc9, 0x79, 0x64,
0x5a, 0x1e, 0x19, 0x82, 0x07, 0xe2, 0x93, 0xda, 0x22, 0xcf, 0x6d, 0xdd,
0x38, 0xcb, 0x6e, 0x6b, 0x0f, 0x95, 0x8d, 0xfa, 0x3f, 0xbb, 0xb8, 0x6a,
0x7d, 0xc3, 0x22, 0x1e, 0x49, 0xcf, 0x98, 0x73, 0x05, 0x5d, 0x97, 0xfa,
0x4c, 0xf2, 0x82, 0x3d, 0x98, 0x61, 0x4e, 0x96, 0x80, 0x26, 0x79, 0xda,
0x24, 0xf8, 0xa1, 0x9c, 0x71, 0x82, 0xe6, 0xc7, 0xdc, 0xc2, 0xa5, 0xd0,
0xf4, 0x36, 0xba, 0xaa, 0xee, 0xd3, 0x43, 0x46, 0x1d, 0xaa, 0x53, 0xea,
0x85, 0x2c, 0x1b, 0xc8, 0x7c, 0x3c, 0xe7, 0x06, 0x44, 0xab, 0x16, 0xad,
0xc6, 0x54, 0x91, 0x9a, 0xb9, 0xc0, 0xeb, 0x93, 0x8c, 0xca, 0x39, 0xcf,
0x6f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x90, 0x26, 0x0a, 0xfc, 0x15, 0x99,
0x7b, 0xac, 0xaa, 0x0c, 0xa2, 0xca, 0x7b, 0xa8, 0xd4, 0xdf, 0x68, 0x56,
0xf9, 0x39
};
unsigned int keyd_len = 458;

246
fuzz-wrapfd.c Normal file
View File

@@ -0,0 +1,246 @@
#define FUZZ_SKIP_WRAP 1
#include "includes.h"
#include "fuzz-wrapfd.h"
#include "dbutil.h"
#include "fuzz.h"
#define IOWRAP_MAXFD (FD_SETSIZE-1)
static const int MAX_RANDOM_IN = 50000;
static const double CHANCE_CLOSE = 1.0 / 600;
static const double CHANCE_INTR = 1.0 / 900;
static const double CHANCE_READ1 = 0.96;
static const double CHANCE_READ2 = 0.5;
static const double CHANCE_WRITE1 = 0.96;
static const double CHANCE_WRITE2 = 0.5;
struct fdwrap {
enum wrapfd_mode mode;
buffer *buf;
int closein;
int closeout;
};
static struct fdwrap wrap_fds[IOWRAP_MAXFD+1];
/* for quick selection of in-use descriptors */
static int wrap_used[IOWRAP_MAXFD+1];
static unsigned int nused;
static unsigned short rand_state[3];
void wrapfd_setup(void) {
TRACE(("wrapfd_setup"))
nused = 0;
memset(wrap_fds, 0x0, sizeof(wrap_fds));
memset(wrap_used, 0x0, sizeof(wrap_used));
memset(rand_state, 0x0, sizeof(rand_state));
wrapfd_setseed(50);
}
void wrapfd_setseed(uint32_t seed) {
memcpy(rand_state, &seed, sizeof(seed));
nrand48(rand_state);
}
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) {
TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode))
assert(fd >= 0);
assert(fd <= IOWRAP_MAXFD);
assert(wrap_fds[fd].mode == UNUSED);
assert(buf || mode == RANDOMIN);
wrap_fds[fd].mode = mode;
wrap_fds[fd].buf = buf;
wrap_fds[fd].closein = 0;
wrap_fds[fd].closeout = 0;
wrap_used[nused] = fd;
nused++;
}
void wrapfd_remove(int fd) {
unsigned int i, j;
TRACE(("wrapfd_remove %d", fd))
assert(fd >= 0);
assert(fd <= IOWRAP_MAXFD);
assert(wrap_fds[fd].mode != UNUSED);
wrap_fds[fd].mode = UNUSED;
/* remove from used list */
for (i = 0, j = 0; i < nused; i++) {
if (wrap_used[i] != fd) {
wrap_used[j] = wrap_used[i];
j++;
}
}
nused--;
}
int wrapfd_close(int fd) {
if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
wrapfd_remove(fd);
return 0;
} else {
return close(fd);
}
}
int wrapfd_read(int fd, void *out, size_t count) {
size_t maxread;
buffer *buf;
if (!fuzz.wrapfds) {
return read(fd, out, count);
}
if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
/* XXX - assertion failure? */
TRACE(("Bad read descriptor %d\n", fd))
errno = EBADF;
return -1;
}
assert(count != 0);
if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
wrap_fds[fd].closein = 1;
errno = ECONNRESET;
return -1;
}
if (erand48(rand_state) < CHANCE_INTR) {
errno = EINTR;
return -1;
}
buf = wrap_fds[fd].buf;
if (buf) {
maxread = MIN(buf->len - buf->pos, count);
/* returns 0 if buf is EOF, as intended */
if (maxread > 0) {
maxread = nrand48(rand_state) % maxread + 1;
}
memcpy(out, buf_getptr(buf, maxread), maxread);
buf_incrpos(buf, maxread);
return maxread;
}
maxread = MIN(MAX_RANDOM_IN, count);
maxread = nrand48(rand_state) % maxread + 1;
memset(out, 0xef, maxread);
return maxread;
}
int wrapfd_write(int fd, const void* in, size_t count) {
unsigned const volatile char* volin = in;
unsigned int i;
if (!fuzz.wrapfds) {
return write(fd, in, count);
}
if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
/* XXX - assertion failure? */
TRACE(("Bad read descriptor %d\n", fd))
errno = EBADF;
return -1;
}
assert(count != 0);
/* force read to exercise sanitisers */
for (i = 0; i < count; i++) {
(void)volin[i];
}
if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
wrap_fds[fd].closeout = 1;
errno = ECONNRESET;
return -1;
}
if (erand48(rand_state) < CHANCE_INTR) {
errno = EINTR;
return -1;
}
return nrand48(rand_state) % (count+1);
}
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout) {
int i, nset, sel;
int ret = 0;
int fdlist[IOWRAP_MAXFD+1];
memset(fdlist, 0x0, sizeof(fdlist));
if (!fuzz.wrapfds) {
return select(nfds, readfds, writefds, exceptfds, timeout);
}
assert(nfds <= IOWRAP_MAXFD+1);
if (erand48(rand_state) < CHANCE_INTR) {
errno = EINTR;
return -1;
}
/* read */
if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
for (i = 0, nset = 0; i < nfds; i++) {
if (FD_ISSET(i, readfds)) {
assert(wrap_fds[i].mode != UNUSED);
fdlist[nset] = i;
nset++;
}
}
DROPBEAR_FD_ZERO(readfds);
if (nset > 0) {
/* set one */
sel = fdlist[nrand48(rand_state) % nset];
FD_SET(sel, readfds);
ret++;
if (erand48(rand_state) < CHANCE_READ2) {
sel = fdlist[nrand48(rand_state) % nset];
if (!FD_ISSET(sel, readfds)) {
FD_SET(sel, readfds);
ret++;
}
}
}
}
/* write */
if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
for (i = 0, nset = 0; i < nfds; i++) {
if (FD_ISSET(i, writefds)) {
assert(wrap_fds[i].mode != UNUSED);
fdlist[nset] = i;
nset++;
}
}
DROPBEAR_FD_ZERO(writefds);
/* set one */
if (nset > 0) {
sel = fdlist[nrand48(rand_state) % nset];
FD_SET(sel, writefds);
ret++;
if (erand48(rand_state) < CHANCE_WRITE2) {
sel = fdlist[nrand48(rand_state) % nset];
if (!FD_ISSET(sel, writefds)) {
FD_SET(sel, writefds);
ret++;
}
}
}
}
return ret;
}

25
fuzz-wrapfd.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef FUZZ_WRAPFD_H
#define FUZZ_WRAPFD_H
#include "buffer.h"
enum wrapfd_mode {
UNUSED = 0,
PLAIN,
INPROGRESS,
RANDOMIN
};
void wrapfd_setup(void);
void wrapfd_setseed(uint32_t seed);
// doesn't take ownership of buf. buf is optional.
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode);
// called via #defines for read/write/select
int wrapfd_read(int fd, void *out, size_t count);
int wrapfd_write(int fd, const void* in, size_t count);
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
int wrapfd_close(int fd);
#endif // FUZZ_WRAPFD_H

72
fuzz.h Normal file
View File

@@ -0,0 +1,72 @@
#ifndef DROPBEAR_FUZZ_H
#define DROPBEAR_FUZZ_H
#include "config.h"
#if DROPBEAR_FUZZ
#include "includes.h"
#include "buffer.h"
#include "algo.h"
#include "fuzz-wrapfd.h"
// once per process
void fuzz_common_setup(void);
void fuzz_svr_setup(void);
// must be called once per fuzz iteration.
// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
int fuzz_set_input(const uint8_t *Data, size_t Size);
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths);
const void* fuzz_get_algo(const algo_type *algos, const char* name);
// fuzzer functions that intrude into general code
void fuzz_kex_fakealgos(void);
int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const char* algo, unsigned int algolen,
const unsigned char* keyblob, unsigned int keybloblen);
extern const char * const * fuzz_signkey_names;
void fuzz_seed(void);
void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void fuzz_fake_send_kexdh_reply(void);
// fake IO wrappers
#ifndef FUZZ_SKIP_WRAP
#define select(nfds, readfds, writefds, exceptfds, timeout) \
wrapfd_select(nfds, readfds, writefds, exceptfds, timeout)
#define write(fd, buf, count) wrapfd_write(fd, buf, count)
#define read(fd, buf, count) wrapfd_read(fd, buf, count)
#define close(fd) wrapfd_close(fd)
#endif // FUZZ_SKIP_WRAP
struct dropbear_fuzz_options {
int fuzzing;
// fuzzing input
buffer *input;
struct dropbear_cipher recv_cipher;
struct dropbear_hash recv_mac;
int wrapfds;
// whether to skip slow bignum maths
int skip_kexmaths;
// dropbear_exit() jumps back
int do_jmp;
sigjmp_buf jmp;
uid_t pw_uid;
gid_t pw_gid;
char* pw_name;
char* pw_dir;
char* pw_shell;
char* pw_passwd;
};
extern struct dropbear_fuzz_options fuzz;
#endif // DROPBEAR_FUZZ
#endif /* DROPBEAR_FUZZ_H */

76
fuzzer-kexdh.c Normal file
View File

@@ -0,0 +1,76 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
#include "runopts.h"
#include "algo.h"
#include "bignum.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters is limited by the timeout for the first run.
TODO move this to the libfuzzer initialiser function instead if the timeout
doesn't apply there */
#define NUM_PARAMS 20
static struct kex_dh_param *dh_params[NUM_PARAMS];
if (!once) {
fuzz_common_setup();
fuzz_svr_setup();
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "diffie-hellman-group14-sha256");
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
dh_params[i] = gen_kexdh_param();
}
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
with DROPBEAR_KEX_NORMAL_DH */
ses.newkeys = keep_newkeys;
/* Choose from the collection of ecdh params */
unsigned int e = buf_getint(fuzz.input);
struct kex_dh_param * dh_param = dh_params[e % NUM_PARAMS];
DEF_MP_INT(dh_e);
m_mp_init(&dh_e);
if (buf_getmpint(fuzz.input, &dh_e) != DROPBEAR_SUCCESS) {
dropbear_exit("Bad kex value");
}
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
kexdh_comb_key(dh_param, &dh_e, svr_opts.hostkey);
mp_clear(ses.dh_K);
m_free(ses.dh_K);
mp_clear(&dh_e);
buf_free(ses.hash);
buf_free(ses.session_id);
/* kexhashbuf is freed in kexdh_comb_key */
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}

82
fuzzer-kexecdh.c Normal file
View File

@@ -0,0 +1,82 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
#include "runopts.h"
#include "algo.h"
#include "bignum.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters is limited by the timeout for the first run */
#define NUM_PARAMS 80
static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
if (!once) {
fuzz_common_setup();
fuzz_svr_setup();
/* ses gets zeroed by fuzz_set_input */
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
assert(ecdh[0]);
assert(ecdh[1]);
assert(ecdh[2]);
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
ses.newkeys->algo_kex = ecdh[i % 3];
ecdh_params[i] = gen_kexecdh_param();
}
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
with DROPBEAR_KEX_ECDH */
ses.newkeys = keep_newkeys;
/* random choice of ecdh 256, 384, 521 */
unsigned char b = buf_getbyte(fuzz.input);
ses.newkeys->algo_kex = ecdh[b % 3];
/* Choose from the collection of ecdh params */
unsigned int e = buf_getint(fuzz.input);
struct kex_ecdh_param *ecdh_param = ecdh_params[e % NUM_PARAMS];
buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
mp_clear(ses.dh_K);
m_free(ses.dh_K);
buf_free(ecdh_qs);
buf_free(ses.hash);
buf_free(ses.session_id);
/* kexhashbuf is freed in kexdh_comb_key */
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}

6
fuzzer-preauth.c Normal file
View File

@@ -0,0 +1,6 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_preauth(Data, Size, 0);
}

6
fuzzer-preauth_nomaths.c Normal file
View File

@@ -0,0 +1,6 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_preauth(Data, Size, 1);
}

54
fuzzer-pubkey.c Normal file
View File

@@ -0,0 +1,54 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
static void setup_fuzzer(void) {
fuzz_common_setup();
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
if (!once) {
setup_fuzzer();
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
buffer *line = buf_getstringbuf(fuzz.input);
buffer *keyblob = buf_getstringbuf(fuzz.input);
unsigned int algolen;
char* algoname = buf_getstring(keyblob, &algolen);
if (have_algo(algoname, algolen, sshhostkey) == DROPBEAR_FAILURE) {
dropbear_exit("fuzzer imagined a bogus algorithm");
}
int ret = fuzz_checkpubkey_line(line, 5, "/home/me/authorized_keys",
algoname, algolen,
keyblob->data, keyblob->len);
if (ret == DROPBEAR_SUCCESS) {
/* fuzz_checkpubkey_line() should have cleaned up for failure */
svr_pubkey_options_cleanup();
}
buf_free(line);
buf_free(keyblob);
m_free(algoname);
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}

64
fuzzer-verify.c Normal file
View File

@@ -0,0 +1,64 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
static void setup_fuzzer(void) {
fuzz_common_setup();
}
static buffer *verifydata;
/* Tests reading a public key and verifying a signature */
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
if (!once) {
setup_fuzzer();
verifydata = buf_new(30);
buf_putstring(verifydata, "x", 1);
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
sign_key *key = new_sign_key();
enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
if (buf_get_pub_key(fuzz.input, key, &type) == DROPBEAR_SUCCESS) {
if (buf_verify(fuzz.input, key, verifydata) == DROPBEAR_SUCCESS) {
/* The fuzzer is capable of generating keys with a signature to match.
We don't want false positives if the key is bogus, since a client/server
wouldn't be trusting a bogus key anyway */
int boguskey = 0;
if (type == DROPBEAR_SIGNKEY_DSS) {
/* So far have seen dss keys with bad p/q/g domain parameters */
int pprime, qprime;
assert(mp_prime_is_prime(key->dsskey->p, 5, &pprime) == MP_OKAY);
assert(mp_prime_is_prime(key->dsskey->q, 18, &qprime) == MP_OKAY);
boguskey = !(pprime && qprime);
/* Could also check g**q mod p == 1 */
}
if (!boguskey) {
printf("Random key/signature managed to verify!\n");
abort();
}
}
}
sign_key_free(key);
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}

12
fuzzers_test.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
# runs fuzz corpus with standalone fuzzers
result=0
hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
for f in `make list-fuzz-targets`; do
./$f fuzzcorpus/$f/* || result=1
done
exit $result

View File

@@ -2,6 +2,6 @@
# Wrap all "#define X Y" with a #ifndef X...#endif"
sed -E 's/^( *#define ([^ ]+) .*)/#ifndef \2\
sed 's/^\( *#define \([^ ][^ ]*\) .*\)/#ifndef \2\
\1\
#endif/'

View File

@@ -56,6 +56,7 @@
#include <stdarg.h>
#include <dirent.h>
#include <time.h>
#include <setjmp.h>
#ifdef HAVE_UTMP_H
#include <utmp.h>
@@ -131,7 +132,6 @@
#include <tommath.h>
#endif
#include "compat.h"
#ifndef HAVE_U_INT8_T
@@ -155,6 +155,10 @@ typedef unsigned int u_int32_t;
typedef u_int32_t uint32_t;
#endif /* HAVE_UINT32_T */
#ifndef SIZE_T_MAX
#define SIZE_T_MAX ULONG_MAX
#endif /* SIZE_T_MAX */
#ifdef HAVE_LINUX_PKT_SCHED_H
#include <linux/types.h>
#include <linux/pkt_sched.h>
@@ -162,6 +166,8 @@ typedef u_int32_t uint32_t;
#include "fake-rfc2553.h"
#include "fuzz.h"
#ifndef LOG_AUTHPRIV
#define LOG_AUTHPRIV LOG_AUTH
#endif

4
kex.h
View File

@@ -34,6 +34,7 @@ void recv_msg_kexinit(void);
void send_msg_newkeys(void);
void recv_msg_newkeys(void);
void kexfirstinitialise(void);
void finish_kexhashbuf(void);
struct kex_dh_param *gen_kexdh_param(void);
void free_kexdh_param(struct kex_dh_param *param);
@@ -105,7 +106,4 @@ struct kex_curve25519_param {
int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsigned char *other);
#endif
#define MAX_KEXHASHBUF 2000
#endif /* DROPBEAR_KEX_H_ */

View File

@@ -1097,7 +1097,9 @@ static int openssh_write(const char *filename, sign_key *key,
buf_putbytes(seq_buf, curve_oid, curve_oid_len);
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 1, 2+1+pubkey_size, 0xa0));
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 1,
(pubkey_size +1 < 128 ? 2 : 3 ) +1 +pubkey_size, 0xa0));
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
buf_putbyte(seq_buf, 0);

View File

@@ -12,6 +12,12 @@
#include "tomcrypt_dropbear.h"
#include "dbmalloc.h"
#define XMALLOC m_malloc
#define XFREE m_free_direct
#define XREALLOC m_realloc
#define XCALLOC m_calloc
/* macros for various libc functions you can change for embedded targets */
#ifndef XMALLOC
#define XMALLOC malloc

View File

@@ -87,7 +87,7 @@ int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
{
mp_digit *tmpc;
tmpc = c->dp;
for (ix = 0; ix < (pa + 1); ix++) {
for (ix = 0; ix < pa; ix++) {
/* now extract the previous digit [below the carry] */
*tmpc++ = W[ix];
}

View File

@@ -1062,6 +1062,12 @@
#undef BN_MP_TOOM_MUL_C
#undef BN_MP_TOOM_SQR_C
#include "dbmalloc.h"
#define XMALLOC m_malloc
#define XFREE m_free_direct
#define XREALLOC m_realloc
#define XCALLOC m_calloc
/* $Source$ */
/* $Revision$ */
/* $Date$ */

30
netio.c
View File

@@ -224,7 +224,6 @@ void remove_connect_pending() {
void set_connect_fds(fd_set *writefd) {
m_list_elem *iter;
TRACE(("enter set_connect_fds"))
iter = ses.conn_pending.first;
while (iter) {
m_list_elem *next_iter = iter->next;
@@ -249,7 +248,6 @@ void set_connect_fds(fd_set *writefd) {
void handle_connect_fds(const fd_set *writefd) {
m_list_elem *iter;
TRACE(("enter handle_connect_fds"))
for (iter = ses.conn_pending.first; iter; iter = iter->next) {
int val;
socklen_t vallen = sizeof(val);
@@ -283,7 +281,6 @@ void handle_connect_fds(const fd_set *writefd) {
return;
}
}
TRACE(("leave handle_connect_fds - end iter"))
}
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) {
@@ -297,7 +294,11 @@ void packet_queue_to_iovec(const struct Queue *queue, struct iovec *iov, unsigne
buffer *writebuf;
#ifndef IOV_MAX
#define IOV_MAX UIO_MAXIOV
#if defined(__CYGWIN__) && !defined(UIO_MAXIOV)
#define IOV_MAX 1024
#else
#define IOV_MAX UIO_MAXIOV
#endif
#endif
*iov_count = MIN(MIN(queue->count, IOV_MAX), *iov_count);
@@ -305,10 +306,10 @@ void packet_queue_to_iovec(const struct Queue *queue, struct iovec *iov, unsigne
for (l = queue->head, i = 0; i < *iov_count; l = l->link, i++)
{
writebuf = (buffer*)l->item;
len = writebuf->len - 1 - writebuf->pos;
len = writebuf->len - writebuf->pos;
dropbear_assert(len > 0);
TRACE2(("write_packet writev #%d type %d len %d/%d", i, writebuf->data[writebuf->len-1],
len, writebuf->len-1))
TRACE2(("write_packet writev #%d len %d/%d", i,
len, writebuf->len))
iov[i].iov_base = buf_getptr(writebuf, len);
iov[i].iov_len = len;
}
@@ -319,7 +320,7 @@ void packet_queue_consume(struct Queue *queue, ssize_t written) {
int len;
while (written > 0) {
writebuf = (buffer*)examine(queue);
len = writebuf->len - 1 - writebuf->pos;
len = writebuf->len - writebuf->pos;
if (len > written) {
/* partial buffer write */
buf_incrpos(writebuf, written);
@@ -360,6 +361,12 @@ void set_sock_priority(int sock, enum dropbear_prio prio) {
int so_prio_val = 0;
#endif
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
TRACE(("fuzzing skips set_sock_prio"))
return;
}
#endif
/* Don't log ENOTSOCK errors so that this can harmlessly be called
* on a client '-J' proxy pipe */
@@ -584,6 +591,13 @@ void get_socket_address(int fd, char **local_host, char **local_port,
{
struct sockaddr_storage addr;
socklen_t addrlen;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
fuzz_get_socket_address(fd, local_host, local_port, remote_host, remote_port, host_lookup);
return;
}
#endif
if (local_host || local_port) {
addrlen = sizeof(addr);

View File

@@ -5,6 +5,7 @@
> > > Don't edit this file any more! < < <
Local compile-time configuration should be defined in localoptions.h
in the build directory.
See default_options.h.in for a description of the available options.
*/

View File

@@ -35,6 +35,7 @@
#include "auth.h"
#include "channel.h"
#include "netio.h"
#include "runopts.h"
static int read_packet_init(void);
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
@@ -57,14 +58,13 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len);
void write_packet() {
ssize_t written;
#ifdef HAVE_WRITEV
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
/* 50 is somewhat arbitrary */
unsigned int iov_count = 50;
struct iovec iov[50];
#else
int len;
buffer* writebuf;
int packet_type;
#endif
TRACE2(("enter write_packet"))
@@ -76,6 +76,15 @@ void write_packet() {
/* This may return EAGAIN. The main loop sometimes
calls write_packet() without bothering to test with select() since
it's likely to be necessary */
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
/* pretend to write one packet at a time */
/* TODO(fuzz): randomise amount written based on the fuzz input */
written = iov[0].iov_len;
}
else
#endif
{
written = writev(ses.sock_out, iov, iov_count);
if (written < 0) {
if (errno == EINTR || errno == EAGAIN) {
@@ -85,6 +94,7 @@ void write_packet() {
dropbear_exit("Error writing: %s", strerror(errno));
}
}
}
packet_queue_consume(&ses.writequeue, written);
ses.writequeue_len -= written;
@@ -94,15 +104,13 @@ void write_packet() {
}
#else /* No writev () */
#if DROPBEAR_FUZZ
_Static_assert(0, "No fuzzing code for no-writev writes");
#endif
/* Get the next buffer in the queue of encrypted packets to write*/
writebuf = (buffer*)examine(&ses.writequeue);
/* The last byte of the buffer is not to be transmitted, but is
* a cleartext packet_type indicator */
packet_type = writebuf->data[writebuf->len-1];
len = writebuf->len - 1 - writebuf->pos;
TRACE2(("write_packet type %d len %d/%d", packet_type,
len, writebuf->len-1))
len = writebuf->len - writebuf->pos;
dropbear_assert(len > 0);
/* Try to write as much as possible */
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
@@ -352,6 +360,20 @@ static int checkmac() {
buf_setpos(ses.readbuf, 0);
make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
/* fail 1 in 2000 times to test error path. */
unsigned int value = 0;
if (mac_size > sizeof(value)) {
memcpy(&value, mac_bytes, sizeof(value));
}
if (value % 2000 == 99) {
return DROPBEAR_FAILURE;
}
return DROPBEAR_SUCCESS;
}
#endif
/* compare the hash */
buf_setpos(ses.readbuf, contents_len);
if (constant_time_memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
@@ -578,7 +600,7 @@ void encrypt_packet() {
/* Update counts */
ses.kexstate.datatrans += writebuf->len;
writebuf_enqueue(writebuf, packet_type);
writebuf_enqueue(writebuf);
/* Update counts */
ses.transseq++;
@@ -598,14 +620,11 @@ void encrypt_packet() {
TRACE2(("leave encrypt_packet()"))
}
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type) {
/* The last byte of the buffer stores the cleartext packet_type. It is not
* transmitted but is used for transmit timeout purposes */
buf_putbyte(writebuf, packet_type);
void writebuf_enqueue(buffer * writebuf) {
/* enqueue the packet for sending. It will get freed after transmission. */
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, (void*)writebuf);
ses.writequeue_len += writebuf->len-1;
ses.writequeue_len += writebuf->len;
}

View File

@@ -35,7 +35,7 @@ void read_packet(void);
void decrypt_packet(void);
void encrypt_packet(void);
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type);
void writebuf_enqueue(buffer * writebuf);
void process_packet(void);

View File

@@ -38,7 +38,7 @@ rm "$RELDIR/.hgtags"
(cd "$RELDIR/.." && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
ls -l $ARCHIVE
openssl sha -sha256 $ARCHIVE
openssl sha256 $ARCHIVE
echo Done to
echo "$ARCHIVE"
echo Sign it with

View File

@@ -136,7 +136,7 @@ typedef struct cli_runopts {
char *progname;
char *remotehost;
char *remoteport;
const char *remoteport;
char *own_user;
char *username;

View File

@@ -102,7 +102,7 @@ xstrdup(const char *str)
len = strlen(str) + 1;
cp = xmalloc(len);
strncpy(cp, str, len);
strlcpy(cp, str, len);
return cp;
}

View File

@@ -27,8 +27,8 @@ struct passwd *pwcopy(struct passwd *);
typedef struct arglist arglist;
struct arglist {
char **list;
int num;
int nalloc;
u_int num;
u_int nalloc;
};
void addargs(arglist *, char *, ...);
void replacearg(arglist *, u_int, char *, ...);

View File

@@ -580,6 +580,10 @@ int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
/* now we have the actual data */
len = line->len - line->pos;
if (len == 0) {
/* base64_decode doesn't like NULL argument */
return DROPBEAR_FAILURE;
}
decodekeylen = len * 2; /* big to be safe */
decodekey = buf_new(decodekeylen);
@@ -623,3 +627,8 @@ out:
return ret;
}
#endif
#if DROPBEAR_FUZZ
const char * const * fuzz_signkey_names = signkey_names;
#endif

View File

@@ -151,6 +151,7 @@ void svr_agentcleanup(struct ChanSess * chansess) {
if (chansess->agentfile != NULL && chansess->agentdir != NULL) {
#if DROPBEAR_SVR_MULTIUSER
/* Remove the dir as the user. That way they can't cause problems except
* for themselves */
uid = getuid();
@@ -159,6 +160,7 @@ void svr_agentcleanup(struct ChanSess * chansess) {
(seteuid(ses.authstate.pw_uid)) < 0) {
dropbear_exit("Failed to set euid");
}
#endif
/* 2 for "/" and "\0" */
len = strlen(chansess->agentdir) + strlen(chansess->agentfile) + 2;
@@ -170,10 +172,12 @@ void svr_agentcleanup(struct ChanSess * chansess) {
rmdir(chansess->agentdir);
#if DROPBEAR_SVR_MULTIUSER
if ((seteuid(uid)) < 0 ||
(setegid(gid)) < 0) {
dropbear_exit("Failed to revert euid");
}
#endif
m_free(chansess->agentfile);
m_free(chansess->agentdir);
@@ -187,6 +191,7 @@ static const struct ChanType chan_svr_agent = {
NULL,
NULL,
NULL,
NULL,
NULL
};
@@ -208,13 +213,14 @@ static int bindagent(int fd, struct ChanSess * chansess) {
struct sockaddr_un addr;
unsigned int prefix;
char path[sizeof(addr.sun_path)], sockfile[sizeof(addr.sun_path)];
char path[(sizeof(addr.sun_path)-1)/2], sockfile[(sizeof(addr.sun_path)-1)/2];
mode_t mode;
int i;
uid_t uid;
gid_t gid;
int ret = DROPBEAR_FAILURE;
#if DROPBEAR_SVR_MULTIUSER
/* drop to user privs to make the dir/file */
uid = getuid();
gid = getgid();
@@ -222,6 +228,7 @@ static int bindagent(int fd, struct ChanSess * chansess) {
(seteuid(ses.authstate.pw_uid)) < 0) {
dropbear_exit("Failed to set euid");
}
#endif
memset((void*)&addr, 0x0, sizeof(addr));
addr.sun_family = AF_UNIX;
@@ -261,10 +268,12 @@ bindsocket:
out:
#if DROPBEAR_SVR_MULTIUSER
if ((seteuid(uid)) < 0 ||
(setegid(gid)) < 0) {
dropbear_exit("Failed to revert euid");
}
#endif
return ret;
}

View File

@@ -79,6 +79,9 @@ void recv_msg_userauth_request() {
TRACE(("enter recv_msg_userauth_request"))
/* for compensating failure delay */
gettime_wrapper(&ses.authstate.auth_starttime);
/* ignore packets if auth is already done */
if (ses.authstate.authdone == 1) {
TRACE(("leave recv_msg_userauth_request: authdone already"))
@@ -149,10 +152,8 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
if (valid_user) {
svr_auth_password();
goto out;
}
svr_auth_password(valid_user);
goto out;
}
}
#endif
@@ -164,10 +165,8 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
if (valid_user) {
svr_auth_pam();
goto out;
}
svr_auth_pam(valid_user);
goto out;
}
}
#endif
@@ -177,12 +176,7 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
strncmp(methodname, AUTH_METHOD_PUBKEY,
AUTH_METHOD_PUBKEY_LEN) == 0) {
if (valid_user) {
svr_auth_pubkey();
} else {
/* pubkey has no failure delay */
send_msg_userauth_failure(0, 0);
}
svr_auth_pubkey(valid_user);
goto out;
}
#endif
@@ -282,7 +276,7 @@ static int checkusername(const char *username, unsigned int userlen) {
/* check if we are running as non-root, and login user is different from the server */
uid = geteuid();
if (uid != 0 && uid != ses.authstate.pw_uid) {
if (!(DROPBEAR_SVR_MULTIUSER && uid == 0) && uid != ses.authstate.pw_uid) {
TRACE(("running as nonroot, only server uid is allowed"))
dropbear_log(LOG_WARNING,
"Login attempt with wrong user %s from %s",
@@ -312,7 +306,7 @@ static int checkusername(const char *username, unsigned int userlen) {
return DROPBEAR_FAILURE;
}
}
#endif HAVE_GETGROUPLIST
#endif /* HAVE_GETGROUPLIST */
TRACE(("shell is %s", ses.authstate.pw_shell))
@@ -391,11 +385,48 @@ void send_msg_userauth_failure(int partial, int incrfail) {
encrypt_packet();
if (incrfail) {
unsigned int delay;
genrandom((unsigned char*)&delay, sizeof(delay));
/* We delay for 300ms +- 50ms */
delay = 250000 + (delay % 100000);
usleep(delay);
/* The SSH_MSG_AUTH_FAILURE response is delayed to attempt to
avoid user enumeration and slow brute force attempts.
The delay is adjusted by the time already spent in processing
authentication (ses.authstate.auth_starttime timestamp). */
/* Desired total delay 300ms +-50ms (in nanoseconds).
Beware of integer overflow if increasing these values */
const unsigned int mindelay = 250000000;
const unsigned int vardelay = 100000000;
unsigned int rand_delay;
struct timespec delay;
gettime_wrapper(&delay);
delay.tv_sec -= ses.authstate.auth_starttime.tv_sec;
delay.tv_nsec -= ses.authstate.auth_starttime.tv_nsec;
/* carry */
if (delay.tv_nsec < 0) {
delay.tv_nsec += 1000000000;
delay.tv_sec -= 1;
}
genrandom((unsigned char*)&rand_delay, sizeof(rand_delay));
rand_delay = mindelay + (rand_delay % vardelay);
if (delay.tv_sec == 0 && delay.tv_nsec <= mindelay) {
/* Compensate for elapsed time */
delay.tv_nsec = rand_delay - delay.tv_nsec;
} else {
/* No time left or time went backwards, just delay anyway */
delay.tv_sec = 0;
delay.tv_nsec = rand_delay;
}
#if DROPBEAR_FUZZ
if (!fuzz.fuzzing)
#endif
{
while (nanosleep(&delay, &delay) == -1 && errno == EINTR) { /* Go back to sleep */ }
}
ses.authstate.failcount++;
}

View File

@@ -178,13 +178,14 @@ pamConvFunc(int num_msg,
* Keyboard interactive would be a lot nicer, but since PAM is synchronous, it
* gets very messy trying to send the interactive challenges, and read the
* interactive responses, over the network. */
void svr_auth_pam() {
void svr_auth_pam(int valid_user) {
struct UserDataS userData = {NULL, NULL};
struct pam_conv pamConv = {
pamConvFunc,
&userData /* submitted to pamvConvFunc as appdata_ptr */
};
const char* printable_user = NULL;
pam_handle_t* pamHandlep = NULL;
@@ -204,12 +205,23 @@ void svr_auth_pam() {
password = buf_getstring(ses.payload, &passwordlen);
/* We run the PAM conversation regardless of whether the username is valid
in case the conversation function has an inherent delay.
Use ses.authstate.username rather than ses.authstate.pw_name.
After PAM succeeds we then check the valid_user flag too */
/* used to pass data to the PAM conversation function - don't bother with
* strdup() etc since these are touched only by our own conversation
* function (above) which takes care of it */
userData.user = ses.authstate.pw_name;
userData.user = ses.authstate.username;
userData.passwd = password;
if (ses.authstate.pw_name) {
printable_user = ses.authstate.pw_name;
} else {
printable_user = "<invalid username>";
}
/* Init pam */
if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) {
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s",
@@ -242,7 +254,7 @@ void svr_auth_pam() {
rc, pam_strerror(pamHandlep, rc));
dropbear_log(LOG_WARNING,
"Bad PAM password attempt for '%s' from %s",
ses.authstate.pw_name,
printable_user,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
goto cleanup;
@@ -253,12 +265,19 @@ void svr_auth_pam() {
rc, pam_strerror(pamHandlep, rc));
dropbear_log(LOG_WARNING,
"Bad PAM password attempt for '%s' from %s",
ses.authstate.pw_name,
printable_user,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
goto cleanup;
}
if (!valid_user) {
/* PAM auth succeeded but the username isn't allowed in for another reason
(checkusername() failed) */
send_msg_userauth_failure(0, 1);
goto cleanup;
}
/* successful authentication */
dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s",
ses.authstate.pw_name,

View File

@@ -48,22 +48,14 @@ static int constant_time_strcmp(const char* a, const char* b) {
/* Process a password auth request, sending success or failure messages as
* appropriate */
void svr_auth_password() {
void svr_auth_password(int valid_user) {
char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
char * testcrypt = NULL; /* crypt generated from the user's password sent */
char * password;
char * password = NULL;
unsigned int passwordlen;
unsigned int changepw;
passwdcrypt = ses.authstate.pw_passwd;
#ifdef DEBUG_HACKCRYPT
/* debugging crypt for non-root testing with shadows */
passwdcrypt = DEBUG_HACKCRYPT;
#endif
/* check if client wants to change password */
changepw = buf_getbool(ses.payload);
if (changepw) {
@@ -73,12 +65,30 @@ void svr_auth_password() {
}
password = buf_getstring(ses.payload, &passwordlen);
/* the first bytes of passwdcrypt are the salt */
testcrypt = crypt(password, passwdcrypt);
if (valid_user && passwordlen <= DROPBEAR_MAX_PASSWORD_LEN) {
/* the first bytes of passwdcrypt are the salt */
passwdcrypt = ses.authstate.pw_passwd;
testcrypt = crypt(password, passwdcrypt);
}
m_burn(password, passwordlen);
m_free(password);
/* After we have got the payload contents we can exit if the username
is invalid. Invalid users have already been logged. */
if (!valid_user) {
send_msg_userauth_failure(0, 1);
return;
}
if (passwordlen > DROPBEAR_MAX_PASSWORD_LEN) {
dropbear_log(LOG_WARNING,
"Too-long password attempt for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
return;
}
if (testcrypt == NULL) {
/* crypt() with an invalid salt like "!!" */
dropbear_log(LOG_WARNING, "User account '%s' is locked",

View File

@@ -79,7 +79,7 @@ static int checkfileperm(char * filename);
/* process a pubkey auth request, sending success or failure message as
* appropriate */
void svr_auth_pubkey() {
void svr_auth_pubkey(int valid_user) {
unsigned char testkey; /* whether we're just checking if a key is usable */
char* algo = NULL; /* pubkey algo */
@@ -102,6 +102,15 @@ void svr_auth_pubkey() {
keybloblen = buf_getint(ses.payload);
keyblob = buf_getptr(ses.payload, keybloblen);
if (!valid_user) {
/* Return failure once we have read the contents of the packet
required to validate a public key.
Avoids blind user enumeration though it isn't possible to prevent
testing for user existence if the public key is known */
send_msg_userauth_failure(0, 0);
goto out;
}
/* check if the key is valid */
if (checkpubkey(algo, algolen, keyblob, keybloblen) == DROPBEAR_FAILURE) {
send_msg_userauth_failure(0, 0);
@@ -167,6 +176,10 @@ out:
sign_key_free(key);
key = NULL;
}
/* Retain pubkey options only if auth succeeded */
if (!ses.authstate.authdone) {
svr_pubkey_options_cleanup();
}
TRACE(("leave pubkeyauth"))
}
@@ -197,7 +210,12 @@ static int checkpubkey_line(buffer* line, int line_num, const char* filename,
if (line->len < MIN_AUTHKEYS_LINE || line->len > MAX_AUTHKEYS_LINE) {
TRACE(("checkpubkey_line: bad line length %d", line->len))
return DROPBEAR_FAILURE;
goto out;
}
if (memchr(line->data, 0x0, line->len) != NULL) {
TRACE(("checkpubkey_line: bad line has null char"))
goto out;
}
/* compare the algorithm. +3 so we have enough bytes to read a space and some base64 characters too. */
@@ -329,6 +347,7 @@ static int checkpubkey(const char* algo, unsigned int algolen,
snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
ses.authstate.pw_dir);
#if DROPBEAR_SVR_MULTIUSER
/* open the file as the authenticating user. */
origuid = getuid();
origgid = getgid();
@@ -336,13 +355,16 @@ static int checkpubkey(const char* algo, unsigned int algolen,
(seteuid(ses.authstate.pw_uid)) < 0) {
dropbear_exit("Failed to set euid");
}
#endif
authfile = fopen(filename, "r");
#if DROPBEAR_SVR_MULTIUSER
if ((seteuid(origuid)) < 0 ||
(setegid(origgid)) < 0) {
dropbear_exit("Failed to revert euid");
}
#endif
if (authfile == NULL) {
goto out;
@@ -406,8 +428,9 @@ static int checkpubkeyperms() {
/* allocate max required pathname storage,
* = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
filename = m_malloc(len + 22);
strncpy(filename, ses.authstate.pw_dir, len+1);
len += 22;
filename = m_malloc(len);
strlcpy(filename, ses.authstate.pw_dir, len);
/* check ~ */
if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
@@ -415,13 +438,13 @@ static int checkpubkeyperms() {
}
/* check ~/.ssh */
strncat(filename, "/.ssh", 5); /* strlen("/.ssh") == 5 */
strlcat(filename, "/.ssh", len);
if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
goto out;
}
/* now check ~/.ssh/authorized_keys */
strncat(filename, "/authorized_keys", 16);
strlcat(filename, "/authorized_keys", len);
if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
goto out;
}
@@ -473,4 +496,12 @@ static int checkfileperm(char * filename) {
return DROPBEAR_SUCCESS;
}
#if DROPBEAR_FUZZ
int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const char* algo, unsigned int algolen,
const unsigned char* keyblob, unsigned int keybloblen) {
return checkpubkey_line(line, line_num, filename, algo, algolen, keyblob, keybloblen);
}
#endif
#endif

View File

@@ -113,7 +113,6 @@ void svr_pubkey_options_cleanup() {
m_free(ses.authstate.pubkey_options->forced_command);
}
m_free(ses.authstate.pubkey_options);
ses.authstate.pubkey_options = NULL;
}
}
@@ -169,6 +168,12 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
if (match_option(options_buf, "command=\"") == DROPBEAR_SUCCESS) {
int escaped = 0;
const unsigned char* command_start = buf_getptr(options_buf, 0);
if (ses.authstate.pubkey_options->forced_command) {
/* multiple command= options */
goto bad_option;
}
while (options_buf->pos < options_buf->len) {
const char c = buf_getbyte(options_buf);
if (!escaped && c == '"') {

View File

@@ -51,6 +51,7 @@ static void execchild(const void *user_data_chansess);
static void addchildpid(struct ChanSess *chansess, pid_t pid);
static void sesssigchild_handler(int val);
static void closechansess(const struct Channel *channel);
static void cleanupchansess(const struct Channel *channel);
static int newchansess(struct Channel *channel);
static void chansessionrequest(struct Channel *channel);
static int sesscheckclose(const struct Channel *channel);
@@ -69,6 +70,7 @@ const struct ChanType svrchansess = {
sesscheckclose, /* checkclosehandler */
chansessionrequest, /* reqhandler */
closechansess, /* closehandler */
cleanupchansess /* cleanup */
};
/* required to clear environment */
@@ -91,7 +93,7 @@ void svr_chansess_checksignal(void) {
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
unsigned int i;
struct exitinfo *ex = NULL;
TRACE(("sigchld handler: pid %d", pid))
TRACE(("svr_chansess_checksignal : pid %d", pid))
ex = NULL;
/* find the corresponding chansess */
@@ -285,8 +287,25 @@ chansess_login_alloc(const struct ChanSess *chansess) {
return li;
}
/* clean a session channel */
/* send exit status message before the channel is closed */
static void closechansess(const struct Channel *channel) {
struct ChanSess *chansess;
TRACE(("enter closechansess"))
chansess = (struct ChanSess*)channel->typedata;
if (chansess == NULL) {
TRACE(("leave closechansess: chansess == NULL"))
return;
}
send_exitsignalstatus(channel);
TRACE(("leave closechansess"))
}
/* clean a session channel */
static void cleanupchansess(const struct Channel *channel) {
struct ChanSess *chansess;
unsigned int i;
@@ -301,8 +320,6 @@ static void closechansess(const struct Channel *channel) {
return;
}
send_exitsignalstatus(channel);
m_free(chansess->cmd);
m_free(chansess->term);
@@ -932,6 +949,7 @@ static void execchild(const void *user_data) {
#endif /* HAVE_CLEARENV */
#endif /* DEBUG_VALGRIND */
#if DROPBEAR_SVR_MULTIUSER
/* We can only change uid/gid as root ... */
if (getuid() == 0) {
@@ -955,6 +973,7 @@ static void execchild(const void *user_data) {
dropbear_exit("Couldn't change user as non-root");
}
}
#endif
/* set env vars */
addnewvar("USER", ses.authstate.pw_name);

View File

@@ -179,6 +179,13 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
}
#endif
#if DROPBEAR_FUZZ
if (fuzz.fuzzing && fuzz.skip_kexmaths) {
fuzz_fake_send_kexdh_reply();
return;
}
#endif
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY);
buf_put_pub_key(ses.writepayload, svr_opts.hostkey,
ses.newkeys->algo_hostkey);

View File

@@ -178,7 +178,7 @@ static void main_noinetd() {
/* incoming connection select loop */
for(;;) {
FD_ZERO(&fds);
DROPBEAR_FD_ZERO(&fds);
/* listening sockets */
for (i = 0; i < listensockcount; i++) {

View File

@@ -523,10 +523,13 @@ static void addhostkey(const char *keyfile) {
svr_opts.num_hostkey_files++;
}
void load_all_hostkeys() {
int i;
int disable_unset_keys = 1;
int any_keys = 0;
#ifdef DROPBEAR_ECDSA
int loaded_any_ecdsa = 0;
#endif
svr_opts.hostkey = new_sign_key();
@@ -551,14 +554,8 @@ void load_all_hostkeys() {
#endif
}
#if DROPBEAR_DELAY_HOSTKEY
if (svr_opts.delay_hostkey) {
disable_unset_keys = 0;
}
#endif
#if DROPBEAR_RSA
if (disable_unset_keys && !svr_opts.hostkey->rsakey) {
if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
disablekey(DROPBEAR_SIGNKEY_RSA);
} else {
any_keys = 1;
@@ -566,39 +563,54 @@ void load_all_hostkeys() {
#endif
#if DROPBEAR_DSS
if (disable_unset_keys && !svr_opts.hostkey->dsskey) {
if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
disablekey(DROPBEAR_SIGNKEY_DSS);
} else {
any_keys = 1;
}
#endif
#if DROPBEAR_ECDSA
/* We want to advertise a single ecdsa algorithm size.
- If there is a ecdsa hostkey at startup we choose that that size.
- If we generate at runtime we choose the default ecdsa size.
- Otherwise no ecdsa keys will be advertised */
/* check if any keys were loaded at startup */
loaded_any_ecdsa =
0
#if DROPBEAR_ECC_256
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 256)
&& !svr_opts.hostkey->ecckey256) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
} else {
any_keys = 1;
}
|| svr_opts.hostkey->ecckey256
#endif
#if DROPBEAR_ECC_384
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 384)
&& !svr_opts.hostkey->ecckey384) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
} else {
any_keys = 1;
|| svr_opts.hostkey->ecckey384
#endif
#if DROPBEAR_ECC_521
|| svr_opts.hostkey->ecckey521
#endif
;
any_keys |= loaded_any_ecdsa;
/* Or an ecdsa key could be generated at runtime */
any_keys |= svr_opts.delay_hostkey;
/* At most one ecdsa key size will be left enabled */
#if DROPBEAR_ECC_256
if (!svr_opts.hostkey->ecckey256
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
}
#endif
#if DROPBEAR_ECC_384
if (!svr_opts.hostkey->ecckey384
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
}
#endif
#if DROPBEAR_ECC_521
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 521)
&& !svr_opts.hostkey->ecckey521) {
if (!svr_opts.hostkey->ecckey521
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
} else {
any_keys = 1;
}
#endif
#endif /* DROPBEAR_ECDSA */

View File

@@ -40,6 +40,7 @@
#include "auth.h"
#include "runopts.h"
#include "crypto_desc.h"
#include "fuzz.h"
static void svr_remoteclosed(void);
static void svr_algos_initialise(void);
@@ -184,6 +185,13 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
session_cleanup();
}
#if DROPBEAR_FUZZ
/* longjmp before cleaning up svr_opts */
if (fuzz.do_jmp) {
longjmp(fuzz.jmp, 1);
}
#endif
if (svr_opts.hostkey) {
sign_key_free(svr_opts.hostkey);
svr_opts.hostkey = NULL;
@@ -193,6 +201,7 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
m_free(svr_opts.ports[i]);
}
exit(exitcode);
}
@@ -238,7 +247,9 @@ void svr_dropbear_log(int priority, const char* format, va_list param) {
static void svr_remoteclosed() {
m_close(ses.sock_in);
m_close(ses.sock_out);
if (ses.sock_in != ses.sock_out) {
m_close(ses.sock_out);
}
ses.sock_in = -1;
ses.sock_out = -1;
dropbear_close("Exited normally");

View File

@@ -57,6 +57,7 @@ static const struct ChanType svr_chan_tcpremote = {
tcp_prio_inithandler,
NULL,
NULL,
NULL,
NULL
};
@@ -168,6 +169,7 @@ static int svr_remotetcpreq(int *allocated_listen_port) {
unsigned int addrlen;
struct TCPListener *tcpinfo = NULL;
unsigned int port;
struct Listener *listener = NULL;
TRACE(("enter remotetcpreq"))
@@ -208,9 +210,9 @@ static int svr_remotetcpreq(int *allocated_listen_port) {
tcpinfo->listenaddr = m_strdup(request_addr);
}
ret = listen_tcpfwd(tcpinfo);
ret = listen_tcpfwd(tcpinfo, &listener);
if (DROPBEAR_SUCCESS == ret) {
tcpinfo->listenport = get_sock_port(ses.listeners[0]->socks[0]);
tcpinfo->listenport = get_sock_port(listener->socks[0]);
*allocated_listen_port = tcpinfo->listenport;
}
@@ -237,7 +239,8 @@ const struct ChanType svr_chan_tcpdirect = {
newtcpdirect, /* init */
NULL, /* checkclose */
NULL, /* reqhandler */
NULL /* closehandler */
NULL, /* closehandler */
NULL /* cleanup */
};
/* Called upon creating a new direct tcp channel (ie we connect out to an

View File

@@ -216,7 +216,8 @@ static const struct ChanType chan_x11 = {
x11_inithandler, /* inithandler */
NULL, /* checkclose */
NULL, /* reqhandler */
NULL /* closehandler */
NULL, /* closehandler */
NULL /* cleanup */
};

View File

@@ -4,7 +4,7 @@
*******************************************************************/
#ifndef DROPBEAR_VERSION
#define DROPBEAR_VERSION "2018.76"
#define DROPBEAR_VERSION "2019.78"
#endif
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
@@ -86,6 +86,8 @@
/* Required for pubkey auth */
#define DROPBEAR_SIGNKEY_VERIFY ((DROPBEAR_SVR_PUBKEY_AUTH) || (DROPBEAR_CLIENT))
#define DROPBEAR_MAX_PASSWORD_LEN 100
#define SHA1_HASH_SIZE 20
#define MD5_HASH_SIZE 16
#define MAX_HASH_SIZE 64 /* sha512 */
@@ -225,7 +227,7 @@ If you test it please contact the Dropbear author */
#define DROPBEAR_ZLIB_MEM_LEVEL 8
#if (DROPBEAR_SVR_PASSWORD_AUTH) && (DROPBEAR_SVR_PAM_AUTH)
#error "You can't turn on PASSWORD and PAM auth both at once. Fix it in options.h"
#error "You can't turn on PASSWORD and PAM auth both at once. Fix it in localoptions.h"
#endif
/* PAM requires ./configure --enable-pam */
@@ -316,4 +318,17 @@ If you test it please contact the Dropbear author */
#define DROPBEAR_CLIENT_TCP_FAST_OPEN 0
#endif
#define DROPBEAR_TRACKING_MALLOC (DROPBEAR_FUZZ)
/* Used to work around Memory Sanitizer false positives */
#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
# define DROPBEAR_MSAN 1
# endif
#endif
#ifndef DROPBEAR_MSAN
#define DROPBEAR_MSAN 0
#endif
/* no include guard for this file */

View File

@@ -110,12 +110,12 @@ static void tcp_acceptor(const struct Listener *listener, int sock) {
}
}
int listen_tcpfwd(struct TCPListener* tcpinfo) {
int listen_tcpfwd(struct TCPListener* tcpinfo, struct Listener **ret_listener) {
char portstring[NI_MAXSERV];
int socks[DROPBEAR_MAX_SOCKS];
struct Listener *listener = NULL;
int nsocks;
struct Listener *listener;
char* errstring = NULL;
TRACE(("enter listen_tcpfwd"))
@@ -142,6 +142,10 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) {
return DROPBEAR_FAILURE;
}
if (ret_listener) {
*ret_listener = listener;
}
TRACE(("leave listen_tcpfwd: success"))
return DROPBEAR_SUCCESS;
}

View File

@@ -26,6 +26,7 @@
#include "channel.h"
#include "list.h"
#include "listener.h"
struct TCPListener {
@@ -69,7 +70,7 @@ void cli_recv_msg_request_success(void);
void cli_recv_msg_request_failure(void);
/* Common */
int listen_tcpfwd(struct TCPListener* tcpinfo);
int listen_tcpfwd(struct TCPListener* tcpinfo, struct Listener **ret_listener);
int tcp_prio_inithandler(struct Channel* chan);
/* A random identifier */