Vulnerability: The read_packet function in knc (Kerberised NetCat) before 1.11-1 is vulnerable to denial of service (memory exhaustion) that can be exploited remotely without authentication, possibly affecting another services running on the targeted host.
Vulnerability ID: CVE-2017-9732
CWE: CWE-400
Severity score: 2.9
Project: https://github.com/elric1/knc
Published: 2018-12-20
File: bin/gssstdio.c
Commit message: knc: fix a couple of memory leaks.

One of these can be remotely triggered during the authentication
phase which leads to a remote DoS possibility.

Pointed out by: Imre Rad <radimre83@gmail.com>
Commit author: Roland C. Dowdeswell

Vulnerable version (before fix):
 gstd_accept(int fd, char **display_creds, char **export_name, char **mech) 	    &in, GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_oid, &out, NULL, 	    NULL, NULL);  	if (out.length && write_packet(fd, &out)) { 		gss_release_buffer(&min, &out); 		return NULL; 	}  	GSTD_GSS_ERROR(maj, min, NULL, "gss_accept_sec_context");  read_packet(int fd, gss_buffer_t buf, int timeout, int first) 				return -2;  			LOG(LOG_ERR, ("%s", strerror(errno))); 			return -1; 		}  		if (ret == 0) {		/* EOF */ read_packet(int fd, gss_buffer_t buf, int timeout, int first) 			 * a protocol error. 			 */ 			LOG(LOG_INFO, ("EOF reading packet len")); 			return -1; 		}  		len_buf_pos += ret; read_packet(int fd, gss_buffer_t buf, int timeout, int first) 	 */ 	if (len > GSTD_MAXPACKETCONTENTS + 512) { 		LOG(LOG_ERR, ("ridiculous length, %ld", len)); 		return -1; 	}  	if (!tmpbuf) { 		if ((tmpbuf = malloc(len)) == NULL) { 			LOG(LOG_CRIT, ("malloc failure, %ld bytes", len)); 			return -1; 		} 	}  	ret = timed_read(fd, tmpbuf + tmpbuf_pos, len - tmpbuf_pos, timeout); 	if (ret == -1) { 		if (errno == EINTR || errno == EAGAIN) 			return -2;  		LOG(LOG_ERR, ("%s", strerror(errno))); 		return -1; 	}  	if (ret == 0) { 		LOG(LOG_ERR, ("EOF while reading packet (len=%d)", len)); 		return -1; 	}  	tmpbuf_pos += ret; read_packet(int fd, gss_buffer_t buf, int timeout, int first) 	}  	return -2; }  static int

Fixed version (after fix):
 gstd_accept(int fd, char **display_creds, char **export_name, char **mech) 	    &in, GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_oid, &out, NULL, 	    NULL, NULL);  	gss_release_buffer(&min, &in);  	if (out.length && write_packet(fd, &out)) { 		gss_release_buffer(&min, &out); 		return NULL; 	} 	gss_release_buffer(&min, &out);  	GSTD_GSS_ERROR(maj, min, NULL, "gss_accept_sec_context");  read_packet(int fd, gss_buffer_t buf, int timeout, int first) 				return -2;  			LOG(LOG_ERR, ("%s", strerror(errno))); 			goto bail; 		}  		if (ret == 0) {		/* EOF */ read_packet(int fd, gss_buffer_t buf, int timeout, int first) 			 * a protocol error. 			 */ 			LOG(LOG_INFO, ("EOF reading packet len")); 			goto bail; 		}  		len_buf_pos += ret; read_packet(int fd, gss_buffer_t buf, int timeout, int first) 	 */ 	if (len > GSTD_MAXPACKETCONTENTS + 512) { 		LOG(LOG_ERR, ("ridiculous length, %ld", len)); 		goto bail; 	}  	if (!tmpbuf) { 		if ((tmpbuf = malloc(len)) == NULL) { 			LOG(LOG_CRIT, ("malloc failure, %ld bytes", len)); 			goto bail; 		} 	}  	ret = timed_read(fd, tmpbuf + tmpbuf_pos, len - tmpbuf_pos, timeout); 	if (ret == -1) {  		if (errno == EINTR || errno == EAGAIN) 			return -2;  		LOG(LOG_ERR, ("%s", strerror(errno))); 		goto bail; 	}  	if (ret == 0) { 		LOG(LOG_ERR, ("EOF while reading packet (len=%d)", len)); 		goto bail; 	}  	tmpbuf_pos += ret; read_packet(int fd, gss_buffer_t buf, int timeout, int first) 	}  	return -2;  bail: 	free(tmpbuf); 	tmpbuf = NULL;  	return -1; }  static int

Patch:
patch: @@ -220,10 +220,13 @@ gstd_accept(int fd, char **display_creds, char **export_name, char **mech)
 	    &in, GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_oid, &out, NULL,
 	    NULL, NULL);
 
+	gss_release_buffer(&min, &in);
+
 	if (out.length && write_packet(fd, &out)) {
 		gss_release_buffer(&min, &out);
 		return NULL;
 	}
+	gss_release_buffer(&min, &out);
 
 	GSTD_GSS_ERROR(maj, min, NULL, "gss_accept_sec_context");
 
@@ -473,7 +476,7 @@ read_packet(int fd, gss_buffer_t buf, int timeout, int first)
 				return -2;
 
 			LOG(LOG_ERR, ("%s", strerror(errno)));
-			return -1;
+			goto bail;
 		}
 
 		if (ret == 0) {		/* EOF */
@@ -486,7 +489,7 @@ read_packet(int fd, gss_buffer_t buf, int timeout, int first)
 			 * a protocol error.
 			 */
 			LOG(LOG_INFO, ("EOF reading packet len"));
-			return -1;
+			goto bail;
 		}
 
 		len_buf_pos += ret;
@@ -506,28 +509,29 @@ read_packet(int fd, gss_buffer_t buf, int timeout, int first)
 	 */
 	if (len > GSTD_MAXPACKETCONTENTS + 512) {
 		LOG(LOG_ERR, ("ridiculous length, %ld", len));
-		return -1;
+		goto bail;
 	}
 
 	if (!tmpbuf) {
 		if ((tmpbuf = malloc(len)) == NULL) {
 			LOG(LOG_CRIT, ("malloc failure, %ld bytes", len));
-			return -1;
+			goto bail;
 		}
 	}
 
 	ret = timed_read(fd, tmpbuf + tmpbuf_pos, len - tmpbuf_pos, timeout);
 	if (ret == -1) {
+
 		if (errno == EINTR || errno == EAGAIN)
 			return -2;
 
 		LOG(LOG_ERR, ("%s", strerror(errno)));
-		return -1;
+		goto bail;
 	}
 
 	if (ret == 0) {
 		LOG(LOG_ERR, ("EOF while reading packet (len=%d)", len));
-		return -1;
+		goto bail;
 	}
 
 	tmpbuf_pos += ret;
@@ -543,6 +547,12 @@ read_packet(int fd, gss_buffer_t buf, int timeout, int first)
 	}
 
 	return -2;
+
+bail:
+	free(tmpbuf);
+	tmpbuf = NULL;
+
+	return -1;
 }
 
 static int
path: bin/gssstdio.c