From 1723ec92eb485ce06b4cbf49712d21975d873909 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 11 Oct 2016 21:49:54 +0000 Subject: upstream commit fix the KEX fuzzer - the previous method of obtaining the packet contents was broken. This now uses the new per-packet input hook, so it sees exact post-decrypt packets and doesn't have to pass packet integrity checks. ok markus@ Upstream-Regress-ID: 402fb6ffabd97de590e8e57b25788949dce8d2fd --- regress/misc/kexfuzz/kexfuzz.c | 162 ++++++++++++++++++++++++++--------------- 1 file changed, 103 insertions(+), 59 deletions(-) (limited to 'regress/misc/kexfuzz/kexfuzz.c') diff --git a/regress/misc/kexfuzz/kexfuzz.c b/regress/misc/kexfuzz/kexfuzz.c index 8535980b0..67058027f 100644 --- a/regress/misc/kexfuzz/kexfuzz.c +++ b/regress/misc/kexfuzz/kexfuzz.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexfuzz.c,v 1.2 2016/09/16 01:01:41 djm Exp $ */ +/* $OpenBSD: kexfuzz.c,v 1.3 2016/10/11 21:49:54 djm Exp $ */ /* * Fuzz harness for KEX code * @@ -27,6 +27,7 @@ #include "packet.h" #include "myproposal.h" #include "authfile.h" +#include "log.h" struct ssh *active_state = NULL; /* XXX - needed for linking */ @@ -35,61 +36,93 @@ static int do_debug = 0; enum direction { S2C, C2S }; +struct hook_ctx { + struct ssh *client, *server, *server2; + int *c2s, *s2c; + int trigger_direction, packet_index; + const char *dump_path; + struct sshbuf *replace_data; +}; + static int -do_send_and_receive(struct ssh *from, struct ssh *to, int mydirection, - int *packet_count, int trigger_direction, int packet_index, - const char *dump_path, struct sshbuf *replace_data) +packet_hook(struct ssh *ssh, struct sshbuf *packet, u_char *typep, void *_ctx) +{ + struct hook_ctx *ctx = (struct hook_ctx *)_ctx; + int mydirection = ssh == ctx->client ? S2C : C2S; + int *packet_count = mydirection == S2C ? ctx->s2c : ctx->c2s; + FILE *dumpfile; + int r; + + if (do_debug) { + printf("%s packet %d type %u:\n", + mydirection == S2C ? "s2c" : "c2s", + *packet_count, *typep); + sshbuf_dump(packet, stdout); + } + if (mydirection == ctx->trigger_direction && + ctx->packet_index == *packet_count) { + if (ctx->replace_data != NULL) { + sshbuf_reset(packet); + /* Type is first byte of packet */ + if ((r = sshbuf_get_u8(ctx->replace_data, + typep)) != 0 || + (r = sshbuf_putb(packet, ctx->replace_data)) != 0) + return r; + if (do_debug) { + printf("***** replaced packet type %u\n", + *typep); + sshbuf_dump(packet, stdout); + } + } else if (ctx->dump_path != NULL) { + if ((dumpfile = fopen(ctx->dump_path, "w+")) == NULL) + err(1, "fopen %s", ctx->dump_path); + /* Write { type, packet } */ + if (fwrite(typep, 1, 1, dumpfile) != 1) + err(1, "fwrite type %s", ctx->dump_path); + if (sshbuf_len(packet) != 0 && + fwrite(sshbuf_ptr(packet), sshbuf_len(packet), + 1, dumpfile) != 1) + err(1, "fwrite body %s", ctx->dump_path); + if (do_debug) { + printf("***** dumped packet type %u len %zu\n", + *typep, sshbuf_len(packet)); + } + fclose(dumpfile); + /* No point in continuing */ + exit(0); + } + } + (*packet_count)++; + return 0; +} + +static int +do_send_and_receive(struct ssh *from, struct ssh *to) { u_char type; - size_t len, olen; + size_t len; const u_char *buf; int r; - FILE *dumpfile; for (;;) { if ((r = ssh_packet_next(from, &type)) != 0) { fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r)); return r; } + if (type != 0) return 0; buf = ssh_output_ptr(from, &len); - olen = len; - if (do_debug) { - printf("%s packet %d type %u len %zu:\n", - mydirection == S2C ? "s2c" : "c2s", - *packet_count, type, len); - sshbuf_dump_data(buf, len, stdout); - } - if (mydirection == trigger_direction && - packet_index == *packet_count) { - if (replace_data != NULL) { - buf = sshbuf_ptr(replace_data); - len = sshbuf_len(replace_data); - if (do_debug) { - printf("***** replaced packet " - "len %zu\n", len); - sshbuf_dump_data(buf, len, stdout); - } - } else if (dump_path != NULL) { - if ((dumpfile = fopen(dump_path, "w+")) == NULL) - err(1, "fopen %s", dump_path); - if (len != 0 && - fwrite(buf, len, 1, dumpfile) != 1) - err(1, "fwrite %s", dump_path); - if (do_debug) - printf("***** dumped packet " - "len %zu\n", len); - fclose(dumpfile); - exit(0); - } - } - (*packet_count)++; if (len == 0) return 0; - if ((r = ssh_input_append(to, buf, len)) != 0 || - (r = ssh_output_consume(from, olen)) != 0) + if ((r = ssh_input_append(to, buf, len)) != 0) { + debug("ssh_input_append: %s", ssh_err(r)); + return r; + } + if ((r = ssh_output_consume(from, len)) != 0) { + debug("ssh_output_consume: %s", ssh_err(r)); return r; + } } } @@ -141,19 +174,19 @@ const char *in_test = NULL; static void -run_kex(struct ssh *client, struct ssh *server, int *s2c, int *c2s, - int direction, int packet_index, - const char *dump_path, struct sshbuf *replace_data) +run_kex(struct ssh *client, struct ssh *server) { int r = 0; while (!server->kex->done || !client->kex->done) { - if ((r = do_send_and_receive(server, client, S2C, s2c, - direction, packet_index, dump_path, replace_data))) + if ((r = do_send_and_receive(server, client)) != 0) { + debug("do_send_and_receive S2C: %s", ssh_err(r)); break; - if ((r = do_send_and_receive(client, server, C2S, c2s, - direction, packet_index, dump_path, replace_data))) + } + if ((r = do_send_and_receive(client, server)) != 0) { + debug("do_send_and_receive C2S: %s", ssh_err(r)); break; + } } if (do_debug) printf("done: %s\n", ssh_err(r)); @@ -173,6 +206,7 @@ do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c, struct kex_params kex_params; char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; char *keyname = NULL; + struct hook_ctx hook_ctx; TEST_START("sshkey_from_private"); ASSERT_INT_EQ(sshkey_from_private(prvkey, &pubkey), 0); @@ -187,30 +221,42 @@ do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c, kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0); ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0); + ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0); ASSERT_PTR_NE(client, NULL); ASSERT_PTR_NE(server, NULL); + ASSERT_PTR_NE(server2, NULL); TEST_DONE(); + hook_ctx.c2s = c2s; + hook_ctx.s2c = s2c; + hook_ctx.trigger_direction = direction; + hook_ctx.packet_index = packet_index; + hook_ctx.dump_path = dump_path; + hook_ctx.replace_data = replace_data; + hook_ctx.client = client; + hook_ctx.server = server; + hook_ctx.server2 = server2; + ssh_packet_set_input_hook(client, packet_hook, &hook_ctx); + ssh_packet_set_input_hook(server, packet_hook, &hook_ctx); + ssh_packet_set_input_hook(server2, packet_hook, &hook_ctx); + TEST_START("ssh_add_hostkey"); ASSERT_INT_EQ(ssh_add_hostkey(server, prvkey), 0); ASSERT_INT_EQ(ssh_add_hostkey(client, pubkey), 0); TEST_DONE(); TEST_START("kex"); - run_kex(client, server, s2c, c2s, direction, packet_index, - dump_path, replace_data); + run_kex(client, server); TEST_DONE(); TEST_START("rekeying client"); ASSERT_INT_EQ(kex_send_kexinit(client), 0); - run_kex(client, server, s2c, c2s, direction, packet_index, - dump_path, replace_data); + run_kex(client, server); TEST_DONE(); TEST_START("rekeying server"); ASSERT_INT_EQ(kex_send_kexinit(server), 0); - run_kex(client, server, s2c, c2s, direction, packet_index, - dump_path, replace_data); + run_kex(client, server); TEST_DONE(); TEST_START("ssh_packet_get_state"); @@ -221,9 +267,6 @@ do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c, TEST_DONE(); TEST_START("ssh_packet_set_state"); - server2 = NULL; - ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0); - ASSERT_PTR_NE(server2, NULL); ASSERT_INT_EQ(ssh_add_hostkey(server2, prvkey), 0); kex_free(server2->kex); /* XXX or should ssh_packet_set_state()? */ ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0); @@ -251,11 +294,9 @@ do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c, TEST_START("rekeying server2"); ASSERT_INT_EQ(kex_send_kexinit(server2), 0); - run_kex(client, server2, s2c, c2s, direction, packet_index, - dump_path, replace_data); + run_kex(client, server2); ASSERT_INT_EQ(kex_send_kexinit(client), 0); - run_kex(client, server2, s2c, c2s, direction, packet_index, - dump_path, replace_data); + run_kex(client, server2); TEST_DONE(); TEST_START("cleanup"); @@ -357,6 +398,9 @@ main(int argc, char **argv) argc -= optind; argv += optind; + log_init(argv[0], do_debug ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO, + SYSLOG_FACILITY_USER, 1); + /* Must select a single mode */ if ((count_flag + dump_flag + replace_flag) != 1) badusage("Must select one mode: -c, -d or -r"); -- cgit v1.2.3