From 1951e1b5a4588596d383aea91198d9da715e077b Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Wed, 1 Jul 2015 19:46:19 +0200 Subject: [PATCH] Security fixes released with openssh-6.9 * XSECURITY restrictions bypass under certain conditions in ssh(1) (#1238231) * https://anongit.mindrot.org/openssh.git/commit/?h=V_6_9&id=1bf477d3cdf1a864646d59820878783d42357a1d * weakness of agent locking (ssh-add -x) to password guessing (#1238238) * https://anongit.mindrot.org/openssh.git/commit/?h=V_6_9&id=9173d0fbe44de7ebcad8a15618e13a8b8d78902e * https://anongit.mindrot.org/openssh.git/commit/?h=V_6_9&id=e97201feca10b5196da35819ae516d0b87cf3a50 --- openssh-6.6p1-security-from-6.9.patch | 214 ++++++++++++++++++++++++++ openssh.spec | 5 + 2 files changed, 219 insertions(+) create mode 100644 openssh-6.6p1-security-from-6.9.patch diff --git a/openssh-6.6p1-security-from-6.9.patch b/openssh-6.6p1-security-from-6.9.patch new file mode 100644 index 0000000..3435cf2 --- /dev/null +++ b/openssh-6.6p1-security-from-6.9.patch @@ -0,0 +1,214 @@ +diff -up openssh-6.6p1/channels.c.security openssh-6.6p1/channels.c +--- openssh-6.6p1/channels.c.security 2015-07-01 19:27:08.521162690 +0200 ++++ openssh-6.6p1/channels.c 2015-07-01 19:27:08.597162521 +0200 +@@ -151,6 +151,9 @@ static char *x11_saved_proto = NULL; + static char *x11_saved_data = NULL; + static u_int x11_saved_data_len = 0; + ++/* Deadline after which all X11 connections are refused */ ++static u_int x11_refuse_time; ++ + /* + * Fake X11 authentication data. This is what the server will be sending us; + * we should replace any occurrences of this by the real data. +@@ -894,6 +897,13 @@ x11_open_helper(Buffer *b) + u_char *ucp; + u_int proto_len, data_len; + ++ /* Is this being called after the refusal deadline? */ ++ if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) { ++ verbose("Rejected X11 connection after ForwardX11Timeout " ++ "expired"); ++ return -1; ++ } ++ + /* Check if the fixed size part of the packet is in buffer. */ + if (buffer_len(b) < 12) + return 0; +@@ -1457,6 +1467,12 @@ channel_set_reuseaddr(int fd) + error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno)); + } + ++void ++channel_set_x11_refuse_time(u_int refuse_time) ++{ ++ x11_refuse_time = refuse_time; ++} ++ + /* + * This socket is listening for connections to a forwarded TCP/IP port. + */ +diff -up openssh-6.6p1/channels.h.security openssh-6.6p1/channels.h +--- openssh-6.6p1/channels.h.security 2015-07-01 19:27:08.597162521 +0200 ++++ openssh-6.6p1/channels.h 2015-07-01 19:43:32.900950560 +0200 +@@ -279,6 +279,7 @@ int permitopen_port(const char *); + + /* x11 forwarding */ + ++void channel_set_x11_refuse_time(u_int); + int x11_connect_display(void); + int x11_create_display_inet(int, int, int, u_int *, int **); + void x11_input_open(int, u_int32_t, void *); +diff -up openssh-6.6p1/clientloop.c.security openssh-6.6p1/clientloop.c +--- openssh-6.6p1/clientloop.c.security 2015-07-01 19:27:08.540162648 +0200 ++++ openssh-6.6p1/clientloop.c 2015-07-01 19:44:51.139761508 +0200 +@@ -164,7 +164,7 @@ static int connection_in; /* Connection + static int connection_out; /* Connection to server (output). */ + static int need_rekeying; /* Set to non-zero if rekeying is requested. */ + static int session_closed; /* In SSH2: login session closed. */ +-static int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ ++static u_int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ + + static void client_init_dispatch(void); + int session_ident = -1; +@@ -302,7 +302,8 @@ client_x11_display_valid(const char *dis + return 1; + } + +-#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" ++#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" ++#define X11_TIMEOUT_SLACK 60 + void + client_x11_get_proto(const char *display, const char *xauth_path, + u_int trusted, u_int timeout, char **_proto, char **_data) +@@ -315,7 +316,7 @@ client_x11_get_proto(const char *display + int got_data = 0, generated = 0, do_unlink = 0, i; + char *xauthdir, *xauthfile; + struct stat st; +- u_int now; ++ u_int now, x11_timeout_real; + + xauthdir = xauthfile = NULL; + *_proto = proto; +@@ -348,6 +349,15 @@ client_x11_get_proto(const char *display + xauthdir = xmalloc(MAXPATHLEN); + xauthfile = xmalloc(MAXPATHLEN); + mktemp_proto(xauthdir, MAXPATHLEN); ++ /* ++ * The authentication cookie should briefly outlive ++ * ssh's willingness to forward X11 connections to ++ * avoid nasty fail-open behaviour in the X server. ++ */ ++ if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) ++ x11_timeout_real = UINT_MAX; ++ else ++ x11_timeout_real = timeout + X11_TIMEOUT_SLACK; + if (mkdtemp(xauthdir) != NULL) { + do_unlink = 1; + snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", +@@ -355,17 +365,20 @@ client_x11_get_proto(const char *display + snprintf(cmd, sizeof(cmd), + "%s -f %s generate %s " SSH_X11_PROTO + " untrusted timeout %u 2>" _PATH_DEVNULL, +- xauth_path, xauthfile, display, timeout); ++ xauth_path, xauthfile, display, ++ x11_timeout_real); + debug2("x11_get_proto: %s", cmd); +- if (system(cmd) == 0) +- generated = 1; + if (x11_refuse_time == 0) { + now = monotime() + 1; + if (UINT_MAX - timeout < now) + x11_refuse_time = UINT_MAX; + else + x11_refuse_time = now + timeout; ++ channel_set_x11_refuse_time( ++ x11_refuse_time); + } ++ if (system(cmd) == 0) ++ generated = 1; + } + } + +@@ -1884,7 +1897,7 @@ client_request_x11(const char *request_t + "malicious server."); + return NULL; + } +- if (x11_refuse_time != 0 && monotime() >= x11_refuse_time) { ++ if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) { + verbose("Rejected X11 connection after ForwardX11Timeout " + "expired"); + return NULL; +diff -up openssh-6.6p1/ssh-agent.c.security openssh-6.6p1/ssh-agent.c +--- openssh-6.6p1/ssh-agent.c.security 2015-07-01 19:27:08.597162521 +0200 ++++ openssh-6.6p1/ssh-agent.c 2015-07-01 19:42:35.691088800 +0200 +@@ -64,6 +64,9 @@ + #include + #include + #include ++#ifdef HAVE_UTIL_H ++#include ++#endif + + #include "xmalloc.h" + #include "ssh.h" +@@ -129,8 +130,12 @@ char socket_name[MAXPATHLEN]; + char socket_dir[MAXPATHLEN]; + + /* locking */ ++#define LOCK_SIZE 32 ++#define LOCK_SALT_SIZE 16 ++#define LOCK_ROUNDS 1 + int locked = 0; +-char *lock_passwd = NULL; ++char lock_passwd[LOCK_SIZE]; ++char lock_salt[LOCK_SALT_SIZE]; + + extern char *__progname; + +@@ -548,22 +553,45 @@ send: + static void + process_lock_agent(SocketEntry *e, int lock) + { +- int success = 0; +- char *passwd; ++ int success = 0, delay; ++ char *passwd, passwdhash[LOCK_SIZE]; ++ static u_int fail_count = 0; ++ size_t pwlen; + + passwd = buffer_get_string(&e->request, NULL); +- if (locked && !lock && strcmp(passwd, lock_passwd) == 0) { +- locked = 0; +- explicit_bzero(lock_passwd, strlen(lock_passwd)); +- free(lock_passwd); +- lock_passwd = NULL; +- success = 1; ++ pwlen = strlen(passwd); ++ if (pwlen == 0) { ++ debug("empty password not supported"); ++ } else if (locked && !lock) { ++ if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt), ++ passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0) ++ fatal("bcrypt_pbkdf"); ++ if (timingsafe_bcmp(passwdhash, lock_passwd, LOCK_SIZE) == 0) { ++ debug("agent unlocked"); ++ locked = 0; ++ fail_count = 0; ++ explicit_bzero(lock_passwd, sizeof(lock_passwd)); ++ success = 1; ++ } else { ++ /* delay in 0.1s increments up to 10s */ ++ if (fail_count < 100) ++ fail_count++; ++ delay = 100000 * fail_count; ++ debug("unlock failed, delaying %0.1lf seconds", ++ (double)delay/1000000); ++ usleep(delay); ++ } ++ explicit_bzero(passwdhash, sizeof(passwdhash)); + } else if (!locked && lock) { ++ debug("agent locked"); + locked = 1; +- lock_passwd = xstrdup(passwd); ++ arc4random_buf(lock_salt, sizeof(lock_salt)); ++ if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt), ++ lock_passwd, sizeof(lock_passwd), LOCK_ROUNDS) < 0) ++ fatal("bcrypt_pbkdf"); + success = 1; + } +- explicit_bzero(passwd, strlen(passwd)); ++ explicit_bzero(passwd, pwlen); + free(passwd); + + buffer_put_int(&e->output, 1); diff --git a/openssh.spec b/openssh.spec index c2de683..ae4dd4b 100644 --- a/openssh.spec +++ b/openssh.spec @@ -226,6 +226,10 @@ Patch920: openssh-6.6.1p1-ip-port-config-parser.patch Patch921: openssh-6.7p1-fix-ssh-copy-id-on-non-sh-shell.patch # Solve issue with ssh-copy-id and keys without trailing newline (#1093168) Patch922: openssh-6.7p1-ssh-copy-id-truncated-keys.patch +# Security fixes backported from openssh-6.9 +# XSECURITY restrictions bypass under certain conditions in ssh(1) (#1238231) +# weakness of agent locking (ssh-add -x) to password guessing (#1238238) +Patch923: openssh-6.6p1-security-from-6.9.patch License: BSD Group: Applications/Internet @@ -441,6 +445,7 @@ popd %patch802 -p1 -b .GSSAPIEnablek5users %patch921 -p1 -b .ssh-copy-id %patch922 -p1 -b .newline +%patch923 -p1 -b .security %patch200 -p1 -b .audit %patch201 -p1 -b .audit-fps