# HG changeset patch # User Matt Johnston # Date 1495119578 -28800 # Node ID 8747c2b1915265a1ddc9f55f1c4c4308f84e9532 # Parent ab35a9ccc2eb918172dee10241ad26d8f98ab298# Parent c13aa2cd8d51e3a9f089c1eebb04c21a5efa3acd merge 2017.75 diff -r c13aa2cd8d51 -r 8747c2b19152 .hgsigs --- 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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 diff -r c13aa2cd8d51 -r 8747c2b19152 .hgtags --- 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 diff -r c13aa2cd8d51 -r 8747c2b19152 CHANGES --- 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. diff -r c13aa2cd8d51 -r 8747c2b19152 buffer.c --- 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 */ diff -r c13aa2cd8d51 -r 8747c2b19152 dbutil.c --- 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 +} diff -r c13aa2cd8d51 -r 8747c2b19152 dbutil.h --- 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_ */ diff -r c13aa2cd8d51 -r 8747c2b19152 debian/changelog --- 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 Thu, 18 May 2017 22:51:57 +0800 + dropbear (2016.74-0.1) unstable; urgency=low * New upstream release. diff -r c13aa2cd8d51 -r 8747c2b19152 dropbearkey.c --- 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"); } diff -r c13aa2cd8d51 -r 8747c2b19152 gensignkey.c --- 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; } diff -r c13aa2cd8d51 -r 8747c2b19152 gensignkey.h --- 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 diff -r c13aa2cd8d51 -r 8747c2b19152 svr-authpubkey.c --- 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; } diff -r c13aa2cd8d51 -r 8747c2b19152 svr-authpubkeyoptions.c --- 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: diff -r c13aa2cd8d51 -r 8747c2b19152 svr-kex.c --- 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); diff -r c13aa2cd8d51 -r 8747c2b19152 svr-tcpfwd.c --- 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); diff -r c13aa2cd8d51 -r 8747c2b19152 sysoptions.h --- 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