]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Merge Ben's branch on which he's been fuzzing PuTTY.
authorSimon Tatham <anakin@pobox.com>
Sat, 7 Nov 2015 13:29:53 +0000 (13:29 +0000)
committerSimon Tatham <anakin@pobox.com>
Sat, 7 Nov 2015 13:29:53 +0000 (13:29 +0000)
This includes fixes arising from the fuzzing, and also changes to make
the code compile into usefully fuzzable forms.

Recipe
fuzzterm.c [new file with mode: 0644]
misc.c
putty.h
ssh.c
sshbn.c
sshecc.c
sshrand.c
terminal.c
unix/uxplink.c
unix/uxproxy.c

diff --git a/Recipe b/Recipe
index 89609df68c4d3313c6c431c1df190b71edc0327d..0bc27c7f448688737627df42364ced16067291c4 100644 (file)
--- a/Recipe
+++ b/Recipe
 #      show up as GPFs at the point of failure rather than appearing
 #      later on as second-level damage.
 #
+#  - XFLAGS=/DFUZZING
+#      Builds a version of PuTTY with some tweaks to make fuzz testing
+#      easier: the SSH random number generator is replaced by one that
+#      always returns the same thing.  Note that this makes SSH
+#      completely insecure -- a FUZZING build should never be used to
+#      connect to a real server.
 !end
 
 # ------------------------------------------------------------
@@ -310,3 +316,6 @@ pageant  : [X] uxpgnt uxagentc pageant sshrsa sshpubk sshdes sshbn sshmd5
 
 PuTTY    : [MX] osxmain OSXTERM OSXMISC CHARSET U_BE_ALL NONSSH UXSSH
          + ux_x11 uxpty uxsignal testback putty.icns info.plist
+
+fuzzterm : [U] UXTERM CHARSET misc uxmisc uxucs fuzzterm time settings
+        + uxstore be_none
diff --git a/fuzzterm.c b/fuzzterm.c
new file mode 100644 (file)
index 0000000..0da3b68
--- /dev/null
@@ -0,0 +1,185 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define PUTTY_DO_GLOBALS
+#include "putty.h"
+#include "terminal.h"
+
+int main(int argc, char **argv)
+{
+       char blk[512];
+       size_t len;
+       Terminal *term;
+       Conf *conf;
+       struct unicode_data ucsdata;
+
+       conf = conf_new();
+       do_defaults(NULL, conf);
+       init_ucs(&ucsdata, conf_get_str(conf, CONF_line_codepage),
+                conf_get_int(conf, CONF_utf8_override),
+                CS_NONE, conf_get_int(conf, CONF_vtmode));
+
+       term = term_init(conf, &ucsdata, NULL);
+       term_size(term, 24, 80, 10000);
+       term->ldisc = NULL;
+       /* Tell american fuzzy lop that this is a good place to fork. */
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+       __AFL_INIT();
+#endif
+       while (!feof(stdin)) {
+               len = fread(blk, 1, sizeof(blk), stdin);
+               term_data(term, 0, blk, len);
+       }
+       term_update(term);
+       return 0;
+}
+
+int from_backend(void *frontend, int is_stderr, const char *data, int len)
+{ return 0; }
+
+/* functions required by terminal.c */
+
+void request_resize(void *frontend, int x, int y) { }
+void do_text(Context ctx, int x, int y, wchar_t * text, int len,
+            unsigned long attr, int lattr)
+{
+    int i;
+
+    printf("TEXT[attr=%08lx,lattr=%02x]@(%d,%d):", attr, lattr, x, y);
+    for (i = 0; i < len; i++) {
+       printf(" %x", (unsigned)text[i]);
+    }
+    printf("\n");
+}
+void do_cursor(Context ctx, int x, int y, wchar_t * text, int len,
+            unsigned long attr, int lattr)
+{
+    int i;
+
+    printf("CURS[attr=%08lx,lattr=%02x]@(%d,%d):", attr, lattr, x, y);
+    for (i = 0; i < len; i++) {
+       printf(" %x", (unsigned)text[i]);
+    }
+    printf("\n");
+}
+int char_width(Context ctx, int uc) { return 1; }
+void set_title(void *frontend, char *t) { }
+void set_icon(void *frontend, char *t) { }
+void set_sbar(void *frontend, int a, int b, int c) { }
+
+void ldisc_send(void *handle, const char *buf, int len, int interactive) {}
+void ldisc_echoedit_update(void *handle) {}
+Context get_ctx(void *frontend) { 
+    static char x;
+
+    return &x;
+}
+void free_ctx(Context ctx) { }
+void palette_set(void *frontend, int a, int b, int c, int d) { }
+void palette_reset(void *frontend) { }
+void write_clip(void *frontend, wchar_t *a, int *b, int c, int d) { }
+void get_clip(void *frontend, wchar_t **w, int *i) { }
+void set_raw_mouse_mode(void *frontend, int m) { }
+void request_paste(void *frontend) { }
+void do_beep(void *frontend, int a) { }
+void sys_cursor(void *frontend, int x, int y) { }
+void fatalbox(const char *fmt, ...) { exit(0); }
+void modalfatalbox(const char *fmt, ...) { exit(0); }
+void nonfatal(const char *fmt, ...) { }
+
+void set_iconic(void *frontend, int iconic) { }
+void move_window(void *frontend, int x, int y) { }
+void set_zorder(void *frontend, int top) { }
+void refresh_window(void *frontend) { }
+void set_zoomed(void *frontend, int zoomed) { }
+int is_iconic(void *frontend) { return 0; }
+void get_window_pos(void *frontend, int *x, int *y) { *x = 0; *y = 0; }
+void get_window_pixels(void *frontend, int *x, int *y) { *x = 0; *y = 0; }
+char *get_window_title(void *frontend, int icon) { return "moo"; }
+
+/* needed by timing.c */
+void timer_change_notify(unsigned long next) { }
+
+/* needed by config.c and sercfg.c */
+
+void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton) { }
+int dlg_radiobutton_get(union control *ctrl, void *dlg) { return 0; }
+void dlg_checkbox_set(union control *ctrl, void *dlg, int checked) { }
+int dlg_checkbox_get(union control *ctrl, void *dlg) { return 0; }
+void dlg_editbox_set(union control *ctrl, void *dlg, char const *text) { }
+char *dlg_editbox_get(union control *ctrl, void *dlg) { return dupstr("moo"); }
+void dlg_listbox_clear(union control *ctrl, void *dlg) { }
+void dlg_listbox_del(union control *ctrl, void *dlg, int index) { }
+void dlg_listbox_add(union control *ctrl, void *dlg, char const *text) { }
+void dlg_listbox_addwithid(union control *ctrl, void *dlg,
+                          char const *text, int id) { }
+int dlg_listbox_getid(union control *ctrl, void *dlg, int index) { return 0; }
+int dlg_listbox_index(union control *ctrl, void *dlg) { return -1; }
+int dlg_listbox_issel(union control *ctrl, void *dlg, int index) { return 0; }
+void dlg_listbox_select(union control *ctrl, void *dlg, int index) { }
+void dlg_text_set(union control *ctrl, void *dlg, char const *text) { }
+void dlg_filesel_set(union control *ctrl, void *dlg, Filename *fn) { }
+Filename *dlg_filesel_get(union control *ctrl, void *dlg) { return NULL; }
+void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec *fn) { }
+FontSpec *dlg_fontsel_get(union control *ctrl, void *dlg) { return NULL; }
+void dlg_update_start(union control *ctrl, void *dlg) { }
+void dlg_update_done(union control *ctrl, void *dlg) { }
+void dlg_set_focus(union control *ctrl, void *dlg) { }
+void dlg_label_change(union control *ctrl, void *dlg, char const *text) { }
+union control *dlg_last_focused(union control *ctrl, void *dlg) { return NULL; }
+void dlg_beep(void *dlg) { }
+void dlg_error_msg(void *dlg, const char *msg) { }
+void dlg_end(void *dlg, int value) { }
+void dlg_coloursel_start(union control *ctrl, void *dlg,
+                        int r, int g, int b) { }
+int dlg_coloursel_results(union control *ctrl, void *dlg,
+                         int *r, int *g, int *b) { return 0; }
+void dlg_refresh(union control *ctrl, void *dlg) { }
+
+/* miscellany */
+void logevent(void *frontend, const char *msg) { }
+int askappend(void *frontend, Filename *filename,
+             void (*callback)(void *ctx, int result), void *ctx) { return 0; }
+
+const char *const appname = "FuZZterm";
+const int ngsslibs = 0;
+const char *const gsslibnames[0] = { };
+const struct keyvalwhere gsslibkeywords[0] = { };
+
+/*
+ * Default settings that are specific to Unix plink.
+ */
+char *platform_default_s(const char *name)
+{
+    if (!strcmp(name, "TermType"))
+       return dupstr(getenv("TERM"));
+    if (!strcmp(name, "SerialLine"))
+       return dupstr("/dev/ttyS0");
+    return NULL;
+}
+
+int platform_default_i(const char *name, int def)
+{
+    return def;
+}
+
+FontSpec *platform_default_fontspec(const char *name)
+{
+    return fontspec_new("");
+}
+
+Filename *platform_default_filename(const char *name)
+{
+    if (!strcmp(name, "LogFileName"))
+       return filename_from_str("putty.log");
+    else
+       return filename_from_str("");
+}
+
+char *x_get_default(const char *key)
+{
+    return NULL;                      /* this is a stub */
+}
+
+
diff --git a/misc.c b/misc.c
index b1bfb36176fab38832a9244e03e8422620bc8cbf..6af441c301129df44f30009c4ae4829c71d29242 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -1064,7 +1064,7 @@ int match_ssh_id(int stringlen, const void *string, const char *id)
 void *get_ssh_string(int *datalen, const void **data, int *stringlen)
 {
     void *ret;
-    int len;
+    unsigned int len;
 
     if (*datalen < 4)
         return NULL;
diff --git a/putty.h b/putty.h
index c854d9449ebd194e93054564dd26c50c2944afc5..3ccd96cb868beb52d8286d617b3ae1a7ddef1ab8 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -291,7 +291,7 @@ enum {
      * Proxy types.
      */
     PROXY_NONE, PROXY_SOCKS4, PROXY_SOCKS5,
-    PROXY_HTTP, PROXY_TELNET, PROXY_CMD
+    PROXY_HTTP, PROXY_TELNET, PROXY_CMD, PROXY_FUZZ
 };
 
 enum {
diff --git a/ssh.c b/ssh.c
index 1f8a214b6a07e165872d4e83cfecd8af7517ac21..de8259ed1db41662ad1e38c8004df691c17ea219 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -3017,6 +3017,10 @@ static void ssh_send_verstring(Ssh ssh, const char *protoname, char *svers)
     }
 
     ssh_fix_verstring(verstring + strlen(protoname));
+#ifdef FUZZING
+    /* FUZZING make PuTTY insecure, so make live use difficult. */
+    verstring[0] = 'I';
+#endif
 
     if (ssh->version == 2) {
        size_t len;
@@ -4050,6 +4054,9 @@ static int do_ssh1_login(Ssh ssh, const unsigned char *in, int inlen,
                                             "rsa", keystr, fingerprint,
                                             ssh_dialog_callback, ssh);
             sfree(keystr);
+#ifdef FUZZING
+           s->dlgret = 1;
+#endif
             if (s->dlgret < 0) {
                 do {
                     crReturn(0);
@@ -6487,6 +6494,11 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
        /* List encryption algorithms (client->server then server->client). */
        for (k = KEXLIST_CSCIPHER; k <= KEXLIST_SCCIPHER; k++) {
            warn = FALSE;
+#ifdef FUZZING
+           alg = ssh2_kexinit_addalg(s->kexlists[k], "none");
+           alg->u.cipher.cipher = NULL;
+           alg->u.cipher.warn = warn;
+#endif /* FUZZING */
            for (i = 0; i < s->n_preferred_ciphers; i++) {
                const struct ssh2_ciphers *c = s->preferred_ciphers[i];
                if (!c) warn = TRUE;
@@ -6500,6 +6512,11 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
        }
        /* List MAC algorithms (client->server then server->client). */
        for (j = KEXLIST_CSMAC; j <= KEXLIST_SCMAC; j++) {
+#ifdef FUZZING
+           alg = ssh2_kexinit_addalg(s->kexlists[j], "none");
+           alg->u.mac.mac = NULL;
+           alg->u.mac.etm = FALSE;
+#endif /* FUZZING */
            for (i = 0; i < s->nmacs; i++) {
                alg = ssh2_kexinit_addalg(s->kexlists[j], s->maclist[i]->name);
                alg->u.mac.mac = s->maclist[i];
@@ -6772,8 +6789,8 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
         {
             int csbits, scbits;
 
-            csbits = s->cscipher_tobe->real_keybits;
-            scbits = s->sccipher_tobe->real_keybits;
+            csbits = s->cscipher_tobe ? s->cscipher_tobe->real_keybits : 0;
+            scbits = s->sccipher_tobe ? s->sccipher_tobe->real_keybits : 0;
             s->nbits = (csbits > scbits ? csbits : scbits);
         }
         /* The keys only have hlen-bit entropy, since they're based on
@@ -7109,12 +7126,18 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
     dmemdump(s->exchange_hash, ssh->kex->hash->hlen);
 #endif
 
-    if (!s->hkey ||
-       !ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen,
+    if (!s->hkey) {
+       bombout(("Server's host key is invalid"));
+       crStopV;
+    }
+
+    if (!ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen,
                                 (char *)s->exchange_hash,
                                 ssh->kex->hash->hlen)) {
+#ifndef FUZZING
        bombout(("Server's host key did not match the signature supplied"));
-       crStopV;
+       crStopV;f 
+#endif
     }
 
     s->keystr = ssh->hostkey->fmtkey(s->hkey);
@@ -7139,6 +7162,9 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
                                             ssh->hostkey->keytype, s->keystr,
                                             s->fingerprint,
                                             ssh_dialog_callback, ssh);
+#ifdef FUZZING
+           s->dlgret = 1;
+#endif
             if (s->dlgret < 0) {
                 do {
                     crReturnV;
@@ -7171,8 +7197,10 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
          * the one we saw before.
          */
         if (strcmp(ssh->hostkey_str, s->keystr)) {
+#ifndef FUZZING
             bombout(("Host key was different in repeat key exchange"));
             crStopV;
+#endif
         }
         sfree(s->keystr);
     }
@@ -7206,13 +7234,14 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
     if (ssh->cs_cipher_ctx)
        ssh->cscipher->free_context(ssh->cs_cipher_ctx);
     ssh->cscipher = s->cscipher_tobe;
-    ssh->cs_cipher_ctx = ssh->cscipher->make_context();
+    if (ssh->cscipher) ssh->cs_cipher_ctx = ssh->cscipher->make_context();
 
     if (ssh->cs_mac_ctx)
        ssh->csmac->free_context(ssh->cs_mac_ctx);
     ssh->csmac = s->csmac_tobe;
     ssh->csmac_etm = s->csmac_etm_tobe;
-    ssh->cs_mac_ctx = ssh->csmac->make_context(ssh->cs_cipher_ctx);
+    if (ssh->csmac)
+        ssh->cs_mac_ctx = ssh->csmac->make_context(ssh->cs_cipher_ctx);
 
     if (ssh->cs_comp_ctx)
        ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx);
@@ -7223,7 +7252,7 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
      * Set IVs on client-to-server keys. Here we use the exchange
      * hash from the _first_ key exchange.
      */
-    {
+    if (ssh->cscipher) {
        unsigned char *key;
 
        key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'C',
@@ -7237,6 +7266,9 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
        ssh->cscipher->setiv(ssh->cs_cipher_ctx, key);
         smemclr(key, ssh->cscipher->blksize);
         sfree(key);
+    }
+    if (ssh->csmac) {
+       unsigned char *key;
 
        key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'E',
                          ssh->csmac->keylen);
@@ -7245,12 +7277,14 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
         sfree(key);
     }
 
-    logeventf(ssh, "Initialised %.200s client->server encryption",
-             ssh->cscipher->text_name);
-    logeventf(ssh, "Initialised %.200s client->server MAC algorithm%s%s",
-             ssh->csmac->text_name,
-              ssh->csmac_etm ? " (in ETM mode)" : "",
-              ssh->cscipher->required_mac ? " (required by cipher)" : "");
+    if (ssh->cscipher)
+       logeventf(ssh, "Initialised %.200s client->server encryption",
+                 ssh->cscipher->text_name);
+    if (ssh->csmac)
+       logeventf(ssh, "Initialised %.200s client->server MAC algorithm%s%s",
+                 ssh->csmac->text_name,
+                 ssh->csmac_etm ? " (in ETM mode)" : "",
+                 ssh->cscipher->required_mac ? " (required by cipher)" : "");
     if (ssh->cscomp->text_name)
        logeventf(ssh, "Initialised %s compression",
                  ssh->cscomp->text_name);
@@ -7278,14 +7312,18 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
      */
     if (ssh->sc_cipher_ctx)
        ssh->sccipher->free_context(ssh->sc_cipher_ctx);
-    ssh->sccipher = s->sccipher_tobe;
-    ssh->sc_cipher_ctx = ssh->sccipher->make_context();
+    if (ssh->sccipher) {
+       ssh->sccipher = s->sccipher_tobe;
+       ssh->sc_cipher_ctx = ssh->sccipher->make_context();
+    }
 
     if (ssh->sc_mac_ctx)
        ssh->scmac->free_context(ssh->sc_mac_ctx);
-    ssh->scmac = s->scmac_tobe;
-    ssh->scmac_etm = s->scmac_etm_tobe;
-    ssh->sc_mac_ctx = ssh->scmac->make_context(ssh->sc_cipher_ctx);
+    if (ssh->scmac) {
+       ssh->scmac = s->scmac_tobe;
+       ssh->scmac_etm = s->scmac_etm_tobe;
+       ssh->sc_mac_ctx = ssh->scmac->make_context(ssh->sc_cipher_ctx);
+    }
 
     if (ssh->sc_comp_ctx)
        ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx);
@@ -7296,7 +7334,7 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
      * Set IVs on server-to-client keys. Here we use the exchange
      * hash from the _first_ key exchange.
      */
-    {
+    if (ssh->sccipher) {
        unsigned char *key;
 
        key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'D',
@@ -7310,6 +7348,9 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
        ssh->sccipher->setiv(ssh->sc_cipher_ctx, key);
         smemclr(key, ssh->sccipher->blksize);
         sfree(key);
+    }
+    if (ssh->scmac) {
+       unsigned char *key;
 
        key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'F',
                          ssh->scmac->keylen);
@@ -7317,12 +7358,14 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
         smemclr(key, ssh->scmac->keylen);
         sfree(key);
     }
-    logeventf(ssh, "Initialised %.200s server->client encryption",
-             ssh->sccipher->text_name);
-    logeventf(ssh, "Initialised %.200s server->client MAC algorithm%s%s",
-             ssh->scmac->text_name,
-              ssh->scmac_etm ? " (in ETM mode)" : "",
-              ssh->sccipher->required_mac ? " (required by cipher)" : "");
+    if (ssh->sccipher)
+       logeventf(ssh, "Initialised %.200s server->client encryption",
+                 ssh->sccipher->text_name);
+    if (ssh->scmac)
+       logeventf(ssh, "Initialised %.200s server->client MAC algorithm%s%s",
+                 ssh->scmac->text_name,
+                 ssh->scmac_etm ? " (in ETM mode)" : "",
+                 ssh->sccipher->required_mac ? " (required by cipher)" : "");
     if (ssh->sccomp->text_name)
        logeventf(ssh, "Initialised %s decompression",
                  ssh->sccomp->text_name);
diff --git a/sshbn.c b/sshbn.c
index fd9e5c0aee3aa73d1966650de81ef4e8fe854643..7aa1069709f774964aa1de309fcb9f3412d528ef 100644 (file)
--- a/sshbn.c
+++ b/sshbn.c
@@ -1142,8 +1142,7 @@ Bignum bignum_from_bytes(const unsigned char *data, int nbytes)
             (BignumInt)byte << (8*i % BIGNUM_INT_BITS);
     }
 
-    while (result[0] > 1 && result[result[0]] == 0)
-       result[0]--;
+    bn_restore_invariant(result);
     return result;
 }
 
@@ -1165,8 +1164,7 @@ Bignum bignum_from_bytes_le(const unsigned char *data, int nbytes)
             (BignumInt)byte << (8*i % BIGNUM_INT_BITS);
     }
 
-    while (result[0] > 1 && result[result[0]] == 0)
-        result[0]--;
+    bn_restore_invariant(result);
     return result;
 }
 
@@ -1311,9 +1309,9 @@ int bignum_bit(Bignum bn, int i)
  */
 void bignum_set_bit(Bignum bn, int bitnum, int value)
 {
-    if (bitnum < 0 || bitnum >= (int)(BIGNUM_INT_BITS * bn[0]))
-       abort();                       /* beyond the end */
-    else {
+    if (bitnum < 0 || bitnum >= (int)(BIGNUM_INT_BITS * bn[0])) {
+        if (value) abort();                   /* beyond the end */
+    else {
        int v = bitnum / BIGNUM_INT_BITS + 1;
        BignumInt mask = (BignumInt)1 << (bitnum % BIGNUM_INT_BITS);
        if (value)
index 5f170215dbc2dd9764158b5334254943ae40709c..3912c5f1bd3e82ee58a032e13ead034124a1af66 100644 (file)
--- a/sshecc.c
+++ b/sshecc.c
@@ -1648,6 +1648,7 @@ static int decodepoint_ed(const char *p, int length, struct ec_point *point)
     /* Read x bit and then reset it */
     negative = bignum_bit(point->y, point->curve->fieldBits - 1);
     bignum_set_bit(point->y, point->curve->fieldBits - 1, 0);
+    bn_restore_invariant(point->y);
 
     /* Get the x from the y */
     point->x = ecp_edx(point->curve, point->y);
@@ -1770,6 +1771,7 @@ static void *ecdsa_newkey(const struct ssh_signkey *self,
     /* Curve name is duplicated for Weierstrass form */
     if (curve->type == EC_WEIERSTRASS) {
         getstring(&data, &len, &p, &slen);
+       if (!p) return NULL;
         if (!match_ssh_id(slen, p, curve->name)) return NULL;
     }
 
@@ -1781,11 +1783,11 @@ static void *ecdsa_newkey(const struct ssh_signkey *self,
     ec->publicKey.x = NULL;
     ec->publicKey.y = NULL;
     ec->publicKey.z = NULL;
+    ec->privateKey = NULL;
     if (!getmppoint(&data, &len, &ec->publicKey)) {
         ecdsa_freekey(ec);
         return NULL;
     }
-    ec->privateKey = NULL;
 
     if (!ec->publicKey.x || !ec->publicKey.y ||
         bignum_cmp(ec->publicKey.x, curve->p) >= 0 ||
@@ -2266,6 +2268,7 @@ static int ecdsa_verifysig(void *key, const char *sig, int siglen,
     }
 
     getstring(&sig, &siglen, &p, &slen);
+    if (!p) return 0;
     if (ec->publicKey.curve->type == EC_EDWARDS) {
         struct ec_point *r;
         Bignum s, h;
index ead39a9bdad917ec144faddd1ee4df1ec2cd22fd..0fbefb48370179f7b6b3fdf3bcd24c014dc0b6c6 100644 (file)
--- a/sshrand.c
+++ b/sshrand.c
@@ -45,8 +45,23 @@ struct RandPool {
     int stir_pending;
 };
 
-static struct RandPool pool;
 int random_active = 0;
+
+#ifdef FUZZING
+/*
+ * Special dummy version of the RNG for use when fuzzing.
+ */
+void random_add_noise(void *noise, int length) { }
+void random_add_heavynoise(void *noise, int length) { }
+void random_ref(void) { }
+void random_unref(void) { }
+int random_byte(void)
+{
+    return 0x45; /* Chosen by eight fair coin tosses */
+}
+void random_get_savedata(void **data, int *len) { }
+#else /* !FUZZING */
+static struct RandPool pool;
 long next_noise_collection;
 
 #ifdef RANDOM_DIAGNOSTICS
@@ -326,3 +341,4 @@ void random_get_savedata(void **data, int *len)
     *data = buf;
     random_stir();
 }
+#endif
index c5fdeeb0245643a3c9584211f7664505e9b23761..26a3f0c93f64b90228802ea6a50027a6500dd21d 100644 (file)
@@ -4725,7 +4725,7 @@ static void term_out(Terminal *term)
     }
 
     term_print_flush(term);
-    if (term->logflush)
+    if (term->logflush && term->logctx)
        logflush(term->logctx);
 }
 
index 8351a6ea7280528acbe8660a0db18e66237823c0..b8c554894002033dcb0e5583fd0285b9223bf11c 100644 (file)
@@ -25,7 +25,7 @@
 
 #define MAX_STDIN_BACKLOG 4096
 
-void *logctx;
+static void *logctx;
 
 static struct termios orig_termios;
 
@@ -690,6 +690,10 @@ int main(int argc, char **argv)
                }
            } else if (!strcmp(p, "-shareexists")) {
                 just_test_share_exists = TRUE;
+           } else if (!strcmp(p, "-fuzznet")) {
+               conf_set_int(conf, CONF_proxy_type, PROXY_FUZZ);
+               conf_set_str(conf, CONF_proxy_telnet_command,
+                            "%host");
            } else {
                fprintf(stderr, "plink: unknown option \"%s\"\n", p);
                errors = 1;
@@ -988,6 +992,11 @@ int main(int argc, char **argv)
        /* nodelay is only useful if stdin is a terminal device */
        int nodelay = conf_get_int(conf, CONF_tcp_nodelay) && isatty(0);
 
+       /* This is a good place for a fuzzer to fork us. */
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+       __AFL_INIT();
+#endif
+
        error = back->init(NULL, &backhandle, conf,
                           conf_get_str(conf, CONF_host),
                           conf_get_int(conf, CONF_port),
index 0399245d0c28bd8e7269390d991d835c66176bf5..8c916dc99d7111eb8b898b4b14827555c048c0f5 100644 (file)
@@ -250,13 +250,12 @@ Socket platform_new_connection(SockAddr addr, const char *hostname,
     };
 
     Local_Proxy_Socket ret;
-    int to_cmd_pipe[2], from_cmd_pipe[2], pid;
+    int to_cmd_pipe[2], from_cmd_pipe[2], pid, proxytype;
 
-    if (conf_get_int(conf, CONF_proxy_type) != PROXY_CMD)
+    proxytype = conf_get_int(conf, CONF_proxy_type);
+    if (proxytype != PROXY_CMD && proxytype != PROXY_FUZZ)
        return NULL;
 
-    cmd = format_telnet_command(addr, port, conf);
-
     ret = snew(struct Socket_localproxy_tag);
     ret->fn = &socket_fn_table;
     ret->plug = plug;
@@ -266,45 +265,64 @@ Socket platform_new_connection(SockAddr addr, const char *hostname,
     bufchain_init(&ret->pending_input_data);
     bufchain_init(&ret->pending_output_data);
 
-    /*
-     * Create the pipes to the proxy command, and spawn the proxy
-     * command process.
-     */
-    if (pipe(to_cmd_pipe) < 0 ||
-       pipe(from_cmd_pipe) < 0) {
-       ret->error = dupprintf("pipe: %s", strerror(errno));
-        sfree(cmd);
-       return (Socket)ret;
-    }
-    cloexec(to_cmd_pipe[1]);
-    cloexec(from_cmd_pipe[0]);
-
-    pid = fork();
-
-    if (pid < 0) {
-       ret->error = dupprintf("fork: %s", strerror(errno));
-        sfree(cmd);
-       return (Socket)ret;
-    } else if (pid == 0) {
-       close(0);
-       close(1);
-       dup2(to_cmd_pipe[0], 0);
-       dup2(from_cmd_pipe[1], 1);
-       close(to_cmd_pipe[0]);
-       close(from_cmd_pipe[1]);
-       noncloexec(0);
-       noncloexec(1);
-       execl("/bin/sh", "sh", "-c", cmd, (void *)NULL);
-       _exit(255);
-    }
+    if (proxytype == PROXY_CMD) {
+       cmd = format_telnet_command(addr, port, conf);
+
+       /*
+        * Create the pipes to the proxy command, and spawn the proxy
+        * command process.
+        */
+       if (pipe(to_cmd_pipe) < 0 ||
+           pipe(from_cmd_pipe) < 0) {
+           ret->error = dupprintf("pipe: %s", strerror(errno));
+           sfree(cmd);
+           return (Socket)ret;
+       }
+       cloexec(to_cmd_pipe[1]);
+       cloexec(from_cmd_pipe[0]);
+
+       pid = fork();
+
+       if (pid < 0) {
+           ret->error = dupprintf("fork: %s", strerror(errno));
+           sfree(cmd);
+           return (Socket)ret;
+       } else if (pid == 0) {
+           close(0);
+           close(1);
+           dup2(to_cmd_pipe[0], 0);
+           dup2(from_cmd_pipe[1], 1);
+           close(to_cmd_pipe[0]);
+           close(from_cmd_pipe[1]);
+           noncloexec(0);
+           noncloexec(1);
+           execl("/bin/sh", "sh", "-c", cmd, (void *)NULL);
+           _exit(255);
+       }
 
-    sfree(cmd);
+       sfree(cmd);
 
-    close(to_cmd_pipe[0]);
-    close(from_cmd_pipe[1]);
+       close(to_cmd_pipe[0]);
+       close(from_cmd_pipe[1]);
 
-    ret->to_cmd = to_cmd_pipe[1];
-    ret->from_cmd = from_cmd_pipe[0];
+       ret->to_cmd = to_cmd_pipe[1];
+       ret->from_cmd = from_cmd_pipe[0];
+    } else {
+       cmd = format_telnet_command(addr, port, conf);
+       ret->to_cmd = open("/dev/null", O_WRONLY);
+       if (ret->to_cmd == -1) {
+           ret->error = dupprintf("/dev/null: %s", strerror(errno));
+           sfree(cmd);
+           return (Socket)ret;
+       }
+       ret->from_cmd = open(cmd, O_RDONLY);
+       if (ret->from_cmd == -1) {
+           ret->error = dupprintf("%s: %s", cmd, strerror(errno));
+           sfree(cmd);
+           return (Socket)ret;
+       }
+       sfree(cmd);
+    }
 
     if (!localproxy_by_fromfd)
        localproxy_by_fromfd = newtree234(localproxy_fromfd_cmp);