changeset 1342:8747c2b19152

merge 2017.75
author Matt Johnston <matt@ucc.asn.au>
date Thu, 18 May 2017 22:59:38 +0800
parents ab35a9ccc2eb (diff) c13aa2cd8d51 (current diff)
children bbc0a0ee3843
files .hgsigs .hgtags dbutil.c dbutil.h dropbearkey.c gensignkey.c svr-authpubkey.c svr-authpubkeyoptions.c svr-kex.c svr-tcpfwd.c sysoptions.h
diffstat 15 files changed, 114 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsigs	Fri Nov 18 23:56:22 2016 +0800
+++ b/.hgsigs	Thu May 18 22:59:38 2017 +0800
@@ -22,3 +22,4 @@
 fd1981f41c626a969f07b4823848deaefef3c8aa 0 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
+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
--- a/.hgtags	Fri Nov 18 23:56:22 2016 +0800
+++ b/.hgtags	Thu May 18 22:59:38 2017 +0800
@@ -54,3 +54,4 @@
 78b12b6549be08b0bea3da329b2578060a76ca31 DROPBEAR_2016.72
 309e1c4a87682b6ca7d80b8555a1db416c3cb7ac DROPBEAR_2016.73
 0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74
+c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
--- a/CHANGES	Fri Nov 18 23:56:22 2016 +0800
+++ b/CHANGES	Thu May 18 22:59:38 2017 +0800
@@ -1,3 +1,28 @@
+2017.75 - 18 May 2017
+
+- Security: Fix double-free in server TCP listener cleanup
+  A double-free in the server could be triggered by an authenticated user if
+  dropbear is running with -a (Allow connections to forwarded ports from any host)
+  This could potentially allow arbitrary code execution as root by an authenticated user.
+  Affects versions 2013.56 to 2016.74. Thanks to Mark Shepard for reporting the crash.
+
+- Security: Fix information disclosure with ~/.ssh/authorized_keys symlink.
+  Dropbear parsed authorized_keys as root, even if it were a symlink. The fix
+  is to switch to user permissions when opening authorized_keys
+
+  A user could symlink their ~/.ssh/authorized_keys to a root-owned file they
+  couldn't normally read. If they managed to get that file to contain valid
+  authorized_keys with command= options it might be possible to read other
+  contents of that file.
+  This information disclosure is to an already authenticated user.
+  Thanks to Jann Horn of Google Project Zero for reporting this.
+
+- Generate hostkeys with dropbearkey atomically and flush to disk with fsync
+  Thanks to Andrei Gherzan for a patch
+
+- Fix out of tree builds with bundled libtom
+  Thanks to Henrik Nordström and Peter Krefting for patches.
+
 2016.74 - 21 July 2016
 
 - Security: Message printout was vulnerable to format string injection.
--- a/buffer.c	Fri Nov 18 23:56:22 2016 +0800
+++ b/buffer.c	Thu May 18 22:59:38 2017 +0800
@@ -109,6 +109,7 @@
 		dropbear_exit("Bad buf_setlen");
 	}
 	buf->len = len;
+	buf->pos = MIN(buf->pos, buf->len);
 }
 
 /* Increment the length of the buffer */
--- a/dbutil.c	Fri Nov 18 23:56:22 2016 +0800
+++ b/dbutil.c	Thu May 18 22:59:38 2017 +0800
@@ -681,4 +681,21 @@
 	return time(NULL);
 }
 
+void fsync_parent_dir(const char* fn) {
+#ifdef HAVE_LIBGEN_H
+	char *fn_dir = m_strdup(fn);
+	char *dir = dirname(fn_dir);
+	int dirfd = open(dir, O_RDONLY);
 
+	if (dirfd != -1) {
+		if (fsync(dirfd) != 0) {
+			TRACE(("fsync of directory %s failed: %s", dir, strerror(errno)))
+		}
+		m_close(dirfd);
+	} else {
+		TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
+	}
+
+	free(fn_dir);
+#endif
+}
--- a/dbutil.h	Fri Nov 18 23:56:22 2016 +0800
+++ b/dbutil.h	Thu May 18 22:59:38 2017 +0800
@@ -89,4 +89,6 @@
 
 char * expand_homedir_path(const char *inpath);
 
+void fsync_parent_dir(const char* fn);
+
 #endif /* DROPBEAR_DBUTIL_H_ */
--- a/debian/changelog	Fri Nov 18 23:56:22 2016 +0800
+++ b/debian/changelog	Thu May 18 22:59:38 2017 +0800
@@ -1,3 +1,9 @@
+dropbear (2017.75-0.1) unstable; urgency=low
+
+  * New upstream release.
+
+ -- Matt Johnston <[email protected]>  Thu, 18 May 2017 22:51:57 +0800
+
 dropbear (2016.74-0.1) unstable; urgency=low
 
   * New upstream release.
--- a/dropbearkey.c	Fri Nov 18 23:56:22 2016 +0800
+++ b/dropbearkey.c	Thu May 18 22:59:38 2017 +0800
@@ -241,7 +241,7 @@
 	}
 
 	fprintf(stderr, "Generating key, this may take a while...\n");
-	if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
+	if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)
 	{
 		dropbear_exit("Failed to generate key.\n");
 	}
--- a/gensignkey.c	Fri Nov 18 23:56:22 2016 +0800
+++ b/gensignkey.c	Thu May 18 22:59:38 2017 +0800
@@ -76,10 +76,12 @@
 	}
 }
 
-int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
+/* if skip_exist is set it will silently return if the key file exists */
+int signkey_generate(enum signkey_type keytype, int bits, const char* filename, int skip_exist)
 {
 	sign_key * key = NULL;
 	buffer *buf = NULL;
+	char *fn_temp = NULL;
 	int ret = DROPBEAR_FAILURE;
 	if (bits == 0)
 	{
@@ -126,10 +128,37 @@
 	sign_key_free(key);
 	key = NULL;
 	buf_setpos(buf, 0);
-	ret = buf_writefile(buf, filename);
+
+	fn_temp = m_malloc(strlen(filename) + 30);
+	snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
+	ret = buf_writefile(buf, fn_temp);
+
+	if (ret == DROPBEAR_FAILURE) {
+		goto out;
+	}
 
-	buf_burn(buf);
-	buf_free(buf);
-	buf = NULL;
+	if (link(fn_temp, filename) < 0) {
+		/* If generating keys on connection (skipexist) it's OK to get EEXIST 
+		- we probably just lost a race with another connection to generate the key */
+		if (!(skip_exist && errno == EEXIST)) {
+			dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
+				strerror(errno));
+			/* XXX fallback to non-atomic copy for some filesystems? */
+			ret = DROPBEAR_FAILURE;
+			goto out;
+		}
+	}
+
+out:
+	if (buf) {
+		buf_burn(buf);
+		buf_free(buf);
+	}
+	
+	if (fn_temp) {
+		unlink(fn_temp);
+		m_free(fn_temp);
+	}
+
 	return ret;
 }
--- a/gensignkey.h	Fri Nov 18 23:56:22 2016 +0800
+++ b/gensignkey.h	Thu May 18 22:59:38 2017 +0800
@@ -3,6 +3,6 @@
 
 #include "signkey.h"
 
-int signkey_generate(enum signkey_type type, int bits, const char* filename);
+int signkey_generate(enum signkey_type type, int bits, const char* filename, int skip_exist);
 
 #endif
--- a/svr-authpubkey.c	Fri Nov 18 23:56:22 2016 +0800
+++ b/svr-authpubkey.c	Thu May 18 22:59:38 2017 +0800
@@ -201,6 +201,8 @@
 	unsigned int len, pos;
 	buffer * options_buf = NULL;
 	int line_num;
+	uid_t origuid;
+	gid_t origgid;
 
 	TRACE(("enter checkpubkey"))
 
@@ -227,8 +229,21 @@
 	snprintf(filename, len + 22, "%s/.ssh/authorized_keys", 
 				ses.authstate.pw_dir);
 
-	/* open the file */
+	/* open the file as the authenticating user. */
+	origuid = getuid();
+	origgid = getgid();
+	if ((setegid(ses.authstate.pw_gid)) < 0 ||
+		(seteuid(ses.authstate.pw_uid)) < 0) {
+		dropbear_exit("Failed to set euid");
+	}
+
 	authfile = fopen(filename, "r");
+
+	if ((seteuid(origuid)) < 0 ||
+		(setegid(origgid)) < 0) {
+		dropbear_exit("Failed to revert euid");
+	}
+
 	if (authfile == NULL) {
 		goto out;
 	}
--- a/svr-authpubkeyoptions.c	Fri Nov 18 23:56:22 2016 +0800
+++ b/svr-authpubkeyoptions.c	Thu May 18 22:59:38 2017 +0800
@@ -95,6 +95,7 @@
 		if (chansess->cmd) {
 			/* original_command takes ownership */
 			chansess->original_command = chansess->cmd;
+			chansess->cmd = NULL;
 		} else {
 			chansess->original_command = m_strdup("");
 		}
@@ -108,6 +109,9 @@
 /* Free potential public key options */
 void svr_pubkey_options_cleanup() {
 	if (ses.authstate.pubkey_options) {
+		if (ses.authstate.pubkey_options->forced_command) {
+			m_free(ses.authstate.pubkey_options->forced_command);
+		}
 		m_free(ses.authstate.pubkey_options);
 		ses.authstate.pubkey_options = NULL;
 	}
@@ -200,8 +204,7 @@
 
 bad_option:
 	ret = DROPBEAR_FAILURE;
-	m_free(ses.authstate.pubkey_options);
-	ses.authstate.pubkey_options = NULL;
+	svr_pubkey_options_cleanup();
 	dropbear_log(LOG_WARNING, "Bad public key options at %s:%d", filename, line_num);
 
 end:
--- a/svr-kex.c	Fri Nov 18 23:56:22 2016 +0800
+++ b/svr-kex.c	Thu May 18 22:59:38 2017 +0800
@@ -93,29 +93,9 @@
 
 #if DROPBEAR_DELAY_HOSTKEY
 
-static void fsync_parent_dir(const char* fn) {
-#ifdef HAVE_LIBGEN_H
-	char *fn_dir = m_strdup(fn);
-	char *dir = dirname(fn_dir);
-	int dirfd = open(dir, O_RDONLY);
-
-	if (dirfd != -1) {
-		if (fsync(dirfd) != 0) {
-			TRACE(("fsync of directory %s failed: %s", dir, strerror(errno)))
-		}
-		m_close(dirfd);
-	} else {
-		TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
-	}
-
-	free(fn_dir);
-#endif
-}
-
 static void svr_ensure_hostkey() {
 
 	const char* fn = NULL;
-	char *fn_temp = NULL;
 	enum signkey_type type = ses.newkeys->algo_hostkey;
 	void **hostkey = signkey_key_ptr(svr_opts.hostkey, type);
 	int ret = DROPBEAR_FAILURE;
@@ -151,28 +131,10 @@
 		return;
 	}
 
-	fn_temp = m_malloc(strlen(fn) + 20);
-	snprintf(fn_temp, strlen(fn)+20, "%s.tmp%d", fn, getpid());
-
-	if (signkey_generate(type, 0, fn_temp) == DROPBEAR_FAILURE) {
+	if (signkey_generate(type, 0, fn, 1) == DROPBEAR_FAILURE) {
 		goto out;
 	}
-
-	if (link(fn_temp, fn) < 0) {
-		/* It's OK to get EEXIST - we probably just lost a race
-		with another connection to generate the key */
-		if (errno != EEXIST) {
-			dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", fn,
-				strerror(errno));
-			/* XXX fallback to non-atomic copy for some filesystems? */
-			goto out;
-		}
-	}
-
-	/* ensure directory update is flushed to disk, otherwise we can end up
-	with zero-byte hostkey files if the power goes off */
-	fsync_parent_dir(fn);
-
+	
 	ret = readhostkey(fn, svr_opts.hostkey, &type);
 
 	if (ret == DROPBEAR_SUCCESS) {
@@ -190,11 +152,6 @@
 	}
 
 out:
-	if (fn_temp) {
-		unlink(fn_temp);
-		m_free(fn_temp);
-	}
-
 	if (ret == DROPBEAR_FAILURE)
 	{
 		dropbear_exit("Couldn't read or generate hostkey %s", fn);
--- a/svr-tcpfwd.c	Fri Nov 18 23:56:22 2016 +0800
+++ b/svr-tcpfwd.c	Thu May 18 22:59:38 2017 +0800
@@ -199,7 +199,7 @@
 	}
 	else
 	{
-		tcpinfo->listenaddr = request_addr;
+		tcpinfo->listenaddr = m_strdup(request_addr);
 	}
 
 	ret = listen_tcpfwd(tcpinfo);
--- a/sysoptions.h	Fri Nov 18 23:56:22 2016 +0800
+++ b/sysoptions.h	Thu May 18 22:59:38 2017 +0800
@@ -4,7 +4,7 @@
  *******************************************************************/
 
 #ifndef DROPBEAR_VERSION
-#define DROPBEAR_VERSION "2016.74"
+#define DROPBEAR_VERSION "2017.75"
 #endif
 
 #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION