From 8350d0afd8f5a93c39c2569bd78b8f5c92f85348 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <j@w1.fi>
Date: Sat, 30 Jun 2012 16:16:32 +0300
Subject: [PATCH] EAP-pwd: Avoid double-frees on some error paths

At least some error paths (e.g., hitting the limit on hunt-and-peck
iterations) could have resulted in double-freeing of some memory
allocations. Avoid this by setting the pointers to NULL after they have
been freed instead of trying to free the data structure in a location
where some external references cannot be cleared. [Bug 453]

Signed-hostap: Jouni Malinen <j@w1.fi>
---
 src/eap_common/eap_pwd_common.c | 6 ++++--
 src/eap_peer/eap_pwd.c          | 6 +++++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index f85564aeb..c32f9fb93 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -252,11 +252,13 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
 	if (0) {
  fail:
 		EC_GROUP_free(grp->group);
+		grp->group = NULL;
 		EC_POINT_free(grp->pwe);
+		grp->pwe = NULL;
 		BN_free(grp->order);
+		grp->order = NULL;
 		BN_free(grp->prime);
-		os_free(grp);
-		grp = NULL;
+		grp->prime = NULL;
 		ret = 1;
 	}
 	/* cleanliness and order.... */
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 37e92348c..a5caf543d 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -725,6 +725,7 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
 		 */
 		if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
 			wpabuf_free(data->outbuf);
+			data->outbuf = NULL;
 			data->out_frag_pos = 0;
 		}
 		wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes",
@@ -856,8 +857,11 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
 	/*
 	 * if we're not fragmenting then there's no need to carry this around
 	 */
-	if (data->out_frag_pos == 0)
+	if (data->out_frag_pos == 0) {
 		wpabuf_free(data->outbuf);
+		data->outbuf = NULL;
+		data->out_frag_pos = 0;
+	}
 
 	return resp;
 }