From 7a0223435314084f51e9521781b0b64464967c6d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 16 Sep 2021 09:27:25 +0100 Subject: [PATCH] userauth2: add a missing free_prompts(). If a userauth layer is destroyed while userpass input is still ongoing, ssh2_userauth_free forgot to free the active prompts_t, leaking memory. But adding the missing free_prompts call to ssh2_userauth_free results in a double-free, because another thing I forgot was to null out that pointer field everywhere _else_ it's freed. Fixed that too. --- ssh/userauth2-client.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ssh/userauth2-client.c b/ssh/userauth2-client.c index d4f546b5..f1e2f319 100644 --- a/ssh/userauth2-client.c +++ b/ssh/userauth2-client.c @@ -193,6 +193,8 @@ static void ssh2_userauth_free(PacketProtocolLayer *ppl) sfree(s->locally_allocated_username); sfree(s->hostname); sfree(s->fullhostname); + if (s->cur_prompt) + free_prompts(s->cur_prompt); sfree(s->publickey_comment); sfree(s->publickey_algorithm); if (s->publickey_blob) @@ -455,6 +457,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * Terminate. */ free_prompts(s->cur_prompt); + s->cur_prompt = NULL; ssh_user_close(s->ppl.ssh, "No username provided"); return; } @@ -462,6 +465,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) s->username = s->locally_allocated_username = prompt_get_result(s->cur_prompt->prompts[0]); free_prompts(s->cur_prompt); + s->cur_prompt = NULL; } else { if (seat_verbose(s->ppl.seat) || seat_interactive(s->ppl.seat)) ppl_printf("Using username \"%s\".\r\n", s->username); @@ -918,6 +922,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) if (!s->userpass_ret) { /* Failed to get a passphrase. Terminate. */ free_prompts(s->cur_prompt); + s->cur_prompt = NULL; ssh_bpp_queue_disconnect( s->ppl.bpp, "Unable to authenticate", SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); @@ -928,6 +933,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) passphrase = prompt_get_result(s->cur_prompt->prompts[0]); free_prompts(s->cur_prompt); + s->cur_prompt = NULL; } else { passphrase = NULL; /* no passphrase needed */ } @@ -1397,6 +1403,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * Failed to get responses. Terminate. */ free_prompts(s->cur_prompt); + s->cur_prompt = NULL; ssh_bpp_queue_disconnect( s->ppl.bpp, "Unable to authenticate", SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); @@ -1424,6 +1431,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * when we return to the top of this while loop. */ free_prompts(s->cur_prompt); + s->cur_prompt = NULL; /* * Get the next packet in case it's another @@ -1476,6 +1484,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) * Failed to get responses. Terminate. */ free_prompts(s->cur_prompt); + s->cur_prompt = NULL; ssh_bpp_queue_disconnect( s->ppl.bpp, "Unable to authenticate", SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); @@ -1489,6 +1498,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) */ s->password = prompt_get_result(s->cur_prompt->prompts[0]); free_prompts(s->cur_prompt); + s->cur_prompt = NULL; /* * Send the password packet. @@ -1587,6 +1597,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) */ /* burn the evidence */ free_prompts(s->cur_prompt); + s->cur_prompt = NULL; smemclr(s->password, strlen(s->password)); sfree(s->password); ssh_bpp_queue_disconnect( @@ -1638,6 +1649,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) put_stringz(s->pktout, prompt_get_result_ref( s->cur_prompt->prompts[1])); free_prompts(s->cur_prompt); + s->cur_prompt = NULL; s->pktout->minlen = 256; pq_push(s->ppl.out_pq, s->pktout); ppl_logevent("Sent new password");