Mercurial > dropbear
changeset 1388:271c57aa3da5
Merge pull request #31 from bengardner/PATH_DEVNULL
Use DROPBEAR_PATH_DEVNULL instead of undefined _PATH_DEVNULL
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 02 Jun 2017 22:57:09 +0800 |
parents | 1a3c4ec0f840 (diff) e7f11ed5fe28 (current diff) |
children | b413787adcdb |
files | compat.c |
diffstat | 30 files changed, 325 insertions(+), 191 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgsigs Tue May 24 17:34:10 2016 -0500 +++ b/.hgsigs Fri Jun 02 22:57:09 2017 +0800 @@ -21,3 +21,5 @@ 926e7275cef4f4f2a4251597ee4814748394824c 0 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
--- a/.hgtags Tue May 24 17:34:10 2016 -0500 +++ b/.hgtags Fri Jun 02 22:57:09 2017 +0800 @@ -53,3 +53,5 @@ 9a944a243f08be6b22d32f166a0690eb4872462b DROPBEAR_2015.71 78b12b6549be08b0bea3da329b2578060a76ca31 DROPBEAR_2016.72 309e1c4a87682b6ca7d80b8555a1db416c3cb7ac DROPBEAR_2016.73 +0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74 +c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
--- a/CHANGES Tue May 24 17:34:10 2016 -0500 +++ b/CHANGES Fri Jun 02 22:57:09 2017 +0800 @@ -1,3 +1,70 @@ +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. + CVE-2017-9078 https://secure.ucc.asn.au/hg/dropbear/rev/c8114a48837c + +- 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. + CVE-2017-9079 https://secure.ucc.asn.au/hg/dropbear/rev/0d889b068123 + +- 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. + + If specific usernames including "%" symbols can be created on a system + (validated by getpwnam()) then an attacker could run arbitrary code as root + when connecting to Dropbear server. + + A dbclient user who can control username or host arguments could potentially + run arbitrary code as the dbclient user. This could be a problem if scripts + or webpages pass untrusted input to the dbclient program. + CVE-2016-7406 + https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb + +- Security: dropbearconvert import of OpenSSH keys could run arbitrary code as + the local dropbearconvert user when parsing malicious key files + CVE-2016-7407 + https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e + +- Security: dbclient could run arbitrary code as the local dbclient user if + particular -m or -c arguments are provided. This could be an issue where + dbclient is used in scripts. + CVE-2016-7408 + https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6 + +- Security: dbclient or dropbear server could expose process memory to the + running user if compiled with DEBUG_TRACE and running with -v + CVE-2016-7409 + https://secure.ucc.asn.au/hg/dropbear/rev/6a14b1f6dc04 + + The security issues were reported by an anonymous researcher working with + Beyond Security's SecuriTeam Secure Disclosure www.beyondsecurity.com/ssd.html + +- Fix port forwarding failure when connecting to domains that have both + IPv4 and IPv6 addresses. The bug was introduced in 2015.68 + +- Fix 100% CPU use while waiting for rekey to complete. Thanks to Zhang Hui P + for the patch + + 2016.73 - 18 March 2016 - Support syslog in dbclient, option -o usesyslog=yes. Patch from Konstantin Tokarev @@ -32,6 +99,7 @@ - Validate X11 forwarding input. Could allow bypass of authorized_keys command= restrictions, found by github.com/tintinweb. Thanks for Damien Miller for a patch. CVE-2016-3116 + https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff 2015.71 - 3 December 2015 @@ -310,9 +378,11 @@ - Limit the size of decompressed payloads, avoids memory exhaustion denial of service Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421 + https://secure.ucc.asn.au/hg/dropbear/rev/0bf76f54de6f - Avoid disclosing existence of valid users through inconsistent delays Thanks to Logan Lamb for reporting. CVE-2013-4434 + https://secure.ucc.asn.au/hg/dropbear/rev/d7784616409a - Update config.guess and config.sub for newer architectures @@ -415,6 +485,7 @@ This bug affects releases 0.52 onwards. Ref CVE-2012-0920. Thanks to Danny Fullerton of Mantor Organization for reporting the bug. + https://secure.ucc.asn.au/hg/dropbear/rev/818108bf7749 - Compile fix, only apply IPV6 socket options if they are available in headers Thanks to Gustavo Zacarias for the patch
--- a/atomicio.c Tue May 24 17:34:10 2016 -0500 +++ b/atomicio.c Fri Jun 02 22:57:09 2017 +0800 @@ -1,6 +1,8 @@ +/* $OpenBSD: atomicio.c,v 1.17 2006/04/01 05:51:34 djm Exp $ */ /* - * Copied from OpenSSH 3.6.1p2. + * Copied from OpenSSH/OpenBSD. * + * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. * All rights reserved. * @@ -25,39 +27,32 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp "); */ +#include "includes.h" #include "atomicio.h" /* - * ensure all of data on socket comes through. f==read || f==write + * ensure all of data on socket comes through. f==read || f==vwrite */ -ssize_t -atomicio(f, fd, _s, n) - ssize_t (*f) (); - int fd; - void *_s; - size_t n; +size_t +atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) { char *s = _s; + size_t pos = 0; ssize_t res; - size_t pos = 0; while (n > pos) { res = (f) (fd, s + pos, n - pos); switch (res) { case -1: -#ifdef EWOULDBLOCK - if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) -#else if (errno == EINTR || errno == EAGAIN) -#endif continue; - /* FALLTHROUGH */ + return 0; case 0: - return (res); + errno = EPIPE; + return pos; default: - pos += res; + pos += (size_t)res; } } return (pos);
--- a/atomicio.h Tue May 24 17:34:10 2016 -0500 +++ b/atomicio.h Fri Jun 02 22:57:09 2017 +0800 @@ -1,8 +1,7 @@ +/* $OpenBSD: atomicio.h,v 1.7 2006/03/25 22:22:42 djm Exp $ */ /* - * Copied from OpenSSH 3.6.1p2, required for loginrec.c - * - * $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $ + * Copied from OpenSSH/OpenBSD, required for loginrec.c * * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. * All rights reserved. @@ -28,9 +27,9 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "includes.h" +/* + * Ensure all of data on socket comes through. f==read || f==vwrite + */ +size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); -/* - * Ensure all of data on socket comes through. f==read || f==write - */ -ssize_t atomicio(ssize_t (*)(), int, void *, size_t); +#define vwrite (ssize_t (*)(int, void *, size_t))write
--- a/buffer.c Tue May 24 17:34:10 2016 -0500 +++ b/buffer.c Fri Jun 02 22:57:09 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 */ @@ -141,9 +142,10 @@ /* increment the position by incr, negative values are allowed, to * decrement the pos*/ void buf_incrpos(buffer* buf, int incr) { - if (incr > BUF_MAX_INCR || - (unsigned int)((int)buf->pos + incr) > buf->len - || ((int)buf->pos + incr) < 0) { + if (incr > BUF_MAX_INCR + || incr < -BUF_MAX_INCR + || (unsigned int)((int)buf->pos + incr) > buf->len + || ((int)buf->pos + incr) < 0) { dropbear_exit("Bad buf_incrpos"); } buf->pos += incr; @@ -184,7 +186,7 @@ * the next len bytes from that position can be used */ unsigned char* buf_getptr(buffer* buf, unsigned int len) { - if (buf->pos + len > buf->len) { + if (len > BUF_MAX_INCR || buf->pos + len > buf->len) { dropbear_exit("Bad buf_getptr"); } return &buf->data[buf->pos]; @@ -194,7 +196,7 @@ * This allows writing past the used length, but not past the size */ unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) { - if (buf->pos + len > buf->size) { + if (len > BUF_MAX_INCR || buf->pos + len > buf->size) { dropbear_exit("Bad buf_getwriteptr"); } return &buf->data[buf->pos];
--- a/cli-agentfwd.c Tue May 24 17:34:10 2016 -0500 +++ b/cli-agentfwd.c Fri Jun 02 22:57:09 2017 +0800 @@ -130,7 +130,7 @@ } buf_setpos(payload, 0); - ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len); + ret = atomicio(vwrite, fd, buf_getptr(payload, payload->len), payload->len); if ((size_t)ret != payload->len) { TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno))) goto out;
--- a/cli-main.c Tue May 24 17:34:10 2016 -0500 +++ b/cli-main.c Fri Jun 02 22:57:09 2017 +0800 @@ -98,29 +98,30 @@ #endif /* DBMULTI stuff */ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { + char exitmsg[150]; + char fullmsg[300]; - char fmtbuf[300]; - char exitmsg[500]; + /* Note that exit message must be rendered before session cleanup */ + /* Render the formatted exit message */ + vsnprintf(exitmsg, sizeof(exitmsg), format, param); + + /* Add the prefix depending on session/auth state */ if (!sessinitdone) { - snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s", - format); + snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg); } else { - snprintf(fmtbuf, sizeof(fmtbuf), + snprintf(fullmsg, sizeof(fullmsg), "Connection to %s@%s:%s exited: %s", cli_opts.username, cli_opts.remotehost, - cli_opts.remoteport, format); + cli_opts.remoteport, exitmsg); } - /* Arguments to the exit printout may be unsafe to use after session_cleanup() */ - vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param); - /* Do the cleanup first, since then the terminal will be reset */ session_cleanup(); /* Avoid printing onwards from terminal cruft */ fprintf(stderr, "\n"); - dropbear_log(LOG_INFO, "%s", exitmsg);; + dropbear_log(LOG_INFO, "%s", fullmsg); exit(exitcode); }
--- a/cli-tcpfwd.c Tue May 24 17:34:10 2016 -0500 +++ b/cli-tcpfwd.c Fri Jun 02 22:57:09 2017 +0800 @@ -234,7 +234,7 @@ char *origaddr = NULL; unsigned int origport; m_list_elem * iter = NULL; - struct TCPFwdEntry *fwd; + struct TCPFwdEntry *fwd = NULL; char portstring[NI_MAXSERV]; int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; @@ -265,7 +265,7 @@ } - if (iter == NULL) { + if (iter == NULL || fwd == NULL) { /* We didn't request forwarding on that port */ cleantext(origaddr); dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
--- a/common-algo.c Tue May 24 17:34:10 2016 -0500 +++ b/common-algo.c Fri Jun 02 22:57:09 2017 +0800 @@ -529,21 +529,6 @@ return NULL; } -static void -try_add_algo(const char *algo_name, algo_type *algos, - const char *algo_desc, algo_type * new_algos, int *num_ret) -{ - algo_type *match_algo = check_algo(algo_name, algos); - if (!match_algo) - { - dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc); - return; - } - - new_algos[*num_ret] = *match_algo; - (*num_ret)++; -} - /* Checks a user provided comma-separated algorithm list for available * options. Any that are not acceptable are removed in-place. Returns the * number of valid algorithms. */ @@ -551,30 +536,43 @@ check_user_algos(const char* user_algo_list, algo_type * algos, const char *algo_desc) { - algo_type new_algos[MAX_PROPOSED_ALGO]; - /* this has two passes. first we sweep through the given list of - * algorithms and mark them as usable=2 in the algo_type[] array... */ - int num_ret = 0; + algo_type new_algos[MAX_PROPOSED_ALGO+1]; char *work_list = m_strdup(user_algo_list); - char *last_name = work_list; + char *start = work_list; char *c; - for (c = work_list; *c; c++) + int n; + /* So we can iterate and look for null terminator */ + memset(new_algos, 0x0, sizeof(new_algos)); + for (c = work_list, n = 0; ; c++) { - if (*c == ',') - { + char oc = *c; + if (n >= MAX_PROPOSED_ALGO) { + dropbear_exit("Too many algorithms '%s'", user_algo_list); + } + if (*c == ',' || *c == '\0') { + algo_type *match_algo = NULL; *c = '\0'; - try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret); + match_algo = check_algo(start, algos); + if (match_algo) { + if (check_algo(start, new_algos)) { + TRACE(("Skip repeated algorithm '%s'", start)) + } else { + new_algos[n] = *match_algo; + n++; + } + } else { + dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", start, algo_desc); + } c++; - last_name = c; + start = c; + } + if (oc == '\0') { + break; } } - try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret); m_free(work_list); - - new_algos[num_ret].name = NULL; - - /* Copy one more as a blank delimiter */ - memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1)); - return num_ret; + /* n+1 to include a null terminator */ + memcpy(algos, new_algos, sizeof(*new_algos) * (n+1)); + return n; } #endif /* DROPBEAR_USER_ALGO_LIST */
--- a/common-channel.c Tue May 24 17:34:10 2016 -0500 +++ b/common-channel.c Fri Jun 02 22:57:09 2017 +0800 @@ -32,7 +32,6 @@ #include "circbuffer.h" #include "dbutil.h" #include "channel.h" -#include "ssh.h" #include "listener.h" #include "runopts.h" #include "netio.h"
--- a/common-session.c Tue May 24 17:34:10 2016 -0500 +++ b/common-session.c Fri Jun 02 22:57:09 2017 +0800 @@ -361,7 +361,7 @@ } if (!done) { - TRACE(("err: %s for '%s'\n", strerror(errno), linebuf)) + TRACE(("error reading remote ident: %s\n", strerror(errno))) ses.remoteclosed(); } else { /* linebuf is already null terminated */
--- a/compat.c Tue May 24 17:34:10 2016 -0500 +++ b/compat.c Fri Jun 02 22:57:09 2017 +0800 @@ -114,8 +114,8 @@ #endif /* HAVE_STRLCPY */ #ifndef HAVE_STRLCAT -/* taken from openbsd-compat for OpenSSH 3.6.1p1 */ -/* "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $" +/* taken from openbsd-compat for OpenSSH 7.2p2 */ +/* "$OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $" * * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters @@ -123,15 +123,12 @@ * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ - size_t -strlcat(dst, src, siz) - char *dst; - const char *src; - size_t siz; +size_t +strlcat(char *dst, const char *src, size_t siz) { - register char *d = dst; - register const char *s = src; - register size_t n = siz; + char *d = dst; + const char *s = src; + size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */
--- a/dbutil.c Tue May 24 17:34:10 2016 -0500 +++ b/dbutil.c Fri Jun 02 22:57:09 2017 +0800 @@ -182,7 +182,7 @@ void dropbear_trace(const char* format, ...) { va_list param; - if (!ses.debug_trace) { + if (!debug_trace) { return; } @@ -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 Tue May 24 17:34:10 2016 -0500 +++ b/dbutil.h Fri Jun 02 22:57:09 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 Tue May 24 17:34:10 2016 -0500 +++ b/debian/changelog Fri Jun 02 22:57:09 2017 +0800 @@ -1,3 +1,15 @@ +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. + + -- Matt Johnston <[email protected]> Thu, 21 Jul 2016 22:51:57 +0800 + dropbear (2016.73-0.1) unstable; urgency=low * New upstream release.
--- a/dropbearkey.c Tue May 24 17:34:10 2016 -0500 +++ b/dropbearkey.c Fri Jun 02 22:57:09 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 Tue May 24 17:34:10 2016 -0500 +++ b/gensignkey.c Fri Jun 02 22:57:09 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 Tue May 24 17:34:10 2016 -0500 +++ b/gensignkey.h Fri Jun 02 22:57:09 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/keyimport.c Tue May 24 17:34:10 2016 -0500 +++ b/keyimport.c Fri Jun 02 22:57:09 2017 +0800 @@ -62,6 +62,8 @@ static int dropbear_write(const char*filename, sign_key * key); static sign_key *dropbear_read(const char* filename); +static int toint(unsigned u); + #if 0 static int sshcom_encrypted(const char *filename, char **comment); static struct ssh2_userkey *sshcom_read(const char *filename, char *passphrase); @@ -243,12 +245,11 @@ if ((*p & 0x1F) == 0x1F) { *id = 0; while (*p & 0x80) { - *id = (*id << 7) | (*p & 0x7F); p++, sourcelen--; if (sourcelen == 0) return -1; + *id = (*id << 7) | (*p & 0x7F); } - *id = (*id << 7) | (*p & 0x7F); p++, sourcelen--; } else { *id = *p & 0x1F; @@ -259,19 +260,26 @@ return -1; if (*p & 0x80) { + unsigned len; int n = *p & 0x7F; p++, sourcelen--; if (sourcelen < n) return -1; - *length = 0; + len = 0; while (n--) - *length = (*length << 8) | (*p++); + len = (len << 8) | (*p++); sourcelen -= n; + *length = toint(len); } else { *length = *p; p++, sourcelen--; } + if (*length < 0) { + printf("Negative ASN.1 length\n"); + return -1; + } + return p - (unsigned char *) source; } @@ -469,7 +477,7 @@ m_burn(buffer, sizeof(buffer)); return ret; - error: +error: m_burn(buffer, sizeof(buffer)); if (ret) { if (ret->keyblob) { @@ -584,8 +592,9 @@ /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */ ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); p += ret; - if (ret < 0 || id != 16) { - errmsg = "ASN.1 decoding failure - wrong password?"; + if (ret < 0 || id != 16 || len < 0 || + key->keyblob+key->keyblob_len-p < len) { + errmsg = "ASN.1 decoding failure"; goto error; } @@ -619,7 +628,7 @@ ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 2 || + if (ret < 0 || id != 2 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; goto error; @@ -685,7 +694,7 @@ &id, &len, &flags); p += ret; /* id==4 for octet string */ - if (ret < 0 || id != 4 || + if (ret < 0 || id != 4 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; goto error; @@ -699,7 +708,7 @@ &id, &len, &flags); p += ret; /* id==0 */ - if (ret < 0 || id != 0) { + if (ret < 0 || id != 0 || len < 0) { errmsg = "ASN.1 decoding failure"; goto error; } @@ -708,7 +717,7 @@ &id, &len, &flags); p += ret; /* id==6 for object */ - if (ret < 0 || id != 6 || + if (ret < 0 || id != 6 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; goto error; @@ -747,7 +756,7 @@ &id, &len, &flags); p += ret; /* id==1 */ - if (ret < 0 || id != 1) { + if (ret < 0 || id != 1 || len < 0) { errmsg = "ASN.1 decoding failure"; goto error; } @@ -756,7 +765,7 @@ &id, &len, &flags); p += ret; /* id==3 for bit string */ - if (ret < 0 || id != 3 || + if (ret < 0 || id != 3 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; goto error; @@ -1381,7 +1390,7 @@ memset(ret->keyblob, 0, ret->keyblob_size); m_free(ret->keyblob); } - memset(&ret, 0, sizeof(ret)); + memset(ret, 0, sizeof(*ret)); m_free(ret); } return NULL; @@ -1409,11 +1418,12 @@ pos = 8; if (key->keyblob_len < pos+4) goto done; /* key is far too short */ - pos += 4 + GET_32BIT(key->keyblob + pos); /* skip key type */ - if (key->keyblob_len < pos+4) + len = toint(GET_32BIT(key->keyblob + pos)); + if (len < 0 || len > key->keyblob_len - pos - 4) goto done; /* key is far too short */ - len = GET_32BIT(key->keyblob + pos); /* find cipher-type length */ - if (key->keyblob_len < pos+4+len) + pos += 4 + len; /* skip key type */ + len = toint(GET_32BIT(key->keyblob + pos)); /* find cipher-type length */ + if (len < 0 || len > key->keyblob_len - pos - 4) goto done; /* cipher type string is incomplete */ if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) answer = 1; @@ -1422,15 +1432,14 @@ *comment = dupstr(key->comment); memset(key->keyblob, 0, key->keyblob_size); m_free(key->keyblob); - memset(&key, 0, sizeof(key)); + memset(key, 0, sizeof(*key)); m_free(key); return answer; } static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) { - int bits; - int bytes; + unsigned bits, bytes; unsigned char *d = (unsigned char *) data; if (len < 4) @@ -1483,7 +1492,7 @@ struct ssh2_userkey *ret = NULL, *retkey; const struct ssh_signkey *alg; unsigned char *blob = NULL; - int blobsize, publen, privlen; + int blobsize = 0, publen, privlen; if (!key) return NULL; @@ -1603,8 +1612,8 @@ /* * Strip away the containing string to get to the real meat. */ - len = GET_32BIT(ciphertext); - if (len > cipherlen-4) { + len = toint(GET_32BIT(ciphertext)); + if (len < 0 || len > cipherlen-4) { errmsg = "containing string was ill-formed"; goto error; } @@ -1671,7 +1680,8 @@ publen = pos; pos += put_mp(blob+pos, x.start, x.bytes); privlen = pos - publen; - } + } else + return NULL; dropbear_assert(privlen > 0); /* should have bombed by now if not */ @@ -1695,7 +1705,7 @@ } memset(key->keyblob, 0, key->keyblob_size); m_free(key->keyblob); - memset(&key, 0, sizeof(key)); + memset(key, 0, sizeof(*key)); m_free(key); return ret; } @@ -1908,3 +1918,27 @@ return ret; } #endif /* ssh.com stuff disabled */ + +/* From PuTTY misc.c */ +static int toint(unsigned u) +{ + /* + * Convert an unsigned to an int, without running into the + * undefined behaviour which happens by the strict C standard if + * the value overflows. You'd hope that sensible compilers would + * do the sensible thing in response to a cast, but actually I + * don't trust modern compilers not to do silly things like + * assuming that _obviously_ you wouldn't have caused an overflow + * and so they can elide an 'if (i < 0)' test immediately after + * the cast. + * + * Sensible compilers ought of course to optimise this entire + * function into 'just return the input value'! + */ + if (u <= (unsigned)INT_MAX) + return (int)u; + else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */ + return INT_MIN + (int)(u - (unsigned)INT_MIN); + else + return INT_MIN; /* fallback; should never occur on binary machines */ +}
--- a/loginrec.c Tue May 24 17:34:10 2016 -0500 +++ b/loginrec.c Fri Jun 02 22:57:09 2017 +0800 @@ -706,7 +706,7 @@ } (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET); - if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) + if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) dropbear_log(LOG_WARNING, "utmp_write_direct: error writing %s: %s", UTMP_FILE, strerror(errno)); @@ -895,7 +895,7 @@ return 0; } if (fstat(fd, &buf) == 0) - if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) { + if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { ftruncate(fd, buf.st_size); dropbear_log(LOG_WARNING, "wtmp_write: problem writing %s: %s", WTMP_FILE, strerror(errno)); @@ -1062,7 +1062,7 @@ } if (fstat(fd, &buf) == 0) - if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) { + if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) { ftruncate(fd, buf.st_size); dropbear_log(LOG_WARNING, "wtmpx_write: problem writing %s: %s", WTMPX_FILE, strerror(errno)); @@ -1351,7 +1351,7 @@ return(0); /* write the entry */ - if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) { + if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) { close(fd); dropbear_log(LOG_WARNING, "lastlog_write_filemode: Error writing to %s: %s", LASTLOG_FILE, strerror(errno));
--- a/netio.c Tue May 24 17:34:10 2016 -0500 +++ b/netio.c Fri Jun 02 22:57:09 2017 +0800 @@ -61,7 +61,7 @@ { dropbear_assert(c->sock == -1); - c->sock = socket(c->res_iter->ai_family, c->res_iter->ai_socktype, c->res_iter->ai_protocol); + c->sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol); if (c->sock < 0) { continue; }
--- a/scpmisc.h Tue May 24 17:34:10 2016 -0500 +++ b/scpmisc.h Fri Jun 02 22:57:09 2017 +0800 @@ -12,9 +12,6 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* actually from atomicio, but is only used in scp code */ -#define vwrite (ssize_t (*)(int, void *, size_t))write - char *chop(char *); char *strdelim(char **); void set_nonblock(int);
--- a/svr-authpubkey.c Tue May 24 17:34:10 2016 -0500 +++ b/svr-authpubkey.c Fri Jun 02 22:57:09 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 Tue May 24 17:34:10 2016 -0500 +++ b/svr-authpubkeyoptions.c Fri Jun 02 22:57:09 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-chansession.c Tue May 24 17:34:10 2016 -0500 +++ b/svr-chansession.c Fri Jun 02 22:57:09 2017 +0800 @@ -634,7 +634,7 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess, int iscmd, int issubsys) { - unsigned int cmdlen; + unsigned int cmdlen = 0; int ret; TRACE(("enter sessioncommand"))
--- a/svr-kex.c Tue May 24 17:34:10 2016 -0500 +++ b/svr-kex.c Fri Jun 02 22:57:09 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-session.c Tue May 24 17:34:10 2016 -0500 +++ b/svr-session.c Fri Jun 02 22:57:09 2017 +0800 @@ -144,31 +144,33 @@ /* failure exit - format must be <= 100 chars */ void svr_dropbear_exit(int exitcode, const char* format, va_list param) { - - char fmtbuf[300]; + char exitmsg[150]; + char fullmsg[300]; int i; + /* Render the formatted exit message */ + vsnprintf(exitmsg, sizeof(exitmsg), format, param); + + /* Add the prefix depending on session/auth state */ if (!sessinitdone) { /* before session init */ - snprintf(fmtbuf, sizeof(fmtbuf), - "Early exit: %s", format); + snprintf(fullmsg, sizeof(fullmsg), "Early exit: %s", exitmsg); } else if (ses.authstate.authdone) { /* user has authenticated */ - snprintf(fmtbuf, sizeof(fmtbuf), + snprintf(fullmsg, sizeof(fullmsg), "Exit (%s): %s", - ses.authstate.pw_name, format); + ses.authstate.pw_name, exitmsg); } else if (ses.authstate.pw_name) { /* we have a potential user */ - snprintf(fmtbuf, sizeof(fmtbuf), + snprintf(fullmsg, sizeof(fullmsg), "Exit before auth (user '%s', %u fails): %s", - ses.authstate.pw_name, ses.authstate.failcount, format); + ses.authstate.pw_name, ses.authstate.failcount, exitmsg); } else { /* before userauth */ - snprintf(fmtbuf, sizeof(fmtbuf), - "Exit before auth: %s", format); + snprintf(fullmsg, sizeof(fullmsg), "Exit before auth: %s", exitmsg); } - _dropbear_log(LOG_INFO, fmtbuf, param); + dropbear_log(LOG_INFO, "%s", fullmsg); #if DROPBEAR_VFORK /* For uclinux only the main server process should cleanup - we don't want
--- a/svr-tcpfwd.c Tue May 24 17:34:10 2016 -0500 +++ b/svr-tcpfwd.c Fri Jun 02 22:57:09 2017 +0800 @@ -199,7 +199,7 @@ } else { - tcpinfo->listenaddr = request_addr; + tcpinfo->listenaddr = m_strdup(request_addr); } ret = listen_tcpfwd(tcpinfo);
--- a/sysoptions.h Tue May 24 17:34:10 2016 -0500 +++ b/sysoptions.h Fri Jun 02 22:57:09 2017 +0800 @@ -4,7 +4,7 @@ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "2016.73" +#define DROPBEAR_VERSION "2017.75" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION